|
1 /* $KAME: getaddrinfo.c,v 1.15 2000/07/09 04:37:24 itojun Exp $ */ |
|
2 |
|
3 /* |
|
4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. |
|
5 * All rights reserved. |
|
6 * |
|
7 * Redistribution and use in source and binary forms, with or without |
|
8 * modification, are permitted provided that the following conditions |
|
9 * are met: |
|
10 * 1. Redistributions of source code must retain the above copyright |
|
11 * notice, this list of conditions and the following disclaimer. |
|
12 * 2. Redistributions in binary form must reproduce the above copyright |
|
13 * notice, this list of conditions and the following disclaimer in the |
|
14 * documentation and/or other materials provided with the distribution. |
|
15 * 3. Neither the name of the project nor the names of its contributors |
|
16 * may be used to endorse or promote products derived from this software |
|
17 * without specific prior written permission. |
|
18 * |
|
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND |
|
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE |
|
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
|
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
|
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
|
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
|
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
|
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
|
29 * SUCH DAMAGE. |
|
30 * |
|
31 * Portions Copyright (c) 2006-2008 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. |
|
32 */ |
|
33 |
|
34 /* |
|
35 * "#ifdef FAITH" part is local hack for supporting IPv4-v6 translator. |
|
36 * |
|
37 * Issues to be discussed: |
|
38 * - Thread safe-ness must be checked. |
|
39 * - Return values. There are nonstandard return values defined and used |
|
40 * in the source code. This is because RFC2553 is silent about which error |
|
41 * code must be returned for which situation. |
|
42 * - freeaddrinfo(NULL). RFC2553 is silent about it. XNET 5.2 says it is |
|
43 * invalid. current code - SEGV on freeaddrinfo(NULL) |
|
44 * |
|
45 * Note: |
|
46 * - The code filters out AFs that are not supported by the kernel, |
|
47 * when globbing NULL hostname (to loopback, or wildcard). Is it the right |
|
48 * thing to do? What is the relationship with post-RFC2553 AI_ADDRCONFIG |
|
49 * in ai_flags? |
|
50 * - (post-2553) semantics of AI_ADDRCONFIG itself is too vague. |
|
51 * (1) what should we do against numeric hostname (2) what should we do |
|
52 * against NULL hostname (3) what is AI_ADDRCONFIG itself. AF not ready? |
|
53 * non-loopback address configured? global address configured? |
|
54 * |
|
55 * OS specific notes for netbsd/openbsd/freebsd4/bsdi4: |
|
56 * - To avoid search order issue, we have a big amount of code duplicate |
|
57 * from gethnamaddr.c and some other places. The issues that there's no |
|
58 * lower layer function to lookup "IPv4 or IPv6" record. Calling |
|
59 * gethostbyname2 from getaddrinfo will end up in wrong search order, as |
|
60 * presented above. |
|
61 * |
|
62 * OS specific notes for freebsd4: |
|
63 * - FreeBSD supported $GAI. The code does not. |
|
64 * - FreeBSD allowed classful IPv4 numeric (127.1), the code does not. |
|
65 */ |
|
66 |
|
67 #include <sys/cdefs.h> |
|
68 __FBSDID("$FreeBSD: src/lib/libc/net/getaddrinfo.c,v 1.69.2.1 2005/07/22 20:17:30 ume Exp $"); |
|
69 |
|
70 #include <unistd.h> |
|
71 #include <sys/socket.h> |
|
72 #include <net/if.h> |
|
73 #include "namespace.h" |
|
74 #include <sys/types.h> |
|
75 #include <sys/param.h> |
|
76 #include <netinet/in.h> |
|
77 #include <sys/queue.h> |
|
78 #ifdef INET6 |
|
79 #ifndef __SYMBIAN32__ |
|
80 #include <net/if_var.h> |
|
81 #include <sys/sysctl.h> |
|
82 #endif //__SYMBIAN32__ |
|
83 #include <sys/ioctl.h> |
|
84 #include <netinet6/in6_var.h> /* XXX */ |
|
85 #endif |
|
86 #include <arpa/inet.h> |
|
87 #include <arpa/nameser.h> |
|
88 #ifndef __SYMBIAN32__ |
|
89 #include <rpc/rpc.h> |
|
90 #include <rpcsvc/yp_prot.h> |
|
91 #include <rpcsvc/ypclnt.h> |
|
92 #endif //__SYMBIAN32__ |
|
93 #include <netdb.h> |
|
94 #include <resolv.h> |
|
95 #include <string.h> |
|
96 #include <stdlib.h> |
|
97 #include <stddef.h> |
|
98 #include <ctype.h> |
|
99 #include <stdio.h> |
|
100 #include <errno.h> |
|
101 |
|
102 #include "res_config.h" |
|
103 |
|
104 #ifdef DEBUG |
|
105 #include "sys/syslog.h" |
|
106 #endif |
|
107 |
|
108 #include <stdarg.h> |
|
109 #include <nsswitch.h> |
|
110 #include "un-namespace.h" |
|
111 #include "libc_private.h" |
|
112 |
|
113 #ifdef __SYMBIAN32__ |
|
114 #if defined(__KAME__) |
|
115 #undef __KAME__ |
|
116 #endif |
|
117 #endif |
|
118 |
|
119 #if defined(__KAME__) && defined(INET6) |
|
120 # define FAITH |
|
121 #endif |
|
122 |
|
123 #define SUCCESS 0 |
|
124 #define ANY 0 |
|
125 #define YES 1 |
|
126 #define NO 0 |
|
127 |
|
128 static const char in_addrany[] = { 0, 0, 0, 0 }; |
|
129 static const char in_loopback[] = { 127, 0, 0, 1 }; |
|
130 #ifdef INET6 |
|
131 static const char in6_addrany[] = { |
|
132 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 |
|
133 }; |
|
134 static const char in6_loopback[] = { |
|
135 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 |
|
136 }; |
|
137 #endif |
|
138 |
|
139 struct policyqueue { |
|
140 TAILQ_ENTRY(policyqueue) pc_entry; |
|
141 #ifdef INET6 |
|
142 struct in6_addrpolicy pc_policy; |
|
143 #endif |
|
144 }; |
|
145 TAILQ_HEAD(policyhead, policyqueue); |
|
146 |
|
147 static const struct afd { |
|
148 int a_af; |
|
149 int a_addrlen; |
|
150 socklen_t a_socklen; |
|
151 int a_off; |
|
152 const char *a_addrany; |
|
153 const char *a_loopback; |
|
154 int a_scoped; |
|
155 } afdl [] = { |
|
156 #ifdef INET6 |
|
157 #define N_INET6 0 |
|
158 {PF_INET6, sizeof(struct in6_addr), |
|
159 sizeof(struct sockaddr_in6), |
|
160 offsetof(struct sockaddr_in6, sin6_addr), |
|
161 in6_addrany, in6_loopback, 1}, |
|
162 #define N_INET 1 |
|
163 #else |
|
164 #define N_INET 0 |
|
165 #endif |
|
166 {PF_INET, sizeof(struct in_addr), |
|
167 sizeof(struct sockaddr_in), |
|
168 offsetof(struct sockaddr_in, sin_addr), |
|
169 in_addrany, in_loopback, 0}, |
|
170 {0, 0, 0, 0, NULL, NULL, 0}, |
|
171 }; |
|
172 |
|
173 struct explore { |
|
174 int e_af; |
|
175 int e_socktype; |
|
176 int e_protocol; |
|
177 const char *e_protostr; |
|
178 int e_wild; |
|
179 #define WILD_AF(ex) ((ex)->e_wild & 0x01) |
|
180 #define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02) |
|
181 #define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04) |
|
182 }; |
|
183 |
|
184 static const struct explore explore[] = { |
|
185 #if 0 |
|
186 { PF_LOCAL, 0, ANY, ANY, NULL, 0x01 }, |
|
187 #endif |
|
188 #ifdef INET6 |
|
189 { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, |
|
190 { PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, |
|
191 { PF_INET6, SOCK_RAW, ANY, NULL, 0x05 }, |
|
192 #endif |
|
193 { PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, |
|
194 { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, |
|
195 { PF_INET, SOCK_RAW, ANY, NULL, 0x05 }, |
|
196 { PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, |
|
197 { PF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, |
|
198 { PF_UNSPEC, SOCK_RAW, ANY, NULL, 0x05 }, |
|
199 { -1, 0, 0, NULL, 0 }, |
|
200 }; |
|
201 |
|
202 #ifdef INET6 |
|
203 #define PTON_MAX 16 |
|
204 #else |
|
205 #define PTON_MAX 4 |
|
206 #endif |
|
207 |
|
208 #define AIO_SRCFLAG_DEPRECATED 0x1 |
|
209 |
|
210 struct ai_order { |
|
211 union { |
|
212 struct sockaddr_storage aiou_ss; |
|
213 struct sockaddr aiou_sa; |
|
214 } aio_src_un; |
|
215 #define aio_srcsa aio_src_un.aiou_sa |
|
216 u_int32_t aio_srcflag; |
|
217 int aio_srcscope; |
|
218 int aio_dstscope; |
|
219 struct policyqueue *aio_srcpolicy; |
|
220 struct policyqueue *aio_dstpolicy; |
|
221 struct addrinfo *aio_ai; |
|
222 int aio_matchlen; |
|
223 }; |
|
224 |
|
225 #ifndef __SYMBIAN32__ |
|
226 static const ns_src default_dns_files[] = { |
|
227 { NSSRC_FILES, NS_SUCCESS }, |
|
228 { NSSRC_DNS, NS_SUCCESS }, |
|
229 { 0 } |
|
230 }; |
|
231 #endif//__SYMBIAN32__ |
|
232 |
|
233 struct res_target { |
|
234 struct res_target *next; |
|
235 const char *name; /* domain name */ |
|
236 int qclass, qtype; /* class and type of query */ |
|
237 u_char *answer; /* buffer to put answer */ |
|
238 int anslen; /* size of answer buffer */ |
|
239 int n; /* result length */ |
|
240 }; |
|
241 |
|
242 #define MAXPACKET (64*1024) |
|
243 |
|
244 typedef union { |
|
245 HEADER hdr; |
|
246 u_char buf[MAXPACKET]; |
|
247 } querybuf; |
|
248 |
|
249 static int str2number(const char *); |
|
250 static int explore_null(const struct addrinfo *, |
|
251 const char *, struct addrinfo **); |
|
252 static int explore_numeric(const struct addrinfo *, const char *, |
|
253 const char *, struct addrinfo **, const char *); |
|
254 static int explore_numeric_scope(const struct addrinfo *, const char *, |
|
255 const char *, struct addrinfo **); |
|
256 static int get_canonname(const struct addrinfo *, |
|
257 struct addrinfo *, const char *); |
|
258 static struct addrinfo *get_ai(const struct addrinfo *, |
|
259 const struct afd *, const char *); |
|
260 static int get_portmatch(const struct addrinfo *, const char *); |
|
261 static int get_port(struct addrinfo *, const char *, int); |
|
262 static const struct afd *find_afd(int); |
|
263 static int addrconfig(struct addrinfo *); |
|
264 static void set_source(struct ai_order *, struct policyhead *); |
|
265 static int comp_dst(const void *, const void *); |
|
266 #ifdef INET6 |
|
267 static int ip6_str2scopeid(char *, struct sockaddr_in6 *, u_int32_t *); |
|
268 #endif |
|
269 static int gai_addr2scopetype(struct sockaddr *); |
|
270 #ifndef __SYMBIAN32__ |
|
271 static int explore_fqdn(const struct addrinfo *, const char *, |
|
272 const char *, struct addrinfo **); |
|
273 #endif //__SYMBIAN32__ |
|
274 static int reorder(struct addrinfo *); |
|
275 static int get_addrselectpolicy(struct policyhead *); |
|
276 static void free_addrselectpolicy(struct policyhead *); |
|
277 static struct policyqueue *match_addrselectpolicy(struct sockaddr *, |
|
278 struct policyhead *); |
|
279 static int matchlen(struct sockaddr *, struct sockaddr *); |
|
280 |
|
281 #ifndef __SYMBIAN32__ |
|
282 static struct addrinfo *getanswer(const querybuf *, int, const char *, int, |
|
283 const struct addrinfo *); |
|
284 #endif //__SYMBIAN32__ |
|
285 |
|
286 #if defined(RESOLVSORT) |
|
287 static int addr4sort(struct addrinfo *); |
|
288 #endif |
|
289 #ifndef __SYMBIAN32__ |
|
290 static int _dns_getaddrinfo(void *, void *, va_list); |
|
291 static void _sethtent(FILE **); |
|
292 static void _endhtent(FILE **); |
|
293 #endif /* __SYMBIAN32__ */ |
|
294 #ifndef __SYMBIAN32__ |
|
295 static struct addrinfo *_gethtent(FILE **, const char *, |
|
296 const struct addrinfo *); |
|
297 static int _files_getaddrinfo(void *, void *, va_list); |
|
298 #endif // __SYMBIAN32__ |
|
299 #ifdef YP |
|
300 static struct addrinfo *_yphostent(char *, const struct addrinfo *); |
|
301 static int _yp_getaddrinfo(void *, void *, va_list); |
|
302 #endif |
|
303 |
|
304 #ifndef __SYMBIAN32__ |
|
305 static int res_queryN(const char *, struct res_target *); |
|
306 static int res_searchN(const char *, struct res_target *); |
|
307 static int res_querydomainN(const char *, const char *, |
|
308 struct res_target *); |
|
309 #endif //__SYMBIAN32__ |
|
310 #ifdef __SYMBIAN32__ |
|
311 extern int getaddrinfo_private(const char*, const struct addrinfo*, struct addrinfo**); |
|
312 extern void freeaddrinfo_private(struct addrinfo*); |
|
313 static long int explore_hostname( struct addrinfo *, const char *, |
|
314 const char *, struct addrinfo **, const struct addrinfo *); |
|
315 #endif |
|
316 /* XXX macros that make external reference is BAD. */ |
|
317 |
|
318 #define GET_AI(ai, afd, addr) \ |
|
319 do { \ |
|
320 /* external reference: pai, error, and label free */ \ |
|
321 (ai) = get_ai(pai, (afd), (addr)); \ |
|
322 if ((ai) == NULL) { \ |
|
323 error = EAI_MEMORY; \ |
|
324 goto free; \ |
|
325 } \ |
|
326 } while (/*CONSTCOND*/0) |
|
327 |
|
328 #define GET_PORT(ai, serv) \ |
|
329 do { \ |
|
330 /* external reference: error and label free */ \ |
|
331 error = get_port((ai), (serv), 0); \ |
|
332 if (error != 0) \ |
|
333 goto free; \ |
|
334 } while (/*CONSTCOND*/0) |
|
335 |
|
336 #define GET_CANONNAME(ai, str) \ |
|
337 do { \ |
|
338 /* external reference: pai, error and label free */ \ |
|
339 error = get_canonname(pai, (ai), (str)); \ |
|
340 if (error != 0) \ |
|
341 goto free; \ |
|
342 } while (/*CONSTCOND*/0) |
|
343 |
|
344 #define ERR(err) \ |
|
345 do { \ |
|
346 /* external reference: error, and label bad */ \ |
|
347 error = (err); \ |
|
348 goto bad; \ |
|
349 /*NOTREACHED*/ \ |
|
350 } while (/*CONSTCOND*/0) |
|
351 |
|
352 #define MATCH_FAMILY(x, y, w) \ |
|
353 ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC))) |
|
354 #define MATCH(x, y, w) \ |
|
355 ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY))) |
|
356 |
|
357 EXPORT_C void |
|
358 freeaddrinfo(ai) |
|
359 struct addrinfo *ai; |
|
360 { |
|
361 struct addrinfo *next; |
|
362 |
|
363 if(ai == NULL) |
|
364 { |
|
365 return ; |
|
366 } |
|
367 |
|
368 |
|
369 do { |
|
370 next = ai->ai_next; |
|
371 if (ai->ai_canonname) |
|
372 free(ai->ai_canonname); |
|
373 /* no need to free(ai->ai_addr) */ |
|
374 free(ai); |
|
375 ai = next; |
|
376 } while (ai); |
|
377 } |
|
378 |
|
379 static int |
|
380 str2number(p) |
|
381 const char *p; |
|
382 { |
|
383 char *ep; |
|
384 unsigned long v; |
|
385 |
|
386 if (*p == '\0') |
|
387 return -1; |
|
388 ep = NULL; |
|
389 errno = 0; |
|
390 v = strtoul(p, &ep, 10); |
|
391 if (errno == 0 && ep && *ep == '\0' && v <= UINT_MAX) |
|
392 return v; |
|
393 else |
|
394 return -1; |
|
395 } |
|
396 |
|
397 EXPORT_C int |
|
398 getaddrinfo(hostname, servname, hints, res) |
|
399 const char *hostname, *servname; |
|
400 const struct addrinfo *hints; |
|
401 struct addrinfo **res; |
|
402 { |
|
403 struct addrinfo sentinel; |
|
404 struct addrinfo *cur; |
|
405 int error = 0; |
|
406 struct addrinfo ai; |
|
407 struct addrinfo ai0; |
|
408 struct addrinfo *pai; |
|
409 const struct explore *ex; |
|
410 int numeric = 0; |
|
411 memset(&sentinel, 0, sizeof(sentinel)); |
|
412 cur = &sentinel; |
|
413 pai = &ai; |
|
414 pai->ai_flags = 0; |
|
415 pai->ai_family = PF_UNSPEC; |
|
416 pai->ai_socktype = ANY; |
|
417 pai->ai_protocol = ANY; |
|
418 pai->ai_addrlen = 0; |
|
419 pai->ai_canonname = NULL; |
|
420 pai->ai_addr = NULL; |
|
421 pai->ai_next = NULL; |
|
422 if (hostname == NULL && servname == NULL) |
|
423 return EAI_NONAME; |
|
424 if (hints) { |
|
425 /* error check for hints */ |
|
426 if (hints->ai_addrlen || hints->ai_canonname || |
|
427 hints->ai_addr || hints->ai_next) |
|
428 ERR(EAI_BADHINTS); /* xxx */ |
|
429 if (hints->ai_flags & ~AI_MASK) |
|
430 ERR(EAI_BADFLAGS); |
|
431 switch (hints->ai_family) { |
|
432 case PF_UNSPEC: |
|
433 case PF_INET: |
|
434 #ifdef INET6 |
|
435 case PF_INET6: |
|
436 #endif |
|
437 break; |
|
438 default: |
|
439 ERR(EAI_FAMILY); |
|
440 } |
|
441 memcpy(pai, hints, sizeof(*pai)); |
|
442 |
|
443 /* |
|
444 * if both socktype/protocol are specified, check if they |
|
445 * are meaningful combination. |
|
446 */ |
|
447 if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) { |
|
448 for (ex = explore; ex->e_af >= 0; ex++) { |
|
449 if (pai->ai_family != ex->e_af) |
|
450 continue; |
|
451 if (ex->e_socktype == ANY) |
|
452 continue; |
|
453 if (ex->e_protocol == ANY) |
|
454 continue; |
|
455 if (pai->ai_socktype == ex->e_socktype && |
|
456 pai->ai_protocol != ex->e_protocol) { |
|
457 ERR(EAI_BADHINTS); |
|
458 } |
|
459 } |
|
460 } |
|
461 } |
|
462 |
|
463 /* |
|
464 * post-2553: AI_ALL and AI_V4MAPPED are effective only against |
|
465 * AF_INET6 query. They need to be ignored if specified in other |
|
466 * occassions. |
|
467 */ |
|
468 switch (pai->ai_flags & (AI_ALL | AI_V4MAPPED)) { |
|
469 case AI_V4MAPPED: |
|
470 case AI_ALL | AI_V4MAPPED: |
|
471 if (pai->ai_family != AF_INET6) |
|
472 pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED); |
|
473 break; |
|
474 #ifndef __SYMBIAN32__ |
|
475 case AI_ALL: |
|
476 #if 1 |
|
477 /* illegal */ |
|
478 ERR(EAI_BADFLAGS); |
|
479 #else |
|
480 pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED); |
|
481 #endif |
|
482 break; |
|
483 #endif /*__SYMBIAN32__*/ |
|
484 } |
|
485 |
|
486 /* |
|
487 * check for special cases. (1) numeric servname is disallowed if |
|
488 * socktype/protocol are left unspecified. (2) servname is disallowed |
|
489 * for raw and other inet{,6} sockets. |
|
490 */ |
|
491 if (MATCH_FAMILY(pai->ai_family, PF_INET, 1) |
|
492 #ifdef PF_INET6 |
|
493 || MATCH_FAMILY(pai->ai_family, PF_INET6, 1) |
|
494 #endif |
|
495 ) { |
|
496 ai0 = *pai; /* backup *pai */ |
|
497 |
|
498 if (pai->ai_family == PF_UNSPEC) { |
|
499 #ifdef PF_INET6 |
|
500 #ifdef __SYMBIAN32__ |
|
501 // XXX: Fix this |
|
502 pai->ai_family = PF_INET; |
|
503 #else |
|
504 pai->ai_family = PF_INET6; |
|
505 #endif // __SYMBIAN32__ |
|
506 #else |
|
507 pai->ai_family = PF_INET; |
|
508 #endif |
|
509 } |
|
510 error = get_portmatch(pai, servname); |
|
511 if (error) |
|
512 ERR(error); |
|
513 |
|
514 *pai = ai0; |
|
515 } |
|
516 |
|
517 ai0 = *pai; |
|
518 |
|
519 /* NULL hostname, or numeric hostname */ |
|
520 for (ex = explore; ex->e_af >= 0; ex++) { |
|
521 *pai = ai0; |
|
522 |
|
523 /* PF_UNSPEC entries are prepared for DNS queries only */ |
|
524 if (ex->e_af == PF_UNSPEC) |
|
525 continue; |
|
526 |
|
527 if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex))) |
|
528 continue; |
|
529 if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex))) |
|
530 continue; |
|
531 if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex))) |
|
532 continue; |
|
533 |
|
534 if (pai->ai_family == PF_UNSPEC) |
|
535 pai->ai_family = ex->e_af; |
|
536 if (pai->ai_socktype == ANY && ex->e_socktype != ANY) |
|
537 pai->ai_socktype = ex->e_socktype; |
|
538 if (pai->ai_protocol == ANY && ex->e_protocol != ANY) |
|
539 pai->ai_protocol = ex->e_protocol; |
|
540 |
|
541 if (hostname == NULL) |
|
542 error = explore_null(pai, servname, &cur->ai_next); |
|
543 else |
|
544 error = explore_numeric_scope(pai, hostname, servname, |
|
545 &cur->ai_next); |
|
546 |
|
547 if (error) |
|
548 goto free; |
|
549 |
|
550 while (cur && cur->ai_next) |
|
551 cur = cur->ai_next; |
|
552 } |
|
553 |
|
554 /* |
|
555 * XXX |
|
556 * If numreic representation of AF1 can be interpreted as FQDN |
|
557 * representation of AF2, we need to think again about the code below. |
|
558 */ |
|
559 if (sentinel.ai_next) { |
|
560 numeric = 1; |
|
561 goto good; |
|
562 } |
|
563 |
|
564 if (hostname == NULL) |
|
565 ERR(EAI_NONAME); /* used to be EAI_NODATA */ |
|
566 if (pai->ai_flags & AI_NUMERICHOST) |
|
567 ERR(EAI_NONAME); |
|
568 |
|
569 if ((pai->ai_flags & AI_ADDRCONFIG) != 0 && !addrconfig(&ai0)) |
|
570 ERR(EAI_FAIL); |
|
571 |
|
572 /* |
|
573 * hostname as alphabetical name. |
|
574 * we would like to prefer AF_INET6 than AF_INET, so we'll make a |
|
575 * outer loop by AFs. |
|
576 */ |
|
577 for (ex = explore; ex->e_af >= 0; ex++) { |
|
578 *pai = ai0; |
|
579 |
|
580 /* require exact match for family field */ |
|
581 if (pai->ai_family != ex->e_af) |
|
582 continue; |
|
583 |
|
584 if (!MATCH(pai->ai_socktype, ex->e_socktype, |
|
585 WILD_SOCKTYPE(ex))) { |
|
586 continue; |
|
587 } |
|
588 if (!MATCH(pai->ai_protocol, ex->e_protocol, |
|
589 WILD_PROTOCOL(ex))) { |
|
590 continue; |
|
591 |
|
592 } |
|
593 |
|
594 #ifdef __SYMBIAN32__ |
|
595 if (pai->ai_family == PF_UNSPEC) |
|
596 pai->ai_family = ex->e_af; |
|
597 #endif |
|
598 if (pai->ai_socktype == ANY && ex->e_socktype != ANY) |
|
599 pai->ai_socktype = ex->e_socktype; |
|
600 if (pai->ai_protocol == ANY && ex->e_protocol != ANY) |
|
601 pai->ai_protocol = ex->e_protocol; |
|
602 |
|
603 #ifndef __SYMBIAN32__ |
|
604 error = explore_fqdn(pai, hostname, servname, |
|
605 &cur->ai_next); |
|
606 #else |
|
607 |
|
608 error = explore_hostname(pai, hostname, servname, |
|
609 &cur->ai_next, hints); |
|
610 if(error == -1 || error == EAI_MEMORY) |
|
611 goto bad; |
|
612 else |
|
613 error = 0; |
|
614 |
|
615 |
|
616 #endif//__SYMBIAN32__ |
|
617 while (cur && cur->ai_next) |
|
618 cur = cur->ai_next; |
|
619 } |
|
620 /* XXX inhibit errors if we have the result */ |
|
621 if (sentinel.ai_next) |
|
622 error = 0; |
|
623 |
|
624 good: |
|
625 /* |
|
626 * ensure we return either: |
|
627 * - error == 0, non-NULL *res |
|
628 * - error != 0, NULL *res |
|
629 */ |
|
630 if (error == 0) { |
|
631 if (sentinel.ai_next) { |
|
632 /* |
|
633 * If the returned entry is for an active connection, |
|
634 * and the given name is not numeric, reorder the |
|
635 * list, so that the application would try the list |
|
636 * in the most efficient order. |
|
637 */ |
|
638 if (hints == NULL || !(hints->ai_flags & AI_PASSIVE)) { |
|
639 if (!numeric) |
|
640 (void)reorder(&sentinel); |
|
641 } |
|
642 *res = sentinel.ai_next; |
|
643 return SUCCESS; |
|
644 } else |
|
645 error = EAI_FAIL; |
|
646 } |
|
647 free: |
|
648 bad: |
|
649 if (sentinel.ai_next) |
|
650 freeaddrinfo(sentinel.ai_next); |
|
651 *res = NULL; |
|
652 return error; |
|
653 } |
|
654 |
|
655 static int |
|
656 reorder(sentinel) |
|
657 struct addrinfo *sentinel; |
|
658 { |
|
659 struct addrinfo *ai, **aip; |
|
660 struct ai_order *aio; |
|
661 int i, n; |
|
662 struct policyhead policyhead; |
|
663 |
|
664 /* count the number of addrinfo elements for sorting. */ |
|
665 for (n = 0, ai = sentinel->ai_next; ai != NULL; ai = ai->ai_next, n++) |
|
666 ; |
|
667 |
|
668 /* |
|
669 * If the number is small enough, we can skip the reordering process. |
|
670 */ |
|
671 if (n <= 1) |
|
672 return(n); |
|
673 |
|
674 /* allocate a temporary array for sort and initialization of it. */ |
|
675 if ((aio = malloc(sizeof(*aio) * n)) == NULL) |
|
676 return(n); /* give up reordering */ |
|
677 memset(aio, 0, sizeof(*aio) * n); |
|
678 |
|
679 /* retrieve address selection policy from the kernel */ |
|
680 TAILQ_INIT(&policyhead); |
|
681 if (!get_addrselectpolicy(&policyhead)) { |
|
682 /* no policy is installed into kernel, we don't sort. */ |
|
683 free(aio); |
|
684 return (n); |
|
685 } |
|
686 |
|
687 for (i = 0, ai = sentinel->ai_next; i < n; ai = ai->ai_next, i++) { |
|
688 aio[i].aio_ai = ai; |
|
689 aio[i].aio_dstscope = gai_addr2scopetype(ai->ai_addr); |
|
690 aio[i].aio_dstpolicy = match_addrselectpolicy(ai->ai_addr, |
|
691 &policyhead); |
|
692 set_source(&aio[i], &policyhead); |
|
693 } |
|
694 |
|
695 /* perform sorting. */ |
|
696 qsort(aio, n, sizeof(*aio), comp_dst); |
|
697 |
|
698 /* reorder the addrinfo chain. */ |
|
699 for (i = 0, aip = &sentinel->ai_next; i < n; i++) { |
|
700 *aip = aio[i].aio_ai; |
|
701 aip = &aio[i].aio_ai->ai_next; |
|
702 } |
|
703 *aip = NULL; |
|
704 |
|
705 /* cleanup and return */ |
|
706 free(aio); |
|
707 free_addrselectpolicy(&policyhead); |
|
708 return(n); |
|
709 } |
|
710 |
|
711 static int |
|
712 get_addrselectpolicy(head) |
|
713 struct policyhead *head; |
|
714 { |
|
715 #ifdef __SYMBIAN32__ |
|
716 |
|
717 head = head; /*to fix warning 'variable/argument not used in function' */ |
|
718 #endif //__SYMBIAN32__ |
|
719 |
|
720 #ifndef __SYMBIAN32__ |
|
721 #ifdef INET6 |
|
722 int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_ADDRCTLPOLICY }; |
|
723 size_t l; |
|
724 char *buf; |
|
725 struct in6_addrpolicy *pol, *ep; |
|
726 |
|
727 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) |
|
728 return (0); |
|
729 if ((buf = malloc(l)) == NULL) |
|
730 return (0); |
|
731 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) { |
|
732 free(buf); |
|
733 return (0); |
|
734 } |
|
735 |
|
736 ep = (struct in6_addrpolicy *)(buf + l); |
|
737 for (pol = (struct in6_addrpolicy *)buf; pol + 1 <= ep; pol++) { |
|
738 struct policyqueue *new; |
|
739 |
|
740 if ((new = malloc(sizeof(*new))) == NULL) { |
|
741 free_addrselectpolicy(head); /* make the list empty */ |
|
742 break; |
|
743 } |
|
744 new->pc_policy = *pol; |
|
745 TAILQ_INSERT_TAIL(head, new, pc_entry); |
|
746 } |
|
747 |
|
748 free(buf); |
|
749 return (1); |
|
750 #else |
|
751 return (0); |
|
752 #endif |
|
753 #else |
|
754 return (0); |
|
755 #endif /* __SYMBIAN32__ */ |
|
756 } |
|
757 |
|
758 static void |
|
759 free_addrselectpolicy(head) |
|
760 struct policyhead *head; |
|
761 { |
|
762 struct policyqueue *ent, *nent; |
|
763 |
|
764 for (ent = TAILQ_FIRST(head); ent; ent = nent) { |
|
765 nent = TAILQ_NEXT(ent, pc_entry); |
|
766 TAILQ_REMOVE(head, ent, pc_entry); |
|
767 free(ent); |
|
768 } |
|
769 } |
|
770 |
|
771 static struct policyqueue * |
|
772 match_addrselectpolicy(addr, head) |
|
773 struct sockaddr *addr; |
|
774 struct policyhead *head; |
|
775 { |
|
776 #ifdef INET6 |
|
777 struct policyqueue *ent, *bestent = NULL; |
|
778 struct in6_addrpolicy *pol; |
|
779 int matchlen, bestmatchlen = -1; |
|
780 u_char *mp, *ep, *k, *p, m; |
|
781 struct sockaddr_in6 key; |
|
782 |
|
783 switch(addr->sa_family) { |
|
784 case AF_INET6: |
|
785 key = *(struct sockaddr_in6 *)addr; |
|
786 break; |
|
787 case AF_INET: |
|
788 /* convert the address into IPv4-mapped IPv6 address. */ |
|
789 memset(&key, 0, sizeof(key)); |
|
790 key.sin6_family = AF_INET6; |
|
791 key.sin6_len = sizeof(key); |
|
792 key.sin6_addr.s6_addr[10] = 0xff; |
|
793 key.sin6_addr.s6_addr[11] = 0xff; |
|
794 memcpy(&key.sin6_addr.s6_addr[12], |
|
795 &((struct sockaddr_in *)addr)->sin_addr, 4); |
|
796 break; |
|
797 default: |
|
798 return(NULL); |
|
799 } |
|
800 |
|
801 for (ent = TAILQ_FIRST(head); ent; ent = TAILQ_NEXT(ent, pc_entry)) { |
|
802 pol = &ent->pc_policy; |
|
803 matchlen = 0; |
|
804 |
|
805 mp = (u_char *)&pol->addrmask.sin6_addr; |
|
806 ep = mp + 16; /* XXX: scope field? */ |
|
807 k = (u_char *)&key.sin6_addr; |
|
808 p = (u_char *)&pol->addr.sin6_addr; |
|
809 for (; mp < ep && *mp; mp++, k++, p++) { |
|
810 m = *mp; |
|
811 if ((*k & m) != *p) |
|
812 goto next; /* not match */ |
|
813 if (m == 0xff) /* short cut for a typical case */ |
|
814 matchlen += 8; |
|
815 else { |
|
816 while (m >= 0x80) { |
|
817 matchlen++; |
|
818 m <<= 1; |
|
819 } |
|
820 } |
|
821 } |
|
822 |
|
823 /* matched. check if this is better than the current best. */ |
|
824 if (matchlen > bestmatchlen) { |
|
825 bestent = ent; |
|
826 bestmatchlen = matchlen; |
|
827 } |
|
828 |
|
829 next: |
|
830 continue; |
|
831 } |
|
832 |
|
833 return(bestent); |
|
834 #else |
|
835 return(NULL); |
|
836 #endif |
|
837 |
|
838 } |
|
839 |
|
840 static void |
|
841 set_source(aio, ph) |
|
842 struct ai_order *aio; |
|
843 struct policyhead *ph; |
|
844 { |
|
845 struct addrinfo ai = *aio->aio_ai; |
|
846 struct sockaddr_storage ss; |
|
847 socklen_t srclen; |
|
848 int s; |
|
849 |
|
850 /* set unspec ("no source is available"), just in case */ |
|
851 aio->aio_srcsa.sa_family = AF_UNSPEC; |
|
852 aio->aio_srcscope = -1; |
|
853 |
|
854 switch(ai.ai_family) { |
|
855 case AF_INET: |
|
856 #ifdef INET6 |
|
857 case AF_INET6: |
|
858 #endif |
|
859 break; |
|
860 default: /* ignore unsupported AFs explicitly */ |
|
861 return; |
|
862 } |
|
863 |
|
864 /* XXX: make a dummy addrinfo to call connect() */ |
|
865 ai.ai_socktype = SOCK_DGRAM; |
|
866 ai.ai_protocol = IPPROTO_UDP; /* is UDP too specific? */ |
|
867 ai.ai_next = NULL; |
|
868 memset(&ss, 0, sizeof(ss)); |
|
869 memcpy(&ss, ai.ai_addr, ai.ai_addrlen); |
|
870 ai.ai_addr = (struct sockaddr *)&ss; |
|
871 get_port(&ai, "1", 0); |
|
872 |
|
873 /* open a socket to get the source address for the given dst */ |
|
874 #ifndef __SYMBIAN32__ |
|
875 if ((s = _socket(ai.ai_family, ai.ai_socktype, ai.ai_protocol)) < 0) |
|
876 return; /* give up */ |
|
877 if (_connect(s, ai.ai_addr, ai.ai_addrlen) < 0) |
|
878 goto cleanup; |
|
879 srclen = ai.ai_addrlen; |
|
880 if (_getsockname(s, &aio->aio_srcsa, &srclen) < 0) { |
|
881 aio->aio_srcsa.sa_family = AF_UNSPEC; |
|
882 #else |
|
883 if ((s = socket(ai.ai_family, ai.ai_socktype, ai.ai_protocol)) < 0) |
|
884 return; /* give up */ |
|
885 if (connect(s, ai.ai_addr, ai.ai_addrlen) < 0) |
|
886 goto cleanup; |
|
887 srclen = ai.ai_addrlen; |
|
888 if (getsockname(s, &aio->aio_srcsa, &srclen) < 0) { |
|
889 aio->aio_srcsa.sa_family = AF_UNSPEC; |
|
890 #endif |
|
891 goto cleanup; |
|
892 } |
|
893 aio->aio_srcscope = gai_addr2scopetype(&aio->aio_srcsa); |
|
894 aio->aio_srcpolicy = match_addrselectpolicy(&aio->aio_srcsa, ph); |
|
895 aio->aio_matchlen = matchlen(&aio->aio_srcsa, aio->aio_ai->ai_addr); |
|
896 #ifndef __SYMBIAN32__ |
|
897 /* |
|
898 * XXX: |
|
899 * This path is not traversed |
|
900 * get_addrselectpolicy() returns 0 and reorder() does |
|
901 * not call this routine yet. |
|
902 */ |
|
903 #ifdef INET6 |
|
904 if (ai.ai_family == AF_INET6) { |
|
905 struct in6_ifreq ifr6; |
|
906 u_int32_t flags6; |
|
907 |
|
908 /* XXX: interface name should not be hardcoded */ |
|
909 strncpy(ifr6.ifr_name, "lo0", sizeof(ifr6.ifr_name)); |
|
910 memset(&ifr6, 0, sizeof(ifr6)); |
|
911 memcpy(&ifr6.ifr_addr, ai.ai_addr, ai.ai_addrlen); |
|
912 #ifdef __SYMBIAN32__ |
|
913 if (ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) == 0) { |
|
914 #else |
|
915 if (_ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) == 0) { |
|
916 #endif //__SYMBIAN32__ |
|
917 flags6 = ifr6.ifr_ifru.ifru_flags6; |
|
918 if ((flags6 & IN6_IFF_DEPRECATED)) |
|
919 aio->aio_srcflag |= AIO_SRCFLAG_DEPRECATED; |
|
920 } |
|
921 } |
|
922 #endif |
|
923 #endif |
|
924 |
|
925 cleanup: |
|
926 #ifndef __SYMBIAN32__ |
|
927 _close(s); |
|
928 #else |
|
929 close(s); |
|
930 #endif /* __SYMBIAN32__ */ |
|
931 return; |
|
932 } |
|
933 |
|
934 static int |
|
935 matchlen(src, dst) |
|
936 struct sockaddr *src, *dst; |
|
937 { |
|
938 int match = 0; |
|
939 u_char *s, *d; |
|
940 u_char *lim, r; |
|
941 int addrlen; |
|
942 |
|
943 switch (src->sa_family) { |
|
944 #ifdef INET6 |
|
945 case AF_INET6: |
|
946 s = (u_char *)&((struct sockaddr_in6 *)src)->sin6_addr; |
|
947 d = (u_char *)&((struct sockaddr_in6 *)dst)->sin6_addr; |
|
948 addrlen = sizeof(struct in6_addr); |
|
949 lim = s + addrlen; |
|
950 break; |
|
951 #endif |
|
952 case AF_INET: |
|
953 s = (u_char *)&((struct sockaddr_in *)src)->sin_addr; |
|
954 d = (u_char *)&((struct sockaddr_in *)dst)->sin_addr; |
|
955 addrlen = sizeof(struct in_addr); |
|
956 lim = s + addrlen; |
|
957 break; |
|
958 default: |
|
959 return(0); |
|
960 } |
|
961 |
|
962 while (s < lim) |
|
963 if ((r = (*d++ ^ *s++)) != 0) { |
|
964 while (r < addrlen * 8) { |
|
965 match++; |
|
966 r <<= 1; |
|
967 } |
|
968 break; |
|
969 } else |
|
970 match += 8; |
|
971 return(match); |
|
972 } |
|
973 |
|
974 static int |
|
975 comp_dst(arg1, arg2) |
|
976 const void *arg1, *arg2; |
|
977 { |
|
978 const struct ai_order *dst1 = arg1, *dst2 = arg2; |
|
979 |
|
980 /* |
|
981 * Rule 1: Avoid unusable destinations. |
|
982 * XXX: we currently do not consider if an appropriate route exists. |
|
983 */ |
|
984 if (dst1->aio_srcsa.sa_family != AF_UNSPEC && |
|
985 dst2->aio_srcsa.sa_family == AF_UNSPEC) { |
|
986 return(-1); |
|
987 } |
|
988 if (dst1->aio_srcsa.sa_family == AF_UNSPEC && |
|
989 dst2->aio_srcsa.sa_family != AF_UNSPEC) { |
|
990 return(1); |
|
991 } |
|
992 |
|
993 /* Rule 2: Prefer matching scope. */ |
|
994 if (dst1->aio_dstscope == dst1->aio_srcscope && |
|
995 dst2->aio_dstscope != dst2->aio_srcscope) { |
|
996 return(-1); |
|
997 } |
|
998 if (dst1->aio_dstscope != dst1->aio_srcscope && |
|
999 dst2->aio_dstscope == dst2->aio_srcscope) { |
|
1000 return(1); |
|
1001 } |
|
1002 |
|
1003 /* Rule 3: Avoid deprecated addresses. */ |
|
1004 if (dst1->aio_srcsa.sa_family != AF_UNSPEC && |
|
1005 dst2->aio_srcsa.sa_family != AF_UNSPEC) { |
|
1006 if (!(dst1->aio_srcflag & AIO_SRCFLAG_DEPRECATED) && |
|
1007 (dst2->aio_srcflag & AIO_SRCFLAG_DEPRECATED)) { |
|
1008 return(-1); |
|
1009 } |
|
1010 if ((dst1->aio_srcflag & AIO_SRCFLAG_DEPRECATED) && |
|
1011 !(dst2->aio_srcflag & AIO_SRCFLAG_DEPRECATED)) { |
|
1012 return(1); |
|
1013 } |
|
1014 } |
|
1015 |
|
1016 /* Rule 4: Prefer home addresses. */ |
|
1017 /* XXX: not implemented yet */ |
|
1018 |
|
1019 /* Rule 5: Prefer matching label. */ |
|
1020 #ifdef INET6 |
|
1021 if (dst1->aio_srcpolicy && dst1->aio_dstpolicy && |
|
1022 dst1->aio_srcpolicy->pc_policy.label == |
|
1023 dst1->aio_dstpolicy->pc_policy.label && |
|
1024 (dst2->aio_srcpolicy == NULL || dst2->aio_dstpolicy == NULL || |
|
1025 dst2->aio_srcpolicy->pc_policy.label != |
|
1026 dst2->aio_dstpolicy->pc_policy.label)) { |
|
1027 return(-1); |
|
1028 } |
|
1029 if (dst2->aio_srcpolicy && dst2->aio_dstpolicy && |
|
1030 dst2->aio_srcpolicy->pc_policy.label == |
|
1031 dst2->aio_dstpolicy->pc_policy.label && |
|
1032 (dst1->aio_srcpolicy == NULL || dst1->aio_dstpolicy == NULL || |
|
1033 dst1->aio_srcpolicy->pc_policy.label != |
|
1034 dst1->aio_dstpolicy->pc_policy.label)) { |
|
1035 return(1); |
|
1036 } |
|
1037 #endif |
|
1038 |
|
1039 /* Rule 6: Prefer higher precedence. */ |
|
1040 #ifdef INET6 |
|
1041 if (dst1->aio_dstpolicy && |
|
1042 (dst2->aio_dstpolicy == NULL || |
|
1043 dst1->aio_dstpolicy->pc_policy.preced > |
|
1044 dst2->aio_dstpolicy->pc_policy.preced)) { |
|
1045 return(-1); |
|
1046 } |
|
1047 if (dst2->aio_dstpolicy && |
|
1048 (dst1->aio_dstpolicy == NULL || |
|
1049 dst2->aio_dstpolicy->pc_policy.preced > |
|
1050 dst1->aio_dstpolicy->pc_policy.preced)) { |
|
1051 return(1); |
|
1052 } |
|
1053 #endif |
|
1054 |
|
1055 /* Rule 7: Prefer native transport. */ |
|
1056 /* XXX: not implemented yet */ |
|
1057 |
|
1058 /* Rule 8: Prefer smaller scope. */ |
|
1059 if (dst1->aio_dstscope >= 0 && |
|
1060 dst1->aio_dstscope < dst2->aio_dstscope) { |
|
1061 return(-1); |
|
1062 } |
|
1063 if (dst2->aio_dstscope >= 0 && |
|
1064 dst2->aio_dstscope < dst1->aio_dstscope) { |
|
1065 return(1); |
|
1066 } |
|
1067 |
|
1068 /* |
|
1069 * Rule 9: Use longest matching prefix. |
|
1070 * We compare the match length in a same AF only. |
|
1071 */ |
|
1072 if (dst1->aio_ai->ai_addr->sa_family == |
|
1073 dst2->aio_ai->ai_addr->sa_family) { |
|
1074 if (dst1->aio_matchlen > dst2->aio_matchlen) { |
|
1075 return(-1); |
|
1076 } |
|
1077 if (dst1->aio_matchlen < dst2->aio_matchlen) { |
|
1078 return(1); |
|
1079 } |
|
1080 } |
|
1081 |
|
1082 /* Rule 10: Otherwise, leave the order unchanged. */ |
|
1083 return(-1); |
|
1084 } |
|
1085 |
|
1086 /* |
|
1087 * Copy from scope.c. |
|
1088 * XXX: we should standardize the functions and link them as standard |
|
1089 * library. |
|
1090 */ |
|
1091 static int |
|
1092 gai_addr2scopetype(sa) |
|
1093 struct sockaddr *sa; |
|
1094 { |
|
1095 #ifdef INET6 |
|
1096 struct sockaddr_in6 *sa6; |
|
1097 #endif |
|
1098 struct sockaddr_in *sa4; |
|
1099 |
|
1100 switch(sa->sa_family) { |
|
1101 #ifdef INET6 |
|
1102 case AF_INET6: |
|
1103 sa6 = (struct sockaddr_in6 *)sa; |
|
1104 if (IN6_IS_ADDR_MULTICAST(&sa6->sin6_addr)) { |
|
1105 /* just use the scope field of the multicast address */ |
|
1106 return(sa6->sin6_addr.s6_addr[2] & 0x0f); |
|
1107 } |
|
1108 /* |
|
1109 * Unicast addresses: map scope type to corresponding scope |
|
1110 * value defined for multcast addresses. |
|
1111 * XXX: hardcoded scope type values are bad... |
|
1112 */ |
|
1113 if (IN6_IS_ADDR_LOOPBACK(&sa6->sin6_addr)) |
|
1114 return(1); /* node local scope */ |
|
1115 if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) |
|
1116 return(2); /* link-local scope */ |
|
1117 if (IN6_IS_ADDR_SITELOCAL(&sa6->sin6_addr)) |
|
1118 return(5); /* site-local scope */ |
|
1119 return(14); /* global scope */ |
|
1120 break; |
|
1121 #endif |
|
1122 case AF_INET: |
|
1123 /* |
|
1124 * IPv4 pseudo scoping according to RFC 3484. |
|
1125 */ |
|
1126 sa4 = (struct sockaddr_in *)sa; |
|
1127 /* IPv4 autoconfiguration addresses have link-local scope. */ |
|
1128 if (((u_char *)&sa4->sin_addr)[0] == 169 && |
|
1129 ((u_char *)&sa4->sin_addr)[1] == 254) |
|
1130 return(2); |
|
1131 /* Private addresses have site-local scope. */ |
|
1132 if (((u_char *)&sa4->sin_addr)[0] == 10 || |
|
1133 (((u_char *)&sa4->sin_addr)[0] == 172 && |
|
1134 (((u_char *)&sa4->sin_addr)[1] & 0xf0) == 16) || |
|
1135 (((u_char *)&sa4->sin_addr)[0] == 192 && |
|
1136 ((u_char *)&sa4->sin_addr)[1] == 168)) |
|
1137 return(14); /* XXX: It should be 5 unless NAT */ |
|
1138 /* Loopback addresses have link-local scope. */ |
|
1139 if (((u_char *)&sa4->sin_addr)[0] == 127) |
|
1140 return(2); |
|
1141 return(14); |
|
1142 break; |
|
1143 default: |
|
1144 errno = EAFNOSUPPORT; /* is this a good error? */ |
|
1145 return(-1); |
|
1146 } |
|
1147 } |
|
1148 |
|
1149 /* |
|
1150 * hostname == NULL. |
|
1151 * passive socket -> anyaddr (0.0.0.0 or ::) |
|
1152 * non-passive socket -> localhost (127.0.0.1 or ::1) |
|
1153 */ |
|
1154 static int |
|
1155 explore_null(pai, servname, res) |
|
1156 const struct addrinfo *pai; |
|
1157 const char *servname; |
|
1158 struct addrinfo **res; |
|
1159 { |
|
1160 int s; |
|
1161 const struct afd *afd; |
|
1162 struct addrinfo *cur; |
|
1163 struct addrinfo sentinel; |
|
1164 int error; |
|
1165 |
|
1166 *res = NULL; |
|
1167 sentinel.ai_next = NULL; |
|
1168 cur = &sentinel; |
|
1169 |
|
1170 /* |
|
1171 * filter out AFs that are not supported by the kernel |
|
1172 * XXX errno? |
|
1173 */ |
|
1174 #ifndef __SYMBIAN32__ |
|
1175 s = _socket(pai->ai_family, SOCK_DGRAM, 0); |
|
1176 #else |
|
1177 s=socket(pai->ai_family, SOCK_DGRAM, IPPROTO_UDP); |
|
1178 #endif /* __SYMBIAN32__ */ |
|
1179 if (s < 0) { |
|
1180 if (errno != EMFILE) |
|
1181 return 0; |
|
1182 } else |
|
1183 #ifndef __SYMBIAN32__ |
|
1184 _close(s); |
|
1185 #else |
|
1186 close(s); |
|
1187 #endif /*__SYMBIAN32__*/ |
|
1188 /* |
|
1189 * if the servname does not match socktype/protocol, ignore it. |
|
1190 */ |
|
1191 if (get_portmatch(pai, servname) != 0) |
|
1192 return 0; |
|
1193 |
|
1194 afd = find_afd(pai->ai_family); |
|
1195 if (afd == NULL) |
|
1196 return 0; |
|
1197 |
|
1198 if (pai->ai_flags & AI_PASSIVE) { |
|
1199 GET_AI(cur->ai_next, afd, afd->a_addrany); |
|
1200 /* xxx meaningless? |
|
1201 * GET_CANONNAME(cur->ai_next, "anyaddr"); |
|
1202 */ |
|
1203 GET_PORT(cur->ai_next, servname); |
|
1204 } else { |
|
1205 GET_AI(cur->ai_next, afd, afd->a_loopback); |
|
1206 /* xxx meaningless? |
|
1207 * GET_CANONNAME(cur->ai_next, "localhost"); |
|
1208 */ |
|
1209 GET_PORT(cur->ai_next, servname); |
|
1210 } |
|
1211 cur = cur->ai_next; |
|
1212 |
|
1213 *res = sentinel.ai_next; |
|
1214 return 0; |
|
1215 |
|
1216 free: |
|
1217 if (sentinel.ai_next) |
|
1218 freeaddrinfo(sentinel.ai_next); |
|
1219 return error; |
|
1220 } |
|
1221 |
|
1222 /* |
|
1223 * numeric hostname |
|
1224 */ |
|
1225 static int |
|
1226 explore_numeric(pai, hostname, servname, res, canonname) |
|
1227 const struct addrinfo *pai; |
|
1228 const char *hostname; |
|
1229 const char *servname; |
|
1230 struct addrinfo **res; |
|
1231 const char *canonname; |
|
1232 { |
|
1233 const struct afd *afd; |
|
1234 struct addrinfo *cur; |
|
1235 struct addrinfo sentinel; |
|
1236 int error; |
|
1237 char pton[PTON_MAX]; |
|
1238 |
|
1239 *res = NULL; |
|
1240 sentinel.ai_next = NULL; |
|
1241 cur = &sentinel; |
|
1242 |
|
1243 /* |
|
1244 * if the servname does not match socktype/protocol, ignore it. |
|
1245 */ |
|
1246 if (get_portmatch(pai, servname) != 0) |
|
1247 return 0; |
|
1248 |
|
1249 afd = find_afd(pai->ai_family); |
|
1250 if (afd == NULL) |
|
1251 return 0; |
|
1252 |
|
1253 switch (afd->a_af) { |
|
1254 #if 1 /*X/Open spec*/ |
|
1255 case AF_INET: |
|
1256 if (inet_aton(hostname, (struct in_addr *)pton) == 1) { |
|
1257 if (pai->ai_family == afd->a_af || |
|
1258 pai->ai_family == PF_UNSPEC /*?*/) { |
|
1259 GET_AI(cur->ai_next, afd, pton); |
|
1260 GET_PORT(cur->ai_next, servname); |
|
1261 if ((pai->ai_flags & AI_CANONNAME)) { |
|
1262 /* |
|
1263 * Set the numeric address itself as |
|
1264 * the canonical name, based on a |
|
1265 * clarification in rfc3493. |
|
1266 */ |
|
1267 GET_CANONNAME(cur->ai_next, canonname); |
|
1268 } |
|
1269 while (cur && cur->ai_next) |
|
1270 cur = cur->ai_next; |
|
1271 } else |
|
1272 ERR(EAI_FAMILY); /*xxx*/ |
|
1273 } |
|
1274 break; |
|
1275 #endif |
|
1276 default: |
|
1277 if (inet_pton(afd->a_af, hostname, pton) == 1) { |
|
1278 if (pai->ai_family == afd->a_af || |
|
1279 pai->ai_family == PF_UNSPEC /*?*/) { |
|
1280 GET_AI(cur->ai_next, afd, pton); |
|
1281 GET_PORT(cur->ai_next, servname); |
|
1282 if ((pai->ai_flags & AI_CANONNAME)) { |
|
1283 /* |
|
1284 * Set the numeric address itself as |
|
1285 * the canonical name, based on a |
|
1286 * clarification in rfc3493. |
|
1287 */ |
|
1288 GET_CANONNAME(cur->ai_next, canonname); |
|
1289 } |
|
1290 while (cur && cur->ai_next) |
|
1291 cur = cur->ai_next; |
|
1292 } else |
|
1293 ERR(EAI_FAMILY); /* XXX */ |
|
1294 } |
|
1295 break; |
|
1296 } |
|
1297 |
|
1298 *res = sentinel.ai_next; |
|
1299 return 0; |
|
1300 |
|
1301 free: |
|
1302 bad: |
|
1303 if (sentinel.ai_next) |
|
1304 freeaddrinfo(sentinel.ai_next); |
|
1305 return error; |
|
1306 } |
|
1307 |
|
1308 /* |
|
1309 * numeric hostname with scope |
|
1310 */ |
|
1311 static int |
|
1312 explore_numeric_scope(pai, hostname, servname, res) |
|
1313 const struct addrinfo *pai; |
|
1314 const char *hostname; |
|
1315 const char *servname; |
|
1316 struct addrinfo **res; |
|
1317 { |
|
1318 #if !defined(SCOPE_DELIMITER) || !defined(INET6) |
|
1319 return explore_numeric(pai, hostname, servname, res, hostname); |
|
1320 #else |
|
1321 const struct afd *afd; |
|
1322 struct addrinfo *cur; |
|
1323 int error; |
|
1324 char *cp, *hostname2 = NULL, *scope, *addr; |
|
1325 struct sockaddr_in6 *sin6; |
|
1326 |
|
1327 /* |
|
1328 * if the servname does not match socktype/protocol, ignore it. |
|
1329 */ |
|
1330 if (get_portmatch(pai, servname) != 0) |
|
1331 return 0; |
|
1332 |
|
1333 afd = find_afd(pai->ai_family); |
|
1334 if (afd == NULL) |
|
1335 return 0; |
|
1336 |
|
1337 if (!afd->a_scoped) |
|
1338 return explore_numeric(pai, hostname, servname, res, hostname); |
|
1339 |
|
1340 cp = strchr(hostname, SCOPE_DELIMITER); |
|
1341 if (cp == NULL) |
|
1342 return explore_numeric(pai, hostname, servname, res, hostname); |
|
1343 |
|
1344 /* |
|
1345 * Handle special case of <scoped_address><delimiter><scope id> |
|
1346 */ |
|
1347 hostname2 = strdup(hostname); |
|
1348 if (hostname2 == NULL) |
|
1349 return EAI_MEMORY; |
|
1350 /* terminate at the delimiter */ |
|
1351 hostname2[cp - hostname] = '\0'; |
|
1352 addr = hostname2; |
|
1353 scope = cp + 1; |
|
1354 |
|
1355 error = explore_numeric(pai, addr, servname, res, hostname); |
|
1356 if (error == 0) { |
|
1357 u_int32_t scopeid; |
|
1358 |
|
1359 for (cur = *res; cur; cur = cur->ai_next) { |
|
1360 if (cur->ai_family != AF_INET6) |
|
1361 continue; |
|
1362 sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr; |
|
1363 if (ip6_str2scopeid(scope, sin6, &scopeid) == -1) { |
|
1364 free(hostname2); |
|
1365 return(EAI_NONAME); /* XXX: is return OK? */ |
|
1366 } |
|
1367 sin6->sin6_scope_id = scopeid; |
|
1368 } |
|
1369 } |
|
1370 |
|
1371 free(hostname2); |
|
1372 |
|
1373 return error; |
|
1374 #endif |
|
1375 } |
|
1376 |
|
1377 static int |
|
1378 get_canonname(pai, ai, str) |
|
1379 const struct addrinfo *pai; |
|
1380 struct addrinfo *ai; |
|
1381 const char *str; |
|
1382 { |
|
1383 if ((pai->ai_flags & AI_CANONNAME) != 0) { |
|
1384 ai->ai_canonname = strdup(str); |
|
1385 if (ai->ai_canonname == NULL) |
|
1386 return EAI_MEMORY; |
|
1387 } |
|
1388 return 0; |
|
1389 } |
|
1390 |
|
1391 static struct addrinfo * |
|
1392 get_ai(pai, afd, addr) |
|
1393 const struct addrinfo *pai; |
|
1394 const struct afd *afd; |
|
1395 const char *addr; |
|
1396 { |
|
1397 char *p; |
|
1398 struct addrinfo *ai; |
|
1399 #ifdef FAITH |
|
1400 struct in6_addr faith_prefix; |
|
1401 char *fp_str; |
|
1402 int translate = 0; |
|
1403 #endif |
|
1404 |
|
1405 #ifdef FAITH |
|
1406 /* |
|
1407 * Transfrom an IPv4 addr into a special IPv6 addr format for |
|
1408 * IPv6->IPv4 translation gateway. (only TCP is supported now) |
|
1409 * |
|
1410 * +-----------------------------------+------------+ |
|
1411 * | faith prefix part (12 bytes) | embedded | |
|
1412 * | | IPv4 addr part (4 bytes) |
|
1413 * +-----------------------------------+------------+ |
|
1414 * |
|
1415 * faith prefix part is specified as ascii IPv6 addr format |
|
1416 * in environmental variable GAI. |
|
1417 * For FAITH to work correctly, routing to faith prefix must be |
|
1418 * setup toward a machine where a FAITH daemon operates. |
|
1419 * Also, the machine must enable some mechanizm |
|
1420 * (e.g. faith interface hack) to divert those packet with |
|
1421 * faith prefixed destination addr to user-land FAITH daemon. |
|
1422 */ |
|
1423 fp_str = getenv("GAI"); |
|
1424 if (fp_str && inet_pton(AF_INET6, fp_str, &faith_prefix) == 1 && |
|
1425 afd->a_af == AF_INET && pai->ai_socktype == SOCK_STREAM) { |
|
1426 u_int32_t v4a; |
|
1427 u_int8_t v4a_top; |
|
1428 |
|
1429 memcpy(&v4a, addr, sizeof v4a); |
|
1430 v4a_top = v4a >> IN_CLASSA_NSHIFT; |
|
1431 if (!IN_MULTICAST(v4a) && !IN_EXPERIMENTAL(v4a) && |
|
1432 v4a_top != 0 && v4a != IN_LOOPBACKNET) { |
|
1433 afd = &afdl[N_INET6]; |
|
1434 memcpy(&faith_prefix.s6_addr[12], addr, |
|
1435 sizeof(struct in_addr)); |
|
1436 translate = 1; |
|
1437 } |
|
1438 } |
|
1439 #endif |
|
1440 |
|
1441 ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) |
|
1442 + (afd->a_socklen)); |
|
1443 if (ai == NULL) |
|
1444 return NULL; |
|
1445 |
|
1446 memcpy(ai, pai, sizeof(struct addrinfo)); |
|
1447 ai->ai_addr = (struct sockaddr *)(void *)(ai + 1); |
|
1448 memset(ai->ai_addr, 0, (size_t)afd->a_socklen); |
|
1449 #ifndef __SYMBIAN32__ |
|
1450 ai->ai_addr->sa_len = afd->a_socklen; |
|
1451 #endif /* __SYMBIAN32__ */ |
|
1452 ai->ai_addrlen = afd->a_socklen; |
|
1453 #ifndef __SYMBIAN32__ |
|
1454 ai->ai_addr->sa_family = ai->ai_family = afd->a_af; |
|
1455 #endif |
|
1456 p = (char *)(void *)(ai->ai_addr); |
|
1457 #ifdef FAITH |
|
1458 if (translate == 1) |
|
1459 memcpy(p + afd->a_off, &faith_prefix, (size_t)afd->a_addrlen); |
|
1460 else |
|
1461 #endif |
|
1462 memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen); |
|
1463 return ai; |
|
1464 } |
|
1465 |
|
1466 static int |
|
1467 get_portmatch(ai, servname) |
|
1468 const struct addrinfo *ai; |
|
1469 const char *servname; |
|
1470 { |
|
1471 |
|
1472 /* get_port does not touch first argument when matchonly == 1. */ |
|
1473 /* LINTED const cast */ |
|
1474 return get_port((struct addrinfo *)ai, servname, 1); |
|
1475 } |
|
1476 |
|
1477 static int |
|
1478 get_port(ai, servname, matchonly) |
|
1479 struct addrinfo *ai; |
|
1480 const char *servname; |
|
1481 int matchonly; |
|
1482 { |
|
1483 const char *proto; |
|
1484 struct servent *sp; |
|
1485 int port; |
|
1486 int allownumeric; |
|
1487 |
|
1488 if (servname == NULL) |
|
1489 return 0; |
|
1490 switch (ai->ai_family) { |
|
1491 case AF_INET: |
|
1492 #ifdef AF_INET6 |
|
1493 case AF_INET6: |
|
1494 #endif |
|
1495 break; |
|
1496 default: |
|
1497 return 0; |
|
1498 } |
|
1499 |
|
1500 switch (ai->ai_socktype) { |
|
1501 case SOCK_RAW: |
|
1502 return EAI_SERVICE; |
|
1503 case SOCK_DGRAM: |
|
1504 case SOCK_STREAM: |
|
1505 allownumeric = 1; |
|
1506 break; |
|
1507 case ANY: |
|
1508 allownumeric = 0; |
|
1509 break; |
|
1510 default: |
|
1511 return EAI_SOCKTYPE; |
|
1512 } |
|
1513 |
|
1514 port = str2number(servname); |
|
1515 if (port >= 0) { |
|
1516 if (!allownumeric) |
|
1517 return EAI_SERVICE; |
|
1518 if (port < 0 || port > 65535) |
|
1519 return EAI_SERVICE; |
|
1520 port = htons(port); |
|
1521 } else { |
|
1522 if (ai->ai_flags & AI_NUMERICSERV) |
|
1523 return EAI_NONAME; |
|
1524 switch (ai->ai_socktype) { |
|
1525 case SOCK_DGRAM: |
|
1526 proto = "udp"; |
|
1527 break; |
|
1528 case SOCK_STREAM: |
|
1529 proto = "tcp"; |
|
1530 break; |
|
1531 default: |
|
1532 proto = NULL; |
|
1533 break; |
|
1534 } |
|
1535 |
|
1536 if ((sp = getservbyname(servname, proto)) == NULL) |
|
1537 return EAI_SERVICE; |
|
1538 port = sp->s_port; |
|
1539 } |
|
1540 |
|
1541 if (!matchonly) { |
|
1542 switch (ai->ai_family) { |
|
1543 case AF_INET: |
|
1544 ((struct sockaddr_in *)(void *) |
|
1545 ai->ai_addr)->sin_port = port; |
|
1546 break; |
|
1547 #ifdef INET6 |
|
1548 case AF_INET6: |
|
1549 ((struct sockaddr_in6 *)(void *) |
|
1550 ai->ai_addr)->sin6_port = port; |
|
1551 break; |
|
1552 #endif |
|
1553 } |
|
1554 } |
|
1555 |
|
1556 return 0; |
|
1557 } |
|
1558 |
|
1559 static const struct afd * |
|
1560 find_afd(af) |
|
1561 int af; |
|
1562 { |
|
1563 const struct afd *afd; |
|
1564 |
|
1565 if (af == PF_UNSPEC) |
|
1566 return NULL; |
|
1567 for (afd = afdl; afd->a_af; afd++) { |
|
1568 if (afd->a_af == af) |
|
1569 return afd; |
|
1570 } |
|
1571 return NULL; |
|
1572 } |
|
1573 |
|
1574 /* |
|
1575 * post-2553: AI_ADDRCONFIG check. if we use getipnodeby* as backend, backend |
|
1576 * will take care of it. |
|
1577 * the semantics of AI_ADDRCONFIG is not defined well. we are not sure |
|
1578 * if the code is right or not. |
|
1579 * |
|
1580 * XXX PF_UNSPEC -> PF_INET6 + PF_INET mapping needs to be in sync with |
|
1581 * _dns_getaddrinfo. |
|
1582 */ |
|
1583 static int |
|
1584 addrconfig(pai) |
|
1585 struct addrinfo *pai; |
|
1586 { |
|
1587 int s, af; |
|
1588 |
|
1589 /* |
|
1590 * TODO: |
|
1591 * Note that implementation dependent test for address |
|
1592 * configuration should be done everytime called |
|
1593 * (or apropriate interval), |
|
1594 * because addresses will be dynamically assigned or deleted. |
|
1595 */ |
|
1596 af = pai->ai_family; |
|
1597 if (af == AF_UNSPEC) { |
|
1598 #ifndef __SYMBIAN32__ |
|
1599 if ((s = _socket(AF_INET6, SOCK_DGRAM, 0)) < 0) |
|
1600 af = AF_INET; |
|
1601 else { |
|
1602 _close(s); |
|
1603 if ((s = _socket(AF_INET, SOCK_DGRAM, 0)) < 0) |
|
1604 af = AF_INET6; |
|
1605 else |
|
1606 _close(s); |
|
1607 } |
|
1608 #else |
|
1609 if ((s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0) |
|
1610 af = AF_INET; |
|
1611 else { |
|
1612 close(s); |
|
1613 if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) |
|
1614 af = AF_INET6; |
|
1615 else |
|
1616 close(s); |
|
1617 } |
|
1618 #endif /*__SYMBIAN32__*/ |
|
1619 } |
|
1620 if (af != AF_UNSPEC) { |
|
1621 #ifndef __SYMBIAN32__ |
|
1622 if ((s = _socket(af, SOCK_DGRAM, 0)) < 0) |
|
1623 return 0; |
|
1624 _close(s); |
|
1625 #else |
|
1626 if ((s = socket(af, SOCK_DGRAM, IPPROTO_UDP)) < 0) |
|
1627 return 0; |
|
1628 close(s); |
|
1629 #endif /*__SYMBIAN32__*/ |
|
1630 } |
|
1631 pai->ai_family = af; |
|
1632 return 1; |
|
1633 } |
|
1634 |
|
1635 #ifdef INET6 |
|
1636 /* convert a string to a scope identifier. XXX: IPv6 specific */ |
|
1637 static int |
|
1638 ip6_str2scopeid(scope, sin6, scopeid) |
|
1639 char *scope; |
|
1640 struct sockaddr_in6 *sin6; |
|
1641 u_int32_t *scopeid; |
|
1642 { |
|
1643 u_long lscopeid; |
|
1644 struct in6_addr *a6; |
|
1645 char *ep; |
|
1646 |
|
1647 a6 = &sin6->sin6_addr; |
|
1648 |
|
1649 /* empty scopeid portion is invalid */ |
|
1650 if (*scope == '\0') |
|
1651 return -1; |
|
1652 |
|
1653 if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) { |
|
1654 /* |
|
1655 * We currently assume a one-to-one mapping between links |
|
1656 * and interfaces, so we simply use interface indices for |
|
1657 * like-local scopes. |
|
1658 */ |
|
1659 *scopeid = if_nametoindex(scope); |
|
1660 if (*scopeid == 0) |
|
1661 goto trynumeric; |
|
1662 return 0; |
|
1663 } |
|
1664 |
|
1665 /* still unclear about literal, allow numeric only - placeholder */ |
|
1666 if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6)) |
|
1667 goto trynumeric; |
|
1668 if (IN6_IS_ADDR_MC_ORGLOCAL(a6)) |
|
1669 goto trynumeric; |
|
1670 else |
|
1671 goto trynumeric; /* global */ |
|
1672 |
|
1673 /* try to convert to a numeric id as a last resort */ |
|
1674 trynumeric: |
|
1675 errno = 0; |
|
1676 lscopeid = strtoul(scope, &ep, 10); |
|
1677 *scopeid = (u_int32_t)(lscopeid & 0xffffffffUL); |
|
1678 if (errno == 0 && ep && *ep == '\0' && *scopeid == lscopeid) |
|
1679 return 0; |
|
1680 else |
|
1681 return -1; |
|
1682 } |
|
1683 #endif |
|
1684 |
|
1685 /* |
|
1686 * FQDN hostname, DNS lookup |
|
1687 */ |
|
1688 #ifndef __SYMBIAN32__ |
|
1689 static int |
|
1690 explore_fqdn(pai, hostname, servname, res) |
|
1691 const struct addrinfo *pai; |
|
1692 const char *hostname; |
|
1693 const char *servname; |
|
1694 struct addrinfo **res; |
|
1695 { |
|
1696 struct addrinfo *result; |
|
1697 struct addrinfo *cur; |
|
1698 int error = 0; |
|
1699 static const ns_dtab dtab[] = { |
|
1700 NS_FILES_CB(_files_getaddrinfo, NULL) |
|
1701 { NSSRC_DNS, _dns_getaddrinfo, NULL }, /* force -DHESIOD */ |
|
1702 NS_NIS_CB(_yp_getaddrinfo, NULL) |
|
1703 { 0 } |
|
1704 }; |
|
1705 |
|
1706 result = NULL; |
|
1707 |
|
1708 /* |
|
1709 * if the servname does not match socktype/protocol, ignore it. |
|
1710 */ |
|
1711 if (get_portmatch(pai, servname) != 0) |
|
1712 return 0; |
|
1713 |
|
1714 switch (_nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo", |
|
1715 default_dns_files, hostname, pai)) { |
|
1716 case NS_TRYAGAIN: |
|
1717 error = EAI_AGAIN; |
|
1718 goto free; |
|
1719 case NS_UNAVAIL: |
|
1720 error = EAI_FAIL; |
|
1721 goto free; |
|
1722 case NS_NOTFOUND: |
|
1723 error = EAI_NONAME; |
|
1724 goto free; |
|
1725 case NS_SUCCESS: |
|
1726 error = 0; |
|
1727 for (cur = result; cur; cur = cur->ai_next) { |
|
1728 GET_PORT(cur, servname); |
|
1729 /* canonname should be filled already */ |
|
1730 } |
|
1731 break; |
|
1732 } |
|
1733 |
|
1734 *res = result; |
|
1735 |
|
1736 return 0; |
|
1737 |
|
1738 free: |
|
1739 if (result) |
|
1740 freeaddrinfo(result); |
|
1741 return error; |
|
1742 } |
|
1743 #endif |
|
1744 #ifdef DEBUG |
|
1745 static const char AskedForGot[] = |
|
1746 "gethostby*.getanswer: asked for \"%s\", got \"%s\""; |
|
1747 #endif |
|
1748 |
|
1749 #ifndef __SYMBIAN32__ |
|
1750 static struct addrinfo * |
|
1751 getanswer(answer, anslen, qname, qtype, pai) |
|
1752 const querybuf *answer; |
|
1753 int anslen; |
|
1754 const char *qname; |
|
1755 int qtype; |
|
1756 const struct addrinfo *pai; |
|
1757 { |
|
1758 struct addrinfo sentinel, *cur; |
|
1759 struct addrinfo ai; |
|
1760 const struct afd *afd; |
|
1761 char *canonname; |
|
1762 const HEADER *hp; |
|
1763 const u_char *cp; |
|
1764 int n; |
|
1765 const u_char *eom; |
|
1766 char *bp, *ep; |
|
1767 int type, class, ancount, qdcount; |
|
1768 int haveanswer, had_error; |
|
1769 char tbuf[MAXDNAME]; |
|
1770 int (*name_ok)(const char *); |
|
1771 char hostbuf[8*1024]; |
|
1772 |
|
1773 memset(&sentinel, 0, sizeof(sentinel)); |
|
1774 cur = &sentinel; |
|
1775 |
|
1776 canonname = NULL; |
|
1777 eom = answer->buf + anslen; |
|
1778 switch (qtype) { |
|
1779 case T_A: |
|
1780 case T_AAAA: |
|
1781 case T_ANY: /*use T_ANY only for T_A/T_AAAA lookup*/ |
|
1782 name_ok = res_hnok; |
|
1783 break; |
|
1784 default: |
|
1785 return (NULL); /* XXX should be abort(); */ |
|
1786 } |
|
1787 /* |
|
1788 * find first satisfactory answer |
|
1789 */ |
|
1790 hp = &answer->hdr; |
|
1791 ancount = ntohs(hp->ancount); |
|
1792 qdcount = ntohs(hp->qdcount); |
|
1793 bp = hostbuf; |
|
1794 ep = hostbuf + sizeof hostbuf; |
|
1795 cp = answer->buf + HFIXEDSZ; |
|
1796 if (qdcount != 1) { |
|
1797 h_errno = NO_RECOVERY; |
|
1798 return (NULL); |
|
1799 } |
|
1800 n = dn_expand(answer->buf, eom, cp, bp, ep - bp); |
|
1801 if ((n < 0) || !(*name_ok)(bp)) { |
|
1802 h_errno = NO_RECOVERY; |
|
1803 return (NULL); |
|
1804 } |
|
1805 cp += n + QFIXEDSZ; |
|
1806 if (qtype == T_A || qtype == T_AAAA || qtype == T_ANY) { |
|
1807 /* res_send() has already verified that the query name is the |
|
1808 * same as the one we sent; this just gets the expanded name |
|
1809 * (i.e., with the succeeding search-domain tacked on). |
|
1810 */ |
|
1811 n = strlen(bp) + 1; /* for the \0 */ |
|
1812 if (n >= MAXHOSTNAMELEN) { |
|
1813 h_errno = NO_RECOVERY; |
|
1814 return (NULL); |
|
1815 } |
|
1816 canonname = bp; |
|
1817 bp += n; |
|
1818 /* The qname can be abbreviated, but h_name is now absolute. */ |
|
1819 qname = canonname; |
|
1820 } |
|
1821 haveanswer = 0; |
|
1822 had_error = 0; |
|
1823 while (ancount-- > 0 && cp < eom && !had_error) { |
|
1824 n = dn_expand(answer->buf, eom, cp, bp, ep - bp); |
|
1825 if ((n < 0) || !(*name_ok)(bp)) { |
|
1826 had_error++; |
|
1827 continue; |
|
1828 } |
|
1829 cp += n; /* name */ |
|
1830 type = _getshort(cp); |
|
1831 cp += INT16SZ; /* type */ |
|
1832 class = _getshort(cp); |
|
1833 cp += INT16SZ + INT32SZ; /* class, TTL */ |
|
1834 n = _getshort(cp); |
|
1835 cp += INT16SZ; /* len */ |
|
1836 if (class != C_IN) { |
|
1837 /* XXX - debug? syslog? */ |
|
1838 cp += n; |
|
1839 continue; /* XXX - had_error++ ? */ |
|
1840 } |
|
1841 if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) && |
|
1842 type == T_CNAME) { |
|
1843 n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); |
|
1844 if ((n < 0) || !(*name_ok)(tbuf)) { |
|
1845 had_error++; |
|
1846 continue; |
|
1847 } |
|
1848 cp += n; |
|
1849 /* Get canonical name. */ |
|
1850 n = strlen(tbuf) + 1; /* for the \0 */ |
|
1851 if (n > ep - bp || n >= MAXHOSTNAMELEN) { |
|
1852 had_error++; |
|
1853 continue; |
|
1854 } |
|
1855 strlcpy(bp, tbuf, ep - bp); |
|
1856 canonname = bp; |
|
1857 bp += n; |
|
1858 continue; |
|
1859 } |
|
1860 if (qtype == T_ANY) { |
|
1861 if (!(type == T_A || type == T_AAAA)) { |
|
1862 cp += n; |
|
1863 continue; |
|
1864 } |
|
1865 } else if (type != qtype) { |
|
1866 #ifdef DEBUG |
|
1867 if (type != T_KEY && type != T_SIG) |
|
1868 #ifndef __SYMBIAN32__ |
|
1869 syslog(LOG_NOTICE|LOG_AUTH, |
|
1870 "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"", |
|
1871 qname, p_class(C_IN), p_type(qtype), |
|
1872 p_type(type)); |
|
1873 #endif/* __SYMBIAN32__ */ |
|
1874 #endif/* DEBUG */ |
|
1875 cp += n; |
|
1876 continue; /* XXX - had_error++ ? */ |
|
1877 } |
|
1878 switch (type) { |
|
1879 case T_A: |
|
1880 case T_AAAA: |
|
1881 if (strcasecmp(canonname, bp) != 0) { |
|
1882 #ifdef DEBUG |
|
1883 #ifndef __SYMBIAN32__ |
|
1884 syslog(LOG_NOTICE|LOG_AUTH, |
|
1885 AskedForGot,canonname, bp); |
|
1886 #endif/* __SYMBIAN32__ */ |
|
1887 #endif/* DEBUG */ |
|
1888 cp += n; |
|
1889 continue; /* XXX - had_error++ ? */ |
|
1890 } |
|
1891 if (type == T_A && n != INADDRSZ) { |
|
1892 cp += n; |
|
1893 continue; |
|
1894 } |
|
1895 if (type == T_AAAA && n != IN6ADDRSZ) { |
|
1896 cp += n; |
|
1897 continue; |
|
1898 } |
|
1899 #ifdef FILTER_V4MAPPED |
|
1900 if (type == T_AAAA) { |
|
1901 struct in6_addr in6; |
|
1902 memcpy(&in6, cp, sizeof(in6)); |
|
1903 if (IN6_IS_ADDR_V4MAPPED(&in6)) { |
|
1904 cp += n; |
|
1905 continue; |
|
1906 } |
|
1907 } |
|
1908 #endif |
|
1909 if (!haveanswer) { |
|
1910 int nn; |
|
1911 |
|
1912 canonname = bp; |
|
1913 nn = strlen(bp) + 1; /* for the \0 */ |
|
1914 bp += nn; |
|
1915 } |
|
1916 |
|
1917 /* don't overwrite pai */ |
|
1918 ai = *pai; |
|
1919 ai.ai_family = (type == T_A) ? AF_INET : AF_INET6; |
|
1920 afd = find_afd(ai.ai_family); |
|
1921 if (afd == NULL) { |
|
1922 cp += n; |
|
1923 continue; |
|
1924 } |
|
1925 cur->ai_next = get_ai(&ai, afd, (const char *)cp); |
|
1926 if (cur->ai_next == NULL) |
|
1927 had_error++; |
|
1928 while (cur && cur->ai_next) |
|
1929 cur = cur->ai_next; |
|
1930 cp += n; |
|
1931 break; |
|
1932 default: |
|
1933 abort(); |
|
1934 } |
|
1935 if (!had_error) |
|
1936 haveanswer++; |
|
1937 } |
|
1938 if (haveanswer) { |
|
1939 #if defined(RESOLVSORT) |
|
1940 /* |
|
1941 * We support only IPv4 address for backward |
|
1942 * compatibility against gethostbyname(3). |
|
1943 */ |
|
1944 if (_res.nsort && qtype == T_A) { |
|
1945 if (addr4sort(&sentinel) < 0) { |
|
1946 freeaddrinfo(sentinel.ai_next); |
|
1947 h_errno = NO_RECOVERY; |
|
1948 return NULL; |
|
1949 } |
|
1950 } |
|
1951 #endif /*RESOLVSORT*/ |
|
1952 if (!canonname) |
|
1953 (void)get_canonname(pai, sentinel.ai_next, qname); |
|
1954 else |
|
1955 (void)get_canonname(pai, sentinel.ai_next, canonname); |
|
1956 h_errno = NETDB_SUCCESS; |
|
1957 return sentinel.ai_next; |
|
1958 } |
|
1959 |
|
1960 h_errno = NO_RECOVERY; |
|
1961 return NULL; |
|
1962 } |
|
1963 #endif /* __SYMBIAN32__ */ |
|
1964 |
|
1965 |
|
1966 #ifdef RESOLVSORT |
|
1967 #ifndef __SYMBIAN32__ |
|
1968 |
|
1969 struct addr_ptr { |
|
1970 struct addrinfo *ai; |
|
1971 int aval; |
|
1972 }; |
|
1973 |
|
1974 static int |
|
1975 addr4sort(struct addrinfo *sentinel) |
|
1976 { |
|
1977 struct addrinfo *ai; |
|
1978 struct addr_ptr *addrs, addr; |
|
1979 struct sockaddr_in *sin; |
|
1980 int naddrs, i, j; |
|
1981 int needsort = 0; |
|
1982 |
|
1983 if (!sentinel) |
|
1984 return -1; |
|
1985 naddrs = 0; |
|
1986 for (ai = sentinel->ai_next; ai; ai = ai->ai_next) |
|
1987 naddrs++; |
|
1988 if (naddrs < 2) |
|
1989 return 0; /* We don't need sorting. */ |
|
1990 if ((addrs = malloc(sizeof(struct addr_ptr) * naddrs)) == NULL) |
|
1991 return -1; |
|
1992 i = 0; |
|
1993 for (ai = sentinel->ai_next; ai; ai = ai->ai_next) { |
|
1994 sin = (struct sockaddr_in *)ai->ai_addr; |
|
1995 for (j = 0; (unsigned)j < _res.nsort; j++) { |
|
1996 if (_res.sort_list[j].addr.s_addr == |
|
1997 (sin->sin_addr.s_addr & _res.sort_list[j].mask)) |
|
1998 break; |
|
1999 } |
|
2000 addrs[i].ai = ai; |
|
2001 addrs[i].aval = j; |
|
2002 if (needsort == 0 && i > 0 && j < addrs[i - 1].aval) |
|
2003 needsort = i; |
|
2004 i++; |
|
2005 } |
|
2006 if (!needsort) { |
|
2007 free(addrs); |
|
2008 return 0; |
|
2009 } |
|
2010 |
|
2011 while (needsort < naddrs) { |
|
2012 for (j = needsort - 1; j >= 0; j--) { |
|
2013 if (addrs[j].aval > addrs[j+1].aval) { |
|
2014 addr = addrs[j]; |
|
2015 addrs[j] = addrs[j + 1]; |
|
2016 addrs[j + 1] = addr; |
|
2017 } else |
|
2018 break; |
|
2019 } |
|
2020 needsort++; |
|
2021 } |
|
2022 |
|
2023 ai = sentinel; |
|
2024 for (i = 0; i < naddrs; ++i) { |
|
2025 ai->ai_next = addrs[i].ai; |
|
2026 ai = ai->ai_next; |
|
2027 } |
|
2028 ai->ai_next = NULL; |
|
2029 free(addrs); |
|
2030 return 0; |
|
2031 } |
|
2032 #endif /*RESOLVSORT*/ |
|
2033 #endif /*__SYMBIAN32__*/ |
|
2034 |
|
2035 /*ARGSUSED*/ |
|
2036 |
|
2037 #ifndef __SYMBIAN32__ |
|
2038 static int |
|
2039 _dns_getaddrinfo(rv, cb_data, ap) |
|
2040 void *rv; |
|
2041 void *cb_data; |
|
2042 va_list ap; |
|
2043 { |
|
2044 struct addrinfo *ai; |
|
2045 querybuf *buf, *buf2; |
|
2046 const char *hostname; |
|
2047 const struct addrinfo *pai; |
|
2048 struct addrinfo sentinel, *cur; |
|
2049 struct res_target q, q2; |
|
2050 |
|
2051 hostname = va_arg(ap, char *); |
|
2052 pai = va_arg(ap, const struct addrinfo *); |
|
2053 |
|
2054 memset(&q, 0, sizeof(q2)); |
|
2055 memset(&q2, 0, sizeof(q2)); |
|
2056 memset(&sentinel, 0, sizeof(sentinel)); |
|
2057 cur = &sentinel; |
|
2058 |
|
2059 buf = malloc(sizeof(*buf)); |
|
2060 if (!buf) { |
|
2061 h_errno = NETDB_INTERNAL; |
|
2062 return NS_NOTFOUND; |
|
2063 } |
|
2064 buf2 = malloc(sizeof(*buf2)); |
|
2065 if (!buf2) { |
|
2066 free(buf); |
|
2067 h_errno = NETDB_INTERNAL; |
|
2068 return NS_NOTFOUND; |
|
2069 } |
|
2070 |
|
2071 switch (pai->ai_family) { |
|
2072 case AF_UNSPEC: |
|
2073 q.name = hostname; |
|
2074 q.qclass = C_IN; |
|
2075 q.qtype = T_A; |
|
2076 q.answer = buf->buf; |
|
2077 q.anslen = sizeof(buf->buf); |
|
2078 q.next = &q2; |
|
2079 q2.name = hostname; |
|
2080 q2.qclass = C_IN; |
|
2081 q2.qtype = T_AAAA; |
|
2082 q2.answer = buf2->buf; |
|
2083 q2.anslen = sizeof(buf2->buf); |
|
2084 break; |
|
2085 case AF_INET: |
|
2086 q.name = hostname; |
|
2087 q.qclass = C_IN; |
|
2088 q.qtype = T_A; |
|
2089 q.answer = buf->buf; |
|
2090 q.anslen = sizeof(buf->buf); |
|
2091 break; |
|
2092 case AF_INET6: |
|
2093 q.name = hostname; |
|
2094 q.qclass = C_IN; |
|
2095 q.qtype = T_AAAA; |
|
2096 q.answer = buf->buf; |
|
2097 q.anslen = sizeof(buf->buf); |
|
2098 break; |
|
2099 default: |
|
2100 free(buf); |
|
2101 free(buf2); |
|
2102 return NS_UNAVAIL; |
|
2103 } |
|
2104 if (res_searchN(hostname, &q) < 0) { |
|
2105 free(buf); |
|
2106 free(buf2); |
|
2107 return NS_NOTFOUND; |
|
2108 } |
|
2109 /* prefer IPv6 */ |
|
2110 if (q.next) { |
|
2111 ai = getanswer(buf2, q2.n, q2.name, q2.qtype, pai); |
|
2112 if (ai) { |
|
2113 cur->ai_next = ai; |
|
2114 while (cur && cur->ai_next) |
|
2115 cur = cur->ai_next; |
|
2116 } |
|
2117 } |
|
2118 ai = getanswer(buf, q.n, q.name, q.qtype, pai); |
|
2119 if (ai) |
|
2120 cur->ai_next = ai; |
|
2121 free(buf); |
|
2122 free(buf2); |
|
2123 if (sentinel.ai_next == NULL) |
|
2124 switch (h_errno) { |
|
2125 case HOST_NOT_FOUND: |
|
2126 return NS_NOTFOUND; |
|
2127 case TRY_AGAIN: |
|
2128 return NS_TRYAGAIN; |
|
2129 default: |
|
2130 return NS_UNAVAIL; |
|
2131 } |
|
2132 *((struct addrinfo **)rv) = sentinel.ai_next; |
|
2133 return NS_SUCCESS; |
|
2134 } |
|
2135 |
|
2136 #endif /* __SYMBIAN32__ */ |
|
2137 |
|
2138 #ifndef __SYMBIAN32__ |
|
2139 static void |
|
2140 _sethtent(FILE **hostf) |
|
2141 { |
|
2142 if (!*hostf) { } |
|
2143 |
|
2144 #ifndef __SYMBIAN32__ |
|
2145 *hostf = fopen(_PATH_HOSTS, "r"); |
|
2146 #endif |
|
2147 else |
|
2148 rewind(*hostf); |
|
2149 } |
|
2150 |
|
2151 static void |
|
2152 _endhtent(FILE **hostf) |
|
2153 { |
|
2154 if (*hostf) { |
|
2155 (void) fclose(*hostf); |
|
2156 *hostf = NULL; |
|
2157 } |
|
2158 } |
|
2159 #endif /* __SYMBIAN32__ */ |
|
2160 |
|
2161 #ifndef __SYMBIAN32__ |
|
2162 |
|
2163 static struct addrinfo * |
|
2164 _gethtent(FILE **hostf, const char *name, const struct addrinfo *pai) |
|
2165 { |
|
2166 char *p; |
|
2167 char *cp, *tname, *cname; |
|
2168 struct addrinfo hints, *res0, *res; |
|
2169 int error; |
|
2170 const char *addr; |
|
2171 char hostbuf[8*1024]; |
|
2172 #ifndef __SYMBIAN32__ |
|
2173 if (!*hostf && !(*hostf = fopen(_PATH_HOSTS, "r"))) |
|
2174 #endif//__SYMBIAN32__ |
|
2175 return (NULL); |
|
2176 again: |
|
2177 if (!(p = fgets(hostbuf, sizeof hostbuf, *hostf))) |
|
2178 return (NULL); |
|
2179 if (*p == '#') |
|
2180 goto again; |
|
2181 // to strip both carriage return and line feed character |
|
2182 cp = strpbrk(p, "#\r\n"); |
|
2183 |
|
2184 if (cp != NULL) |
|
2185 *cp = '\0'; |
|
2186 if (!(cp = strpbrk(p, " \t"))) |
|
2187 goto again; |
|
2188 *cp++ = '\0'; |
|
2189 addr = p; |
|
2190 cname = NULL; |
|
2191 /* if this is not something we're looking for, skip it. */ |
|
2192 while (cp && *cp) { |
|
2193 if (*cp == ' ' || *cp == '\t') { |
|
2194 cp++; |
|
2195 continue; |
|
2196 } |
|
2197 tname = cp; |
|
2198 if (cname == NULL) |
|
2199 cname = cp; |
|
2200 if ((cp = strpbrk(cp, " \t")) != NULL) |
|
2201 *cp++ = '\0'; |
|
2202 if (strcasecmp(name, tname) == 0) |
|
2203 goto found; |
|
2204 } |
|
2205 goto again; |
|
2206 |
|
2207 found: |
|
2208 /* we should not glob socktype/protocol here */ |
|
2209 memset(&hints, 0, sizeof(hints)); |
|
2210 hints.ai_family = pai->ai_family; |
|
2211 hints.ai_socktype = SOCK_DGRAM; |
|
2212 hints.ai_protocol = 0; |
|
2213 hints.ai_flags = AI_NUMERICHOST; |
|
2214 error = getaddrinfo(addr, "0", &hints, &res0); |
|
2215 if (error) |
|
2216 goto again; |
|
2217 #ifdef FILTER_V4MAPPED |
|
2218 /* XXX should check all items in the chain */ |
|
2219 if (res0->ai_family == AF_INET6 && |
|
2220 IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)res0->ai_addr)->sin6_addr)) { |
|
2221 freeaddrinfo(res0); |
|
2222 goto again; |
|
2223 } |
|
2224 #endif |
|
2225 for (res = res0; res; res = res->ai_next) { |
|
2226 /* cover it up */ |
|
2227 res->ai_flags = pai->ai_flags; |
|
2228 res->ai_socktype = pai->ai_socktype; |
|
2229 res->ai_protocol = pai->ai_protocol; |
|
2230 |
|
2231 if (pai->ai_flags & AI_CANONNAME) { |
|
2232 if (get_canonname(pai, res, cname) != 0) { |
|
2233 freeaddrinfo(res0); |
|
2234 goto again; |
|
2235 } |
|
2236 } |
|
2237 } |
|
2238 return res0; |
|
2239 } |
|
2240 |
|
2241 #endif //__SYMBIAN32__ |
|
2242 /*ARGSUSED*/ |
|
2243 #ifndef __SYMBIAN32__ |
|
2244 |
|
2245 static int |
|
2246 _files_getaddrinfo(rv, cb_data, ap) |
|
2247 void *rv; |
|
2248 void *cb_data; |
|
2249 va_list ap; |
|
2250 { |
|
2251 const char *name; |
|
2252 const struct addrinfo *pai; |
|
2253 struct addrinfo sentinel, *cur; |
|
2254 struct addrinfo *p; |
|
2255 FILE *hostf = NULL; |
|
2256 name = va_arg(ap, char *); |
|
2257 pai = va_arg(ap, struct addrinfo *); |
|
2258 |
|
2259 memset(&sentinel, 0, sizeof(sentinel)); |
|
2260 cur = &sentinel; |
|
2261 |
|
2262 _sethtent(&hostf); |
|
2263 while ((p = _gethtent(&hostf, name, pai)) != NULL) { |
|
2264 cur->ai_next = p; |
|
2265 while (cur && cur->ai_next) |
|
2266 cur = cur->ai_next; |
|
2267 } |
|
2268 _endhtent(&hostf); |
|
2269 |
|
2270 *((struct addrinfo **)rv) = sentinel.ai_next; |
|
2271 if (sentinel.ai_next == NULL) |
|
2272 return NS_NOTFOUND; |
|
2273 return NS_SUCCESS; |
|
2274 } |
|
2275 #endif // __SYMBIAN32__ |
|
2276 |
|
2277 #ifdef YP |
|
2278 /*ARGSUSED*/ |
|
2279 static struct addrinfo * |
|
2280 _yphostent(line, pai) |
|
2281 char *line; |
|
2282 const struct addrinfo *pai; |
|
2283 { |
|
2284 struct addrinfo sentinel, *cur; |
|
2285 struct addrinfo hints, *res, *res0; |
|
2286 int error; |
|
2287 char *p = line; |
|
2288 const char *addr, *canonname; |
|
2289 char *nextline; |
|
2290 char *cp; |
|
2291 |
|
2292 addr = canonname = NULL; |
|
2293 |
|
2294 memset(&sentinel, 0, sizeof(sentinel)); |
|
2295 cur = &sentinel; |
|
2296 |
|
2297 nextline: |
|
2298 /* terminate line */ |
|
2299 cp = strchr(p, '\n'); |
|
2300 if (cp) { |
|
2301 *cp++ = '\0'; |
|
2302 nextline = cp; |
|
2303 } else |
|
2304 nextline = NULL; |
|
2305 |
|
2306 cp = strpbrk(p, " \t"); |
|
2307 if (cp == NULL) { |
|
2308 if (canonname == NULL) |
|
2309 return (NULL); |
|
2310 else |
|
2311 goto done; |
|
2312 } |
|
2313 *cp++ = '\0'; |
|
2314 |
|
2315 addr = p; |
|
2316 |
|
2317 while (cp && *cp) { |
|
2318 if (*cp == ' ' || *cp == '\t') { |
|
2319 cp++; |
|
2320 continue; |
|
2321 } |
|
2322 if (!canonname) |
|
2323 canonname = cp; |
|
2324 if ((cp = strpbrk(cp, " \t")) != NULL) |
|
2325 *cp++ = '\0'; |
|
2326 } |
|
2327 |
|
2328 hints = *pai; |
|
2329 hints.ai_flags = AI_NUMERICHOST; |
|
2330 error = getaddrinfo(addr, NULL, &hints, &res0); |
|
2331 if (error == 0) { |
|
2332 for (res = res0; res; res = res->ai_next) { |
|
2333 /* cover it up */ |
|
2334 res->ai_flags = pai->ai_flags; |
|
2335 |
|
2336 if (pai->ai_flags & AI_CANONNAME) |
|
2337 (void)get_canonname(pai, res, canonname); |
|
2338 } |
|
2339 } else |
|
2340 res0 = NULL; |
|
2341 if (res0) { |
|
2342 cur->ai_next = res0; |
|
2343 while (cur && cur->ai_next) |
|
2344 cur = cur->ai_next; |
|
2345 } |
|
2346 |
|
2347 if (nextline) { |
|
2348 p = nextline; |
|
2349 goto nextline; |
|
2350 } |
|
2351 |
|
2352 done: |
|
2353 return sentinel.ai_next; |
|
2354 } |
|
2355 |
|
2356 /*ARGSUSED*/ |
|
2357 static int |
|
2358 _yp_getaddrinfo(rv, cb_data, ap) |
|
2359 void *rv; |
|
2360 void *cb_data; |
|
2361 va_list ap; |
|
2362 { |
|
2363 struct addrinfo sentinel, *cur; |
|
2364 struct addrinfo *ai = NULL; |
|
2365 char *ypbuf; |
|
2366 int ypbuflen, r; |
|
2367 const char *name; |
|
2368 const struct addrinfo *pai; |
|
2369 char *ypdomain; |
|
2370 |
|
2371 if (_yp_check(&ypdomain) == 0) |
|
2372 return NS_UNAVAIL; |
|
2373 |
|
2374 name = va_arg(ap, char *); |
|
2375 pai = va_arg(ap, const struct addrinfo *); |
|
2376 |
|
2377 memset(&sentinel, 0, sizeof(sentinel)); |
|
2378 cur = &sentinel; |
|
2379 |
|
2380 /* hosts.byname is only for IPv4 (Solaris8) */ |
|
2381 if (pai->ai_family == PF_UNSPEC || pai->ai_family == PF_INET) { |
|
2382 r = yp_match(ypdomain, "hosts.byname", name, |
|
2383 (int)strlen(name), &ypbuf, &ypbuflen); |
|
2384 if (r == 0) { |
|
2385 struct addrinfo ai4; |
|
2386 |
|
2387 ai4 = *pai; |
|
2388 ai4.ai_family = AF_INET; |
|
2389 ai = _yphostent(ypbuf, &ai4); |
|
2390 if (ai) { |
|
2391 cur->ai_next = ai; |
|
2392 while (cur && cur->ai_next) |
|
2393 cur = cur->ai_next; |
|
2394 } |
|
2395 free(ypbuf); |
|
2396 } |
|
2397 } |
|
2398 |
|
2399 /* ipnodes.byname can hold both IPv4/v6 */ |
|
2400 r = yp_match(ypdomain, "ipnodes.byname", name, |
|
2401 (int)strlen(name), &ypbuf, &ypbuflen); |
|
2402 if (r == 0) { |
|
2403 ai = _yphostent(ypbuf, pai); |
|
2404 if (ai) |
|
2405 cur->ai_next = ai; |
|
2406 free(ypbuf); |
|
2407 } |
|
2408 |
|
2409 if (sentinel.ai_next == NULL) { |
|
2410 h_errno = HOST_NOT_FOUND; |
|
2411 return NS_NOTFOUND; |
|
2412 } |
|
2413 *((struct addrinfo **)rv) = sentinel.ai_next; |
|
2414 return NS_SUCCESS; |
|
2415 } |
|
2416 #endif |
|
2417 |
|
2418 /* resolver logic */ |
|
2419 |
|
2420 extern const char *_res_hostalias(const char *, char *, size_t); |
|
2421 |
|
2422 /* |
|
2423 * Formulate a normal query, send, and await answer. |
|
2424 * Returned answer is placed in supplied buffer "answer". |
|
2425 * Perform preliminary check of answer, returning success only |
|
2426 * if no error is indicated and the answer count is nonzero. |
|
2427 * Return the size of the response on success, -1 on error. |
|
2428 * Error number is left in h_errno. |
|
2429 * |
|
2430 * Caller must parse answer and determine whether it answers the question. |
|
2431 */ |
|
2432 #ifndef __SYMBIAN32__ |
|
2433 static int |
|
2434 res_queryN(name, target) |
|
2435 const char *name; /* domain name */ |
|
2436 struct res_target *target; |
|
2437 { |
|
2438 u_char *buf; |
|
2439 HEADER *hp; |
|
2440 int n; |
|
2441 struct res_target *t; |
|
2442 int rcode; |
|
2443 int ancount; |
|
2444 |
|
2445 rcode = NOERROR; |
|
2446 ancount = 0; |
|
2447 |
|
2448 buf = malloc(MAXPACKET); |
|
2449 if (!buf) { |
|
2450 h_errno = NETDB_INTERNAL; |
|
2451 return -1; |
|
2452 } |
|
2453 |
|
2454 for (t = target; t; t = t->next) { |
|
2455 int class, type; |
|
2456 u_char *answer; |
|
2457 int anslen; |
|
2458 |
|
2459 hp = (HEADER *)(void *)t->answer; |
|
2460 hp->rcode = NOERROR; /* default */ |
|
2461 |
|
2462 /* make it easier... */ |
|
2463 class = t->qclass; |
|
2464 type = t->qtype; |
|
2465 answer = t->answer; |
|
2466 anslen = t->anslen; |
|
2467 #ifdef DEBUG |
|
2468 if (_res.options & RES_DEBUG) |
|
2469 printf(";; res_query(%s, %d, %d)\n", name, class, type); |
|
2470 #endif |
|
2471 |
|
2472 n = res_mkquery(QUERY, name, class, type, NULL, 0, NULL, |
|
2473 buf, MAXPACKET); |
|
2474 if (n > 0 && (_res.options & RES_USE_EDNS0) != 0) |
|
2475 n = res_opt(n, buf, MAXPACKET, anslen); |
|
2476 if (n <= 0) { |
|
2477 #ifdef DEBUG |
|
2478 if (_res.options & RES_DEBUG) |
|
2479 printf(";; res_query: mkquery failed\n"); |
|
2480 #endif |
|
2481 free(buf); |
|
2482 h_errno = NO_RECOVERY; |
|
2483 return (n); |
|
2484 } |
|
2485 n = res_send(buf, n, answer, anslen); |
|
2486 #if 0 |
|
2487 if (n < 0) { |
|
2488 #ifdef DEBUG |
|
2489 if (_res.options & RES_DEBUG) |
|
2490 printf(";; res_query: send error\n"); |
|
2491 #endif |
|
2492 free(buf); |
|
2493 h_errno = TRY_AGAIN; |
|
2494 return (n); |
|
2495 } |
|
2496 #endif |
|
2497 |
|
2498 if (n < 0 || n > anslen) |
|
2499 hp->rcode = FORMERR; /* XXX not very informative */ |
|
2500 if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) { |
|
2501 rcode = hp->rcode; /* record most recent error */ |
|
2502 #ifdef DEBUG |
|
2503 if (_res.options & RES_DEBUG) |
|
2504 printf(";; rcode = %u, ancount=%u\n", hp->rcode, |
|
2505 ntohs(hp->ancount)); |
|
2506 #endif |
|
2507 continue; |
|
2508 } |
|
2509 |
|
2510 ancount += ntohs(hp->ancount); |
|
2511 |
|
2512 t->n = n; |
|
2513 } |
|
2514 |
|
2515 free(buf); |
|
2516 |
|
2517 if (ancount == 0) { |
|
2518 switch (rcode) { |
|
2519 case NXDOMAIN: |
|
2520 h_errno = HOST_NOT_FOUND; |
|
2521 break; |
|
2522 case SERVFAIL: |
|
2523 h_errno = TRY_AGAIN; |
|
2524 break; |
|
2525 case NOERROR: |
|
2526 h_errno = NO_DATA; |
|
2527 break; |
|
2528 case FORMERR: |
|
2529 case NOTIMP: |
|
2530 case REFUSED: |
|
2531 default: |
|
2532 h_errno = NO_RECOVERY; |
|
2533 break; |
|
2534 } |
|
2535 return (-1); |
|
2536 } |
|
2537 return (ancount); |
|
2538 } |
|
2539 |
|
2540 #endif |
|
2541 |
|
2542 /* |
|
2543 * Formulate a normal query, send, and retrieve answer in supplied buffer. |
|
2544 * Return the size of the response on success, -1 on error. |
|
2545 * If enabled, implement search rules until answer or unrecoverable failure |
|
2546 * is detected. Error code, if any, is left in h_errno. |
|
2547 */ |
|
2548 #ifndef __SYMBIAN32__ |
|
2549 static int |
|
2550 res_searchN(name, target) |
|
2551 const char *name; /* domain name */ |
|
2552 struct res_target *target; |
|
2553 { |
|
2554 const char *cp, * const *domain; |
|
2555 HEADER *hp = (HEADER *)(void *)target->answer; /*XXX*/ |
|
2556 u_int dots; |
|
2557 int trailing_dot, ret, saved_herrno; |
|
2558 int got_nodata = 0, got_servfail = 0, tried_as_is = 0; |
|
2559 char abuf[MAXDNAME]; |
|
2560 |
|
2561 if ((_res.options & RES_INIT) == 0 && res_init() == -1) { |
|
2562 h_errno = NETDB_INTERNAL; |
|
2563 return (-1); |
|
2564 } |
|
2565 |
|
2566 errno = 0; |
|
2567 h_errno = HOST_NOT_FOUND; /* default, if we never query */ |
|
2568 dots = 0; |
|
2569 for (cp = name; *cp; cp++) |
|
2570 dots += (*cp == '.'); |
|
2571 trailing_dot = 0; |
|
2572 if (cp > name && *--cp == '.') |
|
2573 trailing_dot++; |
|
2574 |
|
2575 /* |
|
2576 * if there aren't any dots, it could be a user-level alias |
|
2577 */ |
|
2578 if (!dots && (cp = _res_hostalias(name, abuf, sizeof(abuf))) != NULL) |
|
2579 return (res_queryN(cp, target)); |
|
2580 |
|
2581 /* |
|
2582 * If there are dots in the name already, let's just give it a try |
|
2583 * 'as is'. The threshold can be set with the "ndots" option. |
|
2584 */ |
|
2585 saved_herrno = -1; |
|
2586 if (dots >= _res.ndots) { |
|
2587 ret = res_querydomainN(name, NULL, target); |
|
2588 if (ret > 0) |
|
2589 return (ret); |
|
2590 saved_herrno = h_errno; |
|
2591 tried_as_is++; |
|
2592 } |
|
2593 |
|
2594 /* |
|
2595 * We do at least one level of search if |
|
2596 * - there is no dot and RES_DEFNAME is set, or |
|
2597 * - there is at least one dot, there is no trailing dot, |
|
2598 * and RES_DNSRCH is set. |
|
2599 */ |
|
2600 if ((!dots && (_res.options & RES_DEFNAMES)) || |
|
2601 (dots && !trailing_dot && (_res.options & RES_DNSRCH))) { |
|
2602 int done = 0; |
|
2603 |
|
2604 for (domain = (const char * const *)_res.dnsrch; |
|
2605 *domain && !done; |
|
2606 domain++) { |
|
2607 |
|
2608 ret = res_querydomainN(name, *domain, target); |
|
2609 if (ret > 0) |
|
2610 return (ret); |
|
2611 |
|
2612 /* |
|
2613 * If no server present, give up. |
|
2614 * If name isn't found in this domain, |
|
2615 * keep trying higher domains in the search list |
|
2616 * (if that's enabled). |
|
2617 * On a NO_DATA error, keep trying, otherwise |
|
2618 * a wildcard entry of another type could keep us |
|
2619 * from finding this entry higher in the domain. |
|
2620 * If we get some other error (negative answer or |
|
2621 * server failure), then stop searching up, |
|
2622 * but try the input name below in case it's |
|
2623 * fully-qualified. |
|
2624 */ |
|
2625 if (errno == ECONNREFUSED) { |
|
2626 h_errno = TRY_AGAIN; |
|
2627 return (-1); |
|
2628 } |
|
2629 |
|
2630 switch (h_errno) { |
|
2631 case NO_DATA: |
|
2632 got_nodata++; |
|
2633 /* FALLTHROUGH */ |
|
2634 case HOST_NOT_FOUND: |
|
2635 /* keep trying */ |
|
2636 break; |
|
2637 case TRY_AGAIN: |
|
2638 if (hp->rcode == SERVFAIL) { |
|
2639 /* try next search element, if any */ |
|
2640 got_servfail++; |
|
2641 break; |
|
2642 } |
|
2643 /* FALLTHROUGH */ |
|
2644 default: |
|
2645 /* anything else implies that we're done */ |
|
2646 done++; |
|
2647 } |
|
2648 /* |
|
2649 * if we got here for some reason other than DNSRCH, |
|
2650 * we only wanted one iteration of the loop, so stop. |
|
2651 */ |
|
2652 if (!(_res.options & RES_DNSRCH)) |
|
2653 done++; |
|
2654 } |
|
2655 } |
|
2656 |
|
2657 /* |
|
2658 * if we have not already tried the name "as is", do that now. |
|
2659 * note that we do this regardless of how many dots were in the |
|
2660 * name or whether it ends with a dot. |
|
2661 */ |
|
2662 if (!tried_as_is && (dots || !(_res.options & RES_NOTLDQUERY))) { |
|
2663 ret = res_querydomainN(name, NULL, target); |
|
2664 if (ret > 0) |
|
2665 return (ret); |
|
2666 } |
|
2667 |
|
2668 /* |
|
2669 * if we got here, we didn't satisfy the search. |
|
2670 * if we did an initial full query, return that query's h_errno |
|
2671 * (note that we wouldn't be here if that query had succeeded). |
|
2672 * else if we ever got a nodata, send that back as the reason. |
|
2673 * else send back meaningless h_errno, that being the one from |
|
2674 * the last DNSRCH we did. |
|
2675 */ |
|
2676 if (saved_herrno != -1) |
|
2677 h_errno = saved_herrno; |
|
2678 else if (got_nodata) |
|
2679 h_errno = NO_DATA; |
|
2680 else if (got_servfail) |
|
2681 h_errno = TRY_AGAIN; |
|
2682 return (-1); |
|
2683 } |
|
2684 #endif |
|
2685 /* |
|
2686 * Perform a call on res_query on the concatenation of name and domain, |
|
2687 * removing a trailing dot from name if domain is NULL. |
|
2688 */ |
|
2689 |
|
2690 #ifndef __SYMBIAN32__ |
|
2691 static int |
|
2692 res_querydomainN(name, domain, target) |
|
2693 const char *name, *domain; |
|
2694 struct res_target *target; |
|
2695 { |
|
2696 char nbuf[MAXDNAME]; |
|
2697 const char *longname = nbuf; |
|
2698 size_t n, d; |
|
2699 |
|
2700 #ifdef DEBUG |
|
2701 if (_res.options & RES_DEBUG) |
|
2702 printf(";; res_querydomain(%s, %s)\n", |
|
2703 name, domain?domain:"<Nil>"); |
|
2704 #endif |
|
2705 if (domain == NULL) { |
|
2706 /* |
|
2707 * Check for trailing '.'; |
|
2708 * copy without '.' if present. |
|
2709 */ |
|
2710 n = strlen(name); |
|
2711 if (n >= MAXDNAME) { |
|
2712 h_errno = NO_RECOVERY; |
|
2713 return (-1); |
|
2714 } |
|
2715 if (n > 0 && name[--n] == '.') { |
|
2716 strncpy(nbuf, name, n); |
|
2717 nbuf[n] = '\0'; |
|
2718 } else |
|
2719 longname = name; |
|
2720 } else { |
|
2721 n = strlen(name); |
|
2722 d = strlen(domain); |
|
2723 if (n + d + 1 >= MAXDNAME) { |
|
2724 h_errno = NO_RECOVERY; |
|
2725 return (-1); |
|
2726 } |
|
2727 snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain); |
|
2728 } |
|
2729 return (res_queryN(longname, target)); |
|
2730 } |
|
2731 #endif /*__SYMBIAN32__*/ |
|
2732 |
|
2733 #ifdef __SYMBIAN32__ |
|
2734 static long int |
|
2735 explore_hostname(pai, hostname, servname, res, hints) |
|
2736 struct addrinfo *pai; |
|
2737 const char *hostname; |
|
2738 const char *servname; |
|
2739 struct addrinfo **res; |
|
2740 const struct addrinfo *hints; |
|
2741 { |
|
2742 const struct afd *afd; |
|
2743 struct addrinfo *cur; |
|
2744 struct addrinfo sentinel; |
|
2745 int error; |
|
2746 int family_flag=0; |
|
2747 *res = NULL; |
|
2748 |
|
2749 sentinel.ai_next = NULL; |
|
2750 cur = &sentinel; |
|
2751 |
|
2752 /* |
|
2753 * if the servname does not match socktype/protocol, ignore it. |
|
2754 */ |
|
2755 |
|
2756 if (get_portmatch(pai, servname) != 0) |
|
2757 return 0; |
|
2758 if (pai->ai_family == PF_UNSPEC) { |
|
2759 #ifdef PF_INET6 |
|
2760 #ifdef __SYMBIAN32__ |
|
2761 // XXX: Fix this |
|
2762 pai->ai_family = PF_INET; |
|
2763 #else |
|
2764 pai->ai_family = PF_INET6; |
|
2765 #endif // __SYMBIAN32__ |
|
2766 #else |
|
2767 pai->ai_family = PF_INET; |
|
2768 #endif |
|
2769 family_flag=1; |
|
2770 } |
|
2771 |
|
2772 afd = find_afd(pai->ai_family); |
|
2773 if( afd==NULL && family_flag ) |
|
2774 { |
|
2775 if(pai->ai_family==PF_INET6) |
|
2776 { |
|
2777 pai->ai_family=PF_INET; |
|
2778 } |
|
2779 else |
|
2780 { |
|
2781 pai->ai_family=PF_INET6; |
|
2782 } |
|
2783 afd=find_afd(pai->ai_family); |
|
2784 } |
|
2785 |
|
2786 if (afd == NULL) |
|
2787 { |
|
2788 return 0; |
|
2789 } |
|
2790 |
|
2791 if ( pai->ai_family == PF_UNSPEC ||pai->ai_family == afd->a_af) |
|
2792 { |
|
2793 struct addrinfo *resNative; |
|
2794 struct addrinfo *currNative; |
|
2795 int haveV4Mapped = 0; |
|
2796 /* Get the list of addresses using the native api */ |
|
2797 int ret = getaddrinfo_private(hostname, pai, &resNative); |
|
2798 if(ret != 0) |
|
2799 ERR(ret); |
|
2800 |
|
2801 /* copy the addresses to the local list */ |
|
2802 currNative = resNative; |
|
2803 while(currNative) |
|
2804 { |
|
2805 if(currNative->ai_family == PF_INET && (hints->ai_family == PF_INET || hints->ai_family == PF_UNSPEC)) |
|
2806 { |
|
2807 if(currNative->ai_flags & AI_V4MAPPED) |
|
2808 { |
|
2809 haveV4Mapped = 1; |
|
2810 } |
|
2811 else |
|
2812 { |
|
2813 struct sockaddr_in* sAddrTmp = (struct sockaddr_in*) (currNative->ai_addr); |
|
2814 GET_AI(cur->ai_next, afd, (char*)&(sAddrTmp->sin_addr)); |
|
2815 cur->ai_next->ai_addr->sa_family = cur->ai_next->ai_family = PF_INET; |
|
2816 GET_PORT(cur->ai_next, servname); |
|
2817 |
|
2818 if((pai->ai_flags & AI_CANONNAME)) |
|
2819 GET_CANONNAME(cur->ai_next, currNative->ai_canonname); |
|
2820 |
|
2821 cur = cur->ai_next; |
|
2822 } |
|
2823 } |
|
2824 |
|
2825 if(currNative->ai_family == PF_INET6 && (hints->ai_family == PF_INET6 || hints->ai_family == PF_UNSPEC)) |
|
2826 { |
|
2827 struct sockaddr_in6* sAddrTmp = (struct sockaddr_in6*) (currNative->ai_addr); |
|
2828 GET_AI(cur->ai_next, afd, (char*)&(sAddrTmp->sin6_addr)); |
|
2829 cur->ai_next->ai_addr->sa_family = cur->ai_next->ai_family = PF_INET6; |
|
2830 GET_PORT(cur->ai_next, servname); |
|
2831 |
|
2832 if((pai->ai_flags & AI_CANONNAME)) |
|
2833 GET_CANONNAME(cur->ai_next, currNative->ai_canonname); |
|
2834 |
|
2835 cur = cur->ai_next; |
|
2836 } |
|
2837 |
|
2838 currNative = currNative->ai_next; |
|
2839 } |
|
2840 |
|
2841 if(hints->ai_family == PF_INET && !sentinel.ai_next && haveV4Mapped) |
|
2842 { |
|
2843 currNative = resNative; |
|
2844 while(currNative) |
|
2845 { |
|
2846 //This is the set of Mapped Addresses. |
|
2847 if(currNative->ai_flags & AI_V4MAPPED) |
|
2848 { |
|
2849 struct sockaddr_in* sAddrTmp = (struct sockaddr_in*) (currNative->ai_addr); |
|
2850 currNative->ai_flags &= ~AI_V4MAPPED; |
|
2851 GET_AI(cur->ai_next, afd, (char*)&(sAddrTmp->sin_addr)); |
|
2852 cur->ai_next->ai_addr->sa_family = cur->ai_next->ai_family = PF_INET; |
|
2853 GET_PORT(cur->ai_next, servname); |
|
2854 |
|
2855 if((pai->ai_flags & AI_CANONNAME)) |
|
2856 GET_CANONNAME(cur->ai_next, currNative->ai_canonname); |
|
2857 cur = cur->ai_next; |
|
2858 } |
|
2859 |
|
2860 currNative = currNative->ai_next; |
|
2861 } |
|
2862 } |
|
2863 /* free the address list returned by native api */ |
|
2864 freeaddrinfo_private(resNative); |
|
2865 } |
|
2866 else |
|
2867 ERR(EAI_FAMILY); |
|
2868 |
|
2869 *res = sentinel.ai_next; |
|
2870 return 0; |
|
2871 |
|
2872 free: |
|
2873 bad: |
|
2874 if (sentinel.ai_next) |
|
2875 freeaddrinfo(sentinel.ai_next); |
|
2876 return error; |
|
2877 } |
|
2878 |
|
2879 #endif//__SYMBIAN32__ |