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