getaddrinfo.c revision 1.30 1 /* $NetBSD: getaddrinfo.c,v 1.30 2000/02/16 04:50:23 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
32 /*
33 * Issues to be discussed:
34 * - Thread safe-ness must be checked.
35 * - Return values. There are nonstandard return values defined and used
36 * in the source code. This is because RFC2553 is silent about which error
37 * code must be returned for which situation.
38 * - IPv4 classful (shortened) form. RFC2553 is silent about it. XNET 5.2
39 * says to use inet_aton() to convert IPv4 numeric to binary (alows
40 * classful form as a result).
41 * current code - disallow classful form for IPv4 (due to use of inet_pton).
42 * - freeaddrinfo(NULL). RFC2553 is silent about it. XNET 5.2 says it is
43 * invalid.
44 * current code - SEGV on freeaddrinfo(NULL)
45 * Note:
46 * - We use getipnodebyname() just for thread-safeness. There's no intent
47 * to let it do PF_UNSPEC (actually we never pass PF_UNSPEC to
48 * getipnodebyname().
49 * - The code filters out AFs that are not supported by the kernel,
50 * when globbing NULL hostname (to loopback, or wildcard). Is it the right
51 * thing to do? What is the relationship with post-RFC2553 AI_ADDRCONFIG
52 * in ai_flags?
53 * - (post-2553) semantics of AI_ADDRCONFIG itself is too vague.
54 * (1) what should we do against numeric hostname (2) what should we do
55 * against NULL hostname (3) what is AI_ADDRCONFIG itself. AF not ready?
56 * non-loopback address configured? global address configured?
57 * - The code makes use of following calls when asked to resolver with
58 * ai_family = PF_UNSPEC:
59 * getipnodebyname(host, AF_INET6);
60 * getipnodebyname(host, AF_INET);
61 * This will result in the following queries if the node is configure to
62 * prefer /etc/hosts than DNS:
63 * lookup /etc/hosts for IPv6 address
64 * lookup DNS for IPv6 address
65 * lookup /etc/hosts for IPv4 address
66 * lookup DNS for IPv4 address
67 * which may not meet people's requirement.
68 * The right thing to happen is to have underlying layer which does
69 * PF_UNSPEC lookup (lookup both) and return chain of addrinfos.
70 * This would result in a bit of code duplicate with _dns_ghbyname() and
71 * friends.
72 */
73
74 #include <sys/types.h>
75 #include <sys/param.h>
76 #include <sys/socket.h>
77 #include <net/if.h>
78 #include <netinet/in.h>
79 #include <arpa/inet.h>
80 #include <arpa/nameser.h>
81 #include <netdb.h>
82 #include <resolv.h>
83 #include <string.h>
84 #include <stdlib.h>
85 #include <stddef.h>
86 #include <ctype.h>
87 #include <unistd.h>
88 #include <stdio.h>
89 #include <errno.h>
90
91 #define SUCCESS 0
92 #define ANY 0
93 #define YES 1
94 #define NO 0
95
96 static const char in_addrany[] = { 0, 0, 0, 0 };
97 static const char in6_addrany[] = {
98 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
99 };
100 static const char in_loopback[] = { 127, 0, 0, 1 };
101 static const char in6_loopback[] = {
102 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
103 };
104
105 struct sockinet {
106 u_char si_len;
107 u_char si_family;
108 u_short si_port;
109 u_int32_t si_scope_id;
110 };
111
112 static const struct afd {
113 int a_af;
114 int a_addrlen;
115 int a_socklen;
116 int a_off;
117 const char *a_addrany;
118 const char *a_loopback;
119 int a_scoped;
120 } afdl [] = {
121 #ifdef INET6
122 {PF_INET6, sizeof(struct in6_addr),
123 sizeof(struct sockaddr_in6),
124 offsetof(struct sockaddr_in6, sin6_addr),
125 in6_addrany, in6_loopback, 1},
126 #endif
127 {PF_INET, sizeof(struct in_addr),
128 sizeof(struct sockaddr_in),
129 offsetof(struct sockaddr_in, sin_addr),
130 in_addrany, in_loopback, 0},
131 {0, 0, 0, 0, NULL, NULL, 0},
132 };
133
134 struct explore {
135 int e_af;
136 int e_socktype;
137 int e_protocol;
138 const char *e_protostr;
139 int e_wild;
140 #define WILD_AF(ex) ((ex)->e_wild & 0x01)
141 #define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02)
142 #define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04)
143 };
144
145 static const struct explore explore[] = {
146 #if 0
147 { PF_LOCAL, 0, ANY, ANY, NULL, 0x01 },
148 #endif
149 #ifdef INET6
150 { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
151 { PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
152 { PF_INET6, SOCK_RAW, ANY, NULL, 0x05 },
153 #endif
154 { PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
155 { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
156 { PF_INET, SOCK_RAW, ANY, NULL, 0x05 },
157 { -1, 0, 0, NULL, 0 },
158 };
159
160 #ifdef INET6
161 #define PTON_MAX 16
162 #else
163 #define PTON_MAX 4
164 #endif
165
166
167 static int str_isnumber __P((const char *));
168 static int explore_fqdn __P((const struct addrinfo *, const char *,
169 const char *, struct addrinfo **));
170 static int explore_null __P((const struct addrinfo *,
171 const char *, struct addrinfo **));
172 static int explore_numeric __P((const struct addrinfo *, const char *,
173 const char *, struct addrinfo **));
174 static int explore_numeric_scope __P((const struct addrinfo *, const char *,
175 const char *, struct addrinfo **));
176 static int get_canonname __P((const struct addrinfo *,
177 struct addrinfo *, const char *));
178 static struct addrinfo *get_ai __P((const struct addrinfo *,
179 const struct afd *, const char *));
180 static int get_portmatch __P((const struct addrinfo *, const char *));
181 static int get_port __P((struct addrinfo *, const char *, int));
182 static const struct afd *find_afd __P((int));
183 static int addrconfig __P((const struct addrinfo *));
184 #ifdef INET6
185 static int ip6_str2scopeid __P((char *, struct sockaddr_in6 *));
186 #endif
187
188 static char *ai_errlist[] = {
189 "Success",
190 "Address family for hostname not supported", /* EAI_ADDRFAMILY */
191 "Temporary failure in name resolution", /* EAI_AGAIN */
192 "Invalid value for ai_flags", /* EAI_BADFLAGS */
193 "Non-recoverable failure in name resolution", /* EAI_FAIL */
194 "ai_family not supported", /* EAI_FAMILY */
195 "Memory allocation failure", /* EAI_MEMORY */
196 "No address associated with hostname", /* EAI_NODATA */
197 "hostname nor servname provided, or not known", /* EAI_NONAME */
198 "servname not supported for ai_socktype", /* EAI_SERVICE */
199 "ai_socktype not supported", /* EAI_SOCKTYPE */
200 "System error returned in errno", /* EAI_SYSTEM */
201 "Invalid value for hints", /* EAI_BADHINTS */
202 "Resolved protocol is unknown", /* EAI_PROTOCOL */
203 "Unknown error", /* EAI_MAX */
204 };
205
206 /* XXX macros that make external reference is BAD. */
207
208 #define GET_AI(ai, afd, addr) \
209 do { \
210 /* external reference: pai, error, and label free */ \
211 (ai) = get_ai(pai, (afd), (addr)); \
212 if ((ai) == NULL) { \
213 error = EAI_MEMORY; \
214 goto free; \
215 } \
216 } while (/*CONSTCOND*/0)
217
218 #define GET_PORT(ai, serv) \
219 do { \
220 /* external reference: error and label free */ \
221 error = get_port((ai), (serv), 0); \
222 if (error != 0) \
223 goto free; \
224 } while (/*CONSTCOND*/0)
225
226 #define GET_CANONNAME(ai, str) \
227 do { \
228 /* external reference: pai, error and label free */ \
229 error = get_canonname(pai, (ai), (str)); \
230 if (error != 0) \
231 goto free; \
232 } while (/*CONSTCOND*/0)
233
234 #define ERR(err) \
235 do { \
236 /* external reference: error, and label bad */ \
237 error = (err); \
238 goto bad; \
239 } while (/*CONSTCOND*/0)
240
241 #define MATCH_FAMILY(x, y, w) \
242 ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC)))
243 #define MATCH(x, y, w) \
244 ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY)))
245
246 char *
247 gai_strerror(ecode)
248 int ecode;
249 {
250 if (ecode < 0 || ecode > EAI_MAX)
251 ecode = EAI_MAX;
252 return ai_errlist[ecode];
253 }
254
255 void
256 freeaddrinfo(ai)
257 struct addrinfo *ai;
258 {
259 struct addrinfo *next;
260
261 do {
262 next = ai->ai_next;
263 if (ai->ai_canonname)
264 free(ai->ai_canonname);
265 /* no need to free(ai->ai_addr) */
266 free(ai);
267 ai = next;
268 } while (ai);
269 }
270
271 static int
272 str_isnumber(p)
273 const char *p;
274 {
275 const char *q = (const char *)p;
276 while (*q) {
277 if (!isdigit(*q))
278 return NO;
279 q++;
280 }
281 return YES;
282 }
283
284 int
285 getaddrinfo(hostname, servname, hints, res)
286 const char *hostname, *servname;
287 const struct addrinfo *hints;
288 struct addrinfo **res;
289 {
290 struct addrinfo sentinel;
291 struct addrinfo *cur;
292 int error = 0;
293 struct addrinfo ai;
294 struct addrinfo ai0;
295 struct addrinfo *pai;
296 const struct afd *afd;
297 const struct explore *ex;
298
299 sentinel.ai_next = NULL;
300 cur = &sentinel;
301 pai = &ai;
302 pai->ai_flags = 0;
303 pai->ai_family = PF_UNSPEC;
304 pai->ai_socktype = ANY;
305 pai->ai_protocol = ANY;
306 pai->ai_addrlen = 0;
307 pai->ai_canonname = NULL;
308 pai->ai_addr = NULL;
309 pai->ai_next = NULL;
310
311 if (hostname == NULL && servname == NULL)
312 return EAI_NONAME;
313 if (hints) {
314 /* error check for hints */
315 if (hints->ai_addrlen || hints->ai_canonname ||
316 hints->ai_addr || hints->ai_next)
317 ERR(EAI_BADHINTS); /* xxx */
318 if (hints->ai_flags & ~AI_MASK)
319 ERR(EAI_BADFLAGS);
320 switch (hints->ai_family) {
321 case PF_UNSPEC:
322 case PF_INET:
323 #ifdef INET6
324 case PF_INET6:
325 #endif
326 break;
327 default:
328 ERR(EAI_FAMILY);
329 }
330 memcpy(pai, hints, sizeof(*pai));
331
332 /*
333 * if both socktype/protocol are specified, check if they
334 * are meaningful combination.
335 */
336 if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) {
337 for (ex = explore; ex->e_af >= 0; ex++) {
338 if (pai->ai_family != ex->e_af)
339 continue;
340 if (ex->e_socktype == ANY)
341 continue;
342 if (ex->e_protocol == ANY)
343 continue;
344 if (pai->ai_socktype == ex->e_socktype
345 && pai->ai_protocol != ex->e_protocol) {
346 ERR(EAI_BADHINTS);
347 }
348 }
349 }
350 }
351
352 /*
353 * check for special cases. (1) numeric servname is disallowed if
354 * socktype/protocol are left unspecified. (2) servname is disallowed
355 * for raw and other inet{,6} sockets.
356 */
357 if (MATCH_FAMILY(pai->ai_family, PF_INET, 1)
358 #ifdef PF_INET6
359 || MATCH_FAMILY(pai->ai_family, PF_INET6, 1)
360 #endif
361 ) {
362 ai0 = *pai; /* backup *pai */
363
364 if (pai->ai_family == PF_UNSPEC) {
365 #ifdef PF_INET6
366 pai->ai_family = PF_INET6;
367 #else
368 pai->ai_family = PF_INET;
369 #endif
370 }
371 error = get_portmatch(pai, servname);
372 if (error)
373 ERR(error);
374
375 *pai = ai0;
376 }
377
378 ai0 = *pai;
379
380 /* NULL hostname, or numeric hostname */
381 for (ex = explore; ex->e_af >= 0; ex++) {
382 *pai = ai0;
383
384 if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
385 continue;
386 if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex)))
387 continue;
388 if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex)))
389 continue;
390
391 if (pai->ai_family == PF_UNSPEC)
392 pai->ai_family = ex->e_af;
393 if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
394 pai->ai_socktype = ex->e_socktype;
395 if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
396 pai->ai_protocol = ex->e_protocol;
397
398 if (hostname == NULL)
399 error = explore_null(pai, servname, &cur->ai_next);
400 else
401 error = explore_numeric_scope(pai, hostname, servname, &cur->ai_next);
402
403 if (error)
404 goto free;
405
406 while (cur && cur->ai_next)
407 cur = cur->ai_next;
408 }
409
410 /*
411 * XXX
412 * If numreic representation of AF1 can be interpreted as FQDN
413 * representation of AF2, we need to think again about the code below.
414 */
415 if (sentinel.ai_next)
416 goto good;
417
418 if (pai->ai_flags & AI_NUMERICHOST)
419 ERR(EAI_NONAME);
420 if (hostname == NULL)
421 ERR(EAI_NONAME);
422
423 /*
424 * hostname as alphabetical name.
425 * we would like to prefer AF_INET6 than AF_INET, so we'll make a
426 * outer loop by AFs.
427 */
428 for (afd = afdl; afd->a_af; afd++) {
429 *pai = ai0;
430
431 if (!MATCH_FAMILY(pai->ai_family, afd->a_af, 1))
432 continue;
433
434 for (ex = explore; ex->e_af >= 0; ex++) {
435 *pai = ai0;
436
437 if (pai->ai_family == PF_UNSPEC)
438 pai->ai_family = afd->a_af;
439
440 if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
441 continue;
442 if (!MATCH(pai->ai_socktype, ex->e_socktype,
443 WILD_SOCKTYPE(ex))) {
444 continue;
445 }
446 if (!MATCH(pai->ai_protocol, ex->e_protocol,
447 WILD_PROTOCOL(ex))) {
448 continue;
449 }
450
451 if (pai->ai_family == PF_UNSPEC)
452 pai->ai_family = ex->e_af;
453 if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
454 pai->ai_socktype = ex->e_socktype;
455 if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
456 pai->ai_protocol = ex->e_protocol;
457
458 error = explore_fqdn(pai, hostname, servname,
459 &cur->ai_next);
460
461 while (cur && cur->ai_next)
462 cur = cur->ai_next;
463 }
464 }
465
466 /* XXX */
467 if (sentinel.ai_next)
468 error = 0;
469
470 if (error)
471 goto free;
472 if (error == 0) {
473 if (sentinel.ai_next) {
474 good:
475 *res = sentinel.ai_next;
476 return SUCCESS;
477 } else
478 error = EAI_FAIL;
479 }
480 free:
481 bad:
482 if (sentinel.ai_next)
483 freeaddrinfo(sentinel.ai_next);
484 *res = NULL;
485 return error;
486 }
487
488 /*
489 * FQDN hostname, DNS lookup
490 */
491 static int
492 explore_fqdn(pai, hostname, servname, res)
493 const struct addrinfo *pai;
494 const char *hostname;
495 const char *servname;
496 struct addrinfo **res;
497 {
498 struct hostent *hp;
499 int h_error;
500 int af;
501 char **aplist = NULL, *apbuf = NULL;
502 char *ap;
503 struct addrinfo sentinel, *cur;
504 int i;
505 int naddrs;
506 const struct afd *afd;
507 int error = 0;
508
509 *res = NULL;
510 sentinel.ai_next = NULL;
511 cur = &sentinel;
512
513 /*
514 * If AI_ADDRCONFIG is specified, check if we are expected to
515 * return the address family or not.
516 */
517 if ((pai->ai_flags & AI_ADDRCONFIG) != 0 && !addrconfig(pai))
518 return 0;
519
520 /*
521 * if the servname does not match socktype/protocol, ignore it.
522 */
523 if (get_portmatch(pai, servname) != 0)
524 return 0;
525
526 afd = find_afd(pai->ai_family);
527
528 hp = gethostbyname2(hostname, pai->ai_family);
529 h_error = h_errno;
530
531 if (hp == NULL) {
532 switch (h_error) {
533 case HOST_NOT_FOUND:
534 case NO_DATA:
535 error = EAI_NODATA;
536 break;
537 case TRY_AGAIN:
538 error = EAI_AGAIN;
539 break;
540 case NO_RECOVERY:
541 case NETDB_INTERNAL:
542 default:
543 error = EAI_FAIL;
544 break;
545 }
546 } else if ((hp->h_name == NULL) || (hp->h_name[0] == 0)
547 || (hp->h_addr_list[0] == NULL)) {
548 hp = NULL;
549 error = EAI_FAIL;
550 }
551
552 if (hp == NULL)
553 goto free;
554
555 /*
556 * hp will be overwritten if we use gethostbyname2().
557 * always deep copy for simplification.
558 */
559 for (naddrs = 0; hp->h_addr_list[naddrs] != NULL; naddrs++)
560 ;
561 naddrs++;
562 aplist = (char **)malloc(sizeof(aplist[0]) * naddrs);
563 apbuf = (char *)malloc((size_t)hp->h_length * naddrs);
564 if (aplist == NULL || apbuf == NULL) {
565 error = EAI_MEMORY;
566 goto free;
567 }
568 memset(aplist, 0, sizeof(aplist[0]) * naddrs);
569 for (i = 0; i < naddrs; i++) {
570 if (hp->h_addr_list[i] == NULL) {
571 aplist[i] = NULL;
572 continue;
573 }
574 memcpy(&apbuf[i * hp->h_length], hp->h_addr_list[i],
575 (size_t)hp->h_length);
576 aplist[i] = &apbuf[i * hp->h_length];
577 }
578
579 for (i = 0; aplist[i] != NULL; i++) {
580 af = hp->h_addrtype;
581 ap = aplist[i];
582 #ifdef AF_INET6
583 if (af == AF_INET6
584 && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) {
585 af = AF_INET;
586 ap = ap + sizeof(struct in6_addr)
587 - sizeof(struct in_addr);
588 }
589 #endif
590
591 if (af != pai->ai_family)
592 continue;
593
594 GET_AI(cur->ai_next, afd, ap);
595 GET_PORT(cur->ai_next, servname);
596 if ((pai->ai_flags & AI_CANONNAME) != 0) {
597 /*
598 * RFC2553 says that ai_canonname will be set only for
599 * the first element. we do it for all the elements,
600 * just for convenience.
601 */
602 GET_CANONNAME(cur->ai_next, hp->h_name);
603 }
604
605 while (cur && cur->ai_next)
606 cur = cur->ai_next;
607 }
608
609 *res = sentinel.ai_next;
610 return 0;
611
612 free:
613 if (aplist)
614 free(aplist);
615 if (apbuf)
616 free(apbuf);
617 if (sentinel.ai_next)
618 freeaddrinfo(sentinel.ai_next);
619 return error;
620 }
621
622 /*
623 * hostname == NULL.
624 * passive socket -> anyaddr (0.0.0.0 or ::)
625 * non-passive socket -> localhost (127.0.0.1 or ::1)
626 */
627 static int
628 explore_null(pai, servname, res)
629 const struct addrinfo *pai;
630 const char *servname;
631 struct addrinfo **res;
632 {
633 int s;
634 const struct afd *afd;
635 struct addrinfo *cur;
636 struct addrinfo sentinel;
637 int error;
638
639 *res = NULL;
640 sentinel.ai_next = NULL;
641 cur = &sentinel;
642
643 /*
644 * filter out AFs that are not supported by the kernel
645 * XXX errno?
646 */
647 s = socket(pai->ai_family, SOCK_DGRAM, 0);
648 if (s < 0) {
649 if (errno != EMFILE)
650 return 0;
651 } else
652 close(s);
653
654 /*
655 * if the servname does not match socktype/protocol, ignore it.
656 */
657 if (get_portmatch(pai, servname) != 0)
658 return 0;
659
660 afd = find_afd(pai->ai_family);
661
662 if (pai->ai_flags & AI_PASSIVE) {
663 GET_AI(cur->ai_next, afd, afd->a_addrany);
664 /* xxx meaningless?
665 * GET_CANONNAME(cur->ai_next, "anyaddr");
666 */
667 GET_PORT(cur->ai_next, servname);
668 } else {
669 GET_AI(cur->ai_next, afd, afd->a_loopback);
670 /* xxx meaningless?
671 * GET_CANONNAME(cur->ai_next, "localhost");
672 */
673 GET_PORT(cur->ai_next, servname);
674 }
675 cur = cur->ai_next;
676
677 *res = sentinel.ai_next;
678 return 0;
679
680 free:
681 if (sentinel.ai_next)
682 freeaddrinfo(sentinel.ai_next);
683 return error;
684 }
685
686 /*
687 * numeric hostname
688 */
689 static int
690 explore_numeric(pai, hostname, servname, res)
691 const struct addrinfo *pai;
692 const char *hostname;
693 const char *servname;
694 struct addrinfo **res;
695 {
696 const struct afd *afd;
697 struct addrinfo *cur;
698 struct addrinfo sentinel;
699 int error;
700 char pton[PTON_MAX];
701 int flags;
702
703 *res = NULL;
704 sentinel.ai_next = NULL;
705 cur = &sentinel;
706
707 /*
708 * if the servname does not match socktype/protocol, ignore it.
709 */
710 if (get_portmatch(pai, servname) != 0)
711 return 0;
712
713 afd = find_afd(pai->ai_family);
714 flags = pai->ai_flags;
715
716 switch (afd->a_af) {
717 #if 0 /*X/Open spec*/
718 case AF_INET:
719 if (inet_aton(hostname, (struct in_addr *)pton) == 1) {
720 if (pai->ai_family == afd->a_af ||
721 pai->ai_family == PF_UNSPEC /*?*/) {
722 GET_AI(cur->ai_next, afd, pton);
723 GET_PORT(cur->ai_next, servname);
724 while (cur && cur->ai_next)
725 cur = cur->ai_next;
726 } else
727 ERR(EAI_FAMILY); /*xxx*/
728 }
729 break;
730 #endif
731 default:
732 if (inet_pton(afd->a_af, hostname, pton) == 1) {
733 if (pai->ai_family == afd->a_af ||
734 pai->ai_family == PF_UNSPEC /*?*/) {
735 GET_AI(cur->ai_next, afd, pton);
736 GET_PORT(cur->ai_next, servname);
737 while (cur && cur->ai_next)
738 cur = cur->ai_next;
739 } else
740 ERR(EAI_FAMILY); /*xxx*/
741 }
742 break;
743 }
744
745 *res = sentinel.ai_next;
746 return 0;
747
748 free:
749 bad:
750 if (sentinel.ai_next)
751 freeaddrinfo(sentinel.ai_next);
752 return error;
753 }
754
755 /*
756 * numeric hostname with scope
757 */
758 static int
759 explore_numeric_scope(pai, hostname, servname, res)
760 const struct addrinfo *pai;
761 const char *hostname;
762 const char *servname;
763 struct addrinfo **res;
764 {
765 #if !defined(SCOPE_DELIMITER) || !defined(INET6)
766 return explore_numeric(pai, hostname, servname, res);
767 #else
768 const struct afd *afd;
769 struct addrinfo *cur;
770 int error;
771 char *cp, *hostname2 = NULL, *scope, *addr;
772 struct sockaddr_in6 *sin6;
773
774 /*
775 * if the servname does not match socktype/protocol, ignore it.
776 */
777 if (get_portmatch(pai, servname) != 0)
778 return 0;
779
780 afd = find_afd(pai->ai_family);
781 if (!afd->a_scoped)
782 return explore_numeric(pai, hostname, servname, res);
783
784 cp = strchr(hostname, SCOPE_DELIMITER);
785 if (cp == NULL)
786 return explore_numeric(pai, hostname, servname, res);
787
788 #if 1
789 /*
790 * Handle special case of <scope id><delimiter><scoped_address>
791 */
792 hostname2 = strdup(hostname);
793 if (hostname2 == NULL)
794 return EAI_MEMORY;
795 /* terminate at the delimiter */
796 hostname2[cp - hostname] = '\0';
797 scope = hostname2;
798 addr = cp + 1;
799 #else
800 /*
801 * Handle special case of <scoped_address><delimiter><scope id>
802 */
803 hostname2 = strdup(hostname);
804 if (hostname2 == NULL)
805 return EAI_MEMORY;
806 /* terminate at the delimiter */
807 hostname2[cp - hostname] = '\0';
808 addr = hostname2;
809 scope = cp + 1;
810 #endif
811
812 error = explore_numeric(pai, addr, servname, res);
813 if (error == 0) {
814 int scopeid;
815
816 for (cur = *res; cur; cur = cur->ai_next) {
817 if (cur->ai_family != AF_INET6)
818 continue;
819 sin6 = (struct sockaddr_in6 *)cur->ai_addr;
820 if ((scopeid = ip6_str2scopeid(scope, sin6)) == -1) {
821 free(hostname2);
822 return(EAI_NONAME); /* XXX: is return OK? */
823 }
824 sin6->sin6_scope_id = scopeid;
825 }
826 }
827
828 free(hostname2);
829
830 return error;
831 #endif
832 }
833
834 static int
835 get_canonname(pai, ai, str)
836 const struct addrinfo *pai;
837 struct addrinfo *ai;
838 const char *str;
839 {
840 if ((pai->ai_flags & AI_CANONNAME) != 0) {
841 ai->ai_canonname = (char *)malloc(strlen(str) + 1);
842 if (ai->ai_canonname == NULL)
843 return EAI_MEMORY;
844 strcpy(ai->ai_canonname, str);
845 }
846 return 0;
847 }
848
849 static struct addrinfo *
850 get_ai(pai, afd, addr)
851 const struct addrinfo *pai;
852 const struct afd *afd;
853 const char *addr;
854 {
855 char *p;
856 struct addrinfo *ai;
857
858 ai = (struct addrinfo *)malloc(sizeof(struct addrinfo)
859 + (afd->a_socklen));
860 if (ai == NULL)
861 return NULL;
862
863 memcpy(ai, pai, sizeof(struct addrinfo));
864 ai->ai_addr = (struct sockaddr *)(ai + 1);
865 memset(ai->ai_addr, 0, (size_t)afd->a_socklen);
866 ai->ai_addr->sa_len = afd->a_socklen;
867 ai->ai_addrlen = afd->a_socklen;
868 ai->ai_addr->sa_family = ai->ai_family = afd->a_af;
869 p = (char *)(ai->ai_addr);
870 memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen);
871 return ai;
872 }
873
874 static int
875 get_portmatch(ai, servname)
876 const struct addrinfo *ai;
877 const char *servname;
878 {
879
880 /* get_port does not touch first argument. when matchonly == 1. */
881 return get_port((struct addrinfo *)ai, servname, 1);
882 }
883
884 static int
885 get_port(ai, servname, matchonly)
886 struct addrinfo *ai;
887 const char *servname;
888 int matchonly;
889 {
890 const char *proto;
891 struct servent *sp;
892 int port;
893 int allownumeric;
894
895 if (servname == NULL)
896 return 0;
897 switch (ai->ai_family) {
898 case AF_INET:
899 #ifdef AF_INET6
900 case AF_INET6:
901 #endif
902 break;
903 default:
904 return 0;
905 }
906
907 switch (ai->ai_socktype) {
908 case SOCK_RAW:
909 return EAI_SERVICE;
910 case SOCK_DGRAM:
911 case SOCK_STREAM:
912 allownumeric = 1;
913 break;
914 case ANY:
915 allownumeric = 0;
916 break;
917 default:
918 return EAI_SOCKTYPE;
919 }
920
921 if (str_isnumber(servname)) {
922 if (!allownumeric)
923 return EAI_SERVICE;
924 port = htons(atoi(servname));
925 if (port < 0 || port > 65535)
926 return EAI_SERVICE;
927 } else {
928 switch (ai->ai_socktype) {
929 case SOCK_DGRAM:
930 proto = "udp";
931 break;
932 case SOCK_STREAM:
933 proto = "tcp";
934 break;
935 default:
936 proto = NULL;
937 break;
938 }
939
940 if ((sp = getservbyname(servname, proto)) == NULL)
941 return EAI_SERVICE;
942 port = sp->s_port;
943 }
944
945 if (!matchonly) {
946 switch (ai->ai_family) {
947 case AF_INET:
948 ((struct sockaddr_in *)ai->ai_addr)->sin_port = port;
949 break;
950 #ifdef INET6
951 case AF_INET6:
952 ((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = port;
953 break;
954 #endif
955 }
956 }
957
958 return 0;
959 }
960
961 static const struct afd *
962 find_afd(af)
963 int af;
964 {
965 const struct afd *afd;
966
967 if (af == PF_UNSPEC)
968 return NULL;
969 for (afd = afdl; afd->a_af; afd++) {
970 if (afd->a_af == af)
971 return afd;
972 }
973 return NULL;
974 }
975
976 /*
977 * post-2553: AI_ADDRCONFIG check. if we use getipnodeby* as backend, backend
978 * will take care of it.
979 * the semantics of AI_ADDRCONFIG is not defined well. we are not sure
980 * if the code is right or not.
981 */
982 static int
983 addrconfig(pai)
984 const struct addrinfo *pai;
985 {
986 int s;
987
988 /* XXX errno */
989 s = socket(pai->ai_family, SOCK_DGRAM, 0);
990 if (s < 0)
991 return 0;
992 close(s);
993 return 1;
994 }
995
996 #ifdef INET6
997 /* convert a string to a scope identifier. XXX: IPv6 specific */
998 static int
999 ip6_str2scopeid(scope, sin6)
1000 char *scope;
1001 struct sockaddr_in6 *sin6;
1002 {
1003 int scopeid;
1004 struct in6_addr *a6 = &sin6->sin6_addr;
1005 char *ep;
1006
1007 if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) {
1008 /*
1009 * We currently assume a one-to-one mapping between links
1010 * and interfaces, so we simply use interface indices for
1011 * like-local scopes.
1012 */
1013 scopeid = if_nametoindex(scope);
1014 if (scopeid == 0)
1015 goto trynumeric;
1016 return(scopeid);
1017 }
1018
1019 /* still unclear about literal, allow numeric only - placeholder */
1020 if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6))
1021 goto trynumeric;
1022 if (IN6_IS_ADDR_MC_ORGLOCAL(a6))
1023 goto trynumeric;
1024 else
1025 goto trynumeric; /* global */
1026
1027 /* try to convert to a numeric id as a last resort */
1028 trynumeric:
1029 scopeid = (int)strtoul(scope, &ep, 10);
1030 if (*ep == '\0')
1031 return scopeid;
1032 else
1033 return -1;
1034 }
1035 #endif
1036