Martin v. Löwis | 01dfdb3 | 2001-06-23 16:30:13 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. |
| 3 | * All rights reserved. |
| 4 | * |
| 5 | * Redistribution and use in source and binary forms, with or without |
| 6 | * modification, are permitted provided that the following conditions |
| 7 | * are met: |
| 8 | * 1. Redistributions of source code must retain the above copyright |
| 9 | * notice, this list of conditions and the following disclaimer. |
| 10 | * 2. Redistributions in binary form must reproduce the above copyright |
| 11 | * notice, this list of conditions and the following disclaimer in the |
| 12 | * documentation and/or other materials provided with the distribution. |
| 13 | * 3. Neither the name of the project nor the names of its contributors |
| 14 | * may be used to endorse or promote products derived from this software |
| 15 | * without specific prior written permission. |
| 16 | * |
| 17 | * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND |
| 18 | * GAI_ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE |
| 21 | * FOR GAI_ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| 23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| 24 | * HOWEVER CAUSED AND ON GAI_ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| 25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN GAI_ANY WAY |
| 26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| 27 | * SUCH DAMAGE. |
| 28 | */ |
| 29 | |
| 30 | /* |
| 31 | * "#ifdef FAITH" part is local hack for supporting IPv4-v6 translator. |
| 32 | * |
| 33 | * Issues to be discussed: |
| 34 | * - Thread safe-ness must be checked. |
| 35 | * - Return values. There are nonstandard return values defined and used |
| 36 | * in the source code. This is because RFC2133 is silent about which error |
| 37 | * code must be returned for which situation. |
| 38 | * - PF_UNSPEC case would be handled in getipnodebyname() with the AI_ALL flag. |
| 39 | */ |
| 40 | |
| 41 | #if 0 |
| 42 | #include <sys/types.h> |
| 43 | #include <sys/param.h> |
| 44 | #include <sys/sysctl.h> |
| 45 | #include <sys/socket.h> |
| 46 | #include <netinet/in.h> |
| 47 | #include <arpa/inet.h> |
| 48 | #include <arpa/nameser.h> |
| 49 | #include <netdb.h> |
| 50 | #include <resolv.h> |
| 51 | #include <string.h> |
| 52 | #include <stdlib.h> |
| 53 | #include <stddef.h> |
| 54 | #include <ctype.h> |
| 55 | #include <unistd.h> |
| 56 | |
| 57 | #include "addrinfo.h" |
| 58 | #endif |
| 59 | |
Martin v. Löwis | 44ddbde | 2001-12-02 10:15:37 +0000 | [diff] [blame] | 60 | #if defined(__KAME__) && defined(ENABLE_IPV6) |
Martin v. Löwis | 01dfdb3 | 2001-06-23 16:30:13 +0000 | [diff] [blame] | 61 | # define FAITH |
| 62 | #endif |
| 63 | |
| 64 | #define SUCCESS 0 |
| 65 | #define GAI_ANY 0 |
| 66 | #define YES 1 |
| 67 | #define NO 0 |
| 68 | |
| 69 | #ifdef FAITH |
| 70 | static int translate = NO; |
| 71 | static struct in6_addr faith_prefix = IN6ADDR_GAI_ANY_INIT; |
| 72 | #endif |
| 73 | |
| 74 | static const char in_addrany[] = { 0, 0, 0, 0 }; |
| 75 | static const char in6_addrany[] = { |
| 76 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 |
| 77 | }; |
| 78 | static const char in_loopback[] = { 127, 0, 0, 1 }; |
| 79 | static const char in6_loopback[] = { |
| 80 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 |
| 81 | }; |
| 82 | |
| 83 | struct sockinet { |
| 84 | u_char si_len; |
| 85 | u_char si_family; |
| 86 | u_short si_port; |
| 87 | }; |
| 88 | |
| 89 | static struct gai_afd { |
| 90 | int a_af; |
| 91 | int a_addrlen; |
| 92 | int a_socklen; |
| 93 | int a_off; |
| 94 | const char *a_addrany; |
| 95 | const char *a_loopback; |
| 96 | } gai_afdl [] = { |
Martin v. Löwis | 44ddbde | 2001-12-02 10:15:37 +0000 | [diff] [blame] | 97 | #ifdef ENABLE_IPV6 |
Martin v. Löwis | 01dfdb3 | 2001-06-23 16:30:13 +0000 | [diff] [blame] | 98 | #define N_INET6 0 |
| 99 | {PF_INET6, sizeof(struct in6_addr), |
| 100 | sizeof(struct sockaddr_in6), |
| 101 | offsetof(struct sockaddr_in6, sin6_addr), |
| 102 | in6_addrany, in6_loopback}, |
| 103 | #define N_INET 1 |
| 104 | #else |
| 105 | #define N_INET 0 |
| 106 | #endif |
| 107 | {PF_INET, sizeof(struct in_addr), |
| 108 | sizeof(struct sockaddr_in), |
| 109 | offsetof(struct sockaddr_in, sin_addr), |
| 110 | in_addrany, in_loopback}, |
| 111 | {0, 0, 0, 0, NULL, NULL}, |
| 112 | }; |
| 113 | |
Martin v. Löwis | 44ddbde | 2001-12-02 10:15:37 +0000 | [diff] [blame] | 114 | #ifdef ENABLE_IPV6 |
Martin v. Löwis | 01dfdb3 | 2001-06-23 16:30:13 +0000 | [diff] [blame] | 115 | #define PTON_MAX 16 |
| 116 | #else |
| 117 | #define PTON_MAX 4 |
| 118 | #endif |
| 119 | |
Martin v. Löwis | d783041 | 2001-07-19 17:37:46 +0000 | [diff] [blame] | 120 | #ifndef IN_MULTICAST |
| 121 | #define IN_MULTICAST(i) (((i) & 0xf0000000U) == 0xe0000000U) |
| 122 | #endif |
| 123 | |
| 124 | #ifndef IN_EXPERIMENTAL |
| 125 | #define IN_EXPERIMENTAL(i) (((i) & 0xe0000000U) == 0xe0000000U) |
| 126 | #endif |
| 127 | |
| 128 | #ifndef IN_LOOPBACKNET |
| 129 | #define IN_LOOPBACKNET 127 |
| 130 | #endif |
Martin v. Löwis | 01dfdb3 | 2001-06-23 16:30:13 +0000 | [diff] [blame] | 131 | |
Neal Norwitz | e0387ec | 2007-02-27 19:06:23 +0000 | [diff] [blame] | 132 | static int get_name(const char *, struct gai_afd *, |
Martin v. Löwis | 01dfdb3 | 2001-06-23 16:30:13 +0000 | [diff] [blame] | 133 | struct addrinfo **, char *, struct addrinfo *, |
Neal Norwitz | e0387ec | 2007-02-27 19:06:23 +0000 | [diff] [blame] | 134 | int); |
| 135 | static int get_addr(const char *, int, struct addrinfo **, |
| 136 | struct addrinfo *, int); |
| 137 | static int str_isnumber(const char *); |
Martin v. Löwis | 01dfdb3 | 2001-06-23 16:30:13 +0000 | [diff] [blame] | 138 | |
| 139 | static char *ai_errlist[] = { |
| 140 | "success.", |
| 141 | "address family for hostname not supported.", /* EAI_ADDRFAMILY */ |
| 142 | "temporary failure in name resolution.", /* EAI_AGAIN */ |
| 143 | "invalid value for ai_flags.", /* EAI_BADFLAGS */ |
| 144 | "non-recoverable failure in name resolution.", /* EAI_FAIL */ |
| 145 | "ai_family not supported.", /* EAI_FAMILY */ |
| 146 | "memory allocation failure.", /* EAI_MEMORY */ |
| 147 | "no address associated with hostname.", /* EAI_NODATA */ |
| 148 | "hostname nor servname provided, or not known.",/* EAI_NONAME */ |
| 149 | "servname not supported for ai_socktype.", /* EAI_SERVICE */ |
| 150 | "ai_socktype not supported.", /* EAI_SOCKTYPE */ |
| 151 | "system error returned in errno.", /* EAI_SYSTEM */ |
| 152 | "invalid value for hints.", /* EAI_BADHINTS */ |
| 153 | "resolved protocol is unknown.", /* EAI_PROTOCOL */ |
| 154 | "unknown error.", /* EAI_MAX */ |
| 155 | }; |
| 156 | |
| 157 | #define GET_CANONNAME(ai, str) \ |
| 158 | if (pai->ai_flags & AI_CANONNAME) {\ |
| 159 | if (((ai)->ai_canonname = (char *)malloc(strlen(str) + 1)) != NULL) {\ |
| 160 | strcpy((ai)->ai_canonname, (str));\ |
| 161 | } else {\ |
| 162 | error = EAI_MEMORY;\ |
| 163 | goto free;\ |
| 164 | }\ |
| 165 | } |
| 166 | |
| 167 | #ifdef HAVE_SOCKADDR_SA_LEN |
| 168 | #define GET_AI(ai, gai_afd, addr, port) {\ |
| 169 | char *p;\ |
| 170 | if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\ |
| 171 | ((gai_afd)->a_socklen)))\ |
| 172 | == NULL) goto free;\ |
| 173 | memcpy(ai, pai, sizeof(struct addrinfo));\ |
| 174 | (ai)->ai_addr = (struct sockaddr *)((ai) + 1);\ |
| 175 | memset((ai)->ai_addr, 0, (gai_afd)->a_socklen);\ |
| 176 | (ai)->ai_addr->sa_len = (ai)->ai_addrlen = (gai_afd)->a_socklen;\ |
| 177 | (ai)->ai_addr->sa_family = (ai)->ai_family = (gai_afd)->a_af;\ |
| 178 | ((struct sockinet *)(ai)->ai_addr)->si_port = port;\ |
| 179 | p = (char *)((ai)->ai_addr);\ |
| 180 | memcpy(p + (gai_afd)->a_off, (addr), (gai_afd)->a_addrlen);\ |
| 181 | } |
| 182 | #else |
| 183 | #define GET_AI(ai, gai_afd, addr, port) {\ |
| 184 | char *p;\ |
| 185 | if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\ |
| 186 | ((gai_afd)->a_socklen)))\ |
| 187 | == NULL) goto free;\ |
| 188 | memcpy(ai, pai, sizeof(struct addrinfo));\ |
| 189 | (ai)->ai_addr = (struct sockaddr *)((ai) + 1);\ |
| 190 | memset((ai)->ai_addr, 0, (gai_afd)->a_socklen);\ |
Martin v. Löwis | c7cdc63 | 2001-07-21 18:48:56 +0000 | [diff] [blame] | 191 | (ai)->ai_addrlen = (gai_afd)->a_socklen;\ |
Martin v. Löwis | 01dfdb3 | 2001-06-23 16:30:13 +0000 | [diff] [blame] | 192 | (ai)->ai_addr->sa_family = (ai)->ai_family = (gai_afd)->a_af;\ |
| 193 | ((struct sockinet *)(ai)->ai_addr)->si_port = port;\ |
| 194 | p = (char *)((ai)->ai_addr);\ |
| 195 | memcpy(p + (gai_afd)->a_off, (addr), (gai_afd)->a_addrlen);\ |
| 196 | } |
| 197 | #endif |
| 198 | |
| 199 | #define ERR(err) { error = (err); goto bad; } |
| 200 | |
| 201 | char * |
Guido van Rossum | 2335100 | 2002-07-17 14:33:34 +0000 | [diff] [blame] | 202 | gai_strerror(int ecode) |
Martin v. Löwis | 01dfdb3 | 2001-06-23 16:30:13 +0000 | [diff] [blame] | 203 | { |
| 204 | if (ecode < 0 || ecode > EAI_MAX) |
| 205 | ecode = EAI_MAX; |
| 206 | return ai_errlist[ecode]; |
| 207 | } |
| 208 | |
| 209 | void |
Guido van Rossum | 2335100 | 2002-07-17 14:33:34 +0000 | [diff] [blame] | 210 | freeaddrinfo(struct addrinfo *ai) |
Martin v. Löwis | 01dfdb3 | 2001-06-23 16:30:13 +0000 | [diff] [blame] | 211 | { |
| 212 | struct addrinfo *next; |
| 213 | |
| 214 | do { |
| 215 | next = ai->ai_next; |
| 216 | if (ai->ai_canonname) |
| 217 | free(ai->ai_canonname); |
| 218 | /* no need to free(ai->ai_addr) */ |
| 219 | free(ai); |
| 220 | } while ((ai = next) != NULL); |
| 221 | } |
| 222 | |
| 223 | static int |
Guido van Rossum | 2335100 | 2002-07-17 14:33:34 +0000 | [diff] [blame] | 224 | str_isnumber(const char *p) |
Martin v. Löwis | 01dfdb3 | 2001-06-23 16:30:13 +0000 | [diff] [blame] | 225 | { |
Guido van Rossum | 2335100 | 2002-07-17 14:33:34 +0000 | [diff] [blame] | 226 | unsigned char *q = (unsigned char *)p; |
Martin v. Löwis | 01dfdb3 | 2001-06-23 16:30:13 +0000 | [diff] [blame] | 227 | while (*q) { |
| 228 | if (! isdigit(*q)) |
| 229 | return NO; |
| 230 | q++; |
| 231 | } |
| 232 | return YES; |
| 233 | } |
| 234 | |
| 235 | int |
Martin v. Löwis | 39e0c5d | 2001-09-07 16:10:00 +0000 | [diff] [blame] | 236 | getaddrinfo(const char*hostname, const char*servname, |
| 237 | const struct addrinfo *hints, struct addrinfo **res) |
Martin v. Löwis | 01dfdb3 | 2001-06-23 16:30:13 +0000 | [diff] [blame] | 238 | { |
| 239 | struct addrinfo sentinel; |
| 240 | struct addrinfo *top = NULL; |
| 241 | struct addrinfo *cur; |
| 242 | int i, error = 0; |
| 243 | char pton[PTON_MAX]; |
| 244 | struct addrinfo ai; |
| 245 | struct addrinfo *pai; |
| 246 | u_short port; |
| 247 | |
| 248 | #ifdef FAITH |
| 249 | static int firsttime = 1; |
| 250 | |
| 251 | if (firsttime) { |
| 252 | /* translator hack */ |
| 253 | { |
| 254 | char *q = getenv("GAI"); |
| 255 | if (q && inet_pton(AF_INET6, q, &faith_prefix) == 1) |
| 256 | translate = YES; |
| 257 | } |
| 258 | firsttime = 0; |
| 259 | } |
| 260 | #endif |
| 261 | |
| 262 | /* initialize file static vars */ |
| 263 | sentinel.ai_next = NULL; |
| 264 | cur = &sentinel; |
| 265 | pai = &ai; |
| 266 | pai->ai_flags = 0; |
| 267 | pai->ai_family = PF_UNSPEC; |
| 268 | pai->ai_socktype = GAI_ANY; |
| 269 | pai->ai_protocol = GAI_ANY; |
| 270 | pai->ai_addrlen = 0; |
| 271 | pai->ai_canonname = NULL; |
| 272 | pai->ai_addr = NULL; |
| 273 | pai->ai_next = NULL; |
| 274 | port = GAI_ANY; |
| 275 | |
| 276 | if (hostname == NULL && servname == NULL) |
| 277 | return EAI_NONAME; |
| 278 | if (hints) { |
| 279 | /* error check for hints */ |
| 280 | if (hints->ai_addrlen || hints->ai_canonname || |
| 281 | hints->ai_addr || hints->ai_next) |
| 282 | ERR(EAI_BADHINTS); /* xxx */ |
| 283 | if (hints->ai_flags & ~AI_MASK) |
| 284 | ERR(EAI_BADFLAGS); |
| 285 | switch (hints->ai_family) { |
| 286 | case PF_UNSPEC: |
| 287 | case PF_INET: |
Martin v. Löwis | 44ddbde | 2001-12-02 10:15:37 +0000 | [diff] [blame] | 288 | #ifdef ENABLE_IPV6 |
Martin v. Löwis | 01dfdb3 | 2001-06-23 16:30:13 +0000 | [diff] [blame] | 289 | case PF_INET6: |
| 290 | #endif |
| 291 | break; |
| 292 | default: |
| 293 | ERR(EAI_FAMILY); |
| 294 | } |
| 295 | memcpy(pai, hints, sizeof(*pai)); |
| 296 | switch (pai->ai_socktype) { |
| 297 | case GAI_ANY: |
| 298 | switch (pai->ai_protocol) { |
| 299 | case GAI_ANY: |
| 300 | break; |
| 301 | case IPPROTO_UDP: |
| 302 | pai->ai_socktype = SOCK_DGRAM; |
| 303 | break; |
| 304 | case IPPROTO_TCP: |
| 305 | pai->ai_socktype = SOCK_STREAM; |
| 306 | break; |
| 307 | default: |
| 308 | pai->ai_socktype = SOCK_RAW; |
| 309 | break; |
| 310 | } |
| 311 | break; |
| 312 | case SOCK_RAW: |
| 313 | break; |
| 314 | case SOCK_DGRAM: |
| 315 | if (pai->ai_protocol != IPPROTO_UDP && |
| 316 | pai->ai_protocol != GAI_ANY) |
| 317 | ERR(EAI_BADHINTS); /*xxx*/ |
| 318 | pai->ai_protocol = IPPROTO_UDP; |
| 319 | break; |
| 320 | case SOCK_STREAM: |
| 321 | if (pai->ai_protocol != IPPROTO_TCP && |
| 322 | pai->ai_protocol != GAI_ANY) |
| 323 | ERR(EAI_BADHINTS); /*xxx*/ |
| 324 | pai->ai_protocol = IPPROTO_TCP; |
| 325 | break; |
| 326 | default: |
| 327 | ERR(EAI_SOCKTYPE); |
Sjoerd Mullender | 6f848c1 | 2001-08-30 14:15:38 +0000 | [diff] [blame] | 328 | /* unreachable */ |
Martin v. Löwis | 01dfdb3 | 2001-06-23 16:30:13 +0000 | [diff] [blame] | 329 | } |
| 330 | } |
| 331 | |
| 332 | /* |
| 333 | * service port |
| 334 | */ |
| 335 | if (servname) { |
| 336 | if (str_isnumber(servname)) { |
| 337 | if (pai->ai_socktype == GAI_ANY) { |
| 338 | /* caller accept *GAI_ANY* socktype */ |
| 339 | pai->ai_socktype = SOCK_DGRAM; |
| 340 | pai->ai_protocol = IPPROTO_UDP; |
| 341 | } |
Martin v. Löwis | c925b153 | 2001-07-21 09:42:15 +0000 | [diff] [blame] | 342 | port = htons((u_short)atoi(servname)); |
Martin v. Löwis | 01dfdb3 | 2001-06-23 16:30:13 +0000 | [diff] [blame] | 343 | } else { |
| 344 | struct servent *sp; |
| 345 | char *proto; |
| 346 | |
| 347 | proto = NULL; |
| 348 | switch (pai->ai_socktype) { |
| 349 | case GAI_ANY: |
| 350 | proto = NULL; |
| 351 | break; |
| 352 | case SOCK_DGRAM: |
| 353 | proto = "udp"; |
| 354 | break; |
| 355 | case SOCK_STREAM: |
| 356 | proto = "tcp"; |
| 357 | break; |
| 358 | default: |
| 359 | fprintf(stderr, "panic!\n"); |
| 360 | break; |
| 361 | } |
| 362 | if ((sp = getservbyname(servname, proto)) == NULL) |
| 363 | ERR(EAI_SERVICE); |
| 364 | port = sp->s_port; |
Martin v. Löwis | 39e0c5d | 2001-09-07 16:10:00 +0000 | [diff] [blame] | 365 | if (pai->ai_socktype == GAI_ANY) { |
Martin v. Löwis | 01dfdb3 | 2001-06-23 16:30:13 +0000 | [diff] [blame] | 366 | if (strcmp(sp->s_proto, "udp") == 0) { |
| 367 | pai->ai_socktype = SOCK_DGRAM; |
| 368 | pai->ai_protocol = IPPROTO_UDP; |
| 369 | } else if (strcmp(sp->s_proto, "tcp") == 0) { |
Martin v. Löwis | 39e0c5d | 2001-09-07 16:10:00 +0000 | [diff] [blame] | 370 | pai->ai_socktype = SOCK_STREAM; |
| 371 | pai->ai_protocol = IPPROTO_TCP; |
| 372 | } else |
| 373 | ERR(EAI_PROTOCOL); /*xxx*/ |
| 374 | } |
Martin v. Löwis | 01dfdb3 | 2001-06-23 16:30:13 +0000 | [diff] [blame] | 375 | } |
| 376 | } |
| 377 | |
| 378 | /* |
| 379 | * hostname == NULL. |
| 380 | * passive socket -> anyaddr (0.0.0.0 or ::) |
| 381 | * non-passive socket -> localhost (127.0.0.1 or ::1) |
| 382 | */ |
| 383 | if (hostname == NULL) { |
| 384 | struct gai_afd *gai_afd; |
| 385 | |
| 386 | for (gai_afd = &gai_afdl[0]; gai_afd->a_af; gai_afd++) { |
| 387 | if (!(pai->ai_family == PF_UNSPEC |
| 388 | || pai->ai_family == gai_afd->a_af)) { |
| 389 | continue; |
| 390 | } |
| 391 | |
| 392 | if (pai->ai_flags & AI_PASSIVE) { |
| 393 | GET_AI(cur->ai_next, gai_afd, gai_afd->a_addrany, port); |
| 394 | /* xxx meaningless? |
| 395 | * GET_CANONNAME(cur->ai_next, "anyaddr"); |
| 396 | */ |
| 397 | } else { |
| 398 | GET_AI(cur->ai_next, gai_afd, gai_afd->a_loopback, |
| 399 | port); |
| 400 | /* xxx meaningless? |
| 401 | * GET_CANONNAME(cur->ai_next, "localhost"); |
| 402 | */ |
| 403 | } |
| 404 | cur = cur->ai_next; |
| 405 | } |
| 406 | top = sentinel.ai_next; |
| 407 | if (top) |
| 408 | goto good; |
| 409 | else |
| 410 | ERR(EAI_FAMILY); |
| 411 | } |
| 412 | |
| 413 | /* hostname as numeric name */ |
| 414 | for (i = 0; gai_afdl[i].a_af; i++) { |
| 415 | if (inet_pton(gai_afdl[i].a_af, hostname, pton)) { |
| 416 | u_long v4a; |
Martin v. Löwis | 44ddbde | 2001-12-02 10:15:37 +0000 | [diff] [blame] | 417 | #ifdef ENABLE_IPV6 |
Martin v. Löwis | 01dfdb3 | 2001-06-23 16:30:13 +0000 | [diff] [blame] | 418 | u_char pfx; |
Martin v. Löwis | c925b153 | 2001-07-21 09:42:15 +0000 | [diff] [blame] | 419 | #endif |
Martin v. Löwis | 01dfdb3 | 2001-06-23 16:30:13 +0000 | [diff] [blame] | 420 | |
| 421 | switch (gai_afdl[i].a_af) { |
| 422 | case AF_INET: |
| 423 | v4a = ((struct in_addr *)pton)->s_addr; |
Raymond Hettinger | 3432118 | 2003-08-17 21:28:39 +0000 | [diff] [blame] | 424 | v4a = ntohl(v4a); |
Martin v. Löwis | 01dfdb3 | 2001-06-23 16:30:13 +0000 | [diff] [blame] | 425 | if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a)) |
| 426 | pai->ai_flags &= ~AI_CANONNAME; |
| 427 | v4a >>= IN_CLASSA_NSHIFT; |
| 428 | if (v4a == 0 || v4a == IN_LOOPBACKNET) |
| 429 | pai->ai_flags &= ~AI_CANONNAME; |
| 430 | break; |
Martin v. Löwis | 44ddbde | 2001-12-02 10:15:37 +0000 | [diff] [blame] | 431 | #ifdef ENABLE_IPV6 |
Martin v. Löwis | 01dfdb3 | 2001-06-23 16:30:13 +0000 | [diff] [blame] | 432 | case AF_INET6: |
| 433 | pfx = ((struct in6_addr *)pton)->s6_addr8[0]; |
| 434 | if (pfx == 0 || pfx == 0xfe || pfx == 0xff) |
| 435 | pai->ai_flags &= ~AI_CANONNAME; |
| 436 | break; |
| 437 | #endif |
| 438 | } |
| 439 | |
| 440 | if (pai->ai_family == gai_afdl[i].a_af || |
| 441 | pai->ai_family == PF_UNSPEC) { |
| 442 | if (! (pai->ai_flags & AI_CANONNAME)) { |
| 443 | GET_AI(top, &gai_afdl[i], pton, port); |
| 444 | goto good; |
| 445 | } |
| 446 | /* |
| 447 | * if AI_CANONNAME and if reverse lookup |
| 448 | * fail, return ai anyway to pacify |
| 449 | * calling application. |
| 450 | * |
| 451 | * XXX getaddrinfo() is a name->address |
| 452 | * translation function, and it looks strange |
| 453 | * that we do addr->name translation here. |
| 454 | */ |
| 455 | get_name(pton, &gai_afdl[i], &top, pton, pai, port); |
| 456 | goto good; |
| 457 | } else |
| 458 | ERR(EAI_FAMILY); /*xxx*/ |
| 459 | } |
| 460 | } |
| 461 | |
| 462 | if (pai->ai_flags & AI_NUMERICHOST) |
| 463 | ERR(EAI_NONAME); |
| 464 | |
| 465 | /* hostname as alphabetical name */ |
| 466 | error = get_addr(hostname, pai->ai_family, &top, pai, port); |
| 467 | if (error == 0) { |
| 468 | if (top) { |
| 469 | good: |
| 470 | *res = top; |
| 471 | return SUCCESS; |
| 472 | } else |
| 473 | error = EAI_FAIL; |
| 474 | } |
| 475 | free: |
| 476 | if (top) |
| 477 | freeaddrinfo(top); |
| 478 | bad: |
| 479 | *res = NULL; |
| 480 | return error; |
| 481 | } |
| 482 | |
| 483 | static int |
| 484 | get_name(addr, gai_afd, res, numaddr, pai, port0) |
| 485 | const char *addr; |
| 486 | struct gai_afd *gai_afd; |
| 487 | struct addrinfo **res; |
| 488 | char *numaddr; |
| 489 | struct addrinfo *pai; |
| 490 | int port0; |
| 491 | { |
| 492 | u_short port = port0 & 0xffff; |
| 493 | struct hostent *hp; |
| 494 | struct addrinfo *cur; |
Martin v. Löwis | c925b153 | 2001-07-21 09:42:15 +0000 | [diff] [blame] | 495 | int error = 0; |
Martin v. Löwis | 44ddbde | 2001-12-02 10:15:37 +0000 | [diff] [blame] | 496 | #ifdef ENABLE_IPV6 |
Martin v. Löwis | c925b153 | 2001-07-21 09:42:15 +0000 | [diff] [blame] | 497 | int h_error; |
| 498 | #endif |
Martin v. Löwis | 01dfdb3 | 2001-06-23 16:30:13 +0000 | [diff] [blame] | 499 | |
Martin v. Löwis | 44ddbde | 2001-12-02 10:15:37 +0000 | [diff] [blame] | 500 | #ifdef ENABLE_IPV6 |
Martin v. Löwis | 01dfdb3 | 2001-06-23 16:30:13 +0000 | [diff] [blame] | 501 | hp = getipnodebyaddr(addr, gai_afd->a_addrlen, gai_afd->a_af, &h_error); |
| 502 | #else |
| 503 | hp = gethostbyaddr(addr, gai_afd->a_addrlen, AF_INET); |
| 504 | #endif |
| 505 | if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) { |
| 506 | GET_AI(cur, gai_afd, hp->h_addr_list[0], port); |
| 507 | GET_CANONNAME(cur, hp->h_name); |
| 508 | } else |
| 509 | GET_AI(cur, gai_afd, numaddr, port); |
| 510 | |
Martin v. Löwis | 44ddbde | 2001-12-02 10:15:37 +0000 | [diff] [blame] | 511 | #ifdef ENABLE_IPV6 |
Martin v. Löwis | 01dfdb3 | 2001-06-23 16:30:13 +0000 | [diff] [blame] | 512 | if (hp) |
| 513 | freehostent(hp); |
| 514 | #endif |
| 515 | *res = cur; |
| 516 | return SUCCESS; |
| 517 | free: |
| 518 | if (cur) |
| 519 | freeaddrinfo(cur); |
Martin v. Löwis | 44ddbde | 2001-12-02 10:15:37 +0000 | [diff] [blame] | 520 | #ifdef ENABLE_IPV6 |
Martin v. Löwis | 01dfdb3 | 2001-06-23 16:30:13 +0000 | [diff] [blame] | 521 | if (hp) |
| 522 | freehostent(hp); |
| 523 | #endif |
| 524 | /* bad: */ |
| 525 | *res = NULL; |
| 526 | return error; |
| 527 | } |
| 528 | |
| 529 | static int |
| 530 | get_addr(hostname, af, res, pai, port0) |
| 531 | const char *hostname; |
| 532 | int af; |
| 533 | struct addrinfo **res; |
| 534 | struct addrinfo *pai; |
| 535 | int port0; |
| 536 | { |
| 537 | u_short port = port0 & 0xffff; |
| 538 | struct addrinfo sentinel; |
| 539 | struct hostent *hp; |
| 540 | struct addrinfo *top, *cur; |
| 541 | struct gai_afd *gai_afd; |
| 542 | int i, error = 0, h_error; |
| 543 | char *ap; |
Martin v. Löwis | 01dfdb3 | 2001-06-23 16:30:13 +0000 | [diff] [blame] | 544 | |
| 545 | top = NULL; |
| 546 | sentinel.ai_next = NULL; |
| 547 | cur = &sentinel; |
Martin v. Löwis | 44ddbde | 2001-12-02 10:15:37 +0000 | [diff] [blame] | 548 | #ifdef ENABLE_IPV6 |
Martin v. Löwis | 01dfdb3 | 2001-06-23 16:30:13 +0000 | [diff] [blame] | 549 | if (af == AF_UNSPEC) { |
| 550 | hp = getipnodebyname(hostname, AF_INET6, |
| 551 | AI_ADDRCONFIG|AI_ALL|AI_V4MAPPED, &h_error); |
| 552 | } else |
| 553 | hp = getipnodebyname(hostname, af, AI_ADDRCONFIG, &h_error); |
| 554 | #else |
| 555 | hp = gethostbyname(hostname); |
| 556 | h_error = h_errno; |
| 557 | #endif |
| 558 | if (hp == NULL) { |
| 559 | switch (h_error) { |
| 560 | case HOST_NOT_FOUND: |
| 561 | case NO_DATA: |
| 562 | error = EAI_NODATA; |
| 563 | break; |
| 564 | case TRY_AGAIN: |
| 565 | error = EAI_AGAIN; |
| 566 | break; |
| 567 | case NO_RECOVERY: |
| 568 | default: |
| 569 | error = EAI_FAIL; |
| 570 | break; |
| 571 | } |
Martin v. Löwis | f0b11d2 | 2001-11-07 08:31:03 +0000 | [diff] [blame] | 572 | goto free; |
Martin v. Löwis | 01dfdb3 | 2001-06-23 16:30:13 +0000 | [diff] [blame] | 573 | } |
| 574 | |
| 575 | if ((hp->h_name == NULL) || (hp->h_name[0] == 0) || |
Martin v. Löwis | f0b11d2 | 2001-11-07 08:31:03 +0000 | [diff] [blame] | 576 | (hp->h_addr_list[0] == NULL)) { |
| 577 | error = EAI_FAIL; |
| 578 | goto free; |
| 579 | } |
Martin v. Löwis | 01dfdb3 | 2001-06-23 16:30:13 +0000 | [diff] [blame] | 580 | |
| 581 | for (i = 0; (ap = hp->h_addr_list[i]) != NULL; i++) { |
| 582 | switch (af) { |
Martin v. Löwis | 44ddbde | 2001-12-02 10:15:37 +0000 | [diff] [blame] | 583 | #ifdef ENABLE_IPV6 |
Martin v. Löwis | 01dfdb3 | 2001-06-23 16:30:13 +0000 | [diff] [blame] | 584 | case AF_INET6: |
| 585 | gai_afd = &gai_afdl[N_INET6]; |
| 586 | break; |
| 587 | #endif |
Martin v. Löwis | 44ddbde | 2001-12-02 10:15:37 +0000 | [diff] [blame] | 588 | #ifndef ENABLE_IPV6 |
Martin v. Löwis | 01dfdb3 | 2001-06-23 16:30:13 +0000 | [diff] [blame] | 589 | default: /* AF_UNSPEC */ |
| 590 | #endif |
| 591 | case AF_INET: |
| 592 | gai_afd = &gai_afdl[N_INET]; |
| 593 | break; |
Martin v. Löwis | 44ddbde | 2001-12-02 10:15:37 +0000 | [diff] [blame] | 594 | #ifdef ENABLE_IPV6 |
Martin v. Löwis | 01dfdb3 | 2001-06-23 16:30:13 +0000 | [diff] [blame] | 595 | default: /* AF_UNSPEC */ |
| 596 | if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) { |
| 597 | ap += sizeof(struct in6_addr) - |
| 598 | sizeof(struct in_addr); |
| 599 | gai_afd = &gai_afdl[N_INET]; |
| 600 | } else |
| 601 | gai_afd = &gai_afdl[N_INET6]; |
| 602 | break; |
| 603 | #endif |
| 604 | } |
| 605 | #ifdef FAITH |
| 606 | if (translate && gai_afd->a_af == AF_INET) { |
| 607 | struct in6_addr *in6; |
| 608 | |
| 609 | GET_AI(cur->ai_next, &gai_afdl[N_INET6], ap, port); |
| 610 | in6 = &((struct sockaddr_in6 *)cur->ai_next->ai_addr)->sin6_addr; |
| 611 | memcpy(&in6->s6_addr32[0], &faith_prefix, |
| 612 | sizeof(struct in6_addr) - sizeof(struct in_addr)); |
| 613 | memcpy(&in6->s6_addr32[3], ap, sizeof(struct in_addr)); |
| 614 | } else |
| 615 | #endif /* FAITH */ |
| 616 | GET_AI(cur->ai_next, gai_afd, ap, port); |
| 617 | if (cur == &sentinel) { |
| 618 | top = cur->ai_next; |
| 619 | GET_CANONNAME(top, hp->h_name); |
| 620 | } |
| 621 | cur = cur->ai_next; |
| 622 | } |
Martin v. Löwis | 44ddbde | 2001-12-02 10:15:37 +0000 | [diff] [blame] | 623 | #ifdef ENABLE_IPV6 |
Martin v. Löwis | 01dfdb3 | 2001-06-23 16:30:13 +0000 | [diff] [blame] | 624 | freehostent(hp); |
| 625 | #endif |
| 626 | *res = top; |
| 627 | return SUCCESS; |
| 628 | free: |
| 629 | if (top) |
| 630 | freeaddrinfo(top); |
Martin v. Löwis | 44ddbde | 2001-12-02 10:15:37 +0000 | [diff] [blame] | 631 | #ifdef ENABLE_IPV6 |
Martin v. Löwis | 01dfdb3 | 2001-06-23 16:30:13 +0000 | [diff] [blame] | 632 | if (hp) |
| 633 | freehostent(hp); |
| 634 | #endif |
Martin v. Löwis | f0b11d2 | 2001-11-07 08:31:03 +0000 | [diff] [blame] | 635 | /* bad: */ |
Martin v. Löwis | 01dfdb3 | 2001-06-23 16:30:13 +0000 | [diff] [blame] | 636 | *res = NULL; |
| 637 | return error; |
| 638 | } |