Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals   Related Pages  

getaddrinfo.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
00003  *
00004  * Changes Copyright (C) 2001 by Martin Pool <mbp@samba.org>
00005  * 
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  * 1. Redistributions of source code must retain the above copyright
00010  *    notice, this list of conditions and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright
00012  *    notice, this list of conditions and the following disclaimer in the
00013  *    documentation and/or other materials provided with the distribution.
00014  * 3. Neither the name of the project nor the names of its contributors
00015  *    may be used to endorse or promote products derived from this software
00016  *    without specific prior written permission.
00017  * 
00018  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
00019  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00020  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00021  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
00022  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00023  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00024  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00025  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00026  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00027  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00028  * SUCH DAMAGE.
00029  */
00030 
00031 /*
00032  * "#ifdef FAITH" part is local hack for supporting IPv4-v6 translator.
00033  *
00034  * Issues to be discussed:
00035  * - Thread safe-ness must be checked.
00036  * - Return values.  There are nonstandard return values defined and used
00037  *   in the source code.  This is because RFC2133 is silent about which error
00038  *   code must be returned for which situation.
00039  * - PF_UNSPEC case would be handled in getipnodebyname() with the AI_ALL flag.
00040  */
00041 
00042 #include <rsync.h>
00043 
00044 #if defined(__KAME__) && defined(INET6)
00045 # define FAITH
00046 #endif
00047 
00048 #define SUCCESS 0
00049 #define ANY 0
00050 #define YES 1
00051 #define NO  0
00052 
00053 #ifdef FAITH
00054 static int translate = NO;
00055 static struct in6_addr faith_prefix = IN6ADDR_ANY_INIT;
00056 #endif /* FAITH */
00057 
00058 /* Amdahl's UTS 2.1.2 defines NO_ADDRESS instead of NO_DATA. */
00059 
00060 #ifndef NO_DATA
00061 #ifdef NO_ADDRESS
00062 #define NO_DATA NO_ADDRESS
00063 #endif
00064 #endif /* ndef NO_DATA */
00065 
00066 static const char in_addrany[] = { 0, 0, 0, 0 };
00067 static const char in6_addrany[] = {
00068         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
00069 };
00070 static const char in_loopback[] = { 127, 0, 0, 1 }; 
00071 static const char in6_loopback[] = {
00072         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
00073 };
00074 
00075 struct sockinet {
00076         u_char  si_len;
00077         u_char  si_family;
00078         u_short si_port;
00079 };
00080 
00081 static struct afd {
00082         int a_af;
00083         int a_addrlen;
00084         int a_socklen;
00085         int a_off;
00086         const char *a_addrany;
00087         const char *a_loopback; 
00088 } afdl [] = {
00089 #ifdef INET6
00090 #define N_INET6 0
00091         {PF_INET6, sizeof(struct in6_addr),
00092          sizeof(struct sockaddr_in6),
00093          offsetof(struct sockaddr_in6, sin6_addr),
00094          in6_addrany, in6_loopback},
00095 #define N_INET  1
00096 #else
00097 #define N_INET  0
00098 #endif
00099         {PF_INET, sizeof(struct in_addr),
00100          sizeof(struct sockaddr_in),
00101          offsetof(struct sockaddr_in, sin_addr),
00102          in_addrany, in_loopback},
00103         {0, 0, 0, 0, NULL, NULL},
00104 };
00105 
00106 #ifdef INET6
00107 #define PTON_MAX        16
00108 #else
00109 #define PTON_MAX        4
00110 #endif
00111 
00112 
00113 static int get_name (const char *, struct afd *,
00114                      struct addrinfo **, char *, struct addrinfo *,
00115                      int);
00116 static int get_addr (const char *, int, struct addrinfo **,
00117                         struct addrinfo *, int);
00118 static int str_isnumber (const char *);
00119         
00120 static char *ai_errlist[] = {
00121         "success.",
00122         "address family for hostname not supported.",   /* EAI_ADDRFAMILY */
00123         "temporary failure in name resolution.",        /* EAI_AGAIN      */
00124         "invalid value for ai_flags.",                  /* EAI_BADFLAGS   */
00125         "non-recoverable failure in name resolution.",  /* EAI_FAIL       */
00126         "ai_family not supported.",                     /* EAI_FAMILY     */
00127         "memory allocation failure.",                   /* EAI_MEMORY     */
00128         "no address associated with hostname.",         /* EAI_NODATA     */
00129         "hostname nor servname provided, or not known.",/* EAI_NONAME     */
00130         "servname not supported for ai_socktype.",      /* EAI_SERVICE    */
00131         "ai_socktype not supported.",                   /* EAI_SOCKTYPE   */
00132         "system error returned in errno.",              /* EAI_SYSTEM     */
00133         "invalid value for hints.",                     /* EAI_BADHINTS   */
00134         "resolved protocol is unknown.",                /* EAI_PROTOCOL   */
00135         "unknown error.",                               /* EAI_MAX        */
00136 };
00137 
00138 #define GET_CANONNAME(ai, str) \
00139 if (pai->ai_flags & AI_CANONNAME) {\
00140         if (((ai)->ai_canonname = (char *)malloc(strlen(str) + 1)) != NULL) {\
00141                 strcpy((ai)->ai_canonname, (str));\
00142         } else {\
00143                 error = EAI_MEMORY;\
00144                 goto free;\
00145         }\
00146 }
00147 
00148 
00149 static int get_ai(struct addrinfo ** to_ai,
00150                    struct addrinfo const * pai,
00151                    struct afd *afd,
00152                    const char *addr,
00153                    short port)
00154 {
00155         char *p;
00156         if ((*to_ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) +
00157                                               ((afd)->a_socklen)))
00158             == NULL) 
00159                 return 0;
00160         memcpy(*to_ai, pai, sizeof(struct addrinfo));
00161         (*to_ai)->ai_addr = (struct sockaddr *)((*to_ai) + 1);
00162         memset((*to_ai)->ai_addr, 0, (afd)->a_socklen);
00163         (*to_ai)->ai_addrlen = (afd)->a_socklen;
00164 #if HAVE_SOCKADDR_LEN
00165         (*to_ai)->ai_addr->sa_len= (afd)->a_socklen;
00166 #endif
00167         (*to_ai)->ai_addr->sa_family = (*to_ai)->ai_family = (afd)->a_af;
00168         ((struct sockinet *)(*to_ai)->ai_addr)->si_port = port;
00169         p = (char *)((*to_ai)->ai_addr);
00170         memcpy(p + (afd)->a_off, (addr), (afd)->a_addrlen);
00171         return 1;
00172 }
00173 
00174 #define ERR(err) { error = (err); goto bad; }
00175 
00176 char *
00177 gai_strerror(ecode)
00178         int ecode;
00179 {
00180         if (ecode < 0 || ecode > EAI_MAX)
00181                 ecode = EAI_MAX;
00182         return ai_errlist[ecode];
00183 }
00184 
00185 void
00186 freeaddrinfo(ai)
00187         struct addrinfo *ai;
00188 {
00189         struct addrinfo *next;
00190 
00191         do {
00192                 next = ai->ai_next;
00193                 if (ai->ai_canonname)
00194                         free(ai->ai_canonname);
00195                 /* no need to free(ai->ai_addr) */
00196                 free(ai);
00197         } while ((ai = next) != NULL);
00198 }
00199 
00200 static int
00201 str_isnumber(p)
00202         const char *p;
00203 {
00204         char *q = (char *)p;
00205         while (*q) {
00206                 if (! isdigit(*q))
00207                         return NO;
00208                 q++;
00209         }
00210         return YES;
00211 }
00212 
00213 int
00214 getaddrinfo(hostname, servname, hints, res)
00215         const char *hostname, *servname;
00216         const struct addrinfo *hints;
00217         struct addrinfo **res;
00218 {
00219         struct addrinfo sentinel;
00220         struct addrinfo *top = NULL;
00221         struct addrinfo *cur;
00222         int i, error = 0;
00223         char pton[PTON_MAX];
00224         struct addrinfo ai;
00225         struct addrinfo *pai;
00226         u_short port;
00227 
00228 #ifdef FAITH
00229         static int firsttime = 1;
00230 
00231         if (firsttime) {
00232                 /* translator hack */
00233                 {
00234                         char *q = getenv("GAI");
00235                         if (q && inet_pton(AF_INET6, q, &faith_prefix) == 1)
00236                                 translate = YES;
00237                 }
00238                 firsttime = 0;
00239         }
00240 #endif
00241 
00242         /* initialize file static vars */
00243         sentinel.ai_next = NULL;
00244         cur = &sentinel;
00245         pai = &ai;
00246         pai->ai_flags = 0;
00247         pai->ai_family = PF_UNSPEC;
00248         pai->ai_socktype = ANY;
00249         pai->ai_protocol = ANY;
00250         pai->ai_addrlen = 0;
00251         pai->ai_canonname = NULL;
00252         pai->ai_addr = NULL;
00253         pai->ai_next = NULL;
00254         port = ANY;
00255         
00256         if (hostname == NULL && servname == NULL)
00257                 return EAI_NONAME;
00258         if (hints) {
00259                 /* error check for hints */
00260                 if (hints->ai_addrlen || hints->ai_canonname ||
00261                     hints->ai_addr || hints->ai_next)
00262                         ERR(EAI_BADHINTS); /* xxx */
00263                 if (hints->ai_flags & ~AI_MASK)
00264                         ERR(EAI_BADFLAGS);
00265                 switch (hints->ai_family) {
00266                 case PF_UNSPEC:
00267                 case PF_INET:
00268 #ifdef INET6
00269                 case PF_INET6:
00270 #endif
00271                         break;
00272                 default:
00273                         ERR(EAI_FAMILY);
00274                 }
00275                 memcpy(pai, hints, sizeof(*pai));
00276                 switch (pai->ai_socktype) {
00277                 case ANY:
00278                         switch (pai->ai_protocol) {
00279                         case ANY:
00280                                 break;
00281                         case IPPROTO_UDP:
00282                                 pai->ai_socktype = SOCK_DGRAM;
00283                                 break;
00284                         case IPPROTO_TCP:
00285                                 pai->ai_socktype = SOCK_STREAM;
00286                                 break;
00287                         default:
00288                                 pai->ai_socktype = SOCK_RAW;
00289                                 break;
00290                         }
00291                         break;
00292                 case SOCK_RAW:
00293                         break;
00294                 case SOCK_DGRAM:
00295                         if (pai->ai_protocol != IPPROTO_UDP &&
00296                             pai->ai_protocol != ANY)
00297                                 ERR(EAI_BADHINTS);      /*xxx*/
00298                         pai->ai_protocol = IPPROTO_UDP;
00299                         break;
00300                 case SOCK_STREAM:
00301                         if (pai->ai_protocol != IPPROTO_TCP &&
00302                             pai->ai_protocol != ANY)
00303                                 ERR(EAI_BADHINTS);      /*xxx*/
00304                         pai->ai_protocol = IPPROTO_TCP;
00305                         break;
00306                 default:
00307                         ERR(EAI_SOCKTYPE);
00308                         break;
00309                 }
00310         }
00311 
00312         /*
00313          * service port
00314          */
00315         if (servname) {
00316                 if (str_isnumber(servname)) {
00317                         if (pai->ai_socktype == ANY) {
00318                                 /* caller accept *ANY* socktype */
00319                                 pai->ai_socktype = SOCK_DGRAM;
00320                                 pai->ai_protocol = IPPROTO_UDP;
00321                         }
00322                         port = htons(atoi(servname));
00323                 } else {
00324                         struct servent *sp;
00325                         char *proto;
00326 
00327                         proto = NULL;
00328                         switch (pai->ai_socktype) {
00329                         case ANY:
00330                                 proto = NULL;
00331                                 break;
00332                         case SOCK_DGRAM:
00333                                 proto = "udp";
00334                                 break;
00335                         case SOCK_STREAM:
00336                                 proto = "tcp";
00337                                 break;
00338                         default:
00339                                 fprintf(stderr, "panic!\n");
00340                                 break;
00341                         }
00342                         if ((sp = getservbyname(servname, proto)) == NULL)
00343                                 ERR(EAI_SERVICE);
00344                         port = sp->s_port;
00345                         if (pai->ai_socktype == ANY) {
00346                                 if (strcmp(sp->s_proto, "udp") == 0) {
00347                                         pai->ai_socktype = SOCK_DGRAM;
00348                                         pai->ai_protocol = IPPROTO_UDP;
00349                                 } else if (strcmp(sp->s_proto, "tcp") == 0) {
00350                                         pai->ai_socktype = SOCK_STREAM;
00351                                         pai->ai_protocol = IPPROTO_TCP;
00352                                 } else
00353                                         ERR(EAI_PROTOCOL);      /*xxx*/
00354                         }
00355                 }
00356         }
00357         
00358         /*
00359          * hostname == NULL.
00360          * passive socket -> anyaddr (0.0.0.0 or ::)
00361          * non-passive socket -> localhost (127.0.0.1 or ::1)
00362          */
00363         if (hostname == NULL) {
00364                 struct afd *afd;
00365 
00366                 for (afd = &afdl[0]; afd->a_af; afd++) {
00367                         if (!(pai->ai_family == PF_UNSPEC
00368                            || pai->ai_family == afd->a_af)) {
00369                                 continue;
00370                         }
00371 
00372                         if (pai->ai_flags & AI_PASSIVE) {
00373                                 if (!get_ai(&cur->ai_next, pai, afd, afd->a_addrany, port))
00374                                         goto free;
00375                                 /* xxx meaningless?
00376                                  * GET_CANONNAME(cur->ai_next, "anyaddr");
00377                                  */
00378                         } else {
00379                                 if (!get_ai(&cur->ai_next, pai, afd, afd->a_loopback,
00380                                         port))
00381                                         goto free;
00382                                 /* xxx meaningless?
00383                                  * GET_CANONNAME(cur->ai_next, "localhost");
00384                                  */
00385                         }
00386                         cur = cur->ai_next;
00387                 }
00388                 top = sentinel.ai_next;
00389                 if (top)
00390                         goto good;
00391                 else
00392                         ERR(EAI_FAMILY);
00393         }
00394         
00395         /* hostname as numeric name */
00396         for (i = 0; afdl[i].a_af; i++) {
00397                 if (inet_pton(afdl[i].a_af, hostname, pton)) {
00398                         u_long v4a;
00399 
00400                         switch (afdl[i].a_af) {
00401                         case AF_INET:
00402                                 v4a = ((struct in_addr *)pton)->s_addr;
00403                                 if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
00404                                         pai->ai_flags &= ~AI_CANONNAME;
00405                                 v4a >>= IN_CLASSA_NSHIFT;
00406                                 if (v4a == 0 || v4a == IN_LOOPBACKNET)
00407                                         pai->ai_flags &= ~AI_CANONNAME;
00408                                 break;
00409 #ifdef INET6
00410                         case AF_INET6:
00411                         {
00412                                 u_char pfx;
00413                                 pfx = ((struct in6_addr *)pton)->s6_addr[0];
00414                                 if (pfx == 0 || pfx == 0xfe || pfx == 0xff)
00415                                         pai->ai_flags &= ~AI_CANONNAME;
00416                                 break;
00417                         }
00418 #endif
00419                         }
00420                         
00421                         if (pai->ai_family == afdl[i].a_af ||
00422                             pai->ai_family == PF_UNSPEC) {
00423                                 if (! (pai->ai_flags & AI_CANONNAME)) {
00424                                         if (get_ai(&top, pai, &afdl[i], pton, port))
00425                                                 goto good;
00426                                         else
00427                                                 goto free;
00428                                 }
00429                                 /*
00430                                  * if AI_CANONNAME and if reverse lookup
00431                                  * fail, return ai anyway to pacify
00432                                  * calling application.
00433                                  *
00434                                  * XXX getaddrinfo() is a name->address
00435                                  * translation function, and it looks strange
00436                                  * that we do addr->name translation here.
00437                                  */
00438                                 get_name(pton, &afdl[i], &top, pton, pai, port);
00439                                 goto good;
00440                         } else 
00441                                 ERR(EAI_FAMILY);        /*xxx*/
00442                 }
00443         }
00444 
00445         if (pai->ai_flags & AI_NUMERICHOST)
00446                 ERR(EAI_NONAME);
00447 
00448         /* hostname as alphabetical name */
00449         error = get_addr(hostname, pai->ai_family, &top, pai, port);
00450         if (error == 0) {
00451                 if (top) {
00452  good:
00453                         *res = top;
00454                         return SUCCESS;
00455                 } else
00456                         error = EAI_FAIL;
00457         }
00458  free:
00459         if (top)
00460                 freeaddrinfo(top);
00461  bad:
00462         *res = NULL;
00463         return error;
00464 }
00465 
00466 static int
00467 get_name(addr, afd, res, numaddr, pai, port0)
00468         const char *addr;
00469         struct afd *afd;
00470         struct addrinfo **res;
00471         char *numaddr;
00472         struct addrinfo *pai;
00473         int port0;
00474 {
00475         u_short port = port0 & 0xffff;
00476         struct hostent *hp;
00477         struct addrinfo *cur;
00478         int error = 0;
00479         
00480 #ifdef INET6
00481         {
00482                 int h_error;
00483                 hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error);
00484         }
00485 #else
00486         hp = gethostbyaddr(addr, afd->a_addrlen, AF_INET);
00487 #endif
00488         if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
00489                 if (!get_ai(&cur, pai, afd, hp->h_addr_list[0], port))
00490                         goto free;
00491                 GET_CANONNAME(cur, hp->h_name);
00492         } else {
00493                 if (!get_ai(&cur, pai, afd, numaddr, port))
00494                         goto free;
00495         }
00496         
00497 #ifdef INET6
00498         if (hp)
00499                 freehostent(hp);
00500 #endif
00501         *res = cur;
00502         return SUCCESS;
00503  free:
00504         if (cur)
00505                 freeaddrinfo(cur);
00506 #ifdef INET6
00507         if (hp)
00508                 freehostent(hp);
00509 #endif
00510  /* bad: */
00511         *res = NULL;
00512         return error;
00513 }
00514 
00515 static int
00516 get_addr(hostname, af, res, pai, port0)
00517         const char *hostname;
00518         int af;
00519         struct addrinfo **res;
00520         struct addrinfo *pai;
00521         int port0;
00522 {
00523         u_short port = port0 & 0xffff;
00524         struct addrinfo sentinel;
00525         struct hostent *hp;
00526         struct addrinfo *top, *cur;
00527         struct afd *afd;
00528         int i, error = 0, h_error;
00529         char *ap;
00530 #ifndef INET6
00531         extern int h_errno;
00532 #endif
00533 
00534         top = NULL;
00535         sentinel.ai_next = NULL;
00536         cur = &sentinel;
00537 #ifdef INET6
00538         if (af == AF_UNSPEC) {
00539                 hp = getipnodebyname(hostname, AF_INET6,
00540                                 AI_ADDRCONFIG|AI_ALL|AI_V4MAPPED, &h_error);
00541         } else
00542                 hp = getipnodebyname(hostname, af, AI_ADDRCONFIG, &h_error);
00543 #else
00544         hp = gethostbyname(hostname);
00545         h_error = h_errno;
00546 #endif
00547         if (hp == NULL) {
00548                 switch (h_error) {
00549                 case HOST_NOT_FOUND:
00550                 case NO_DATA:
00551                         error = EAI_NODATA;
00552                         break;
00553                 case TRY_AGAIN:
00554                         error = EAI_AGAIN;
00555                         break;
00556                 case NO_RECOVERY:
00557                 default:
00558                         error = EAI_FAIL;
00559                         break;
00560                 }
00561                 goto bad;
00562         }
00563 
00564         if ((hp->h_name == NULL) || (hp->h_name[0] == 0) ||
00565             (hp->h_addr_list[0] == NULL))
00566                 ERR(EAI_FAIL);
00567         
00568         for (i = 0; (ap = hp->h_addr_list[i]) != NULL; i++) {
00569                 switch (af) {
00570 #ifdef INET6
00571                 case AF_INET6:
00572                         afd = &afdl[N_INET6];
00573                         break;
00574 #endif
00575 #ifndef INET6
00576                 default:        /* AF_UNSPEC */
00577 #endif
00578                 case AF_INET:
00579                         afd = &afdl[N_INET];
00580                         break;
00581 #ifdef INET6
00582                 default:        /* AF_UNSPEC */
00583                         if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) {
00584                                 ap += sizeof(struct in6_addr) -
00585                                         sizeof(struct in_addr);
00586                                 afd = &afdl[N_INET];
00587                         } else
00588                                 afd = &afdl[N_INET6];
00589                         break;
00590 #endif
00591                 }
00592 #ifdef FAITH
00593                 if (translate && afd->a_af == AF_INET) {
00594                         struct in6_addr *in6;
00595 
00596                         if (!get_ai(&cur->ai_next, pai, &afdl[N_INET6], ap, port))
00597                                 goto free;
00598                         in6 = &((struct sockaddr_in6 *)cur->ai_next->ai_addr)->sin6_addr;
00599                         memcpy(&in6->s6_addr32[0], &faith_prefix,
00600                             sizeof(struct in6_addr) - sizeof(struct in_addr));
00601                         memcpy(&in6->s6_addr32[3], ap, sizeof(struct in_addr));
00602                 } else
00603 #endif /* FAITH */
00604                 if (!get_ai(&cur->ai_next, pai, afd, ap, port))
00605                         goto free;
00606                 if (cur == &sentinel) {
00607                         top = cur->ai_next;
00608                         GET_CANONNAME(top, hp->h_name);
00609                 }
00610                 cur = cur->ai_next;
00611         }
00612 #ifdef INET6
00613         freehostent(hp);
00614 #endif
00615         *res = top;
00616         return SUCCESS;
00617  free:
00618         if (top)
00619                 freeaddrinfo(top);
00620 #ifdef INET6
00621         if (hp)
00622                 freehostent(hp);
00623 #endif
00624  bad:
00625         *res = NULL;
00626         return error;
00627 }

Generated on Tue Apr 16 12:37:36 2002 for rsync by doxygen1.2.15