1 /*
2 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the project nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30 /*
31 * "#ifdef FAITH" part is local hack for supporting IPv4-v6 translator.
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 RFC2133 is silent about which error
37 * code must be returned for which situation.
38 * - PF_UNSPEC case would be handled in getipnodebyname() with the AI_ALL flag.
39 */
40
41 #if 0
42 #include <sys/types.h>
43 #include <sys/param.h>
44 #include <sys/sysctl.h>
45 #include <sys/socket.h>
46 #include <netinet/in.h>
47 #include <arpa/inet.h>
48 #include <arpa/nameser.h>
49 #include <netdb.h>
50 #include <resolv.h>
51 #include <string.h>
52 #include <stdlib.h>
53 #include <stddef.h>
54 #include <ctype.h>
55 #include <unistd.h>
56
57 #include "addrinfo.h"
58 #endif
59
60 #if defined(__KAME__) && defined(ENABLE_IPV6)
61 # define FAITH
62 #endif
63
64 #ifdef HAVE_NETDB_H
65 #define HAVE_GETADDRINFO 1
66
67 #define SUCCESS 0
68 #define GAI_ANY 0
69 #define YES 1
70 #define NO 0
71
72 #ifdef FAITH
73 static int translate = NO;
74 static struct in6_addr faith_prefix = IN6ADDR_GAI_ANY_INIT;
75 #endif
76
77 static const char in_addrany[] = { 0, 0, 0, 0 };
78 static const char in6_addrany[] = {
79 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
80 };
81 static const char in_loopback[] = { 127, 0, 0, 1 };
82 static const char in6_loopback[] = {
83 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
84 };
85
86 struct sockinet {
87 u_char si_len;
88 u_char si_family;
89 u_short si_port;
90 };
91
92 static struct gai_afd {
93 int a_af;
94 int a_addrlen;
95 int a_socklen;
96 int a_off;
97 const char *a_addrany;
98 const char *a_loopback;
99 } gai_afdl [] = {
100 #ifdef ENABLE_IPV6
101 #define N_INET6 0
102 {PF_INET6, sizeof(struct in6_addr),
103 sizeof(struct sockaddr_in6),
104 offsetof(struct sockaddr_in6, sin6_addr),
105 in6_addrany, in6_loopback},
106 #define N_INET 1
107 #else
108 #define N_INET 0
109 #endif
110 {PF_INET, sizeof(struct in_addr),
111 sizeof(struct sockaddr_in),
112 offsetof(struct sockaddr_in, sin_addr),
113 in_addrany, in_loopback},
114 {0, 0, 0, 0, NULL, NULL},
115 };
116
117 #ifdef ENABLE_IPV6
118 #define PTON_MAX 16
119 #else
120 #define PTON_MAX 4
121 #endif
122
123 #ifndef IN_MULTICAST
124 #define IN_MULTICAST(i) (((i) & 0xf0000000U) == 0xe0000000U)
125 #endif
126
127 #ifndef IN_EXPERIMENTAL
128 #define IN_EXPERIMENTAL(i) (((i) & 0xe0000000U) == 0xe0000000U)
129 #endif
130
131 #ifndef IN_LOOPBACKNET
132 #define IN_LOOPBACKNET 127
133 #endif
134
135 static int get_name(const char *, struct gai_afd *,
136 struct addrinfo **, char *, struct addrinfo *,
137 int);
138 static int get_addr(const char *, int, struct addrinfo **,
139 struct addrinfo *, int);
140 static int str_isnumber(const char *);
141
142 static const char * const ai_errlist[] = {
143 "success.",
144 "address family for hostname not supported.", /* EAI_ADDRFAMILY */
145 "temporary failure in name resolution.", /* EAI_AGAIN */
146 "invalid value for ai_flags.", /* EAI_BADFLAGS */
147 "non-recoverable failure in name resolution.", /* EAI_FAIL */
148 "ai_family not supported.", /* EAI_FAMILY */
149 "memory allocation failure.", /* EAI_MEMORY */
150 "no address associated with hostname.", /* EAI_NODATA */
151 "hostname nor servname provided, or not known.",/* EAI_NONAME */
152 "servname not supported for ai_socktype.", /* EAI_SERVICE */
153 "ai_socktype not supported.", /* EAI_SOCKTYPE */
154 "system error returned in errno.", /* EAI_SYSTEM */
155 "invalid value for hints.", /* EAI_BADHINTS */
156 "resolved protocol is unknown.", /* EAI_PROTOCOL */
157 "unknown error.", /* EAI_MAX */
158 };
159
160 #define GET_CANONNAME(ai, str) \
161 if (pai->ai_flags & AI_CANONNAME) {\
162 if (((ai)->ai_canonname = (char *)malloc(strlen(str) + 1)) != NULL) {\
163 strcpy((ai)->ai_canonname, (str));\
164 } else {\
165 error = EAI_MEMORY;\
166 goto free;\
167 }\
168 }
169
170 #ifdef HAVE_SOCKADDR_SA_LEN
171 #define GET_AI(ai, gai_afd, addr, port) {\
172 char *p;\
173 if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\
174 ((gai_afd)->a_socklen)))\
175 == NULL) goto free;\
176 memcpy(ai, pai, sizeof(struct addrinfo));\
177 (ai)->ai_addr = (struct sockaddr *)((ai) + 1);\
178 memset((ai)->ai_addr, 0, (gai_afd)->a_socklen);\
179 (ai)->ai_addr->sa_len = (ai)->ai_addrlen = (gai_afd)->a_socklen;\
180 (ai)->ai_addr->sa_family = (ai)->ai_family = (gai_afd)->a_af;\
181 ((struct sockinet *)(ai)->ai_addr)->si_port = port;\
182 p = (char *)((ai)->ai_addr);\
183 memcpy(p + (gai_afd)->a_off, (addr), (gai_afd)->a_addrlen);\
184 }
185 #else
186 #define GET_AI(ai, gai_afd, addr, port) {\
187 char *p;\
188 if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\
189 ((gai_afd)->a_socklen)))\
190 == NULL) goto free;\
191 memcpy(ai, pai, sizeof(struct addrinfo));\
192 (ai)->ai_addr = (struct sockaddr *)((ai) + 1);\
193 memset((ai)->ai_addr, 0, (gai_afd)->a_socklen);\
194 (ai)->ai_addrlen = (gai_afd)->a_socklen;\
195 (ai)->ai_addr->sa_family = (ai)->ai_family = (gai_afd)->a_af;\
196 ((struct sockinet *)(ai)->ai_addr)->si_port = port;\
197 p = (char *)((ai)->ai_addr);\
198 memcpy(p + (gai_afd)->a_off, (addr), (gai_afd)->a_addrlen);\
199 }
200 #endif
201
202 #define ERR(err) { error = (err); goto bad; }
203
204 const char *
205 gai_strerror(int ecode)
206 {
207 if (ecode < 0 || ecode > EAI_MAX)
208 ecode = EAI_MAX;
209 return ai_errlist[ecode];
210 }
211
212 void
213 freeaddrinfo(struct addrinfo *ai)
214 {
215 struct addrinfo *next;
216
217 do {
218 next = ai->ai_next;
219 if (ai->ai_canonname)
220 free(ai->ai_canonname);
221 /* no need to free(ai->ai_addr) */
222 free(ai);
223 } while ((ai = next) != NULL);
224 }
225
226 static int
227 str_isnumber(const char *p)
228 {
229 unsigned char *q = (unsigned char *)p;
230 while (*q) {
231 if (! isdigit(*q))
232 return NO;
233 q++;
234 }
235 return YES;
236 }
237
238 int
239 getaddrinfo(const char*hostname, const char*servname,
240 const struct addrinfo *hints, struct addrinfo **res)
241 {
242 struct addrinfo sentinel;
243 struct addrinfo *top = NULL;
244 struct addrinfo *cur;
245 int i, error = 0;
246 char pton[PTON_MAX];
247 struct addrinfo ai;
248 struct addrinfo *pai;
249 u_short port;
250
251 #ifdef FAITH
252 static int firsttime = 1;
253
254 if (firsttime) {
255 /* translator hack */
256 {
257 const char *q = getenv("GAI");
258 if (q && inet_pton(AF_INET6, q, &faith_prefix) == 1)
259 translate = YES;
260 }
261 firsttime = 0;
262 }
263 #endif
264
265 /* initialize file static vars */
266 sentinel.ai_next = NULL;
267 cur = &sentinel;
268 pai = &ai;
269 pai->ai_flags = 0;
270 pai->ai_family = PF_UNSPEC;
271 pai->ai_socktype = GAI_ANY;
272 pai->ai_protocol = GAI_ANY;
273 pai->ai_addrlen = 0;
274 pai->ai_canonname = NULL;
275 pai->ai_addr = NULL;
276 pai->ai_next = NULL;
277 port = GAI_ANY;
278
279 if (hostname == NULL && servname == NULL)
280 return EAI_NONAME;
281 if (hints) {
282 /* error check for hints */
283 if (hints->ai_addrlen || hints->ai_canonname ||
284 hints->ai_addr || hints->ai_next)
285 ERR(EAI_BADHINTS); /* xxx */
286 if (hints->ai_flags & ~AI_MASK)
287 ERR(EAI_BADFLAGS);
288 switch (hints->ai_family) {
289 case PF_UNSPEC:
290 case PF_INET:
291 #ifdef ENABLE_IPV6
292 case PF_INET6:
293 #endif
294 break;
295 default:
296 ERR(EAI_FAMILY);
297 }
298 memcpy(pai, hints, sizeof(*pai));
299 switch (pai->ai_socktype) {
300 case GAI_ANY:
301 switch (pai->ai_protocol) {
302 case GAI_ANY:
303 break;
304 case IPPROTO_UDP:
305 pai->ai_socktype = SOCK_DGRAM;
306 break;
307 case IPPROTO_TCP:
308 pai->ai_socktype = SOCK_STREAM;
309 break;
310 default:
311 pai->ai_socktype = SOCK_RAW;
312 break;
313 }
314 break;
315 case SOCK_RAW:
316 break;
317 case SOCK_DGRAM:
318 if (pai->ai_protocol != IPPROTO_UDP &&
319 pai->ai_protocol != GAI_ANY)
320 ERR(EAI_BADHINTS); /*xxx*/
321 pai->ai_protocol = IPPROTO_UDP;
322 break;
323 case SOCK_STREAM:
324 if (pai->ai_protocol != IPPROTO_TCP &&
325 pai->ai_protocol != GAI_ANY)
326 ERR(EAI_BADHINTS); /*xxx*/
327 pai->ai_protocol = IPPROTO_TCP;
328 break;
329 default:
330 ERR(EAI_SOCKTYPE);
331 /* unreachable */
332 }
333 }
334
335 /*
336 * service port
337 */
338 if (servname) {
339 if (str_isnumber(servname)) {
340 if (pai->ai_socktype == GAI_ANY) {
341 /* caller accept *GAI_ANY* socktype */
342 pai->ai_socktype = SOCK_DGRAM;
343 pai->ai_protocol = IPPROTO_UDP;
344 }
345 long maybe_port = strtol(servname, NULL, 10);
346 if (maybe_port < 0 || maybe_port > 0xffff) {
347 ERR(EAI_SERVICE);
348 }
349 port = htons((u_short)maybe_port);
350 } else {
351 struct servent *sp;
352 const char *proto;
353
354 proto = NULL;
355 switch (pai->ai_socktype) {
356 case GAI_ANY:
357 proto = NULL;
358 break;
359 case SOCK_DGRAM:
360 proto = "udp";
361 break;
362 case SOCK_STREAM:
363 proto = "tcp";
364 break;
365 default:
366 fprintf(stderr, "panic!\n");
367 break;
368 }
369 if ((sp = getservbyname(servname, proto)) == NULL)
370 ERR(EAI_SERVICE);
371 port = sp->s_port;
372 if (pai->ai_socktype == GAI_ANY) {
373 if (strcmp(sp->s_proto, "udp") == 0) {
374 pai->ai_socktype = SOCK_DGRAM;
375 pai->ai_protocol = IPPROTO_UDP;
376 } else if (strcmp(sp->s_proto, "tcp") == 0) {
377 pai->ai_socktype = SOCK_STREAM;
378 pai->ai_protocol = IPPROTO_TCP;
379 } else
380 ERR(EAI_PROTOCOL); /*xxx*/
381 }
382 }
383 }
384
385 /*
386 * hostname == NULL.
387 * passive socket -> anyaddr (0.0.0.0 or ::)
388 * non-passive socket -> localhost (127.0.0.1 or ::1)
389 */
390 if (hostname == NULL) {
391 struct gai_afd *gai_afd;
392
393 for (gai_afd = &gai_afdl[0]; gai_afd->a_af; gai_afd++) {
394 if (!(pai->ai_family == PF_UNSPEC
395 || pai->ai_family == gai_afd->a_af)) {
396 continue;
397 }
398
399 if (pai->ai_flags & AI_PASSIVE) {
400 GET_AI(cur->ai_next, gai_afd, gai_afd->a_addrany, port);
401 /* xxx meaningless?
402 * GET_CANONNAME(cur->ai_next, "anyaddr");
403 */
404 } else {
405 GET_AI(cur->ai_next, gai_afd, gai_afd->a_loopback,
406 port);
407 /* xxx meaningless?
408 * GET_CANONNAME(cur->ai_next, "localhost");
409 */
410 }
411 cur = cur->ai_next;
412 }
413 top = sentinel.ai_next;
414 if (top)
415 goto good;
416 else
417 ERR(EAI_FAMILY);
418 }
419
420 /* hostname as numeric name */
421 for (i = 0; gai_afdl[i].a_af; i++) {
422 if (inet_pton(gai_afdl[i].a_af, hostname, pton)) {
423 u_long v4a;
424 #ifdef ENABLE_IPV6
425 u_char pfx;
426 #endif
427
428 switch (gai_afdl[i].a_af) {
429 case AF_INET:
430 v4a = ((struct in_addr *)pton)->s_addr;
431 v4a = ntohl(v4a);
432 if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
433 pai->ai_flags &= ~AI_CANONNAME;
434 v4a >>= IN_CLASSA_NSHIFT;
435 if (v4a == 0 || v4a == IN_LOOPBACKNET)
436 pai->ai_flags &= ~AI_CANONNAME;
437 break;
438 #ifdef ENABLE_IPV6
439 case AF_INET6:
440 pfx = ((struct in6_addr *)pton)->s6_addr[0];
441 if (pfx == 0 || pfx == 0xfe || pfx == 0xff)
442 pai->ai_flags &= ~AI_CANONNAME;
443 break;
444 #endif
445 }
446
447 if (pai->ai_family == gai_afdl[i].a_af ||
448 pai->ai_family == PF_UNSPEC) {
449 if (! (pai->ai_flags & AI_CANONNAME)) {
450 GET_AI(top, &gai_afdl[i], pton, port);
451 goto good;
452 }
453 /*
454 * if AI_CANONNAME and if reverse lookup
455 * fail, return ai anyway to pacify
456 * calling application.
457 *
458 * XXX getaddrinfo() is a name->address
459 * translation function, and it looks strange
460 * that we do addr->name translation here.
461 */
462 get_name(pton, &gai_afdl[i], &top, pton, pai, port);
463 goto good;
464 } else
465 ERR(EAI_FAMILY); /*xxx*/
466 }
467 }
468
469 if (pai->ai_flags & AI_NUMERICHOST)
470 ERR(EAI_NONAME);
471
472 /* hostname as alphabetical name */
473 error = get_addr(hostname, pai->ai_family, &top, pai, port);
474 if (error == 0) {
475 if (top) {
476 good:
477 *res = top;
478 return SUCCESS;
479 } else
480 error = EAI_FAIL;
481 }
482 free:
483 if (top)
484 freeaddrinfo(top);
485 bad:
486 *res = NULL;
487 return error;
488 }
489
490 static int
491 get_name(addr, gai_afd, res, numaddr, pai, port0)
492 const char *addr;
493 struct gai_afd *gai_afd;
494 struct addrinfo **res;
495 char *numaddr;
496 struct addrinfo *pai;
497 int port0;
498 {
499 u_short port = port0 & 0xffff;
500 struct hostent *hp;
501 struct addrinfo *cur;
502 int error = 0;
503 #ifdef ENABLE_IPV6
504 int h_error;
505 #endif
506
507 #ifdef ENABLE_IPV6
508 hp = getipnodebyaddr(addr, gai_afd->a_addrlen, gai_afd->a_af, &h_error);
509 #else
510 hp = gethostbyaddr(addr, gai_afd->a_addrlen, AF_INET);
511 #endif
512 if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
513 GET_AI(cur, gai_afd, hp->h_addr_list[0], port);
514 GET_CANONNAME(cur, hp->h_name);
515 } else
516 GET_AI(cur, gai_afd, numaddr, port);
517
518 #ifdef ENABLE_IPV6
519 if (hp)
520 freehostent(hp);
521 #endif
522 *res = cur;
523 return SUCCESS;
524 free:
525 if (cur)
526 freeaddrinfo(cur);
527 #ifdef ENABLE_IPV6
528 if (hp)
529 freehostent(hp);
530 #endif
531 /* bad: */
532 *res = NULL;
533 return error;
534 }
535
536 static int
537 get_addr(hostname, af, res, pai, port0)
538 const char *hostname;
539 int af;
540 struct addrinfo **res;
541 struct addrinfo *pai;
542 int port0;
543 {
544 u_short port = port0 & 0xffff;
545 struct addrinfo sentinel;
546 struct hostent *hp;
547 struct addrinfo *top, *cur;
548 struct gai_afd *gai_afd;
549 int i, error = 0, h_error;
550 char *ap;
551
552 top = NULL;
553 sentinel.ai_next = NULL;
554 cur = &sentinel;
555 #ifdef ENABLE_IPV6
556 if (af == AF_UNSPEC) {
557 hp = getipnodebyname(hostname, AF_INET6,
558 AI_ADDRCONFIG|AI_ALL|AI_V4MAPPED, &h_error);
559 } else
560 hp = getipnodebyname(hostname, af, AI_ADDRCONFIG, &h_error);
561 #else
562 hp = gethostbyname(hostname);
563 h_error = h_errno;
564 #endif
565 if (hp == NULL) {
566 switch (h_error) {
567 case HOST_NOT_FOUND:
568 case NO_DATA:
569 error = EAI_NODATA;
570 break;
571 case TRY_AGAIN:
572 error = EAI_AGAIN;
573 break;
574 case NO_RECOVERY:
575 default:
576 error = EAI_FAIL;
577 break;
578 }
579 goto free;
580 }
581
582 if ((hp->h_name == NULL) || (hp->h_name[0] == 0) ||
583 (hp->h_addr_list[0] == NULL)) {
584 error = EAI_FAIL;
585 goto free;
586 }
587
588 for (i = 0; (ap = hp->h_addr_list[i]) != NULL; i++) {
589 switch (af) {
590 #ifdef ENABLE_IPV6
591 case AF_INET6:
592 gai_afd = &gai_afdl[N_INET6];
593 break;
594 #endif
595 #ifndef ENABLE_IPV6
596 default: /* AF_UNSPEC */
597 #endif
598 case AF_INET:
599 gai_afd = &gai_afdl[N_INET];
600 break;
601 #ifdef ENABLE_IPV6
602 default: /* AF_UNSPEC */
603 if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) {
604 ap += sizeof(struct in6_addr) -
605 sizeof(struct in_addr);
606 gai_afd = &gai_afdl[N_INET];
607 } else
608 gai_afd = &gai_afdl[N_INET6];
609 break;
610 #endif
611 }
612 #ifdef FAITH
613 if (translate && gai_afd->a_af == AF_INET) {
614 struct in6_addr *in6;
615
616 GET_AI(cur->ai_next, &gai_afdl[N_INET6], ap, port);
617 in6 = &((struct sockaddr_in6 *)cur->ai_next->ai_addr)->sin6_addr;
618 memcpy(&in6->s6_addr32[0], &faith_prefix,
619 sizeof(struct in6_addr) - sizeof(struct in_addr));
620 memcpy(&in6->s6_addr32[3], ap, sizeof(struct in_addr));
621 } else
622 #endif /* FAITH */
623 GET_AI(cur->ai_next, gai_afd, ap, port);
624 if (cur == &sentinel) {
625 top = cur->ai_next;
626 GET_CANONNAME(top, hp->h_name);
627 }
628 cur = cur->ai_next;
629 }
630 #ifdef ENABLE_IPV6
631 freehostent(hp);
632 #endif
633 *res = top;
634 return SUCCESS;
635 free:
636 if (top)
637 freeaddrinfo(top);
638 #ifdef ENABLE_IPV6
639 if (hp)
640 freehostent(hp);
641 #endif
642 /* bad: */
643 *res = NULL;
644 return error;
645 }
646
647 #endif // HAVE_NETDB_H