Line data Source code
1 : #include <sys/socket.h>
2 : #include <netinet/in.h>
3 : #include "fd_netdb.h"
4 : #include <net/if.h>
5 : #include <arpa/inet.h>
6 : #include <ctype.h>
7 : #include <stdlib.h>
8 : #include <string.h>
9 : #include <fcntl.h>
10 : #include <unistd.h>
11 : #include <pthread.h>
12 : #include <errno.h>
13 : #include "fd_resolv.h"
14 : #include "fd_lookup.h"
15 : #include "fd_io_readline.h"
16 : #include "../../util/cstr/fd_cstr.h"
17 : #include "../../util/log/fd_log.h"
18 : #include "../../util/io/fd_io.h"
19 : #include "../../util/net/fd_ip6.h"
20 :
21 : static int
22 0 : is_valid_hostname( char const * host ) {
23 0 : uchar const * s;
24 0 : if( strnlen( host, 255 )-1 >= 254 ) return 0;
25 0 : for( s=(void *)host; *s>=0x80 || *s=='.' || *s=='-' || fd_isalnum( *s ); s++ );
26 0 : return !*s;
27 0 : }
28 :
29 : static int
30 : name_from_null( struct address buf[ static 2 ],
31 : char const * name,
32 : int family,
33 0 : int flags ) {
34 0 : int cnt = 0;
35 0 : if( name ) return 0;
36 0 : if( flags & FD_AI_PASSIVE ) {
37 0 : if( family != AF_INET6 )
38 0 : buf[cnt++] = (struct address){ .family = AF_INET };
39 0 : if( family != AF_INET )
40 0 : buf[cnt++] = (struct address){ .family = AF_INET6 };
41 0 : } else {
42 0 : if( family != AF_INET6 )
43 0 : buf[cnt++] = (struct address){ .family = AF_INET, .addr = { 127,0,0,1 } };
44 0 : if( family != AF_INET )
45 0 : buf[cnt++] = (struct address){ .family = AF_INET6, .addr = { [15] = 1 } };
46 0 : }
47 0 : return cnt;
48 0 : }
49 :
50 : static int
51 : name_from_numeric( struct address buf[ static 1 ],
52 : char const * name,
53 0 : int family ) {
54 0 : return fd_lookup_ipliteral( buf, name, family );
55 0 : }
56 :
57 : static int
58 : name_from_hosts( struct address buf[ static MAXADDRS ],
59 : char canon[ static 256 ],
60 : char const * name,
61 0 : int family ) {
62 0 : ulong l = strlen( name );
63 0 : int cnt = 0, badfam = 0, have_canon = 0;
64 :
65 0 : if( fd_etc_hosts_fd<0 ) return 0;
66 :
67 0 : if( FD_UNLIKELY( -1==lseek( fd_etc_hosts_fd, 0, SEEK_SET ) ) ) {
68 0 : FD_LOG_ERR(( "lseek(/etc/hosts,0,SEEK_SET) failed (%i-%s)", errno, fd_io_strerror( errno ) ));
69 0 : }
70 :
71 0 : uchar rbuf[1032];
72 0 : fd_io_buffered_istream_t istream[1];
73 0 : fd_io_buffered_istream_init( istream, fd_etc_hosts_fd, rbuf, sizeof(rbuf) );
74 :
75 0 : char line[512];
76 0 : while( cnt < MAXADDRS ) {
77 0 : int err;
78 0 : if( !fd_io_fgets( line, sizeof(line), istream, &err ) ) break;
79 :
80 0 : char *p, *z;
81 :
82 0 : if( (p=strchr( line, '#' )) ) *p++='\n', *p=0;
83 0 : for( p=line+1; (p=strstr( p, name )) &&
84 0 : (!fd_isspace(p[-1]) || !fd_isspace(p[l])); p++ );
85 0 : if( !p ) continue;
86 :
87 : /* Isolate IP address to parse */
88 0 : for( p=line; *p && !fd_isspace(*p); p++ );
89 0 : *p++ = 0;
90 0 : switch( name_from_numeric( buf+cnt, line, family ) ) {
91 0 : case 1:
92 0 : cnt++;
93 0 : break;
94 0 : case 0:
95 0 : continue;
96 0 : default:
97 0 : badfam = FD_EAI_NODATA;
98 0 : break;
99 0 : }
100 :
101 0 : if( have_canon ) continue;
102 :
103 : /* Extract first name as canonical name */
104 0 : for( ; *p && fd_isspace(*p); p++ );
105 0 : for( z=p; *z && !fd_isspace(*z); z++ );
106 0 : *z = 0;
107 0 : if( is_valid_hostname( p ) ) {
108 0 : have_canon = 1;
109 0 : memcpy( canon, p, (ulong)( z-p+1 ) );
110 0 : }
111 0 : }
112 0 : return cnt ? cnt : badfam;
113 0 : }
114 :
115 : struct dpc_ctx {
116 : struct address *addrs;
117 : char *canon;
118 : int cnt;
119 : int rrtype;
120 : };
121 :
122 0 : #define RR_A 1
123 0 : #define RR_CNAME 5
124 0 : #define RR_AAAA 28
125 :
126 : #define ABUF_SIZE 4800
127 :
128 : static int
129 : dns_parse_callback( void * c,
130 : int rr,
131 : void const * data,
132 : int len,
133 : void const * packet,
134 0 : int plen ) {
135 0 : char tmp[256];
136 0 : int family = AF_UNSPEC;
137 0 : struct dpc_ctx *ctx = c;
138 0 : if( rr == RR_CNAME ) {
139 0 : if( fd_dn_expand( packet, (uchar const *)packet + plen,
140 0 : data, tmp, sizeof tmp ) > 0 && is_valid_hostname( tmp ) )
141 0 : strcpy( ctx->canon, tmp );
142 0 : return 0;
143 0 : }
144 0 : if( ctx->cnt >= MAXADDRS ) return 0;
145 0 : if( rr != ctx->rrtype ) return 0;
146 0 : switch( rr ) {
147 0 : case RR_A:
148 0 : if( len != 4 ) return -1;
149 0 : family = AF_INET;
150 0 : break;
151 0 : case RR_AAAA:
152 0 : if( len != 16 ) return -1;
153 0 : family = AF_INET6;
154 0 : break;
155 0 : }
156 0 : ctx->addrs[ctx->cnt].family = family;
157 0 : ctx->addrs[ctx->cnt].scopeid = 0;
158 0 : memcpy( ctx->addrs[ctx->cnt++].addr, data, (ulong)len );
159 0 : return 0;
160 0 : }
161 :
162 : static int
163 : name_from_dns( struct address buf[ static MAXADDRS ],
164 : char canon[ static 256 ],
165 : char const * name,
166 : int family,
167 0 : fd_resolvconf_t const * conf ) {
168 0 : uchar qbuf[2][280], abuf[2][ABUF_SIZE];
169 0 : uchar const * qp[2] = { qbuf[0], qbuf[1] };
170 0 : uchar * ap[2] = { abuf[0], abuf[1] };
171 0 : int qlens[2], alens[2], qtypes[2];
172 0 : int nq = 0;
173 0 : struct dpc_ctx ctx = { .addrs = buf, .canon = canon };
174 0 : static const struct { int af; int rr; } afrr[2] = {
175 0 : { .af = AF_INET6, .rr = RR_A },
176 0 : { .af = AF_INET, .rr = RR_AAAA },
177 0 : };
178 :
179 0 : for( int i=0; i<2; i++ ) {
180 0 : if( family != afrr[i].af ) {
181 0 : qlens[nq] = fd_res_mkquery( 0, name, 1, afrr[i].rr,
182 0 : qbuf[nq], sizeof *qbuf );
183 0 : if( qlens[nq] == -1 )
184 0 : return 0;
185 0 : qtypes[nq] = afrr[i].rr;
186 0 : qbuf[nq][3] = 0; /* don't need AD flag */
187 : /* Ensure query IDs are distinct. */
188 0 : if( nq && qbuf[nq][0] == qbuf[0][0] )
189 0 : qbuf[nq][0]++;
190 0 : nq++;
191 0 : }
192 0 : }
193 :
194 0 : if( fd_res_msend_rc( nq, qp, qlens, ap, alens, sizeof *abuf, conf )<0 )
195 0 : return FD_EAI_SYSTEM-errno;
196 :
197 0 : for( int i=0; i<nq; i++ ) {
198 0 : if( alens[i] < 4 || (abuf[i][3] & 15) == 2 ) return FD_EAI_AGAIN;
199 0 : if( (abuf[i][3] & 15) == 3 ) return 0;
200 0 : if( (abuf[i][3] & 15) != 0 ) return FD_EAI_FAIL;
201 0 : }
202 :
203 0 : for( int i=nq-1; i>=0; i-- ) {
204 0 : ctx.rrtype = qtypes[i];
205 0 : if( alens[i] > (int)sizeof(abuf[i]) ) alens[i] = sizeof abuf[i];
206 0 : fd_dns_parse( abuf[i], alens[i], dns_parse_callback, &ctx );
207 0 : }
208 :
209 0 : if( ctx.cnt ) return ctx.cnt;
210 0 : return FD_EAI_NODATA;
211 0 : }
212 :
213 : static int
214 : name_from_dns_search( struct address buf[ static MAXADDRS ],
215 : char canon[ static 256 ],
216 : char const * name,
217 0 : int family ) {
218 0 : fd_resolvconf_t conf;
219 0 : size_t l;
220 :
221 0 : if( fd_get_resolv_conf( &conf ) < 0 ) return -1;
222 :
223 : /* Count dots, suppress search when >=ndots or name ends in
224 : * a dot, which is an explicit request for global scope. */
225 0 : for( l=0; name[l]; l++ ) {}
226 :
227 : /* Strip final dot for canon, fail if multiple trailing dots. */
228 0 : if( name[l-1]=='.' ) l--;
229 0 : if( !l || name[l-1]=='.' ) return FD_EAI_NONAME;
230 :
231 : /* This can never happen; the caller already checked length. */
232 0 : if( l >= 256 ) return FD_EAI_NONAME;
233 :
234 : /* Name with search domain appended is setup in canon[]. This both
235 : * provides the desired default canonical name (if the requested
236 : * name is not a CNAME record) and serves as a buffer for passing
237 : * the full requested name to name_from_dns. */
238 0 : memcpy( canon, name, l );
239 0 : canon[l] = '.';
240 :
241 0 : canon[l] = 0;
242 0 : return name_from_dns( buf, canon, name, family, &conf );
243 0 : }
244 :
245 : static const struct policy {
246 : uchar addr[16];
247 : uchar len, mask;
248 : uchar prec, label;
249 : } defpolicy[] = {
250 : { {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01},
251 : 15, 0xff, 50, 0 },
252 : { {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff},
253 : 11, 0xff, 35, 4 },
254 : { {0x20,0x02}, 1, 0xff, 30, 2 },
255 : { {0x20,0x01}, 3, 0xff, 5, 5 },
256 : { {0xfc}, 0, 0xfe, 3, 13 },
257 : #if 0
258 : /* These are deprecated and/or returned to the address
259 : * pool, so despite the RFC, treating them as special
260 : * is probably wrong. */
261 : { "", 11, 0xff, 1, 3 },
262 : { "\xfe\xc0", 1, 0xc0, 1, 11 },
263 : { "\x3f\xfe", 1, 0xff, 1, 12 },
264 : #endif
265 : /* Last rule must match all addresses to stop loop. */
266 : { "", 0, 0, 40, 1 },
267 : };
268 :
269 : static const struct policy *
270 0 : policyof( struct in6_addr const * a ) {
271 0 : for( int i=0; ; i++ ) {
272 0 : if( memcmp( a->s6_addr, defpolicy[i].addr, defpolicy[i].len ) )
273 0 : continue;
274 0 : if( (a->s6_addr[defpolicy[i].len] & defpolicy[i].mask)
275 0 : != defpolicy[i].addr[defpolicy[i].len] )
276 0 : continue;
277 0 : return defpolicy+i;
278 0 : }
279 0 : }
280 :
281 : static int
282 0 : labelof( struct in6_addr const * a ) {
283 0 : return policyof( a )->label;
284 0 : }
285 :
286 : static int
287 0 : scopeof( struct in6_addr const * a ) {
288 0 : if( IN6_IS_ADDR_MULTICAST(a) ) return a->s6_addr[1] & 15;
289 0 : if( IN6_IS_ADDR_LINKLOCAL(a) ) return 2;
290 0 : if( IN6_IS_ADDR_LOOPBACK (a) ) return 2;
291 0 : if( IN6_IS_ADDR_SITELOCAL(a) ) return 5;
292 0 : return 14;
293 0 : }
294 :
295 : static int
296 : prefixmatch( struct in6_addr const * s,
297 0 : struct in6_addr const * d ) {
298 : /* FIXME: The common prefix length should be limited to no greater
299 : * than the nominal length of the prefix portion of the source
300 : * address. However the definition of the source prefix length is
301 : * not clear and thus this limiting is not yet implemented. */
302 0 : uint i;
303 0 : for( i=0; i<128 && !((s->s6_addr[i/8]^d->s6_addr[i/8])&(128>>(i%8))); i++ );
304 0 : return (int)i;
305 0 : }
306 :
307 0 : #define DAS_USABLE 0x40000000
308 0 : #define DAS_MATCHINGSCOPE 0x20000000
309 0 : #define DAS_MATCHINGLABEL 0x10000000
310 0 : #define DAS_PREC_SHIFT 20
311 0 : #define DAS_SCOPE_SHIFT 16
312 0 : #define DAS_PREFIX_SHIFT 8
313 0 : #define DAS_ORDER_SHIFT 0
314 :
315 : static int
316 : addrcmp( void const * _a,
317 0 : void const * _b ) {
318 0 : struct address const * a = _a, *b = _b;
319 0 : return b->sortkey - a->sortkey;
320 0 : }
321 :
322 : int
323 : fd_lookup_name( struct address buf[ static MAXADDRS ],
324 : char canon[ static 256 ],
325 : char const * name,
326 : int family,
327 0 : int flags ) {
328 0 : int cnt = 0, i, j;
329 :
330 0 : *canon = 0;
331 0 : if( name ) {
332 : /* reject empty name and check len so it fits into temp bufs */
333 0 : size_t l = strnlen( name, 255 );
334 0 : if( l-1 >= 254 )
335 0 : return FD_EAI_NONAME;
336 0 : memcpy( canon, name, l+1 );
337 0 : }
338 :
339 : /* Procedurally, a request for v6 addresses with the v4-mapped
340 : * flag set is like a request for unspecified family, followed
341 : * by filtering of the results. */
342 0 : if( flags & FD_AI_V4MAPPED ) {
343 0 : if( family == AF_INET6 ) family = AF_UNSPEC;
344 0 : else flags -= FD_AI_V4MAPPED;
345 0 : }
346 :
347 : /* Try each backend until there's at least one result. */
348 0 : cnt = name_from_null( buf, name, family, flags );
349 0 : if( !cnt ) cnt = name_from_numeric( buf, name, family );
350 0 : if( !cnt && !(flags & FD_AI_NUMERICHOST) ) {
351 0 : cnt = name_from_hosts( buf, canon, name, family );
352 0 : if( !cnt ) cnt = name_from_dns_search( buf, canon, name, family );
353 0 : }
354 0 : if( cnt<=0 ) return cnt ? cnt : FD_EAI_NONAME;
355 :
356 : /* Filter/transform results for v4-mapped lookup, if requested. */
357 0 : if( flags & FD_AI_V4MAPPED ) {
358 0 : if( !(flags & FD_AI_ALL) ) {
359 : /* If any v6 results exist, remove v4 results. */
360 0 : for( i=0; i<cnt && buf[i].family != AF_INET6; i++ );
361 0 : if( i<cnt ) {
362 0 : for( j=0; i<cnt; i++ ) {
363 0 : if( buf[i].family == AF_INET6 )
364 0 : buf[j++] = buf[i];
365 0 : }
366 0 : cnt = i = j;
367 0 : }
368 0 : }
369 : /* Translate any remaining v4 results to v6 */
370 0 : for( int i=0; i<cnt; i++ ) {
371 0 : if( buf[i].family != AF_INET ) continue;
372 0 : uint ip4_addr = FD_LOAD( uint, buf[i].addr );
373 0 : fd_ip6_addr_ip4_mapped( buf[i].addr, ip4_addr );
374 0 : buf[i].family = AF_INET6;
375 0 : }
376 0 : }
377 :
378 : /* No further processing is needed if there are fewer than 2
379 : * results or if there are only IPv4 results. */
380 0 : if( cnt<2 || family==AF_INET ) return cnt;
381 0 : for( i=0; i<cnt; i++ ) if( buf[i].family != AF_INET ) break;
382 0 : if( i==cnt ) return cnt;
383 :
384 : /* The following implements a subset of RFC 3484/6724 destination
385 : * address selection by generating a single 31-bit sort key for
386 : * each address. Rules 3, 4, and 7 are omitted for having
387 : * excessive runtime and code size cost and dubious benefit.
388 : * So far the label/precedence table cannot be customized. */
389 0 : for( int i=0; i<cnt; i++ ) {
390 0 : int family = buf[i].family;
391 0 : int key = 0;
392 0 : struct sockaddr_in6 sa6 = { 0 }, da6 = {
393 0 : .sin6_family = AF_INET6,
394 0 : .sin6_scope_id = buf[i].scopeid,
395 0 : .sin6_port = 65535
396 0 : };
397 0 : struct sockaddr_in sa4 = { 0 }, da4 = {
398 0 : .sin_family = AF_INET,
399 0 : .sin_port = 65535
400 0 : };
401 0 : void *sa, *da;
402 0 : socklen_t salen, dalen;
403 0 : if( family == AF_INET6 ) {
404 0 : memcpy( da6.sin6_addr.s6_addr, buf[i].addr, 16 );
405 0 : da = &da6; dalen = sizeof da6;
406 0 : sa = &sa6; salen = sizeof sa6;
407 0 : } else {
408 0 : uint ip4_addr = FD_LOAD( uint, buf[i].addr );
409 0 : fd_ip6_addr_ip4_mapped( sa6.sin6_addr.s6_addr, ip4_addr );
410 0 : fd_ip6_addr_ip4_mapped( da6.sin6_addr.s6_addr, ip4_addr );
411 0 : memcpy( &da4.sin_addr, buf[i].addr, 4 );
412 0 : da = &da4; dalen = sizeof da4;
413 0 : sa = &sa4; salen = sizeof sa4;
414 0 : }
415 0 : const struct policy *dpolicy = policyof( &da6.sin6_addr );
416 0 : int dscope = scopeof( &da6.sin6_addr );
417 0 : int dlabel = dpolicy->label;
418 0 : int dprec = dpolicy->prec;
419 0 : int prefixlen = 0;
420 0 : int fd = socket( family, SOCK_DGRAM|SOCK_CLOEXEC, IPPROTO_UDP );
421 0 : if( fd >= 0 ) {
422 0 : if( !connect( fd, da, dalen ) ) {
423 0 : key |= DAS_USABLE;
424 0 : if( !getsockname( fd, sa, &salen ) ) {
425 0 : if( family == AF_INET ) memcpy(
426 0 : sa6.sin6_addr.s6_addr+12,
427 0 : &sa4.sin_addr, 4);
428 0 : if( dscope == scopeof( &sa6.sin6_addr ) )
429 0 : key |= DAS_MATCHINGSCOPE;
430 0 : if( dlabel == labelof( &sa6.sin6_addr ) )
431 0 : key |= DAS_MATCHINGLABEL;
432 0 : prefixlen = prefixmatch( &sa6.sin6_addr, &da6.sin6_addr );
433 0 : }
434 0 : }
435 0 : close( fd );
436 0 : }
437 0 : key |= dprec << DAS_PREC_SHIFT;
438 0 : key |= (15-dscope) << DAS_SCOPE_SHIFT;
439 0 : key |= prefixlen << DAS_PREFIX_SHIFT;
440 0 : key |= (MAXADDRS-i) << DAS_ORDER_SHIFT;
441 0 : buf[i].sortkey = key;
442 0 : }
443 0 : qsort( buf, (ulong)cnt, sizeof *buf, addrcmp );
444 :
445 0 : return cnt;
446 0 : }
|