diff options
-rw-r--r-- | lib/libc/net/getaddrinfo.c | 923 | ||||
-rw-r--r-- | lib/libc/net/getnameinfo.c | 388 |
2 files changed, 678 insertions, 633 deletions
diff --git a/lib/libc/net/getaddrinfo.c b/lib/libc/net/getaddrinfo.c index 0e33aa13683..20946923395 100644 --- a/lib/libc/net/getaddrinfo.c +++ b/lib/libc/net/getaddrinfo.c @@ -1,7 +1,7 @@ /* * %%% copyright-cmetz-96-bsd * Copyright (c) 1996-1999, Craig Metz, All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -17,7 +17,7 @@ * 4. Neither the name of the author nor the names of contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -29,7 +29,6 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * */ /* getaddrinfo() v1.38 */ @@ -50,504 +49,518 @@ #include <sys/utsname.h> #include <sys/un.h> #include <netinet/in.h> +#include <arpa/inet.h> #include <netdb.h> #include <errno.h> -#ifndef AF_LOCAL -#define AF_LOCAL AF_UNIX -#endif /* AF_LOCAL */ -#ifndef PF_LOCAL -#define PF_LOCAL PF_UNIX -#endif /* PF_LOCAL */ -#ifndef UNIX_PATH_MAX -#define UNIX_PATH_MAX 108 -#endif /* UNIX_PATH_MAX */ - -#define GAIH_OKIFUNSPEC 0x0100 -#define GAIH_EAI ~(GAIH_OKIFUNSPEC) +#define GAIH_OKIFUNSPEC 0x0100 +#define GAIH_EAI ~(GAIH_OKIFUNSPEC) -static struct addrinfo nullreq = -{ 0, PF_UNSPEC, 0, 0, 0, NULL, NULL, NULL }; +static struct addrinfo nullreq = { + 0, PF_UNSPEC, 0, 0, 0, NULL, NULL, NULL +}; struct gaih_service { - char *name; - int num; + char *name; + int num; }; struct gaih_servtuple { - struct gaih_servtuple *next; - int socktype; - int protocol; - int port; + struct gaih_servtuple *next; + int socktype; + int protocol; + int port; }; static struct gaih_servtuple nullserv = { - NULL, 0, 0, 0 + NULL, 0, 0, 0 }; struct gaih_addrtuple { - struct gaih_addrtuple *next; - int family; - char addr[16]; - char *cname; + struct gaih_addrtuple *next; + int family; + char addr[16]; + char *cname; }; -struct gaih_typeproto { - int socktype; - int protocol; - char *name; +static struct gaih_typeproto { + int socktype; + int protocol; + char *name; +} gaih_inet_typeproto[] = { + { 0, 0, NULL }, + { SOCK_STREAM, IPPROTO_TCP, "tcp" }, + { SOCK_DGRAM, IPPROTO_UDP, "udp" }, + { 0, 0, NULL } }; -#define RETURN_ERROR(x) do { \ - rval = (x); \ - goto ret; \ - } while(0) +static int +netdb_lookup_addr(const char *name, int af, + const struct addrinfo *req, struct gaih_addrtuple **pat) +{ + int rval = 0, herrno, i; + char *prevcname = NULL; + struct hostent *h; + + h = gethostbyname2(name, af); + herrno = h_errno; + + if (!h) { + switch (herrno) { + case NETDB_INTERNAL: + return -EAI_SYSTEM; + case HOST_NOT_FOUND: + return 1; + case TRY_AGAIN: + return -EAI_AGAIN; + case NO_RECOVERY: + return -EAI_FAIL; + case NO_DATA: + return 1; + default: + return -EAI_FAIL; + } + } + + for (i = 0; h->h_addr_list[i]; i++) { + while (*pat) + pat = &((*pat)->next); + + if (!(*pat = malloc(sizeof(struct gaih_addrtuple)))) + return -EAI_MEMORY; + memset(*pat, 0, sizeof(struct gaih_addrtuple)); + + switch ((*pat)->family = af) { + case AF_INET: + memcpy((*pat)->addr, h->h_addr_list[i], + sizeof(struct in_addr)); + break; + case AF_INET6: + memcpy((*pat)->addr, h->h_addr_list[i], + sizeof(struct in6_addr)); + break; + default: + return -EAI_FAIL; + } + + if (req->ai_flags & AI_CANONNAME) { + if (prevcname && !strcmp(prevcname, h->h_name)) + (*pat)->cname = prevcname; + else + prevcname = (*pat)->cname = strdup(h->h_name); + } + pat = &((*pat)->next); + } + return rval; +} -static int netdb_lookup_addr(const char *name, int af, const struct addrinfo *req, struct gaih_addrtuple **pat) +static int +gaih_local(const char *name, const struct gaih_service *service, + const struct addrinfo *req, struct addrinfo **pai) { - int rval, herrno, i; - char *prevcname = NULL; - struct hostent *h; - - h = gethostbyname2(name, af); - herrno = h_errno; - - if (!h) { - switch(herrno) { - case NETDB_INTERNAL: - RETURN_ERROR(-EAI_SYSTEM); - case HOST_NOT_FOUND: - RETURN_ERROR(1); - case TRY_AGAIN: - RETURN_ERROR(-EAI_AGAIN); - case NO_RECOVERY: - RETURN_ERROR(-EAI_FAIL); - case NO_DATA: - RETURN_ERROR(1); - default: - RETURN_ERROR(-EAI_FAIL); - }; - }; - - for (i = 0; h->h_addr_list[i]; i++) { - while(*pat) - pat = &((*pat)->next); - - if (!(*pat = malloc(sizeof(struct gaih_addrtuple)))) - RETURN_ERROR(-EAI_MEMORY); - - memset(*pat, 0, sizeof(struct gaih_addrtuple)); - - switch((*pat)->family = af) { - case AF_INET: - memcpy((*pat)->addr, h->h_addr_list[i], sizeof(struct in_addr)); - break; - case AF_INET6: - memcpy((*pat)->addr, h->h_addr_list[i], sizeof(struct in6_addr)); - break; - default: - RETURN_ERROR(-EAI_FAIL); - }; - - if (req->ai_flags & AI_CANONNAME) { - if (prevcname && !strcmp(prevcname, h->h_name)) - (*pat)->cname = prevcname; - else - prevcname = (*pat)->cname = strdup(h->h_name); - }; - - pat = &((*pat)->next); - } - - rval = 0; + struct utsname utsname; + struct addrinfo *ai; + struct sockaddr_un *sun; + int siz; + + if (name || (req->ai_flags & AI_CANONNAME)) + if (uname(&utsname) < 0) + return (-EAI_SYSTEM); + + if (name && strcmp(name, "localhost") && strcmp(name, "local") && + strcmp(name, "unix") && strcmp(name, utsname.nodename)) + return (GAIH_OKIFUNSPEC | -EAI_NONAME); + + siz = sizeof(struct addrinfo) + sizeof(struct sockaddr_un); + if (req->ai_flags & AI_CANONNAME) + siz += strlen(utsname.nodename) + 1; + + if (!(ai = malloc(siz))) + return -EAI_MEMORY; + + *pai = ai; + ai->ai_next = NULL; + ai->ai_flags = req->ai_flags; + ai->ai_family = AF_LOCAL; + ai->ai_socktype = req->ai_socktype ? req->ai_socktype : SOCK_STREAM; + ai->ai_protocol = req->ai_protocol; + ai->ai_addrlen = sizeof(struct sockaddr_un); + ai->ai_addr = (void *)ai + sizeof(struct addrinfo); + + sun = (struct sockaddr_un *)ai->ai_addr; + sun->sun_len = sizeof(struct sockaddr_un); + sun->sun_family = AF_LOCAL; + memset(&sun->sun_path, 0, sizeof sun->sun_path); + + if (service) { + char *c; + + c = strchr(service->name, '/'); + if (c) { + if (strlen(service->name) >= sizeof(sun->sun_path)) + return (GAIH_OKIFUNSPEC | -EAI_SERVICE); + strlcpy(sun->sun_path, service->name, sizeof (sun->sun_path)); + } else { + if (strlen(P_tmpdir "/") + strlen(service->name) + 1 >= + sizeof(sun->sun_path)) + return(GAIH_OKIFUNSPEC | -EAI_SERVICE); + snprintf(sun->sun_path, sizeof(sun->sun_path), "%s/%s", + P_tmpdir, service->name); + } + } else { + extern char *_mktemp __P((char *)); + char tmpn[MAXPATHLEN], *c; + + snprintf(tmpn, sizeof tmpn, "%stmp.XXXXXXXXXXXXX", P_tmpdir); + if (!(c = _mktemp(tmpn))) + return (GAIH_OKIFUNSPEC | -EAI_SYSTEM); + strlcpy(sun->sun_path, c, sizeof(sun->sun_path)); + } -ret: - return rval; -}; + ai->ai_canonname = NULL; + if (req->ai_flags & AI_CANONNAME) { + ai->ai_canonname = (void *)sun + sizeof(struct sockaddr_un); + strlcpy(ai->ai_canonname, utsname.nodename, + strlen(utsname.nodename)+1); + } + return 0; +} -static int gaih_local(const char *name, const struct gaih_service *service, - const struct addrinfo *req, struct addrinfo **pai) +static int +gaih_inet_serv(char *servicename, struct gaih_typeproto *tp, + struct gaih_servtuple **st) { - int rval; - struct utsname utsname; - - if (name || (req->ai_flags & AI_CANONNAME)) - if (uname(&utsname) < 0) - RETURN_ERROR(-EAI_SYSTEM); - if (name) { - if (strcmp(name, "localhost") && strcmp(name, "local") && strcmp(name, "unix") && strcmp(name, utsname.nodename)) - RETURN_ERROR(GAIH_OKIFUNSPEC | -EAI_NONAME); - }; - - if (!(*pai = malloc(sizeof(struct addrinfo) + sizeof(struct sockaddr_un) + ((req->ai_flags & AI_CANONNAME) ? (strlen(utsname.nodename) + 1): 0)))) - RETURN_ERROR(-EAI_MEMORY); - - (*pai)->ai_next = NULL; - (*pai)->ai_flags = req->ai_flags; - (*pai)->ai_family = AF_LOCAL; - (*pai)->ai_socktype = req->ai_socktype ? req->ai_socktype : SOCK_STREAM; - (*pai)->ai_protocol = req->ai_protocol; - (*pai)->ai_addrlen = sizeof(struct sockaddr_un); - (*pai)->ai_addr = (void *)(*pai) + sizeof(struct addrinfo); - ((struct sockaddr_un *)(*pai)->ai_addr)->sun_len = sizeof(struct sockaddr_un); - ((struct sockaddr_un *)(*pai)->ai_addr)->sun_family = AF_LOCAL; - memset(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path, 0, UNIX_PATH_MAX); - if (service) { - char *c; - if (c = strchr(service->name, '/')) { - if (strlen(service->name) >= sizeof(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path)) - RETURN_ERROR(GAIH_OKIFUNSPEC | -EAI_SERVICE); - strcpy(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path, service->name); - } else { - if (strlen(P_tmpdir "/") + 1 + strlen(service->name) >= sizeof(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path)) - RETURN_ERROR(GAIH_OKIFUNSPEC | -EAI_SERVICE); - strcpy(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path, P_tmpdir "/"); - strcat(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path, service->name); - }; - } else { - char *c; - if (!(c = tmpnam(NULL))) - RETURN_ERROR(GAIH_OKIFUNSPEC | -EAI_SYSTEM); - - strncpy((((struct sockaddr_un *)(*pai)->ai_addr)->sun_path), c, sizeof(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path) - 1); - c[sizeof(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path) - 1] = 0; - }; - if (req->ai_flags & AI_CANONNAME) { - strncpy((*pai)->ai_canonname = (char *)(*pai) + sizeof(struct addrinfo) + sizeof(struct sockaddr_un), utsname.nodename, sizeof(utsname.nodename) - 1); - (*pai)->ai_canonname[sizeof(utsname.nodename) - 1] = 0; - } else - (*pai)->ai_canonname = NULL; - - rval = 0; + struct servent *s; -ret: - return rval; -}; + s = getservbyname(servicename, tp->name); + if (!s) + return (GAIH_OKIFUNSPEC | -EAI_SERVICE); -static struct gaih_typeproto gaih_inet_typeproto[] = { - { 0, 0, NULL }, - { SOCK_STREAM, IPPROTO_TCP, "tcp" }, - { SOCK_DGRAM, IPPROTO_UDP, "udp" }, - { 0, 0, NULL } -}; + if (!(*st = malloc(sizeof(struct gaih_servtuple)))) + return (-EAI_MEMORY); -static int gaih_inet_serv(char *servicename, struct gaih_typeproto *tp, struct gaih_servtuple **st) + (*st)->next = NULL; + (*st)->socktype = tp->socktype; + (*st)->protocol = tp->protocol; + (*st)->port = s->s_port; + return (0); +} + +static int +gaih_inet(const char *name, const struct gaih_service *service, + const struct addrinfo*req, struct addrinfo **pai) { - int rval; - struct servent *s; + struct gaih_typeproto *tp = gaih_inet_typeproto; + struct gaih_servtuple *st = &nullserv; + struct gaih_addrtuple *at = NULL; + char *prevcname = NULL; + struct gaih_servtuple *st2; + struct gaih_addrtuple *at2 = at; + struct addrinfo *ai = NULL; + int canonlen, addrlen, rval = 0; + + if (req->ai_protocol || req->ai_socktype) { + for (tp++; tp->name && + ((req->ai_socktype != tp->socktype) || !req->ai_socktype) && + ((req->ai_protocol != tp->protocol) || !req->ai_protocol); tp++); + if (!tp->name) { + rval = GAIH_OKIFUNSPEC | -EAI_SERVICE; + if (req->ai_socktype) + rval = GAIH_OKIFUNSPEC | -EAI_SOCKTYPE; + goto ret; + } + } + if (service && (service->num < 0)) { + if (tp->name) { + rval = gaih_inet_serv(service->name, tp, &st); + if (rval) + goto ret; + } else { + struct gaih_servtuple **pst = &st; + for (tp++; tp->name; tp++) { + rval = gaih_inet_serv(service->name, tp, pst); + if (rval) { + if (rval & GAIH_OKIFUNSPEC) + continue; + goto ret; + } + pst = &((*pst)->next); + } + if (st == &nullserv) { + rval = GAIH_OKIFUNSPEC | -EAI_SERVICE; + goto ret; + } + } + } else { + if (!(st = malloc(sizeof(struct gaih_servtuple)))) { + rval = -EAI_MEMORY; + goto ret; + } + + st->next = NULL; + st->socktype = tp->socktype; + st->protocol = tp->protocol; + if (service) + st->port = htons(service->num); + else + st->port = 0; + } - if (!(s = getservbyname(servicename, tp->name))) - RETURN_ERROR(GAIH_OKIFUNSPEC | -EAI_SERVICE); + if (!name) { + if (!(at = malloc(sizeof(struct gaih_addrtuple)))) { + rval = -EAI_MEMORY; + goto ret; + } - if (!(*st = malloc(sizeof(struct gaih_servtuple)))) - RETURN_ERROR(-EAI_MEMORY); + memset(at, 0, sizeof(struct gaih_addrtuple)); - (*st)->next = NULL; - (*st)->socktype = tp->socktype; - (*st)->protocol = tp->protocol; - (*st)->port = s->s_port; + if (req->ai_family) + at->family = req->ai_family; + else { + if (!(at->next = malloc(sizeof(struct gaih_addrtuple)))) { + rval = -EAI_MEMORY; + goto ret; + } - rval = 0; + at->family = AF_INET6; -ret: - return rval; -} + memset(at->next, 0, sizeof(struct gaih_addrtuple)); + at->next->family = AF_INET; + } -static int gaih_inet(const char *name, const struct gaih_service *service, - const struct addrinfo *req, struct addrinfo **pai) -{ - int rval; - struct hostent *h = NULL; - struct gaih_typeproto *tp = gaih_inet_typeproto; - struct gaih_servtuple *st = &nullserv; - struct gaih_addrtuple *at = NULL; - int i; - - if (req->ai_protocol || req->ai_socktype) { - for (tp++; tp->name && - ((req->ai_socktype != tp->socktype) || !req->ai_socktype) && - ((req->ai_protocol != tp->protocol) || !req->ai_protocol); tp++); - if (!tp->name) - if (req->ai_socktype) - RETURN_ERROR(GAIH_OKIFUNSPEC | -EAI_SOCKTYPE); - else - RETURN_ERROR(GAIH_OKIFUNSPEC | -EAI_SERVICE); - } - - if (service && (service->num < 0)) { - if (tp->name) { - if (rval = gaih_inet_serv(service->name, tp, &st)) - goto ret; - } else { - struct gaih_servtuple **pst = &st; - for (tp++; tp->name; tp++) { - if (rval = gaih_inet_serv(service->name, tp, pst)) { - if (rval & GAIH_OKIFUNSPEC) - continue; - goto ret; - }; - pst = &((*pst)->next); - }; - if (st == &nullserv) - RETURN_ERROR(GAIH_OKIFUNSPEC | -EAI_SERVICE); - }; - } else { - if (!(st = malloc(sizeof(struct gaih_servtuple)))) - RETURN_ERROR(-EAI_MEMORY); - - st->next = NULL; - st->socktype = tp->socktype; - st->protocol = tp->protocol; - if (service) - st->port = htons(service->num); - else - st->port = 0; - }; - - if (!name) { - if (!(at = malloc(sizeof(struct gaih_addrtuple)))) - RETURN_ERROR(-EAI_MEMORY); - - memset(at, 0, sizeof(struct gaih_addrtuple)); - - if (req->ai_family) - at->family = req->ai_family; - else { - if (!(at->next = malloc(sizeof(struct gaih_addrtuple)))) - RETURN_ERROR(-EAI_MEMORY); - - at->family = AF_INET6; - - memset(at->next, 0, sizeof(struct gaih_addrtuple)); - at->next->family = AF_INET; - }; - - goto build; - }; - - if (!req->ai_family || (req->ai_family == AF_INET)) { - struct in_addr in_addr; - if (inet_pton(AF_INET, name, &in_addr) > 0) { - if (!(at = malloc(sizeof(struct gaih_addrtuple)))) - RETURN_ERROR(-EAI_MEMORY); - - memset(at, 0, sizeof(struct gaih_addrtuple)); - - at->family = AF_INET; - memcpy(at->addr, &in_addr, sizeof(struct in_addr)); - goto build; - }; - }; - - if (!req->ai_family || (req->ai_family == AF_INET6)) { - struct in6_addr in6_addr; - if (inet_pton(AF_INET6, name, &in6_addr) > 0) { - if (!(at = malloc(sizeof(struct gaih_addrtuple)))) - RETURN_ERROR(-EAI_MEMORY); - - memset(at, 0, sizeof(struct gaih_addrtuple)); - - at->family = AF_INET6; - memcpy(at->addr, &in6_addr, sizeof(struct in6_addr)); - goto build; - }; - }; - - if (!(req->ai_flags & AI_NUMERICHOST)) { - if (!req->ai_family || (req->ai_family == AF_INET6)) - if ((rval = netdb_lookup_addr(name, AF_INET6, req, &at)) < 0) - goto ret; - if (!req->ai_family || (req->ai_family == AF_INET)) - if ((rval = netdb_lookup_addr(name, AF_INET, req, &at)) < 0) - goto ret; - - if (!rval) - goto build; - }; - - if (!at) - RETURN_ERROR(GAIH_OKIFUNSPEC | -EAI_NONAME); + goto build; + } + + if (!req->ai_family || (req->ai_family == AF_INET)) { + struct in_addr in_addr; + if (inet_pton(AF_INET, name, &in_addr) > 0) { + if (!(at = malloc(sizeof(struct gaih_addrtuple)))) { + rval = -EAI_MEMORY; + goto ret; + } + + memset(at, 0, sizeof(struct gaih_addrtuple)); + + at->family = AF_INET; + memcpy(at->addr, &in_addr, sizeof(struct in_addr)); + goto build; + } + } + + if (!req->ai_family || (req->ai_family == AF_INET6)) { + struct in6_addr in6_addr; + if (inet_pton(AF_INET6, name, &in6_addr) > 0) { + if (!(at = malloc(sizeof(struct gaih_addrtuple)))) { + rval = -EAI_MEMORY; + goto ret; + } + + memset(at, 0, sizeof(struct gaih_addrtuple)); + + at->family = AF_INET6; + memcpy(at->addr, &in6_addr, sizeof(struct in6_addr)); + goto build; + } + } + + if (!(req->ai_flags & AI_NUMERICHOST)) { + if (!req->ai_family || (req->ai_family == AF_INET6)) + if ((rval = netdb_lookup_addr(name, AF_INET6, req, &at)) < 0) + goto ret; + if (!req->ai_family || (req->ai_family == AF_INET)) + if ((rval = netdb_lookup_addr(name, AF_INET, req, &at)) < 0) + goto ret; + + if (!rval) + goto build; + } + + if (!at) { + rval = GAIH_OKIFUNSPEC | -EAI_NONAME; + goto ret; + } build: - { - char *prevcname = NULL; - struct gaih_servtuple *st2; - struct gaih_addrtuple *at2 = at; - int j; - - while(at2) { - if (req->ai_flags & AI_CANONNAME) { - if (at2->cname) - j = strlen(at2->cname) + 1; - else - if (name) - j = strlen(name) + 1; - else - j = 2; - } else - j = 0; - - if (at2->family == AF_INET6) - i = sizeof(struct sockaddr_in6); - else - i = sizeof(struct sockaddr_in); - - st2 = st; - while(st2) { - if (!(*pai = malloc(sizeof(struct addrinfo) + i + j))) - RETURN_ERROR(-EAI_MEMORY); - - memset(*pai, 0, sizeof(struct addrinfo) + i + j); - - (*pai)->ai_flags = req->ai_flags; - (*pai)->ai_family = at2->family; - (*pai)->ai_socktype = st2->socktype; - (*pai)->ai_protocol = st2->protocol; - (*pai)->ai_addrlen = i; - (*pai)->ai_addr = (void *)(*pai) + sizeof(struct addrinfo); - ((struct sockaddr_in *)(*pai)->ai_addr)->sin_len = i; - ((struct sockaddr_in *)(*pai)->ai_addr)->sin_family = at2->family; - ((struct sockaddr_in *)(*pai)->ai_addr)->sin_port = st2->port; - - if (at2->family == AF_INET6) - memcpy(&((struct sockaddr_in6 *)(*pai)->ai_addr)->sin6_addr, at2->addr, sizeof(struct in6_addr)); - else - memcpy(&((struct sockaddr_in *)(*pai)->ai_addr)->sin_addr, at2->addr, sizeof(struct in_addr)); - - if (j) { - (*pai)->ai_canonname = (void *)(*pai) + sizeof(struct addrinfo) + i; - if (at2->cname) { - strcpy((*pai)->ai_canonname, at2->cname); - if (prevcname != at2->cname) { - if (prevcname) - free(prevcname); - prevcname = at2->cname; - }; - } else - strcpy((*pai)->ai_canonname, name ? name : "*"); - }; - - pai = &((*pai)->ai_next); - - st2 = st2->next; - }; - at2 = at2->next; - }; - }; - - rval = 0; + while (at2) { + if (req->ai_flags & AI_CANONNAME) { + if (at2->cname) + canonlen = strlen(at2->cname) + 1; + else + if (name) + canonlen = strlen(name) + 1; + else + canonlen = 2; + } else + canonlen = 0; + + if (at2->family == AF_INET6) + addrlen = sizeof(struct sockaddr_in6); + else + addrlen = sizeof(struct sockaddr_in); + + st2 = st; + while (st2) { + if (!(ai = malloc(sizeof(struct addrinfo) + + addrlen + canonlen))) { + rval = -EAI_MEMORY; + goto ret; + } + + *pai = ai; + memset(ai, 0, sizeof(struct addrinfo) + addrlen + canonlen); + + ai->ai_flags = req->ai_flags; + ai->ai_family = at2->family; + ai->ai_socktype = st2->socktype; + ai->ai_protocol = st2->protocol; + ai->ai_addrlen = addrlen; + ai->ai_addr = (void *)ai + sizeof(struct addrinfo); + ai->ai_addr->sa_len = addrlen; + ai->ai_addr->sa_family = at2->family; + + switch (at2->family) { + case AF_INET6: + { + struct sockaddr_in6 *sin6 = (void *)ai->ai_addr; + + memcpy(&sin6->sin6_addr, at2->addr, + sizeof(sin6->sin6_addr)); + sin6->sin6_port = st2->port; + break; + } + default: + { + struct sockaddr_in *sin = (void *)ai->ai_addr; + + memcpy(&sin->sin_addr, at2->addr, + sizeof(sin->sin_addr)); + sin->sin_port = st2->port; + break; + } + } + + if (canonlen) { + ai->ai_canonname = (void *) ai->ai_addr + addrlen; + + if (at2->cname) { + strcpy(ai->ai_canonname, at2->cname); + if (prevcname != at2->cname) { + if (prevcname) + free(prevcname); + prevcname = at2->cname; + } + } else + strcpy(ai->ai_canonname, name ? name : "*"); + } + pai = &(ai->ai_next); + st2 = st2->next; + } + at2 = at2->next; + } + rval = 0; ret: - if (st != &nullserv) { - struct gaih_servtuple *st2 = st; - while(st) { - st2 = st->next; - free(st); - st = st2; - } - } - if (at) { - struct gaih_addrtuple *at2 = at; - while(at) { - at2 = at->next; - free(at); - at = at2; - } - } - - return rval; + if (st != &nullserv) { + struct gaih_servtuple *st2 = st; + while (st) { + st2 = st->next; + free(st); + st = st2; + } + } + if (at) { + struct gaih_addrtuple *at2 = at; + while (at) { + at2 = at->next; + free(at); + at = at2; + } + } + return rval; } -struct gaih { - int family; - char *name; - int (*gaih)(const char *name, const struct gaih_service *service, - const struct addrinfo *req, struct addrinfo **pai); -}; - -static struct gaih gaih[] = { - { PF_INET6, "inet6", gaih_inet }, - { PF_INET, "inet", gaih_inet }, - { PF_LOCAL, "local", gaih_local }, - { -1, NULL, NULL } +static struct gaih { + int family; + char *name; + int (*gaih) __P((const char *name, + const struct gaih_service *service, + const struct addrinfo *req, struct addrinfo **pai)); +} gaih[] = { + { PF_INET6, "inet6", gaih_inet }, + { PF_INET, "inet", gaih_inet }, + { PF_LOCAL, "local", gaih_local }, + { -1, NULL, NULL} }; -int getaddrinfo(const char *name, const char *service, - const struct addrinfo *req, struct addrinfo **pai) +int +getaddrinfo(const char *name, const char *service, + const struct addrinfo *req, struct addrinfo **pai) { - int rval = EAI_SYSTEM; /* XXX */ - int i, j = 0; - struct addrinfo *p = NULL, **end; - struct gaih *g = gaih, *pg = NULL; - struct gaih_service gaih_service, *pservice; - - if (name && (name[0] == '*') && !name[1]) - name = NULL; - - if (service && (service[0] == '*') && !service[1]) - service = NULL; - - if (!req) - req = &nullreq; - - if (req->ai_flags & ~(AI_CANONNAME | AI_PASSIVE | AI_NUMERICHOST | AI_EXT)) - RETURN_ERROR(EAI_BADFLAGS); - - if (service && *service) { - char *c; - gaih_service.num = strtoul(gaih_service.name = (void *)service, &c, 10); - if (*c) { - gaih_service.num = -1; - } - - pservice = &gaih_service; - } else - pservice = NULL; - - if (pai) - end = &p; - else - end = NULL; - - while(g->gaih) { - if ((req->ai_family == g->family) || !req->ai_family) { - j++; - if (!((pg && (pg->gaih == g->gaih)))) { - pg = g; - if (rval = g->gaih(name, pservice, req, end)) { - if (!req->ai_family && (rval & GAIH_OKIFUNSPEC)) - continue; - - if (p) - freeaddrinfo(p); - - rval = -(rval & GAIH_EAI); - goto ret; - } - if (end) - while(*end) end = &((*end)->ai_next); - } - } - g++; - } + int rval = EAI_SYSTEM; /* XXX */ + int j = 0; + struct addrinfo *p = NULL, **end; + struct gaih *g = gaih, *pg = NULL; + struct gaih_service gaih_service, *pservice; - if (!j) - RETURN_ERROR(EAI_FAMILY); + if (name && (name[0] == '*') && !name[1]) + name = NULL; - if (p) { - *pai = p; - rval = 0; - goto ret; - } + if (service && service[0] == '*' && service[1] == '\0') + service = NULL; - if (!pai && !rval) { - rval = 0; - goto ret; - }; + if (!req) + req = &nullreq; - RETURN_ERROR(EAI_NONAME); + if (req->ai_flags & ~(AI_CANONNAME | AI_PASSIVE | AI_NUMERICHOST | AI_EXT)) + return (EAI_BADFLAGS); -ret: - return rval; -} + if (service && *service) { + char *c; + gaih_service.num = strtoul(service, &c, 10); + if (*c) + gaih_service.num = -1; + gaih_service.name = (void *)service; + pservice = &gaih_service; + } else + pservice = NULL; + + if (pai) + end = &p; + else + end = NULL; + + while (g->gaih) { + if ((req->ai_family == g->family) || !req->ai_family) { + j++; + if (!((pg && (pg->gaih == g->gaih)))) { + pg = g; + rval = g->gaih(name, pservice, req, end); + if (rval) { + if (!req->ai_family && (rval & GAIH_OKIFUNSPEC)) + continue; + + if (p) + freeaddrinfo(p); + + return -(rval & GAIH_EAI); + } + if (end) + while (*end) + end = &((*end)->ai_next); + } + } + g++; + } + + if (!j) + return (EAI_FAMILY); + + if (p) { + *pai = p; + return (0); + } + if (!pai && !rval) + return (0); + return EAI_NONAME; +} diff --git a/lib/libc/net/getnameinfo.c b/lib/libc/net/getnameinfo.c index 1ae197c15aa..62c4b9d9287 100644 --- a/lib/libc/net/getnameinfo.c +++ b/lib/libc/net/getnameinfo.c @@ -1,7 +1,7 @@ /* * %%% copyright-cmetz-96-bsd * Copyright (c) 1996-1999, Craig Metz, All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -17,7 +17,7 @@ * 4. Neither the name of the author nor the names of contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -36,197 +36,229 @@ #include <sys/types.h> #include <sys/socket.h> - #include <netinet/in.h> #include <sys/un.h> #include <sys/utsname.h> #include <netdb.h> +#include <arpa/inet.h> #include <errno.h> #include <string.h> #include <resolv.h> -#ifndef AF_LOCAL -#define AF_LOCAL AF_UNIX -#endif /* AF_LOCAL */ - -#ifndef min +#ifndef min #define min(x,y) (((x) > (y)) ? (y) : (x)) -#endif /* min */ +#endif /* min */ -#define RETURN_ERROR(x) do { \ - rval = (x); \ - goto ret; \ - } while(0) - -static int netdb_lookup_name(int family, void *addr, int addrlen, char *name, - int namelen, int flags) +static int +netdb_lookup_name(int family, void *addr, int addrlen, char *name, + int namelen, int flags) { - struct hostent *hostent; - char *c, *c2; - int rval, i; - - if (!(hostent = gethostbyaddr(addr, addrlen, family))) { - switch(h_errno) { - case NETDB_INTERNAL: - RETURN_ERROR(EAI_SYSTEM); - case HOST_NOT_FOUND: - RETURN_ERROR(1); - case TRY_AGAIN: - RETURN_ERROR(EAI_AGAIN); - case NO_RECOVERY: - RETURN_ERROR(EAI_FAIL); - case NO_DATA: - RETURN_ERROR(1); - default: - RETURN_ERROR(EAI_FAIL); - }; - }; - - endhostent(); - - c = hostent->h_name; - if ((flags & NI_NOFQDN) && (_res.options & RES_INIT) && _res.defdname[0] && - (c2 = strstr(c + 1, _res.defdname)) && (*(--c2) == '.')) { - *c2 = 0; - i = min(c2 - c, namelen) - 1; - strncpy(name, c, i); - } else - strncpy(name, c, namelen - 1); - - rval = 0; + struct hostent *hostent; + char *c, *c2; + int i; -ret: - return rval; + if (!(hostent = gethostbyaddr(addr, addrlen, family))) { + switch (h_errno) { + case NETDB_INTERNAL: + return(EAI_SYSTEM); + case HOST_NOT_FOUND: + return(1); + case TRY_AGAIN: + return(EAI_AGAIN); + case NO_RECOVERY: + return(EAI_FAIL); + case NO_DATA: + return(1); + default: + return(EAI_FAIL); + } + } + + endhostent(); + + c = hostent->h_name; + if ((flags & NI_NOFQDN) && (_res.options & RES_INIT) && _res.defdname[0] && + (c2 = strstr(c + 1, _res.defdname)) && (*(--c2) == '.')) { + *c2 = 0; + i = min(c2 - c, namelen); + strlcpy(name, c, i); + } else + strlcpy(name, c, namelen); + return 0; } -int getnameinfo(const struct sockaddr *sa, size_t addrlen, char *host, size_t hostlen, char *serv, size_t servlen, int flags) +int +getnameinfo(const struct sockaddr *sa, size_t addrlen, char *host, + size_t hostlen, char *serv, size_t servlen, int flags) { - int rval; - int serrno = errno; - - if (!sa || (addrlen != SA_LEN(sa))) - RETURN_ERROR(EAI_FAIL); - - if (host && (hostlen > 0)) - switch(sa->sa_family) { - case AF_INET6: - if (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)sa)->sin6_addr)) { - if (flags & NI_NUMERICHOST) - goto inet6_noname; - else - strncpy(host, "*", hostlen - 1); - break; - }; - - if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)sa)->sin6_addr)) { - struct sockaddr_in sin; - memset(&sin, 0, sizeof(struct sockaddr_in)); - sin.sin_len = sizeof(struct sockaddr_in); - sin.sin_family = AF_INET; - sin.sin_port = ((struct sockaddr_in6 *)sa)->sin6_port; - sin.sin_addr.s_addr = ((u_int32_t *)&((struct sockaddr_in6 *)sa)->sin6_addr)[3]; - if (!(rval = getnameinfo((struct sockaddr *)&sin, sizeof(struct sockaddr_in), host, hostlen, serv, servlen, flags | NI_NAMEREQD))) - goto ret; - if (rval != EAI_NONAME) - goto ret; - goto inet6_noname; - }; - - if (flags & NI_NUMERICHOST) - goto inet6_noname; - - if ((rval = netdb_lookup_name(AF_INET6, - &((struct sockaddr_in6 *)sa)->sin6_addr, sizeof(struct in6_addr), - host, hostlen, flags)) < 0) - goto ret; - - if (!rval) - break; - -inet6_noname: - if (flags & NI_NAMEREQD) - RETURN_ERROR(EAI_NONAME); - - if (!inet_ntop(AF_INET6, &((struct sockaddr_in6 *)sa)->sin6_addr, host, hostlen)) - RETURN_ERROR(EAI_NONAME); - - break; - case AF_INET: - if (flags & NI_NUMERICHOST) - goto inet_noname; - - if (!((struct sockaddr_in *)sa)->sin_addr.s_addr) { - strncpy(host, "*", hostlen - 1); - break; - }; - - if ((rval = netdb_lookup_name(AF_INET, - &((struct sockaddr_in *)sa)->sin_addr, sizeof(struct in_addr), - host, hostlen, flags)) < 0) - goto ret; - - if (!rval) - break; -inet_noname: - if (flags & NI_NAMEREQD) - RETURN_ERROR(EAI_NONAME); - - if (!inet_ntop(AF_INET, &((struct sockaddr_in *)sa)->sin_addr, host, hostlen)) - RETURN_ERROR(EAI_NONAME); - - break; - case AF_LOCAL: - if (!(flags & NI_NUMERICHOST)) { - struct utsname utsname; - - if (!uname(&utsname)) { - strncpy(host, utsname.nodename, hostlen - 1); - break; - }; - }; - - if (flags & NI_NAMEREQD) - RETURN_ERROR(EAI_NONAME); - - strncpy(host, "localhost", hostlen - 1); - break; - default: - RETURN_ERROR(EAI_FAMILY); - }; - - if (serv && (servlen > 0)) - switch(sa->sa_family) { - case AF_INET: - case AF_INET6: - if (!(flags & NI_NUMERICSERV)) { - struct servent *s; - if (s = getservbyport(((struct sockaddr_in *)sa)->sin_port, (flags & NI_DGRAM) ? "udp" : "tcp")) { - strncpy(serv, s->s_name, servlen - 1); - break; - }; - if (!((struct sockaddr_in *)sa)->sin_port) { - strncpy(serv, "*", servlen - 1); - break; - }; - }; - snprintf(serv, servlen - 1, "%d", ntohs(((struct sockaddr_in *)sa)->sin_port)); - break; - case AF_LOCAL: - strncpy(serv, ((struct sockaddr_un *)sa)->sun_path, servlen - 1); - break; - }; - - if (host && (hostlen > 0)) - host[hostlen-1] = 0; - if (serv && (servlen > 0)) - serv[servlen-1] = 0; - rval = 0; + int rval; + int saved_errno; -ret: - if (rval == 1) - rval = EAI_FAIL; + if (sa == NULL || addrlen != sa->sa_len) + return EAI_FAIL; + saved_errno = errno; + + if (host && hostlen > 0) { + switch (sa->sa_family) { + case AF_INET6: + { + struct sockaddr_in6 *sin6 = (void *)sa; + + if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { + if (flags & NI_NUMERICHOST) + goto inet6_noname; + strlcpy(host, "*", hostlen); + break; + } + + if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { + struct sockaddr_in sin; + + memset(&sin, 0, sizeof(struct sockaddr_in)); + sin.sin_len = sizeof(struct sockaddr_in); + sin.sin_family = AF_INET; + sin.sin_port = sin6->sin6_port; + sin.sin_addr.s_addr = + ((u_int32_t *)&sin6->sin6_addr)[3]; + if (!(rval = getnameinfo((struct sockaddr *)&sin, + sizeof(struct sockaddr_in), host, hostlen, + serv, servlen, flags | NI_NAMEREQD))) + goto ret; + if (rval != EAI_NONAME) + goto ret; + goto inet6_noname; + } + + if (flags & NI_NUMERICHOST) + goto inet6_noname; + if ((rval = netdb_lookup_name(AF_INET6, + &sin6->sin6_addr, sizeof(struct in6_addr), + host, hostlen, flags)) < 0) + goto ret; - errno = serrno; + if (!rval) + break; + inet6_noname: + if (flags & NI_NAMEREQD) { + rval = EAI_NONAME; + goto ret; + } + if (!inet_ntop(AF_INET6, &sin6->sin6_addr, host, hostlen)) { + rval = EAI_NONAME; + goto ret; + } + break; + } + case AF_INET: + { + struct sockaddr_in *sin = (void *)sa; - return rval; -}; + if (flags & NI_NUMERICHOST) + goto inet_noname; + + if (sin->sin_addr.s_addr == 0) { + strlcpy(host, "*", hostlen); + break; + } + + if ((rval = netdb_lookup_name(AF_INET, + &sin->sin_addr, sizeof(struct in_addr), + host, hostlen, flags)) < 0) + goto ret; + + if (!rval) + break; + inet_noname: + if (flags & NI_NAMEREQD) { + rval = EAI_NONAME; + goto ret; + } + if (!inet_ntop(AF_INET, &sin->sin_addr, host, hostlen)) { + rval = EAI_NONAME; + goto ret; + } + break; + } + case AF_LOCAL: + if (!(flags & NI_NUMERICHOST)) { + struct utsname utsname; + + if (!uname(&utsname)) { + strlcpy(host, utsname.nodename, hostlen); + break; + } + } + + if (flags & NI_NAMEREQD) { + rval = EAI_NONAME; + goto ret; + } + + strlcpy(host, "localhost", hostlen); + break; + default: + rval = EAI_FAMILY; + goto ret; + } + } + + if (serv && servlen > 0) { + switch (sa->sa_family) { + case AF_INET: + { + struct sockaddr_in *sin = (void *)sa; + struct servent *s; + + if ((flags & NI_NUMERICSERV) == 0) { + s = getservbyport(sin->sin_port, + (flags & NI_DGRAM) ? "udp" : "tcp"); + if (s) { + strlcpy(serv, s->s_name, servlen); + break; + } + if (sin->sin_port == 0) { + strlcpy(serv, "*", servlen); + break; + } + } + snprintf(serv, servlen, "%d", ntohs(sin->sin_port)); + break; + } + case AF_INET6: + { + struct sockaddr_in6 *sin6 = (void *)sa; + struct servent *s; + + if ((flags & NI_NUMERICSERV) == 0) { + + s = getservbyport(sin6->sin6_port, + (flags & NI_DGRAM) ? "udp" : "tcp"); + if (s) { + strlcpy(serv, s->s_name, servlen); + break; + } + if (sin6->sin6_port == 0) { + strlcpy(serv, "*", servlen); + break; + } + } + snprintf(serv, servlen, "%d", ntohs(sin6->sin6_port)); + break; + } + case AF_LOCAL: + { + struct sockaddr_un *sun = (void *)sa; + + strlcpy(serv, sun->sun_path, servlen); + break; + } + } + } + rval = 0; + +ret: + if (rval == 1) + rval = EAI_FAIL; + errno = saved_errno; + return (rval); +} |