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 *
gai_strerror(int ecode)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
freeaddrinfo(struct addrinfo * ai)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
str_isnumber(const char * p)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
getaddrinfo(const char * hostname,const char * servname,const struct addrinfo * hints,struct addrinfo ** res)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             port = htons((u_short)atoi(servname));
346         } else {
347             struct servent *sp;
348             const char *proto;
349 
350             proto = NULL;
351             switch (pai->ai_socktype) {
352             case GAI_ANY:
353                 proto = NULL;
354                 break;
355             case SOCK_DGRAM:
356                 proto = "udp";
357                 break;
358             case SOCK_STREAM:
359                 proto = "tcp";
360                 break;
361             default:
362                 fprintf(stderr, "panic!\n");
363                 break;
364             }
365             if ((sp = getservbyname(servname, proto)) == NULL)
366                 ERR(EAI_SERVICE);
367             port = sp->s_port;
368             if (pai->ai_socktype == GAI_ANY) {
369                 if (strcmp(sp->s_proto, "udp") == 0) {
370                     pai->ai_socktype = SOCK_DGRAM;
371                     pai->ai_protocol = IPPROTO_UDP;
372                 } else if (strcmp(sp->s_proto, "tcp") == 0) {
373                     pai->ai_socktype = SOCK_STREAM;
374                     pai->ai_protocol = IPPROTO_TCP;
375                 } else
376                     ERR(EAI_PROTOCOL);                          /*xxx*/
377             }
378         }
379     }
380 
381     /*
382      * hostname == NULL.
383      * passive socket -> anyaddr (0.0.0.0 or ::)
384      * non-passive socket -> localhost (127.0.0.1 or ::1)
385      */
386     if (hostname == NULL) {
387         struct gai_afd *gai_afd;
388 
389         for (gai_afd = &gai_afdl[0]; gai_afd->a_af; gai_afd++) {
390             if (!(pai->ai_family == PF_UNSPEC
391                || pai->ai_family == gai_afd->a_af)) {
392                 continue;
393             }
394 
395             if (pai->ai_flags & AI_PASSIVE) {
396                 GET_AI(cur->ai_next, gai_afd, gai_afd->a_addrany, port);
397                 /* xxx meaningless?
398                  * GET_CANONNAME(cur->ai_next, "anyaddr");
399                  */
400             } else {
401                 GET_AI(cur->ai_next, gai_afd, gai_afd->a_loopback,
402                     port);
403                 /* xxx meaningless?
404                  * GET_CANONNAME(cur->ai_next, "localhost");
405                  */
406             }
407             cur = cur->ai_next;
408         }
409         top = sentinel.ai_next;
410         if (top)
411             goto good;
412         else
413             ERR(EAI_FAMILY);
414     }
415 
416     /* hostname as numeric name */
417     for (i = 0; gai_afdl[i].a_af; i++) {
418         if (inet_pton(gai_afdl[i].a_af, hostname, pton)) {
419             u_long v4a;
420 #ifdef ENABLE_IPV6
421             u_char pfx;
422 #endif
423 
424             switch (gai_afdl[i].a_af) {
425             case AF_INET:
426                 v4a = ((struct in_addr *)pton)->s_addr;
427                 v4a = ntohl(v4a);
428                 if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
429                     pai->ai_flags &= ~AI_CANONNAME;
430                 v4a >>= IN_CLASSA_NSHIFT;
431                 if (v4a == 0 || v4a == IN_LOOPBACKNET)
432                     pai->ai_flags &= ~AI_CANONNAME;
433                 break;
434 #ifdef ENABLE_IPV6
435             case AF_INET6:
436                 pfx = ((struct in6_addr *)pton)->s6_addr[0];
437                 if (pfx == 0 || pfx == 0xfe || pfx == 0xff)
438                     pai->ai_flags &= ~AI_CANONNAME;
439                 break;
440 #endif
441             }
442 
443             if (pai->ai_family == gai_afdl[i].a_af ||
444                 pai->ai_family == PF_UNSPEC) {
445                 if (! (pai->ai_flags & AI_CANONNAME)) {
446                     GET_AI(top, &gai_afdl[i], pton, port);
447                     goto good;
448                 }
449                 /*
450                  * if AI_CANONNAME and if reverse lookup
451                  * fail, return ai anyway to pacify
452                  * calling application.
453                  *
454                  * XXX getaddrinfo() is a name->address
455                  * translation function, and it looks strange
456                  * that we do addr->name translation here.
457                  */
458                 get_name(pton, &gai_afdl[i], &top, pton, pai, port);
459                 goto good;
460             } else
461                 ERR(EAI_FAMILY);                        /*xxx*/
462         }
463     }
464 
465     if (pai->ai_flags & AI_NUMERICHOST)
466         ERR(EAI_NONAME);
467 
468     /* hostname as alphabetical name */
469     error = get_addr(hostname, pai->ai_family, &top, pai, port);
470     if (error == 0) {
471         if (top) {
472  good:
473             *res = top;
474             return SUCCESS;
475         } else
476             error = EAI_FAIL;
477     }
478  free:
479     if (top)
480         freeaddrinfo(top);
481  bad:
482     *res = NULL;
483     return error;
484 }
485 
486 static int
get_name(addr,gai_afd,res,numaddr,pai,port0)487 get_name(addr, gai_afd, res, numaddr, pai, port0)
488     const char *addr;
489     struct gai_afd *gai_afd;
490     struct addrinfo **res;
491     char *numaddr;
492     struct addrinfo *pai;
493     int port0;
494 {
495     u_short port = port0 & 0xffff;
496     struct hostent *hp;
497     struct addrinfo *cur;
498     int error = 0;
499 #ifdef ENABLE_IPV6
500     int h_error;
501 #endif
502 
503 #ifdef ENABLE_IPV6
504     hp = getipnodebyaddr(addr, gai_afd->a_addrlen, gai_afd->a_af, &h_error);
505 #else
506     hp = gethostbyaddr(addr, gai_afd->a_addrlen, AF_INET);
507 #endif
508     if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
509         GET_AI(cur, gai_afd, hp->h_addr_list[0], port);
510         GET_CANONNAME(cur, hp->h_name);
511     } else
512         GET_AI(cur, gai_afd, numaddr, port);
513 
514 #ifdef ENABLE_IPV6
515     if (hp)
516         freehostent(hp);
517 #endif
518     *res = cur;
519     return SUCCESS;
520  free:
521     if (cur)
522         freeaddrinfo(cur);
523 #ifdef ENABLE_IPV6
524     if (hp)
525         freehostent(hp);
526 #endif
527  /* bad: */
528     *res = NULL;
529     return error;
530 }
531 
532 static int
get_addr(hostname,af,res,pai,port0)533 get_addr(hostname, af, res, pai, port0)
534     const char *hostname;
535     int af;
536     struct addrinfo **res;
537     struct addrinfo *pai;
538     int port0;
539 {
540     u_short port = port0 & 0xffff;
541     struct addrinfo sentinel;
542     struct hostent *hp;
543     struct addrinfo *top, *cur;
544     struct gai_afd *gai_afd;
545     int i, error = 0, h_error;
546     char *ap;
547 
548     top = NULL;
549     sentinel.ai_next = NULL;
550     cur = &sentinel;
551 #ifdef ENABLE_IPV6
552     if (af == AF_UNSPEC) {
553         hp = getipnodebyname(hostname, AF_INET6,
554                         AI_ADDRCONFIG|AI_ALL|AI_V4MAPPED, &h_error);
555     } else
556         hp = getipnodebyname(hostname, af, AI_ADDRCONFIG, &h_error);
557 #else
558     hp = gethostbyname(hostname);
559     h_error = h_errno;
560 #endif
561     if (hp == NULL) {
562         switch (h_error) {
563         case HOST_NOT_FOUND:
564         case NO_DATA:
565             error = EAI_NODATA;
566             break;
567         case TRY_AGAIN:
568             error = EAI_AGAIN;
569             break;
570         case NO_RECOVERY:
571         default:
572             error = EAI_FAIL;
573             break;
574         }
575         goto free;
576     }
577 
578     if ((hp->h_name == NULL) || (hp->h_name[0] == 0) ||
579         (hp->h_addr_list[0] == NULL)) {
580         error = EAI_FAIL;
581         goto free;
582     }
583 
584     for (i = 0; (ap = hp->h_addr_list[i]) != NULL; i++) {
585         switch (af) {
586 #ifdef ENABLE_IPV6
587         case AF_INET6:
588             gai_afd = &gai_afdl[N_INET6];
589             break;
590 #endif
591 #ifndef ENABLE_IPV6
592         default:                /* AF_UNSPEC */
593 #endif
594         case AF_INET:
595             gai_afd = &gai_afdl[N_INET];
596             break;
597 #ifdef ENABLE_IPV6
598         default:                /* AF_UNSPEC */
599             if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) {
600                 ap += sizeof(struct in6_addr) -
601                     sizeof(struct in_addr);
602                 gai_afd = &gai_afdl[N_INET];
603             } else
604                 gai_afd = &gai_afdl[N_INET6];
605             break;
606 #endif
607         }
608 #ifdef FAITH
609         if (translate && gai_afd->a_af == AF_INET) {
610             struct in6_addr *in6;
611 
612             GET_AI(cur->ai_next, &gai_afdl[N_INET6], ap, port);
613             in6 = &((struct sockaddr_in6 *)cur->ai_next->ai_addr)->sin6_addr;
614             memcpy(&in6->s6_addr32[0], &faith_prefix,
615                 sizeof(struct in6_addr) - sizeof(struct in_addr));
616             memcpy(&in6->s6_addr32[3], ap, sizeof(struct in_addr));
617         } else
618 #endif /* FAITH */
619         GET_AI(cur->ai_next, gai_afd, ap, port);
620         if (cur == &sentinel) {
621             top = cur->ai_next;
622             GET_CANONNAME(top, hp->h_name);
623         }
624         cur = cur->ai_next;
625     }
626 #ifdef ENABLE_IPV6
627     freehostent(hp);
628 #endif
629     *res = top;
630     return SUCCESS;
631  free:
632     if (top)
633         freeaddrinfo(top);
634 #ifdef ENABLE_IPV6
635     if (hp)
636         freehostent(hp);
637 #endif
638 /* bad: */
639     *res = NULL;
640     return error;
641 }
642 
643 #endif // HAVE_NETDB_H
644