• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #define SUCCESS 0
65 #define GAI_ANY 0
66 #define YES 1
67 #define NO  0
68 
69 #ifdef FAITH
70 static int translate = NO;
71 static struct in6_addr faith_prefix = IN6ADDR_GAI_ANY_INIT;
72 #endif
73 
74 static const char in_addrany[] = { 0, 0, 0, 0 };
75 static const char in6_addrany[] = {
76     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
77 };
78 static const char in_loopback[] = { 127, 0, 0, 1 };
79 static const char in6_loopback[] = {
80     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
81 };
82 
83 struct sockinet {
84     u_char      si_len;
85     u_char      si_family;
86     u_short     si_port;
87 };
88 
89 static struct gai_afd {
90     int a_af;
91     int a_addrlen;
92     int a_socklen;
93     int a_off;
94     const char *a_addrany;
95     const char *a_loopback;
96 } gai_afdl [] = {
97 #ifdef ENABLE_IPV6
98 #define N_INET6 0
99     {PF_INET6, sizeof(struct in6_addr),
100      sizeof(struct sockaddr_in6),
101      offsetof(struct sockaddr_in6, sin6_addr),
102      in6_addrany, in6_loopback},
103 #define N_INET  1
104 #else
105 #define N_INET  0
106 #endif
107     {PF_INET, sizeof(struct in_addr),
108      sizeof(struct sockaddr_in),
109      offsetof(struct sockaddr_in, sin_addr),
110      in_addrany, in_loopback},
111     {0, 0, 0, 0, NULL, NULL},
112 };
113 
114 #ifdef ENABLE_IPV6
115 #define PTON_MAX        16
116 #else
117 #define PTON_MAX        4
118 #endif
119 
120 #ifndef IN_MULTICAST
121 #define IN_MULTICAST(i)     (((i) & 0xf0000000U) == 0xe0000000U)
122 #endif
123 
124 #ifndef IN_EXPERIMENTAL
125 #define IN_EXPERIMENTAL(i)  (((i) & 0xe0000000U) == 0xe0000000U)
126 #endif
127 
128 #ifndef IN_LOOPBACKNET
129 #define IN_LOOPBACKNET      127
130 #endif
131 
132 static int get_name(const char *, struct gai_afd *,
133                           struct addrinfo **, char *, struct addrinfo *,
134                           int);
135 static int get_addr(const char *, int, struct addrinfo **,
136                         struct addrinfo *, int);
137 static int str_isnumber(const char *);
138 
139 static const char * const ai_errlist[] = {
140     "success.",
141     "address family for hostname not supported.",       /* EAI_ADDRFAMILY */
142     "temporary failure in name resolution.",            /* EAI_AGAIN      */
143     "invalid value for ai_flags.",                      /* EAI_BADFLAGS   */
144     "non-recoverable failure in name resolution.",      /* EAI_FAIL       */
145     "ai_family not supported.",                         /* EAI_FAMILY     */
146     "memory allocation failure.",                       /* EAI_MEMORY     */
147     "no address associated with hostname.",             /* EAI_NODATA     */
148     "hostname nor servname provided, or not known.",/* EAI_NONAME     */
149     "servname not supported for ai_socktype.",          /* EAI_SERVICE    */
150     "ai_socktype not supported.",                       /* EAI_SOCKTYPE   */
151     "system error returned in errno.",                  /* EAI_SYSTEM     */
152     "invalid value for hints.",                         /* EAI_BADHINTS   */
153     "resolved protocol is unknown.",                    /* EAI_PROTOCOL   */
154     "unknown error.",                                   /* EAI_MAX        */
155 };
156 
157 #define GET_CANONNAME(ai, str) \
158 if (pai->ai_flags & AI_CANONNAME) {\
159     if (((ai)->ai_canonname = (char *)malloc(strlen(str) + 1)) != NULL) {\
160         strcpy((ai)->ai_canonname, (str));\
161     } else {\
162         error = EAI_MEMORY;\
163         goto free;\
164     }\
165 }
166 
167 #ifdef HAVE_SOCKADDR_SA_LEN
168 #define GET_AI(ai, gai_afd, addr, port) {\
169     char *p;\
170     if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\
171                                           ((gai_afd)->a_socklen)))\
172         == NULL) goto free;\
173     memcpy(ai, pai, sizeof(struct addrinfo));\
174     (ai)->ai_addr = (struct sockaddr *)((ai) + 1);\
175     memset((ai)->ai_addr, 0, (gai_afd)->a_socklen);\
176     (ai)->ai_addr->sa_len = (ai)->ai_addrlen = (gai_afd)->a_socklen;\
177     (ai)->ai_addr->sa_family = (ai)->ai_family = (gai_afd)->a_af;\
178     ((struct sockinet *)(ai)->ai_addr)->si_port = port;\
179     p = (char *)((ai)->ai_addr);\
180     memcpy(p + (gai_afd)->a_off, (addr), (gai_afd)->a_addrlen);\
181 }
182 #else
183 #define GET_AI(ai, gai_afd, addr, port) {\
184     char *p;\
185     if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\
186                                           ((gai_afd)->a_socklen)))\
187         == NULL) goto free;\
188     memcpy(ai, pai, sizeof(struct addrinfo));\
189     (ai)->ai_addr = (struct sockaddr *)((ai) + 1);\
190     memset((ai)->ai_addr, 0, (gai_afd)->a_socklen);\
191     (ai)->ai_addrlen = (gai_afd)->a_socklen;\
192     (ai)->ai_addr->sa_family = (ai)->ai_family = (gai_afd)->a_af;\
193     ((struct sockinet *)(ai)->ai_addr)->si_port = port;\
194     p = (char *)((ai)->ai_addr);\
195     memcpy(p + (gai_afd)->a_off, (addr), (gai_afd)->a_addrlen);\
196 }
197 #endif
198 
199 #define ERR(err) { error = (err); goto bad; }
200 
201 const char *
gai_strerror(int ecode)202 gai_strerror(int ecode)
203 {
204     if (ecode < 0 || ecode > EAI_MAX)
205         ecode = EAI_MAX;
206     return ai_errlist[ecode];
207 }
208 
209 void
freeaddrinfo(struct addrinfo * ai)210 freeaddrinfo(struct addrinfo *ai)
211 {
212     struct addrinfo *next;
213 
214     do {
215         next = ai->ai_next;
216         if (ai->ai_canonname)
217             free(ai->ai_canonname);
218         /* no need to free(ai->ai_addr) */
219         free(ai);
220     } while ((ai = next) != NULL);
221 }
222 
223 static int
str_isnumber(const char * p)224 str_isnumber(const char *p)
225 {
226     unsigned char *q = (unsigned char *)p;
227     while (*q) {
228         if (! isdigit(*q))
229             return NO;
230         q++;
231     }
232     return YES;
233 }
234 
235 int
getaddrinfo(const char * hostname,const char * servname,const struct addrinfo * hints,struct addrinfo ** res)236 getaddrinfo(const char*hostname, const char*servname,
237             const struct addrinfo *hints, struct addrinfo **res)
238 {
239     struct addrinfo sentinel;
240     struct addrinfo *top = NULL;
241     struct addrinfo *cur;
242     int i, error = 0;
243     char pton[PTON_MAX];
244     struct addrinfo ai;
245     struct addrinfo *pai;
246     u_short port;
247 
248 #ifdef FAITH
249     static int firsttime = 1;
250 
251     if (firsttime) {
252         /* translator hack */
253         {
254             const char *q = getenv("GAI");
255             if (q && inet_pton(AF_INET6, q, &faith_prefix) == 1)
256                 translate = YES;
257         }
258         firsttime = 0;
259     }
260 #endif
261 
262     /* initialize file static vars */
263     sentinel.ai_next = NULL;
264     cur = &sentinel;
265     pai = &ai;
266     pai->ai_flags = 0;
267     pai->ai_family = PF_UNSPEC;
268     pai->ai_socktype = GAI_ANY;
269     pai->ai_protocol = GAI_ANY;
270     pai->ai_addrlen = 0;
271     pai->ai_canonname = NULL;
272     pai->ai_addr = NULL;
273     pai->ai_next = NULL;
274     port = GAI_ANY;
275 
276     if (hostname == NULL && servname == NULL)
277         return EAI_NONAME;
278     if (hints) {
279         /* error check for hints */
280         if (hints->ai_addrlen || hints->ai_canonname ||
281             hints->ai_addr || hints->ai_next)
282             ERR(EAI_BADHINTS); /* xxx */
283         if (hints->ai_flags & ~AI_MASK)
284             ERR(EAI_BADFLAGS);
285         switch (hints->ai_family) {
286         case PF_UNSPEC:
287         case PF_INET:
288 #ifdef ENABLE_IPV6
289         case PF_INET6:
290 #endif
291             break;
292         default:
293             ERR(EAI_FAMILY);
294         }
295         memcpy(pai, hints, sizeof(*pai));
296         switch (pai->ai_socktype) {
297         case GAI_ANY:
298             switch (pai->ai_protocol) {
299             case GAI_ANY:
300                 break;
301             case IPPROTO_UDP:
302                 pai->ai_socktype = SOCK_DGRAM;
303                 break;
304             case IPPROTO_TCP:
305                 pai->ai_socktype = SOCK_STREAM;
306                 break;
307             default:
308                 pai->ai_socktype = SOCK_RAW;
309                 break;
310             }
311             break;
312         case SOCK_RAW:
313             break;
314         case SOCK_DGRAM:
315             if (pai->ai_protocol != IPPROTO_UDP &&
316                 pai->ai_protocol != GAI_ANY)
317                 ERR(EAI_BADHINTS);                      /*xxx*/
318             pai->ai_protocol = IPPROTO_UDP;
319             break;
320         case SOCK_STREAM:
321             if (pai->ai_protocol != IPPROTO_TCP &&
322                 pai->ai_protocol != GAI_ANY)
323                 ERR(EAI_BADHINTS);                      /*xxx*/
324             pai->ai_protocol = IPPROTO_TCP;
325             break;
326         default:
327             ERR(EAI_SOCKTYPE);
328             /* unreachable */
329         }
330     }
331 
332     /*
333      * service port
334      */
335     if (servname) {
336         if (str_isnumber(servname)) {
337             if (pai->ai_socktype == GAI_ANY) {
338                 /* caller accept *GAI_ANY* socktype */
339                 pai->ai_socktype = SOCK_DGRAM;
340                 pai->ai_protocol = IPPROTO_UDP;
341             }
342             port = htons((u_short)atoi(servname));
343         } else {
344             struct servent *sp;
345             const char *proto;
346 
347             proto = NULL;
348             switch (pai->ai_socktype) {
349             case GAI_ANY:
350                 proto = NULL;
351                 break;
352             case SOCK_DGRAM:
353                 proto = "udp";
354                 break;
355             case SOCK_STREAM:
356                 proto = "tcp";
357                 break;
358             default:
359                 fprintf(stderr, "panic!\n");
360                 break;
361             }
362             if ((sp = getservbyname(servname, proto)) == NULL)
363                 ERR(EAI_SERVICE);
364             port = sp->s_port;
365             if (pai->ai_socktype == GAI_ANY) {
366                 if (strcmp(sp->s_proto, "udp") == 0) {
367                     pai->ai_socktype = SOCK_DGRAM;
368                     pai->ai_protocol = IPPROTO_UDP;
369                 } else if (strcmp(sp->s_proto, "tcp") == 0) {
370                     pai->ai_socktype = SOCK_STREAM;
371                     pai->ai_protocol = IPPROTO_TCP;
372                 } else
373                     ERR(EAI_PROTOCOL);                          /*xxx*/
374             }
375         }
376     }
377 
378     /*
379      * hostname == NULL.
380      * passive socket -> anyaddr (0.0.0.0 or ::)
381      * non-passive socket -> localhost (127.0.0.1 or ::1)
382      */
383     if (hostname == NULL) {
384         struct gai_afd *gai_afd;
385 
386         for (gai_afd = &gai_afdl[0]; gai_afd->a_af; gai_afd++) {
387             if (!(pai->ai_family == PF_UNSPEC
388                || pai->ai_family == gai_afd->a_af)) {
389                 continue;
390             }
391 
392             if (pai->ai_flags & AI_PASSIVE) {
393                 GET_AI(cur->ai_next, gai_afd, gai_afd->a_addrany, port);
394                 /* xxx meaningless?
395                  * GET_CANONNAME(cur->ai_next, "anyaddr");
396                  */
397             } else {
398                 GET_AI(cur->ai_next, gai_afd, gai_afd->a_loopback,
399                     port);
400                 /* xxx meaningless?
401                  * GET_CANONNAME(cur->ai_next, "localhost");
402                  */
403             }
404             cur = cur->ai_next;
405         }
406         top = sentinel.ai_next;
407         if (top)
408             goto good;
409         else
410             ERR(EAI_FAMILY);
411     }
412 
413     /* hostname as numeric name */
414     for (i = 0; gai_afdl[i].a_af; i++) {
415         if (inet_pton(gai_afdl[i].a_af, hostname, pton)) {
416             u_long v4a;
417 #ifdef ENABLE_IPV6
418             u_char pfx;
419 #endif
420 
421             switch (gai_afdl[i].a_af) {
422             case AF_INET:
423                 v4a = ((struct in_addr *)pton)->s_addr;
424                 v4a = ntohl(v4a);
425                 if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
426                     pai->ai_flags &= ~AI_CANONNAME;
427                 v4a >>= IN_CLASSA_NSHIFT;
428                 if (v4a == 0 || v4a == IN_LOOPBACKNET)
429                     pai->ai_flags &= ~AI_CANONNAME;
430                 break;
431 #ifdef ENABLE_IPV6
432             case AF_INET6:
433                 pfx = ((struct in6_addr *)pton)->s6_addr[0];
434                 if (pfx == 0 || pfx == 0xfe || pfx == 0xff)
435                     pai->ai_flags &= ~AI_CANONNAME;
436                 break;
437 #endif
438             }
439 
440             if (pai->ai_family == gai_afdl[i].a_af ||
441                 pai->ai_family == PF_UNSPEC) {
442                 if (! (pai->ai_flags & AI_CANONNAME)) {
443                     GET_AI(top, &gai_afdl[i], pton, port);
444                     goto good;
445                 }
446                 /*
447                  * if AI_CANONNAME and if reverse lookup
448                  * fail, return ai anyway to pacify
449                  * calling application.
450                  *
451                  * XXX getaddrinfo() is a name->address
452                  * translation function, and it looks strange
453                  * that we do addr->name translation here.
454                  */
455                 get_name(pton, &gai_afdl[i], &top, pton, pai, port);
456                 goto good;
457             } else
458                 ERR(EAI_FAMILY);                        /*xxx*/
459         }
460     }
461 
462     if (pai->ai_flags & AI_NUMERICHOST)
463         ERR(EAI_NONAME);
464 
465     /* hostname as alphabetical name */
466     error = get_addr(hostname, pai->ai_family, &top, pai, port);
467     if (error == 0) {
468         if (top) {
469  good:
470             *res = top;
471             return SUCCESS;
472         } else
473             error = EAI_FAIL;
474     }
475  free:
476     if (top)
477         freeaddrinfo(top);
478  bad:
479     *res = NULL;
480     return error;
481 }
482 
483 static int
get_name(addr,gai_afd,res,numaddr,pai,port0)484 get_name(addr, gai_afd, res, numaddr, pai, port0)
485     const char *addr;
486     struct gai_afd *gai_afd;
487     struct addrinfo **res;
488     char *numaddr;
489     struct addrinfo *pai;
490     int port0;
491 {
492     u_short port = port0 & 0xffff;
493     struct hostent *hp;
494     struct addrinfo *cur;
495     int error = 0;
496 #ifdef ENABLE_IPV6
497     int h_error;
498 #endif
499 
500 #ifdef ENABLE_IPV6
501     hp = getipnodebyaddr(addr, gai_afd->a_addrlen, gai_afd->a_af, &h_error);
502 #else
503     hp = gethostbyaddr(addr, gai_afd->a_addrlen, AF_INET);
504 #endif
505     if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
506         GET_AI(cur, gai_afd, hp->h_addr_list[0], port);
507         GET_CANONNAME(cur, hp->h_name);
508     } else
509         GET_AI(cur, gai_afd, numaddr, port);
510 
511 #ifdef ENABLE_IPV6
512     if (hp)
513         freehostent(hp);
514 #endif
515     *res = cur;
516     return SUCCESS;
517  free:
518     if (cur)
519         freeaddrinfo(cur);
520 #ifdef ENABLE_IPV6
521     if (hp)
522         freehostent(hp);
523 #endif
524  /* bad: */
525     *res = NULL;
526     return error;
527 }
528 
529 static int
get_addr(hostname,af,res,pai,port0)530 get_addr(hostname, af, res, pai, port0)
531     const char *hostname;
532     int af;
533     struct addrinfo **res;
534     struct addrinfo *pai;
535     int port0;
536 {
537     u_short port = port0 & 0xffff;
538     struct addrinfo sentinel;
539     struct hostent *hp;
540     struct addrinfo *top, *cur;
541     struct gai_afd *gai_afd;
542     int i, error = 0, h_error;
543     char *ap;
544 
545     top = NULL;
546     sentinel.ai_next = NULL;
547     cur = &sentinel;
548 #ifdef ENABLE_IPV6
549     if (af == AF_UNSPEC) {
550         hp = getipnodebyname(hostname, AF_INET6,
551                         AI_ADDRCONFIG|AI_ALL|AI_V4MAPPED, &h_error);
552     } else
553         hp = getipnodebyname(hostname, af, AI_ADDRCONFIG, &h_error);
554 #else
555     hp = gethostbyname(hostname);
556     h_error = h_errno;
557 #endif
558     if (hp == NULL) {
559         switch (h_error) {
560         case HOST_NOT_FOUND:
561         case NO_DATA:
562             error = EAI_NODATA;
563             break;
564         case TRY_AGAIN:
565             error = EAI_AGAIN;
566             break;
567         case NO_RECOVERY:
568         default:
569             error = EAI_FAIL;
570             break;
571         }
572         goto free;
573     }
574 
575     if ((hp->h_name == NULL) || (hp->h_name[0] == 0) ||
576         (hp->h_addr_list[0] == NULL)) {
577         error = EAI_FAIL;
578         goto free;
579     }
580 
581     for (i = 0; (ap = hp->h_addr_list[i]) != NULL; i++) {
582         switch (af) {
583 #ifdef ENABLE_IPV6
584         case AF_INET6:
585             gai_afd = &gai_afdl[N_INET6];
586             break;
587 #endif
588 #ifndef ENABLE_IPV6
589         default:                /* AF_UNSPEC */
590 #endif
591         case AF_INET:
592             gai_afd = &gai_afdl[N_INET];
593             break;
594 #ifdef ENABLE_IPV6
595         default:                /* AF_UNSPEC */
596             if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) {
597                 ap += sizeof(struct in6_addr) -
598                     sizeof(struct in_addr);
599                 gai_afd = &gai_afdl[N_INET];
600             } else
601                 gai_afd = &gai_afdl[N_INET6];
602             break;
603 #endif
604         }
605 #ifdef FAITH
606         if (translate && gai_afd->a_af == AF_INET) {
607             struct in6_addr *in6;
608 
609             GET_AI(cur->ai_next, &gai_afdl[N_INET6], ap, port);
610             in6 = &((struct sockaddr_in6 *)cur->ai_next->ai_addr)->sin6_addr;
611             memcpy(&in6->s6_addr32[0], &faith_prefix,
612                 sizeof(struct in6_addr) - sizeof(struct in_addr));
613             memcpy(&in6->s6_addr32[3], ap, sizeof(struct in_addr));
614         } else
615 #endif /* FAITH */
616         GET_AI(cur->ai_next, gai_afd, ap, port);
617         if (cur == &sentinel) {
618             top = cur->ai_next;
619             GET_CANONNAME(top, hp->h_name);
620         }
621         cur = cur->ai_next;
622     }
623 #ifdef ENABLE_IPV6
624     freehostent(hp);
625 #endif
626     *res = top;
627     return SUCCESS;
628  free:
629     if (top)
630         freeaddrinfo(top);
631 #ifdef ENABLE_IPV6
632     if (hp)
633         freehostent(hp);
634 #endif
635 /* bad: */
636     *res = NULL;
637     return error;
638 }
639