diff options
Diffstat (limited to 'src/lib/libc')
| -rw-r--r-- | src/lib/libc/net/getaddrinfo.c | 923 | ||||
| -rw-r--r-- | src/lib/libc/net/getnameinfo.c | 388 |
2 files changed, 678 insertions, 633 deletions
diff --git a/src/lib/libc/net/getaddrinfo.c b/src/lib/libc/net/getaddrinfo.c index 0e33aa1368..2094692339 100644 --- a/src/lib/libc/net/getaddrinfo.c +++ b/src/lib/libc/net/getaddrinfo.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * %%% copyright-cmetz-96-bsd | 2 | * %%% copyright-cmetz-96-bsd |
| 3 | * Copyright (c) 1996-1999, Craig Metz, All rights reserved. | 3 | * Copyright (c) 1996-1999, Craig Metz, All rights reserved. |
| 4 | * | 4 | * |
| 5 | * Redistribution and use in source and binary forms, with or without | 5 | * Redistribution and use in source and binary forms, with or without |
| 6 | * modification, are permitted provided that the following conditions | 6 | * modification, are permitted provided that the following conditions |
| 7 | * are met: | 7 | * are met: |
| @@ -17,7 +17,7 @@ | |||
| 17 | * 4. Neither the name of the author nor the names of contributors | 17 | * 4. Neither the name of the author nor the names of contributors |
| 18 | * may be used to endorse or promote products derived from this software | 18 | * may be used to endorse or promote products derived from this software |
| 19 | * without specific prior written permission. | 19 | * without specific prior written permission. |
| 20 | * | 20 | * |
| 21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
| 22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| @@ -29,7 +29,6 @@ | |||
| 29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| 30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| 31 | * SUCH DAMAGE. | 31 | * SUCH DAMAGE. |
| 32 | * | ||
| 33 | */ | 32 | */ |
| 34 | 33 | ||
| 35 | /* getaddrinfo() v1.38 */ | 34 | /* getaddrinfo() v1.38 */ |
| @@ -50,504 +49,518 @@ | |||
| 50 | #include <sys/utsname.h> | 49 | #include <sys/utsname.h> |
| 51 | #include <sys/un.h> | 50 | #include <sys/un.h> |
| 52 | #include <netinet/in.h> | 51 | #include <netinet/in.h> |
| 52 | #include <arpa/inet.h> | ||
| 53 | #include <netdb.h> | 53 | #include <netdb.h> |
| 54 | #include <errno.h> | 54 | #include <errno.h> |
| 55 | 55 | ||
| 56 | #ifndef AF_LOCAL | 56 | #define GAIH_OKIFUNSPEC 0x0100 |
| 57 | #define AF_LOCAL AF_UNIX | 57 | #define GAIH_EAI ~(GAIH_OKIFUNSPEC) |
| 58 | #endif /* AF_LOCAL */ | ||
| 59 | #ifndef PF_LOCAL | ||
| 60 | #define PF_LOCAL PF_UNIX | ||
| 61 | #endif /* PF_LOCAL */ | ||
| 62 | #ifndef UNIX_PATH_MAX | ||
| 63 | #define UNIX_PATH_MAX 108 | ||
| 64 | #endif /* UNIX_PATH_MAX */ | ||
| 65 | |||
| 66 | #define GAIH_OKIFUNSPEC 0x0100 | ||
| 67 | #define GAIH_EAI ~(GAIH_OKIFUNSPEC) | ||
| 68 | 58 | ||
| 69 | static struct addrinfo nullreq = | 59 | static struct addrinfo nullreq = { |
| 70 | { 0, PF_UNSPEC, 0, 0, 0, NULL, NULL, NULL }; | 60 | 0, PF_UNSPEC, 0, 0, 0, NULL, NULL, NULL |
| 61 | }; | ||
| 71 | 62 | ||
| 72 | struct gaih_service { | 63 | struct gaih_service { |
| 73 | char *name; | 64 | char *name; |
| 74 | int num; | 65 | int num; |
| 75 | }; | 66 | }; |
| 76 | 67 | ||
| 77 | struct gaih_servtuple { | 68 | struct gaih_servtuple { |
| 78 | struct gaih_servtuple *next; | 69 | struct gaih_servtuple *next; |
| 79 | int socktype; | 70 | int socktype; |
| 80 | int protocol; | 71 | int protocol; |
| 81 | int port; | 72 | int port; |
| 82 | }; | 73 | }; |
| 83 | 74 | ||
| 84 | static struct gaih_servtuple nullserv = { | 75 | static struct gaih_servtuple nullserv = { |
| 85 | NULL, 0, 0, 0 | 76 | NULL, 0, 0, 0 |
| 86 | }; | 77 | }; |
| 87 | 78 | ||
| 88 | struct gaih_addrtuple { | 79 | struct gaih_addrtuple { |
| 89 | struct gaih_addrtuple *next; | 80 | struct gaih_addrtuple *next; |
| 90 | int family; | 81 | int family; |
| 91 | char addr[16]; | 82 | char addr[16]; |
| 92 | char *cname; | 83 | char *cname; |
| 93 | }; | 84 | }; |
| 94 | 85 | ||
| 95 | struct gaih_typeproto { | 86 | static struct gaih_typeproto { |
| 96 | int socktype; | 87 | int socktype; |
| 97 | int protocol; | 88 | int protocol; |
| 98 | char *name; | 89 | char *name; |
| 90 | } gaih_inet_typeproto[] = { | ||
| 91 | { 0, 0, NULL }, | ||
| 92 | { SOCK_STREAM, IPPROTO_TCP, "tcp" }, | ||
| 93 | { SOCK_DGRAM, IPPROTO_UDP, "udp" }, | ||
| 94 | { 0, 0, NULL } | ||
| 99 | }; | 95 | }; |
| 100 | 96 | ||
| 101 | #define RETURN_ERROR(x) do { \ | 97 | static int |
| 102 | rval = (x); \ | 98 | netdb_lookup_addr(const char *name, int af, |
| 103 | goto ret; \ | 99 | const struct addrinfo *req, struct gaih_addrtuple **pat) |
| 104 | } while(0) | 100 | { |
| 101 | int rval = 0, herrno, i; | ||
| 102 | char *prevcname = NULL; | ||
| 103 | struct hostent *h; | ||
| 104 | |||
| 105 | h = gethostbyname2(name, af); | ||
| 106 | herrno = h_errno; | ||
| 107 | |||
| 108 | if (!h) { | ||
| 109 | switch (herrno) { | ||
| 110 | case NETDB_INTERNAL: | ||
| 111 | return -EAI_SYSTEM; | ||
| 112 | case HOST_NOT_FOUND: | ||
| 113 | return 1; | ||
| 114 | case TRY_AGAIN: | ||
| 115 | return -EAI_AGAIN; | ||
| 116 | case NO_RECOVERY: | ||
| 117 | return -EAI_FAIL; | ||
| 118 | case NO_DATA: | ||
| 119 | return 1; | ||
| 120 | default: | ||
| 121 | return -EAI_FAIL; | ||
| 122 | } | ||
| 123 | } | ||
| 124 | |||
| 125 | for (i = 0; h->h_addr_list[i]; i++) { | ||
| 126 | while (*pat) | ||
| 127 | pat = &((*pat)->next); | ||
| 128 | |||
| 129 | if (!(*pat = malloc(sizeof(struct gaih_addrtuple)))) | ||
| 130 | return -EAI_MEMORY; | ||
| 131 | memset(*pat, 0, sizeof(struct gaih_addrtuple)); | ||
| 132 | |||
| 133 | switch ((*pat)->family = af) { | ||
| 134 | case AF_INET: | ||
| 135 | memcpy((*pat)->addr, h->h_addr_list[i], | ||
| 136 | sizeof(struct in_addr)); | ||
| 137 | break; | ||
| 138 | case AF_INET6: | ||
| 139 | memcpy((*pat)->addr, h->h_addr_list[i], | ||
| 140 | sizeof(struct in6_addr)); | ||
| 141 | break; | ||
| 142 | default: | ||
| 143 | return -EAI_FAIL; | ||
| 144 | } | ||
| 145 | |||
| 146 | if (req->ai_flags & AI_CANONNAME) { | ||
| 147 | if (prevcname && !strcmp(prevcname, h->h_name)) | ||
| 148 | (*pat)->cname = prevcname; | ||
| 149 | else | ||
| 150 | prevcname = (*pat)->cname = strdup(h->h_name); | ||
| 151 | } | ||
| 152 | pat = &((*pat)->next); | ||
| 153 | } | ||
| 154 | return rval; | ||
| 155 | } | ||
| 105 | 156 | ||
| 106 | static int netdb_lookup_addr(const char *name, int af, const struct addrinfo *req, struct gaih_addrtuple **pat) | 157 | static int |
| 158 | gaih_local(const char *name, const struct gaih_service *service, | ||
| 159 | const struct addrinfo *req, struct addrinfo **pai) | ||
| 107 | { | 160 | { |
| 108 | int rval, herrno, i; | 161 | struct utsname utsname; |
| 109 | char *prevcname = NULL; | 162 | struct addrinfo *ai; |
| 110 | struct hostent *h; | 163 | struct sockaddr_un *sun; |
| 111 | 164 | int siz; | |
| 112 | h = gethostbyname2(name, af); | 165 | |
| 113 | herrno = h_errno; | 166 | if (name || (req->ai_flags & AI_CANONNAME)) |
| 114 | 167 | if (uname(&utsname) < 0) | |
| 115 | if (!h) { | 168 | return (-EAI_SYSTEM); |
| 116 | switch(herrno) { | 169 | |
| 117 | case NETDB_INTERNAL: | 170 | if (name && strcmp(name, "localhost") && strcmp(name, "local") && |
| 118 | RETURN_ERROR(-EAI_SYSTEM); | 171 | strcmp(name, "unix") && strcmp(name, utsname.nodename)) |
| 119 | case HOST_NOT_FOUND: | 172 | return (GAIH_OKIFUNSPEC | -EAI_NONAME); |
| 120 | RETURN_ERROR(1); | 173 | |
| 121 | case TRY_AGAIN: | 174 | siz = sizeof(struct addrinfo) + sizeof(struct sockaddr_un); |
| 122 | RETURN_ERROR(-EAI_AGAIN); | 175 | if (req->ai_flags & AI_CANONNAME) |
| 123 | case NO_RECOVERY: | 176 | siz += strlen(utsname.nodename) + 1; |
| 124 | RETURN_ERROR(-EAI_FAIL); | 177 | |
| 125 | case NO_DATA: | 178 | if (!(ai = malloc(siz))) |
| 126 | RETURN_ERROR(1); | 179 | return -EAI_MEMORY; |
| 127 | default: | 180 | |
| 128 | RETURN_ERROR(-EAI_FAIL); | 181 | *pai = ai; |
| 129 | }; | 182 | ai->ai_next = NULL; |
| 130 | }; | 183 | ai->ai_flags = req->ai_flags; |
| 131 | 184 | ai->ai_family = AF_LOCAL; | |
| 132 | for (i = 0; h->h_addr_list[i]; i++) { | 185 | ai->ai_socktype = req->ai_socktype ? req->ai_socktype : SOCK_STREAM; |
| 133 | while(*pat) | 186 | ai->ai_protocol = req->ai_protocol; |
| 134 | pat = &((*pat)->next); | 187 | ai->ai_addrlen = sizeof(struct sockaddr_un); |
| 135 | 188 | ai->ai_addr = (void *)ai + sizeof(struct addrinfo); | |
| 136 | if (!(*pat = malloc(sizeof(struct gaih_addrtuple)))) | 189 | |
| 137 | RETURN_ERROR(-EAI_MEMORY); | 190 | sun = (struct sockaddr_un *)ai->ai_addr; |
| 138 | 191 | sun->sun_len = sizeof(struct sockaddr_un); | |
| 139 | memset(*pat, 0, sizeof(struct gaih_addrtuple)); | 192 | sun->sun_family = AF_LOCAL; |
| 140 | 193 | memset(&sun->sun_path, 0, sizeof sun->sun_path); | |
| 141 | switch((*pat)->family = af) { | 194 | |
| 142 | case AF_INET: | 195 | if (service) { |
| 143 | memcpy((*pat)->addr, h->h_addr_list[i], sizeof(struct in_addr)); | 196 | char *c; |
| 144 | break; | 197 | |
| 145 | case AF_INET6: | 198 | c = strchr(service->name, '/'); |
| 146 | memcpy((*pat)->addr, h->h_addr_list[i], sizeof(struct in6_addr)); | 199 | if (c) { |
| 147 | break; | 200 | if (strlen(service->name) >= sizeof(sun->sun_path)) |
| 148 | default: | 201 | return (GAIH_OKIFUNSPEC | -EAI_SERVICE); |
| 149 | RETURN_ERROR(-EAI_FAIL); | 202 | strlcpy(sun->sun_path, service->name, sizeof (sun->sun_path)); |
| 150 | }; | 203 | } else { |
| 151 | 204 | if (strlen(P_tmpdir "/") + strlen(service->name) + 1 >= | |
| 152 | if (req->ai_flags & AI_CANONNAME) { | 205 | sizeof(sun->sun_path)) |
| 153 | if (prevcname && !strcmp(prevcname, h->h_name)) | 206 | return(GAIH_OKIFUNSPEC | -EAI_SERVICE); |
| 154 | (*pat)->cname = prevcname; | 207 | snprintf(sun->sun_path, sizeof(sun->sun_path), "%s/%s", |
| 155 | else | 208 | P_tmpdir, service->name); |
| 156 | prevcname = (*pat)->cname = strdup(h->h_name); | 209 | } |
| 157 | }; | 210 | } else { |
| 158 | 211 | extern char *_mktemp __P((char *)); | |
| 159 | pat = &((*pat)->next); | 212 | char tmpn[MAXPATHLEN], *c; |
| 160 | } | 213 | |
| 161 | 214 | snprintf(tmpn, sizeof tmpn, "%stmp.XXXXXXXXXXXXX", P_tmpdir); | |
| 162 | rval = 0; | 215 | if (!(c = _mktemp(tmpn))) |
| 216 | return (GAIH_OKIFUNSPEC | -EAI_SYSTEM); | ||
| 217 | strlcpy(sun->sun_path, c, sizeof(sun->sun_path)); | ||
| 218 | } | ||
| 163 | 219 | ||
| 164 | ret: | 220 | ai->ai_canonname = NULL; |
| 165 | return rval; | 221 | if (req->ai_flags & AI_CANONNAME) { |
| 166 | }; | 222 | ai->ai_canonname = (void *)sun + sizeof(struct sockaddr_un); |
| 223 | strlcpy(ai->ai_canonname, utsname.nodename, | ||
| 224 | strlen(utsname.nodename)+1); | ||
| 225 | } | ||
| 226 | return 0; | ||
| 227 | } | ||
| 167 | 228 | ||
| 168 | static int gaih_local(const char *name, const struct gaih_service *service, | 229 | static int |
| 169 | const struct addrinfo *req, struct addrinfo **pai) | 230 | gaih_inet_serv(char *servicename, struct gaih_typeproto *tp, |
| 231 | struct gaih_servtuple **st) | ||
| 170 | { | 232 | { |
| 171 | int rval; | 233 | struct servent *s; |
| 172 | struct utsname utsname; | ||
| 173 | |||
| 174 | if (name || (req->ai_flags & AI_CANONNAME)) | ||
| 175 | if (uname(&utsname) < 0) | ||
| 176 | RETURN_ERROR(-EAI_SYSTEM); | ||
| 177 | if (name) { | ||
| 178 | if (strcmp(name, "localhost") && strcmp(name, "local") && strcmp(name, "unix") && strcmp(name, utsname.nodename)) | ||
| 179 | RETURN_ERROR(GAIH_OKIFUNSPEC | -EAI_NONAME); | ||
| 180 | }; | ||
| 181 | |||
| 182 | if (!(*pai = malloc(sizeof(struct addrinfo) + sizeof(struct sockaddr_un) + ((req->ai_flags & AI_CANONNAME) ? (strlen(utsname.nodename) + 1): 0)))) | ||
| 183 | RETURN_ERROR(-EAI_MEMORY); | ||
| 184 | |||
| 185 | (*pai)->ai_next = NULL; | ||
| 186 | (*pai)->ai_flags = req->ai_flags; | ||
| 187 | (*pai)->ai_family = AF_LOCAL; | ||
| 188 | (*pai)->ai_socktype = req->ai_socktype ? req->ai_socktype : SOCK_STREAM; | ||
| 189 | (*pai)->ai_protocol = req->ai_protocol; | ||
| 190 | (*pai)->ai_addrlen = sizeof(struct sockaddr_un); | ||
| 191 | (*pai)->ai_addr = (void *)(*pai) + sizeof(struct addrinfo); | ||
| 192 | ((struct sockaddr_un *)(*pai)->ai_addr)->sun_len = sizeof(struct sockaddr_un); | ||
| 193 | ((struct sockaddr_un *)(*pai)->ai_addr)->sun_family = AF_LOCAL; | ||
| 194 | memset(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path, 0, UNIX_PATH_MAX); | ||
| 195 | if (service) { | ||
| 196 | char *c; | ||
| 197 | if (c = strchr(service->name, '/')) { | ||
| 198 | if (strlen(service->name) >= sizeof(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path)) | ||
| 199 | RETURN_ERROR(GAIH_OKIFUNSPEC | -EAI_SERVICE); | ||
| 200 | strcpy(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path, service->name); | ||
| 201 | } else { | ||
| 202 | if (strlen(P_tmpdir "/") + 1 + strlen(service->name) >= sizeof(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path)) | ||
| 203 | RETURN_ERROR(GAIH_OKIFUNSPEC | -EAI_SERVICE); | ||
| 204 | strcpy(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path, P_tmpdir "/"); | ||
| 205 | strcat(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path, service->name); | ||
| 206 | }; | ||
| 207 | } else { | ||
| 208 | char *c; | ||
| 209 | if (!(c = tmpnam(NULL))) | ||
| 210 | RETURN_ERROR(GAIH_OKIFUNSPEC | -EAI_SYSTEM); | ||
| 211 | |||
| 212 | strncpy((((struct sockaddr_un *)(*pai)->ai_addr)->sun_path), c, sizeof(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path) - 1); | ||
| 213 | c[sizeof(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path) - 1] = 0; | ||
| 214 | }; | ||
| 215 | if (req->ai_flags & AI_CANONNAME) { | ||
| 216 | strncpy((*pai)->ai_canonname = (char *)(*pai) + sizeof(struct addrinfo) + sizeof(struct sockaddr_un), utsname.nodename, sizeof(utsname.nodename) - 1); | ||
| 217 | (*pai)->ai_canonname[sizeof(utsname.nodename) - 1] = 0; | ||
| 218 | } else | ||
| 219 | (*pai)->ai_canonname = NULL; | ||
| 220 | |||
| 221 | rval = 0; | ||
| 222 | 234 | ||
| 223 | ret: | 235 | s = getservbyname(servicename, tp->name); |
| 224 | return rval; | 236 | if (!s) |
| 225 | }; | 237 | return (GAIH_OKIFUNSPEC | -EAI_SERVICE); |
| 226 | 238 | ||
| 227 | static struct gaih_typeproto gaih_inet_typeproto[] = { | 239 | if (!(*st = malloc(sizeof(struct gaih_servtuple)))) |
| 228 | { 0, 0, NULL }, | 240 | return (-EAI_MEMORY); |
| 229 | { SOCK_STREAM, IPPROTO_TCP, "tcp" }, | ||
| 230 | { SOCK_DGRAM, IPPROTO_UDP, "udp" }, | ||
| 231 | { 0, 0, NULL } | ||
| 232 | }; | ||
| 233 | 241 | ||
| 234 | static int gaih_inet_serv(char *servicename, struct gaih_typeproto *tp, struct gaih_servtuple **st) | 242 | (*st)->next = NULL; |
| 243 | (*st)->socktype = tp->socktype; | ||
| 244 | (*st)->protocol = tp->protocol; | ||
| 245 | (*st)->port = s->s_port; | ||
| 246 | return (0); | ||
| 247 | } | ||
| 248 | |||
| 249 | static int | ||
| 250 | gaih_inet(const char *name, const struct gaih_service *service, | ||
| 251 | const struct addrinfo*req, struct addrinfo **pai) | ||
| 235 | { | 252 | { |
| 236 | int rval; | 253 | struct gaih_typeproto *tp = gaih_inet_typeproto; |
| 237 | struct servent *s; | 254 | struct gaih_servtuple *st = &nullserv; |
| 255 | struct gaih_addrtuple *at = NULL; | ||
| 256 | char *prevcname = NULL; | ||
| 257 | struct gaih_servtuple *st2; | ||
| 258 | struct gaih_addrtuple *at2 = at; | ||
| 259 | struct addrinfo *ai = NULL; | ||
| 260 | int canonlen, addrlen, rval = 0; | ||
| 261 | |||
| 262 | if (req->ai_protocol || req->ai_socktype) { | ||
| 263 | for (tp++; tp->name && | ||
| 264 | ((req->ai_socktype != tp->socktype) || !req->ai_socktype) && | ||
| 265 | ((req->ai_protocol != tp->protocol) || !req->ai_protocol); tp++); | ||
| 266 | if (!tp->name) { | ||
| 267 | rval = GAIH_OKIFUNSPEC | -EAI_SERVICE; | ||
| 268 | if (req->ai_socktype) | ||
| 269 | rval = GAIH_OKIFUNSPEC | -EAI_SOCKTYPE; | ||
| 270 | goto ret; | ||
| 271 | } | ||
| 272 | } | ||
| 273 | if (service && (service->num < 0)) { | ||
| 274 | if (tp->name) { | ||
| 275 | rval = gaih_inet_serv(service->name, tp, &st); | ||
| 276 | if (rval) | ||
| 277 | goto ret; | ||
| 278 | } else { | ||
| 279 | struct gaih_servtuple **pst = &st; | ||
| 280 | for (tp++; tp->name; tp++) { | ||
| 281 | rval = gaih_inet_serv(service->name, tp, pst); | ||
| 282 | if (rval) { | ||
| 283 | if (rval & GAIH_OKIFUNSPEC) | ||
| 284 | continue; | ||
| 285 | goto ret; | ||
| 286 | } | ||
| 287 | pst = &((*pst)->next); | ||
| 288 | } | ||
| 289 | if (st == &nullserv) { | ||
| 290 | rval = GAIH_OKIFUNSPEC | -EAI_SERVICE; | ||
| 291 | goto ret; | ||
| 292 | } | ||
| 293 | } | ||
| 294 | } else { | ||
| 295 | if (!(st = malloc(sizeof(struct gaih_servtuple)))) { | ||
| 296 | rval = -EAI_MEMORY; | ||
| 297 | goto ret; | ||
| 298 | } | ||
| 299 | |||
| 300 | st->next = NULL; | ||
| 301 | st->socktype = tp->socktype; | ||
| 302 | st->protocol = tp->protocol; | ||
| 303 | if (service) | ||
| 304 | st->port = htons(service->num); | ||
| 305 | else | ||
| 306 | st->port = 0; | ||
| 307 | } | ||
| 238 | 308 | ||
| 239 | if (!(s = getservbyname(servicename, tp->name))) | 309 | if (!name) { |
| 240 | RETURN_ERROR(GAIH_OKIFUNSPEC | -EAI_SERVICE); | 310 | if (!(at = malloc(sizeof(struct gaih_addrtuple)))) { |
| 311 | rval = -EAI_MEMORY; | ||
| 312 | goto ret; | ||
| 313 | } | ||
| 241 | 314 | ||
| 242 | if (!(*st = malloc(sizeof(struct gaih_servtuple)))) | 315 | memset(at, 0, sizeof(struct gaih_addrtuple)); |
| 243 | RETURN_ERROR(-EAI_MEMORY); | ||
| 244 | 316 | ||
| 245 | (*st)->next = NULL; | 317 | if (req->ai_family) |
| 246 | (*st)->socktype = tp->socktype; | 318 | at->family = req->ai_family; |
| 247 | (*st)->protocol = tp->protocol; | 319 | else { |
| 248 | (*st)->port = s->s_port; | 320 | if (!(at->next = malloc(sizeof(struct gaih_addrtuple)))) { |
| 321 | rval = -EAI_MEMORY; | ||
| 322 | goto ret; | ||
| 323 | } | ||
| 249 | 324 | ||
| 250 | rval = 0; | 325 | at->family = AF_INET6; |
| 251 | 326 | ||
| 252 | ret: | 327 | memset(at->next, 0, sizeof(struct gaih_addrtuple)); |
| 253 | return rval; | 328 | at->next->family = AF_INET; |
| 254 | } | 329 | } |
| 255 | 330 | ||
| 256 | static int gaih_inet(const char *name, const struct gaih_service *service, | 331 | goto build; |
| 257 | const struct addrinfo *req, struct addrinfo **pai) | 332 | } |
| 258 | { | 333 | |
| 259 | int rval; | 334 | if (!req->ai_family || (req->ai_family == AF_INET)) { |
| 260 | struct hostent *h = NULL; | 335 | struct in_addr in_addr; |
| 261 | struct gaih_typeproto *tp = gaih_inet_typeproto; | 336 | if (inet_pton(AF_INET, name, &in_addr) > 0) { |
| 262 | struct gaih_servtuple *st = &nullserv; | 337 | if (!(at = malloc(sizeof(struct gaih_addrtuple)))) { |
| 263 | struct gaih_addrtuple *at = NULL; | 338 | rval = -EAI_MEMORY; |
| 264 | int i; | 339 | goto ret; |
| 265 | 340 | } | |
| 266 | if (req->ai_protocol || req->ai_socktype) { | 341 | |
| 267 | for (tp++; tp->name && | 342 | memset(at, 0, sizeof(struct gaih_addrtuple)); |
| 268 | ((req->ai_socktype != tp->socktype) || !req->ai_socktype) && | 343 | |
| 269 | ((req->ai_protocol != tp->protocol) || !req->ai_protocol); tp++); | 344 | at->family = AF_INET; |
| 270 | if (!tp->name) | 345 | memcpy(at->addr, &in_addr, sizeof(struct in_addr)); |
| 271 | if (req->ai_socktype) | 346 | goto build; |
| 272 | RETURN_ERROR(GAIH_OKIFUNSPEC | -EAI_SOCKTYPE); | 347 | } |
| 273 | else | 348 | } |
| 274 | RETURN_ERROR(GAIH_OKIFUNSPEC | -EAI_SERVICE); | 349 | |
| 275 | } | 350 | if (!req->ai_family || (req->ai_family == AF_INET6)) { |
| 276 | 351 | struct in6_addr in6_addr; | |
| 277 | if (service && (service->num < 0)) { | 352 | if (inet_pton(AF_INET6, name, &in6_addr) > 0) { |
| 278 | if (tp->name) { | 353 | if (!(at = malloc(sizeof(struct gaih_addrtuple)))) { |
| 279 | if (rval = gaih_inet_serv(service->name, tp, &st)) | 354 | rval = -EAI_MEMORY; |
| 280 | goto ret; | 355 | goto ret; |
| 281 | } else { | 356 | } |
| 282 | struct gaih_servtuple **pst = &st; | 357 | |
| 283 | for (tp++; tp->name; tp++) { | 358 | memset(at, 0, sizeof(struct gaih_addrtuple)); |
| 284 | if (rval = gaih_inet_serv(service->name, tp, pst)) { | 359 | |
| 285 | if (rval & GAIH_OKIFUNSPEC) | 360 | at->family = AF_INET6; |
| 286 | continue; | 361 | memcpy(at->addr, &in6_addr, sizeof(struct in6_addr)); |
| 287 | goto ret; | 362 | goto build; |
| 288 | }; | 363 | } |
| 289 | pst = &((*pst)->next); | 364 | } |
| 290 | }; | 365 | |
| 291 | if (st == &nullserv) | 366 | if (!(req->ai_flags & AI_NUMERICHOST)) { |
| 292 | RETURN_ERROR(GAIH_OKIFUNSPEC | -EAI_SERVICE); | 367 | if (!req->ai_family || (req->ai_family == AF_INET6)) |
| 293 | }; | 368 | if ((rval = netdb_lookup_addr(name, AF_INET6, req, &at)) < 0) |
| 294 | } else { | 369 | goto ret; |
| 295 | if (!(st = malloc(sizeof(struct gaih_servtuple)))) | 370 | if (!req->ai_family || (req->ai_family == AF_INET)) |
| 296 | RETURN_ERROR(-EAI_MEMORY); | 371 | if ((rval = netdb_lookup_addr(name, AF_INET, req, &at)) < 0) |
| 297 | 372 | goto ret; | |
| 298 | st->next = NULL; | 373 | |
| 299 | st->socktype = tp->socktype; | 374 | if (!rval) |
| 300 | st->protocol = tp->protocol; | 375 | goto build; |
| 301 | if (service) | 376 | } |
| 302 | st->port = htons(service->num); | 377 | |
| 303 | else | 378 | if (!at) { |
| 304 | st->port = 0; | 379 | rval = GAIH_OKIFUNSPEC | -EAI_NONAME; |
| 305 | }; | 380 | goto ret; |
| 306 | 381 | } | |
| 307 | if (!name) { | ||
| 308 | if (!(at = malloc(sizeof(struct gaih_addrtuple)))) | ||
| 309 | RETURN_ERROR(-EAI_MEMORY); | ||
| 310 | |||
| 311 | memset(at, 0, sizeof(struct gaih_addrtuple)); | ||
| 312 | |||
| 313 | if (req->ai_family) | ||
| 314 | at->family = req->ai_family; | ||
| 315 | else { | ||
| 316 | if (!(at->next = malloc(sizeof(struct gaih_addrtuple)))) | ||
| 317 | RETURN_ERROR(-EAI_MEMORY); | ||
| 318 | |||
| 319 | at->family = AF_INET6; | ||
| 320 | |||
| 321 | memset(at->next, 0, sizeof(struct gaih_addrtuple)); | ||
| 322 | at->next->family = AF_INET; | ||
| 323 | }; | ||
| 324 | |||
| 325 | goto build; | ||
| 326 | }; | ||
| 327 | |||
| 328 | if (!req->ai_family || (req->ai_family == AF_INET)) { | ||
| 329 | struct in_addr in_addr; | ||
| 330 | if (inet_pton(AF_INET, name, &in_addr) > 0) { | ||
| 331 | if (!(at = malloc(sizeof(struct gaih_addrtuple)))) | ||
| 332 | RETURN_ERROR(-EAI_MEMORY); | ||
| 333 | |||
| 334 | memset(at, 0, sizeof(struct gaih_addrtuple)); | ||
| 335 | |||
| 336 | at->family = AF_INET; | ||
| 337 | memcpy(at->addr, &in_addr, sizeof(struct in_addr)); | ||
| 338 | goto build; | ||
| 339 | }; | ||
| 340 | }; | ||
| 341 | |||
| 342 | if (!req->ai_family || (req->ai_family == AF_INET6)) { | ||
| 343 | struct in6_addr in6_addr; | ||
| 344 | if (inet_pton(AF_INET6, name, &in6_addr) > 0) { | ||
| 345 | if (!(at = malloc(sizeof(struct gaih_addrtuple)))) | ||
| 346 | RETURN_ERROR(-EAI_MEMORY); | ||
| 347 | |||
| 348 | memset(at, 0, sizeof(struct gaih_addrtuple)); | ||
| 349 | |||
| 350 | at->family = AF_INET6; | ||
| 351 | memcpy(at->addr, &in6_addr, sizeof(struct in6_addr)); | ||
| 352 | goto build; | ||
| 353 | }; | ||
| 354 | }; | ||
| 355 | |||
| 356 | if (!(req->ai_flags & AI_NUMERICHOST)) { | ||
| 357 | if (!req->ai_family || (req->ai_family == AF_INET6)) | ||
| 358 | if ((rval = netdb_lookup_addr(name, AF_INET6, req, &at)) < 0) | ||
| 359 | goto ret; | ||
| 360 | if (!req->ai_family || (req->ai_family == AF_INET)) | ||
| 361 | if ((rval = netdb_lookup_addr(name, AF_INET, req, &at)) < 0) | ||
| 362 | goto ret; | ||
| 363 | |||
| 364 | if (!rval) | ||
| 365 | goto build; | ||
| 366 | }; | ||
| 367 | |||
| 368 | if (!at) | ||
| 369 | RETURN_ERROR(GAIH_OKIFUNSPEC | -EAI_NONAME); | ||
| 370 | 382 | ||
| 371 | build: | 383 | build: |
| 372 | { | 384 | while (at2) { |
| 373 | char *prevcname = NULL; | 385 | if (req->ai_flags & AI_CANONNAME) { |
| 374 | struct gaih_servtuple *st2; | 386 | if (at2->cname) |
| 375 | struct gaih_addrtuple *at2 = at; | 387 | canonlen = strlen(at2->cname) + 1; |
| 376 | int j; | 388 | else |
| 377 | 389 | if (name) | |
| 378 | while(at2) { | 390 | canonlen = strlen(name) + 1; |
| 379 | if (req->ai_flags & AI_CANONNAME) { | 391 | else |
| 380 | if (at2->cname) | 392 | canonlen = 2; |
| 381 | j = strlen(at2->cname) + 1; | 393 | } else |
| 382 | else | 394 | canonlen = 0; |
| 383 | if (name) | 395 | |
| 384 | j = strlen(name) + 1; | 396 | if (at2->family == AF_INET6) |
| 385 | else | 397 | addrlen = sizeof(struct sockaddr_in6); |
| 386 | j = 2; | 398 | else |
| 387 | } else | 399 | addrlen = sizeof(struct sockaddr_in); |
| 388 | j = 0; | 400 | |
| 389 | 401 | st2 = st; | |
| 390 | if (at2->family == AF_INET6) | 402 | while (st2) { |
| 391 | i = sizeof(struct sockaddr_in6); | 403 | if (!(ai = malloc(sizeof(struct addrinfo) + |
| 392 | else | 404 | addrlen + canonlen))) { |
| 393 | i = sizeof(struct sockaddr_in); | 405 | rval = -EAI_MEMORY; |
| 394 | 406 | goto ret; | |
| 395 | st2 = st; | 407 | } |
| 396 | while(st2) { | 408 | |
| 397 | if (!(*pai = malloc(sizeof(struct addrinfo) + i + j))) | 409 | *pai = ai; |
| 398 | RETURN_ERROR(-EAI_MEMORY); | 410 | memset(ai, 0, sizeof(struct addrinfo) + addrlen + canonlen); |
| 399 | 411 | ||
| 400 | memset(*pai, 0, sizeof(struct addrinfo) + i + j); | 412 | ai->ai_flags = req->ai_flags; |
| 401 | 413 | ai->ai_family = at2->family; | |
| 402 | (*pai)->ai_flags = req->ai_flags; | 414 | ai->ai_socktype = st2->socktype; |
| 403 | (*pai)->ai_family = at2->family; | 415 | ai->ai_protocol = st2->protocol; |
| 404 | (*pai)->ai_socktype = st2->socktype; | 416 | ai->ai_addrlen = addrlen; |
| 405 | (*pai)->ai_protocol = st2->protocol; | 417 | ai->ai_addr = (void *)ai + sizeof(struct addrinfo); |
| 406 | (*pai)->ai_addrlen = i; | 418 | ai->ai_addr->sa_len = addrlen; |
| 407 | (*pai)->ai_addr = (void *)(*pai) + sizeof(struct addrinfo); | 419 | ai->ai_addr->sa_family = at2->family; |
| 408 | ((struct sockaddr_in *)(*pai)->ai_addr)->sin_len = i; | 420 | |
| 409 | ((struct sockaddr_in *)(*pai)->ai_addr)->sin_family = at2->family; | 421 | switch (at2->family) { |
| 410 | ((struct sockaddr_in *)(*pai)->ai_addr)->sin_port = st2->port; | 422 | case AF_INET6: |
| 411 | 423 | { | |
| 412 | if (at2->family == AF_INET6) | 424 | struct sockaddr_in6 *sin6 = (void *)ai->ai_addr; |
| 413 | memcpy(&((struct sockaddr_in6 *)(*pai)->ai_addr)->sin6_addr, at2->addr, sizeof(struct in6_addr)); | 425 | |
| 414 | else | 426 | memcpy(&sin6->sin6_addr, at2->addr, |
| 415 | memcpy(&((struct sockaddr_in *)(*pai)->ai_addr)->sin_addr, at2->addr, sizeof(struct in_addr)); | 427 | sizeof(sin6->sin6_addr)); |
| 416 | 428 | sin6->sin6_port = st2->port; | |
| 417 | if (j) { | 429 | break; |
| 418 | (*pai)->ai_canonname = (void *)(*pai) + sizeof(struct addrinfo) + i; | 430 | } |
| 419 | if (at2->cname) { | 431 | default: |
| 420 | strcpy((*pai)->ai_canonname, at2->cname); | 432 | { |
| 421 | if (prevcname != at2->cname) { | 433 | struct sockaddr_in *sin = (void *)ai->ai_addr; |
| 422 | if (prevcname) | 434 | |
| 423 | free(prevcname); | 435 | memcpy(&sin->sin_addr, at2->addr, |
| 424 | prevcname = at2->cname; | 436 | sizeof(sin->sin_addr)); |
| 425 | }; | 437 | sin->sin_port = st2->port; |
| 426 | } else | 438 | break; |
| 427 | strcpy((*pai)->ai_canonname, name ? name : "*"); | 439 | } |
| 428 | }; | 440 | } |
| 429 | 441 | ||
| 430 | pai = &((*pai)->ai_next); | 442 | if (canonlen) { |
| 431 | 443 | ai->ai_canonname = (void *) ai->ai_addr + addrlen; | |
| 432 | st2 = st2->next; | 444 | |
| 433 | }; | 445 | if (at2->cname) { |
| 434 | at2 = at2->next; | 446 | strcpy(ai->ai_canonname, at2->cname); |
| 435 | }; | 447 | if (prevcname != at2->cname) { |
| 436 | }; | 448 | if (prevcname) |
| 437 | 449 | free(prevcname); | |
| 438 | rval = 0; | 450 | prevcname = at2->cname; |
| 451 | } | ||
| 452 | } else | ||
| 453 | strcpy(ai->ai_canonname, name ? name : "*"); | ||
| 454 | } | ||
| 455 | pai = &(ai->ai_next); | ||
| 456 | st2 = st2->next; | ||
| 457 | } | ||
| 458 | at2 = at2->next; | ||
| 459 | } | ||
| 460 | rval = 0; | ||
| 439 | 461 | ||
| 440 | ret: | 462 | ret: |
| 441 | if (st != &nullserv) { | 463 | if (st != &nullserv) { |
| 442 | struct gaih_servtuple *st2 = st; | 464 | struct gaih_servtuple *st2 = st; |
| 443 | while(st) { | 465 | while (st) { |
| 444 | st2 = st->next; | 466 | st2 = st->next; |
| 445 | free(st); | 467 | free(st); |
| 446 | st = st2; | 468 | st = st2; |
| 447 | } | 469 | } |
| 448 | } | 470 | } |
| 449 | if (at) { | 471 | if (at) { |
| 450 | struct gaih_addrtuple *at2 = at; | 472 | struct gaih_addrtuple *at2 = at; |
| 451 | while(at) { | 473 | while (at) { |
| 452 | at2 = at->next; | 474 | at2 = at->next; |
| 453 | free(at); | 475 | free(at); |
| 454 | at = at2; | 476 | at = at2; |
| 455 | } | 477 | } |
| 456 | } | 478 | } |
| 457 | 479 | return rval; | |
| 458 | return rval; | ||
| 459 | } | 480 | } |
| 460 | 481 | ||
| 461 | struct gaih { | 482 | static struct gaih { |
| 462 | int family; | 483 | int family; |
| 463 | char *name; | 484 | char *name; |
| 464 | int (*gaih)(const char *name, const struct gaih_service *service, | 485 | int (*gaih) __P((const char *name, |
| 465 | const struct addrinfo *req, struct addrinfo **pai); | 486 | const struct gaih_service *service, |
| 466 | }; | 487 | const struct addrinfo *req, struct addrinfo **pai)); |
| 467 | 488 | } gaih[] = { | |
| 468 | static struct gaih gaih[] = { | 489 | { PF_INET6, "inet6", gaih_inet }, |
| 469 | { PF_INET6, "inet6", gaih_inet }, | 490 | { PF_INET, "inet", gaih_inet }, |
| 470 | { PF_INET, "inet", gaih_inet }, | 491 | { PF_LOCAL, "local", gaih_local }, |
| 471 | { PF_LOCAL, "local", gaih_local }, | 492 | { -1, NULL, NULL} |
| 472 | { -1, NULL, NULL } | ||
| 473 | }; | 493 | }; |
| 474 | 494 | ||
| 475 | int getaddrinfo(const char *name, const char *service, | 495 | int |
| 476 | const struct addrinfo *req, struct addrinfo **pai) | 496 | getaddrinfo(const char *name, const char *service, |
| 497 | const struct addrinfo *req, struct addrinfo **pai) | ||
| 477 | { | 498 | { |
| 478 | int rval = EAI_SYSTEM; /* XXX */ | 499 | int rval = EAI_SYSTEM; /* XXX */ |
| 479 | int i, j = 0; | 500 | int j = 0; |
| 480 | struct addrinfo *p = NULL, **end; | 501 | struct addrinfo *p = NULL, **end; |
| 481 | struct gaih *g = gaih, *pg = NULL; | 502 | struct gaih *g = gaih, *pg = NULL; |
| 482 | struct gaih_service gaih_service, *pservice; | 503 | struct gaih_service gaih_service, *pservice; |
| 483 | |||
| 484 | if (name && (name[0] == '*') && !name[1]) | ||
| 485 | name = NULL; | ||
| 486 | |||
| 487 | if (service && (service[0] == '*') && !service[1]) | ||
| 488 | service = NULL; | ||
| 489 | |||
| 490 | if (!req) | ||
| 491 | req = &nullreq; | ||
| 492 | |||
| 493 | if (req->ai_flags & ~(AI_CANONNAME | AI_PASSIVE | AI_NUMERICHOST | AI_EXT)) | ||
| 494 | RETURN_ERROR(EAI_BADFLAGS); | ||
| 495 | |||
| 496 | if (service && *service) { | ||
| 497 | char *c; | ||
| 498 | gaih_service.num = strtoul(gaih_service.name = (void *)service, &c, 10); | ||
| 499 | if (*c) { | ||
| 500 | gaih_service.num = -1; | ||
| 501 | } | ||
| 502 | |||
| 503 | pservice = &gaih_service; | ||
| 504 | } else | ||
| 505 | pservice = NULL; | ||
| 506 | |||
| 507 | if (pai) | ||
| 508 | end = &p; | ||
| 509 | else | ||
| 510 | end = NULL; | ||
| 511 | |||
| 512 | while(g->gaih) { | ||
| 513 | if ((req->ai_family == g->family) || !req->ai_family) { | ||
| 514 | j++; | ||
| 515 | if (!((pg && (pg->gaih == g->gaih)))) { | ||
| 516 | pg = g; | ||
| 517 | if (rval = g->gaih(name, pservice, req, end)) { | ||
| 518 | if (!req->ai_family && (rval & GAIH_OKIFUNSPEC)) | ||
| 519 | continue; | ||
| 520 | |||
| 521 | if (p) | ||
| 522 | freeaddrinfo(p); | ||
| 523 | |||
| 524 | rval = -(rval & GAIH_EAI); | ||
| 525 | goto ret; | ||
| 526 | } | ||
| 527 | if (end) | ||
| 528 | while(*end) end = &((*end)->ai_next); | ||
| 529 | } | ||
| 530 | } | ||
| 531 | g++; | ||
| 532 | } | ||
| 533 | 504 | ||
| 534 | if (!j) | 505 | if (name && (name[0] == '*') && !name[1]) |
| 535 | RETURN_ERROR(EAI_FAMILY); | 506 | name = NULL; |
| 536 | 507 | ||
| 537 | if (p) { | 508 | if (service && service[0] == '*' && service[1] == '\0') |
| 538 | *pai = p; | 509 | service = NULL; |
| 539 | rval = 0; | ||
| 540 | goto ret; | ||
| 541 | } | ||
| 542 | 510 | ||
| 543 | if (!pai && !rval) { | 511 | if (!req) |
| 544 | rval = 0; | 512 | req = &nullreq; |
| 545 | goto ret; | ||
| 546 | }; | ||
| 547 | 513 | ||
| 548 | RETURN_ERROR(EAI_NONAME); | 514 | if (req->ai_flags & ~(AI_CANONNAME | AI_PASSIVE | AI_NUMERICHOST | AI_EXT)) |
| 515 | return (EAI_BADFLAGS); | ||
| 549 | 516 | ||
| 550 | ret: | 517 | if (service && *service) { |
| 551 | return rval; | 518 | char *c; |
| 552 | } | ||
| 553 | 519 | ||
| 520 | gaih_service.num = strtoul(service, &c, 10); | ||
| 521 | if (*c) | ||
| 522 | gaih_service.num = -1; | ||
| 523 | gaih_service.name = (void *)service; | ||
| 524 | pservice = &gaih_service; | ||
| 525 | } else | ||
| 526 | pservice = NULL; | ||
| 527 | |||
| 528 | if (pai) | ||
| 529 | end = &p; | ||
| 530 | else | ||
| 531 | end = NULL; | ||
| 532 | |||
| 533 | while (g->gaih) { | ||
| 534 | if ((req->ai_family == g->family) || !req->ai_family) { | ||
| 535 | j++; | ||
| 536 | if (!((pg && (pg->gaih == g->gaih)))) { | ||
| 537 | pg = g; | ||
| 538 | rval = g->gaih(name, pservice, req, end); | ||
| 539 | if (rval) { | ||
| 540 | if (!req->ai_family && (rval & GAIH_OKIFUNSPEC)) | ||
| 541 | continue; | ||
| 542 | |||
| 543 | if (p) | ||
| 544 | freeaddrinfo(p); | ||
| 545 | |||
| 546 | return -(rval & GAIH_EAI); | ||
| 547 | } | ||
| 548 | if (end) | ||
| 549 | while (*end) | ||
| 550 | end = &((*end)->ai_next); | ||
| 551 | } | ||
| 552 | } | ||
| 553 | g++; | ||
| 554 | } | ||
| 555 | |||
| 556 | if (!j) | ||
| 557 | return (EAI_FAMILY); | ||
| 558 | |||
| 559 | if (p) { | ||
| 560 | *pai = p; | ||
| 561 | return (0); | ||
| 562 | } | ||
| 563 | if (!pai && !rval) | ||
| 564 | return (0); | ||
| 565 | return EAI_NONAME; | ||
| 566 | } | ||
diff --git a/src/lib/libc/net/getnameinfo.c b/src/lib/libc/net/getnameinfo.c index 1ae197c15a..62c4b9d928 100644 --- a/src/lib/libc/net/getnameinfo.c +++ b/src/lib/libc/net/getnameinfo.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * %%% copyright-cmetz-96-bsd | 2 | * %%% copyright-cmetz-96-bsd |
| 3 | * Copyright (c) 1996-1999, Craig Metz, All rights reserved. | 3 | * Copyright (c) 1996-1999, Craig Metz, All rights reserved. |
| 4 | * | 4 | * |
| 5 | * Redistribution and use in source and binary forms, with or without | 5 | * Redistribution and use in source and binary forms, with or without |
| 6 | * modification, are permitted provided that the following conditions | 6 | * modification, are permitted provided that the following conditions |
| 7 | * are met: | 7 | * are met: |
| @@ -17,7 +17,7 @@ | |||
| 17 | * 4. Neither the name of the author nor the names of contributors | 17 | * 4. Neither the name of the author nor the names of contributors |
| 18 | * may be used to endorse or promote products derived from this software | 18 | * may be used to endorse or promote products derived from this software |
| 19 | * without specific prior written permission. | 19 | * without specific prior written permission. |
| 20 | * | 20 | * |
| 21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
| 22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| @@ -36,197 +36,229 @@ | |||
| 36 | 36 | ||
| 37 | #include <sys/types.h> | 37 | #include <sys/types.h> |
| 38 | #include <sys/socket.h> | 38 | #include <sys/socket.h> |
| 39 | |||
| 40 | #include <netinet/in.h> | 39 | #include <netinet/in.h> |
| 41 | #include <sys/un.h> | 40 | #include <sys/un.h> |
| 42 | #include <sys/utsname.h> | 41 | #include <sys/utsname.h> |
| 43 | #include <netdb.h> | 42 | #include <netdb.h> |
| 43 | #include <arpa/inet.h> | ||
| 44 | #include <errno.h> | 44 | #include <errno.h> |
| 45 | #include <string.h> | 45 | #include <string.h> |
| 46 | #include <resolv.h> | 46 | #include <resolv.h> |
| 47 | 47 | ||
| 48 | #ifndef AF_LOCAL | 48 | #ifndef min |
| 49 | #define AF_LOCAL AF_UNIX | ||
| 50 | #endif /* AF_LOCAL */ | ||
| 51 | |||
| 52 | #ifndef min | ||
| 53 | #define min(x,y) (((x) > (y)) ? (y) : (x)) | 49 | #define min(x,y) (((x) > (y)) ? (y) : (x)) |
| 54 | #endif /* min */ | 50 | #endif /* min */ |
| 55 | 51 | ||
| 56 | #define RETURN_ERROR(x) do { \ | 52 | static int |
| 57 | rval = (x); \ | 53 | netdb_lookup_name(int family, void *addr, int addrlen, char *name, |
| 58 | goto ret; \ | 54 | int namelen, int flags) |
| 59 | } while(0) | ||
| 60 | |||
| 61 | static int netdb_lookup_name(int family, void *addr, int addrlen, char *name, | ||
| 62 | int namelen, int flags) | ||
| 63 | { | 55 | { |
| 64 | struct hostent *hostent; | 56 | struct hostent *hostent; |
| 65 | char *c, *c2; | 57 | char *c, *c2; |
| 66 | int rval, i; | 58 | int i; |
| 67 | |||
| 68 | if (!(hostent = gethostbyaddr(addr, addrlen, family))) { | ||
| 69 | switch(h_errno) { | ||
| 70 | case NETDB_INTERNAL: | ||
| 71 | RETURN_ERROR(EAI_SYSTEM); | ||
| 72 | case HOST_NOT_FOUND: | ||
| 73 | RETURN_ERROR(1); | ||
| 74 | case TRY_AGAIN: | ||
| 75 | RETURN_ERROR(EAI_AGAIN); | ||
| 76 | case NO_RECOVERY: | ||
| 77 | RETURN_ERROR(EAI_FAIL); | ||
| 78 | case NO_DATA: | ||
| 79 | RETURN_ERROR(1); | ||
| 80 | default: | ||
| 81 | RETURN_ERROR(EAI_FAIL); | ||
| 82 | }; | ||
| 83 | }; | ||
| 84 | |||
| 85 | endhostent(); | ||
| 86 | |||
| 87 | c = hostent->h_name; | ||
| 88 | if ((flags & NI_NOFQDN) && (_res.options & RES_INIT) && _res.defdname[0] && | ||
| 89 | (c2 = strstr(c + 1, _res.defdname)) && (*(--c2) == '.')) { | ||
| 90 | *c2 = 0; | ||
| 91 | i = min(c2 - c, namelen) - 1; | ||
| 92 | strncpy(name, c, i); | ||
| 93 | } else | ||
| 94 | strncpy(name, c, namelen - 1); | ||
| 95 | |||
| 96 | rval = 0; | ||
| 97 | 59 | ||
| 98 | ret: | 60 | if (!(hostent = gethostbyaddr(addr, addrlen, family))) { |
| 99 | return rval; | 61 | switch (h_errno) { |
| 62 | case NETDB_INTERNAL: | ||
| 63 | return(EAI_SYSTEM); | ||
| 64 | case HOST_NOT_FOUND: | ||
| 65 | return(1); | ||
| 66 | case TRY_AGAIN: | ||
| 67 | return(EAI_AGAIN); | ||
| 68 | case NO_RECOVERY: | ||
| 69 | return(EAI_FAIL); | ||
| 70 | case NO_DATA: | ||
| 71 | return(1); | ||
| 72 | default: | ||
| 73 | return(EAI_FAIL); | ||
| 74 | } | ||
| 75 | } | ||
| 76 | |||
| 77 | endhostent(); | ||
| 78 | |||
| 79 | c = hostent->h_name; | ||
| 80 | if ((flags & NI_NOFQDN) && (_res.options & RES_INIT) && _res.defdname[0] && | ||
| 81 | (c2 = strstr(c + 1, _res.defdname)) && (*(--c2) == '.')) { | ||
| 82 | *c2 = 0; | ||
| 83 | i = min(c2 - c, namelen); | ||
| 84 | strlcpy(name, c, i); | ||
| 85 | } else | ||
| 86 | strlcpy(name, c, namelen); | ||
| 87 | return 0; | ||
| 100 | } | 88 | } |
| 101 | 89 | ||
| 102 | int getnameinfo(const struct sockaddr *sa, size_t addrlen, char *host, size_t hostlen, char *serv, size_t servlen, int flags) | 90 | int |
| 91 | getnameinfo(const struct sockaddr *sa, size_t addrlen, char *host, | ||
| 92 | size_t hostlen, char *serv, size_t servlen, int flags) | ||
| 103 | { | 93 | { |
| 104 | int rval; | 94 | int rval; |
| 105 | int serrno = errno; | 95 | int saved_errno; |
| 106 | |||
| 107 | if (!sa || (addrlen != SA_LEN(sa))) | ||
| 108 | RETURN_ERROR(EAI_FAIL); | ||
| 109 | |||
| 110 | if (host && (hostlen > 0)) | ||
| 111 | switch(sa->sa_family) { | ||
| 112 | case AF_INET6: | ||
| 113 | if (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)sa)->sin6_addr)) { | ||
| 114 | if (flags & NI_NUMERICHOST) | ||
| 115 | goto inet6_noname; | ||
| 116 | else | ||
| 117 | strncpy(host, "*", hostlen - 1); | ||
| 118 | break; | ||
| 119 | }; | ||
| 120 | |||
| 121 | if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)sa)->sin6_addr)) { | ||
| 122 | struct sockaddr_in sin; | ||
| 123 | memset(&sin, 0, sizeof(struct sockaddr_in)); | ||
| 124 | sin.sin_len = sizeof(struct sockaddr_in); | ||
| 125 | sin.sin_family = AF_INET; | ||
| 126 | sin.sin_port = ((struct sockaddr_in6 *)sa)->sin6_port; | ||
| 127 | sin.sin_addr.s_addr = ((u_int32_t *)&((struct sockaddr_in6 *)sa)->sin6_addr)[3]; | ||
| 128 | if (!(rval = getnameinfo((struct sockaddr *)&sin, sizeof(struct sockaddr_in), host, hostlen, serv, servlen, flags | NI_NAMEREQD))) | ||
| 129 | goto ret; | ||
| 130 | if (rval != EAI_NONAME) | ||
| 131 | goto ret; | ||
| 132 | goto inet6_noname; | ||
| 133 | }; | ||
| 134 | |||
| 135 | if (flags & NI_NUMERICHOST) | ||
| 136 | goto inet6_noname; | ||
| 137 | |||
| 138 | if ((rval = netdb_lookup_name(AF_INET6, | ||
| 139 | &((struct sockaddr_in6 *)sa)->sin6_addr, sizeof(struct in6_addr), | ||
| 140 | host, hostlen, flags)) < 0) | ||
| 141 | goto ret; | ||
| 142 | |||
| 143 | if (!rval) | ||
| 144 | break; | ||
| 145 | |||
| 146 | inet6_noname: | ||
| 147 | if (flags & NI_NAMEREQD) | ||
| 148 | RETURN_ERROR(EAI_NONAME); | ||
| 149 | |||
| 150 | if (!inet_ntop(AF_INET6, &((struct sockaddr_in6 *)sa)->sin6_addr, host, hostlen)) | ||
| 151 | RETURN_ERROR(EAI_NONAME); | ||
| 152 | |||
| 153 | break; | ||
| 154 | case AF_INET: | ||
| 155 | if (flags & NI_NUMERICHOST) | ||
| 156 | goto inet_noname; | ||
| 157 | |||
| 158 | if (!((struct sockaddr_in *)sa)->sin_addr.s_addr) { | ||
| 159 | strncpy(host, "*", hostlen - 1); | ||
| 160 | break; | ||
| 161 | }; | ||
| 162 | |||
| 163 | if ((rval = netdb_lookup_name(AF_INET, | ||
| 164 | &((struct sockaddr_in *)sa)->sin_addr, sizeof(struct in_addr), | ||
| 165 | host, hostlen, flags)) < 0) | ||
| 166 | goto ret; | ||
| 167 | |||
| 168 | if (!rval) | ||
| 169 | break; | ||
| 170 | inet_noname: | ||
| 171 | if (flags & NI_NAMEREQD) | ||
| 172 | RETURN_ERROR(EAI_NONAME); | ||
| 173 | |||
| 174 | if (!inet_ntop(AF_INET, &((struct sockaddr_in *)sa)->sin_addr, host, hostlen)) | ||
| 175 | RETURN_ERROR(EAI_NONAME); | ||
| 176 | |||
| 177 | break; | ||
| 178 | case AF_LOCAL: | ||
| 179 | if (!(flags & NI_NUMERICHOST)) { | ||
| 180 | struct utsname utsname; | ||
| 181 | |||
| 182 | if (!uname(&utsname)) { | ||
| 183 | strncpy(host, utsname.nodename, hostlen - 1); | ||
| 184 | break; | ||
| 185 | }; | ||
| 186 | }; | ||
| 187 | |||
| 188 | if (flags & NI_NAMEREQD) | ||
| 189 | RETURN_ERROR(EAI_NONAME); | ||
| 190 | |||
| 191 | strncpy(host, "localhost", hostlen - 1); | ||
| 192 | break; | ||
| 193 | default: | ||
| 194 | RETURN_ERROR(EAI_FAMILY); | ||
| 195 | }; | ||
| 196 | |||
| 197 | if (serv && (servlen > 0)) | ||
| 198 | switch(sa->sa_family) { | ||
| 199 | case AF_INET: | ||
| 200 | case AF_INET6: | ||
| 201 | if (!(flags & NI_NUMERICSERV)) { | ||
| 202 | struct servent *s; | ||
| 203 | if (s = getservbyport(((struct sockaddr_in *)sa)->sin_port, (flags & NI_DGRAM) ? "udp" : "tcp")) { | ||
| 204 | strncpy(serv, s->s_name, servlen - 1); | ||
| 205 | break; | ||
| 206 | }; | ||
| 207 | if (!((struct sockaddr_in *)sa)->sin_port) { | ||
| 208 | strncpy(serv, "*", servlen - 1); | ||
| 209 | break; | ||
| 210 | }; | ||
| 211 | }; | ||
| 212 | snprintf(serv, servlen - 1, "%d", ntohs(((struct sockaddr_in *)sa)->sin_port)); | ||
| 213 | break; | ||
| 214 | case AF_LOCAL: | ||
| 215 | strncpy(serv, ((struct sockaddr_un *)sa)->sun_path, servlen - 1); | ||
| 216 | break; | ||
| 217 | }; | ||
| 218 | |||
| 219 | if (host && (hostlen > 0)) | ||
| 220 | host[hostlen-1] = 0; | ||
| 221 | if (serv && (servlen > 0)) | ||
| 222 | serv[servlen-1] = 0; | ||
| 223 | rval = 0; | ||
| 224 | 96 | ||
| 225 | ret: | 97 | if (sa == NULL || addrlen != sa->sa_len) |
| 226 | if (rval == 1) | 98 | return EAI_FAIL; |
| 227 | rval = EAI_FAIL; | 99 | saved_errno = errno; |
| 100 | |||
| 101 | if (host && hostlen > 0) { | ||
| 102 | switch (sa->sa_family) { | ||
| 103 | case AF_INET6: | ||
| 104 | { | ||
| 105 | struct sockaddr_in6 *sin6 = (void *)sa; | ||
| 106 | |||
| 107 | if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { | ||
| 108 | if (flags & NI_NUMERICHOST) | ||
| 109 | goto inet6_noname; | ||
| 110 | strlcpy(host, "*", hostlen); | ||
| 111 | break; | ||
| 112 | } | ||
| 113 | |||
| 114 | if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { | ||
| 115 | struct sockaddr_in sin; | ||
| 116 | |||
| 117 | memset(&sin, 0, sizeof(struct sockaddr_in)); | ||
| 118 | sin.sin_len = sizeof(struct sockaddr_in); | ||
| 119 | sin.sin_family = AF_INET; | ||
| 120 | sin.sin_port = sin6->sin6_port; | ||
| 121 | sin.sin_addr.s_addr = | ||
| 122 | ((u_int32_t *)&sin6->sin6_addr)[3]; | ||
| 123 | if (!(rval = getnameinfo((struct sockaddr *)&sin, | ||
| 124 | sizeof(struct sockaddr_in), host, hostlen, | ||
| 125 | serv, servlen, flags | NI_NAMEREQD))) | ||
| 126 | goto ret; | ||
| 127 | if (rval != EAI_NONAME) | ||
| 128 | goto ret; | ||
| 129 | goto inet6_noname; | ||
| 130 | } | ||
| 131 | |||
| 132 | if (flags & NI_NUMERICHOST) | ||
| 133 | goto inet6_noname; | ||
| 134 | if ((rval = netdb_lookup_name(AF_INET6, | ||
| 135 | &sin6->sin6_addr, sizeof(struct in6_addr), | ||
| 136 | host, hostlen, flags)) < 0) | ||
| 137 | goto ret; | ||
| 228 | 138 | ||
| 229 | errno = serrno; | 139 | if (!rval) |
| 140 | break; | ||
| 141 | inet6_noname: | ||
| 142 | if (flags & NI_NAMEREQD) { | ||
| 143 | rval = EAI_NONAME; | ||
| 144 | goto ret; | ||
| 145 | } | ||
| 146 | if (!inet_ntop(AF_INET6, &sin6->sin6_addr, host, hostlen)) { | ||
| 147 | rval = EAI_NONAME; | ||
| 148 | goto ret; | ||
| 149 | } | ||
| 150 | break; | ||
| 151 | } | ||
| 152 | case AF_INET: | ||
| 153 | { | ||
| 154 | struct sockaddr_in *sin = (void *)sa; | ||
| 230 | 155 | ||
| 231 | return rval; | 156 | if (flags & NI_NUMERICHOST) |
| 232 | }; | 157 | goto inet_noname; |
| 158 | |||
| 159 | if (sin->sin_addr.s_addr == 0) { | ||
| 160 | strlcpy(host, "*", hostlen); | ||
| 161 | break; | ||
| 162 | } | ||
| 163 | |||
| 164 | if ((rval = netdb_lookup_name(AF_INET, | ||
| 165 | &sin->sin_addr, sizeof(struct in_addr), | ||
| 166 | host, hostlen, flags)) < 0) | ||
| 167 | goto ret; | ||
| 168 | |||
| 169 | if (!rval) | ||
| 170 | break; | ||
| 171 | inet_noname: | ||
| 172 | if (flags & NI_NAMEREQD) { | ||
| 173 | rval = EAI_NONAME; | ||
| 174 | goto ret; | ||
| 175 | } | ||
| 176 | if (!inet_ntop(AF_INET, &sin->sin_addr, host, hostlen)) { | ||
| 177 | rval = EAI_NONAME; | ||
| 178 | goto ret; | ||
| 179 | } | ||
| 180 | break; | ||
| 181 | } | ||
| 182 | case AF_LOCAL: | ||
| 183 | if (!(flags & NI_NUMERICHOST)) { | ||
| 184 | struct utsname utsname; | ||
| 185 | |||
| 186 | if (!uname(&utsname)) { | ||
| 187 | strlcpy(host, utsname.nodename, hostlen); | ||
| 188 | break; | ||
| 189 | } | ||
| 190 | } | ||
| 191 | |||
| 192 | if (flags & NI_NAMEREQD) { | ||
| 193 | rval = EAI_NONAME; | ||
| 194 | goto ret; | ||
| 195 | } | ||
| 196 | |||
| 197 | strlcpy(host, "localhost", hostlen); | ||
| 198 | break; | ||
| 199 | default: | ||
| 200 | rval = EAI_FAMILY; | ||
| 201 | goto ret; | ||
| 202 | } | ||
| 203 | } | ||
| 204 | |||
| 205 | if (serv && servlen > 0) { | ||
| 206 | switch (sa->sa_family) { | ||
| 207 | case AF_INET: | ||
| 208 | { | ||
| 209 | struct sockaddr_in *sin = (void *)sa; | ||
| 210 | struct servent *s; | ||
| 211 | |||
| 212 | if ((flags & NI_NUMERICSERV) == 0) { | ||
| 213 | s = getservbyport(sin->sin_port, | ||
| 214 | (flags & NI_DGRAM) ? "udp" : "tcp"); | ||
| 215 | if (s) { | ||
| 216 | strlcpy(serv, s->s_name, servlen); | ||
| 217 | break; | ||
| 218 | } | ||
| 219 | if (sin->sin_port == 0) { | ||
| 220 | strlcpy(serv, "*", servlen); | ||
| 221 | break; | ||
| 222 | } | ||
| 223 | } | ||
| 224 | snprintf(serv, servlen, "%d", ntohs(sin->sin_port)); | ||
| 225 | break; | ||
| 226 | } | ||
| 227 | case AF_INET6: | ||
| 228 | { | ||
| 229 | struct sockaddr_in6 *sin6 = (void *)sa; | ||
| 230 | struct servent *s; | ||
| 231 | |||
| 232 | if ((flags & NI_NUMERICSERV) == 0) { | ||
| 233 | |||
| 234 | s = getservbyport(sin6->sin6_port, | ||
| 235 | (flags & NI_DGRAM) ? "udp" : "tcp"); | ||
| 236 | if (s) { | ||
| 237 | strlcpy(serv, s->s_name, servlen); | ||
| 238 | break; | ||
| 239 | } | ||
| 240 | if (sin6->sin6_port == 0) { | ||
| 241 | strlcpy(serv, "*", servlen); | ||
| 242 | break; | ||
| 243 | } | ||
| 244 | } | ||
| 245 | snprintf(serv, servlen, "%d", ntohs(sin6->sin6_port)); | ||
| 246 | break; | ||
| 247 | } | ||
| 248 | case AF_LOCAL: | ||
| 249 | { | ||
| 250 | struct sockaddr_un *sun = (void *)sa; | ||
| 251 | |||
| 252 | strlcpy(serv, sun->sun_path, servlen); | ||
| 253 | break; | ||
| 254 | } | ||
| 255 | } | ||
| 256 | } | ||
| 257 | rval = 0; | ||
| 258 | |||
| 259 | ret: | ||
| 260 | if (rval == 1) | ||
| 261 | rval = EAI_FAIL; | ||
| 262 | errno = saved_errno; | ||
| 263 | return (rval); | ||
| 264 | } | ||
