1/* $NetBSD: getaddrinfo.c,v 1.2.6.2 2012/12/15 05:40:13 riz Exp $ */ 2 3/* 4 * Copyright (C) 2004-2008, 2012 Internet Systems Consortium, Inc. ("ISC") 5 * Copyright (C) 1999-2001 Internet Software Consortium. 6 * 7 * This code is derived from software contributed to ISC by 8 * Berkeley Software Design, Inc. 9 * 10 * Permission to use, copy, modify, and/or distribute this software for any 11 * purpose with or without fee is hereby granted, provided that the above 12 * copyright notice and this permission notice appear in all copies. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND BERKELEY SOFTWARE DESIGN, INC. 15 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 16 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE 17 * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 19 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 20 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 21 */ 22 23/* Id: getaddrinfo.c,v 1.54 2008/11/25 23:47:23 tbox Exp */ 24 25/*! \file */ 26 27/** 28 * lwres_getaddrinfo() is used to get a list of IP addresses and port 29 * numbers for host hostname and service servname. The function is the 30 * lightweight resolver's implementation of getaddrinfo() as defined in 31 * RFC2133. hostname and servname are pointers to null-terminated strings 32 * or NULL. hostname is either a host name or a numeric host address 33 * string: a dotted decimal IPv4 address or an IPv6 address. servname is 34 * either a decimal port number or a service name as listed in 35 * /etc/services. 36 * 37 * If the operating system does not provide a struct addrinfo, the 38 * following structure is used: 39 * 40 * \code 41 * struct addrinfo { 42 * int ai_flags; // AI_PASSIVE, AI_CANONNAME 43 * int ai_family; // PF_xxx 44 * int ai_socktype; // SOCK_xxx 45 * int ai_protocol; // 0 or IPPROTO_xxx for IPv4 and IPv6 46 * size_t ai_addrlen; // length of ai_addr 47 * char *ai_canonname; // canonical name for hostname 48 * struct sockaddr *ai_addr; // binary address 49 * struct addrinfo *ai_next; // next structure in linked list 50 * }; 51 * \endcode 52 * 53 * 54 * hints is an optional pointer to a struct addrinfo. This structure can 55 * be used to provide hints concerning the type of socket that the caller 56 * supports or wishes to use. The caller can supply the following 57 * structure elements in *hints: 58 * 59 * <ul> 60 * <li>ai_family: 61 * The protocol family that should be used. When ai_family is set 62 * to PF_UNSPEC, it means the caller will accept any protocol 63 * family supported by the operating system.</li> 64 * 65 * <li>ai_socktype: 66 * denotes the type of socket -- SOCK_STREAM, SOCK_DGRAM or 67 * SOCK_RAW -- that is wanted. When ai_socktype is zero the caller 68 * will accept any socket type.</li> 69 * 70 * <li>ai_protocol: 71 * indicates which transport protocol is wanted: IPPROTO_UDP or 72 * IPPROTO_TCP. If ai_protocol is zero the caller will accept any 73 * protocol.</li> 74 * 75 * <li>ai_flags: 76 * Flag bits. If the AI_CANONNAME bit is set, a successful call to 77 * lwres_getaddrinfo() will return a null-terminated string 78 * containing the canonical name of the specified hostname in 79 * ai_canonname of the first addrinfo structure returned. Setting 80 * the AI_PASSIVE bit indicates that the returned socket address 81 * structure is intended for used in a call to bind(2). In this 82 * case, if the hostname argument is a NULL pointer, then the IP 83 * address portion of the socket address structure will be set to 84 * INADDR_ANY for an IPv4 address or IN6ADDR_ANY_INIT for an IPv6 85 * address.<br /><br /> 86 * 87 * When ai_flags does not set the AI_PASSIVE bit, the returned 88 * socket address structure will be ready for use in a call to 89 * connect(2) for a connection-oriented protocol or connect(2), 90 * sendto(2), or sendmsg(2) if a connectionless protocol was 91 * chosen. The IP address portion of the socket address structure 92 * will be set to the loopback address if hostname is a NULL 93 * pointer and AI_PASSIVE is not set in ai_flags.<br /><br /> 94 * 95 * If ai_flags is set to AI_NUMERICHOST it indicates that hostname 96 * should be treated as a numeric string defining an IPv4 or IPv6 97 * address and no name resolution should be attempted. 98 * </li></ul> 99 * 100 * All other elements of the struct addrinfo passed via hints must be 101 * zero. 102 * 103 * A hints of NULL is treated as if the caller provided a struct addrinfo 104 * initialized to zero with ai_familyset to PF_UNSPEC. 105 * 106 * After a successful call to lwres_getaddrinfo(), *res is a pointer to a 107 * linked list of one or more addrinfo structures. Each struct addrinfo 108 * in this list cn be processed by following the ai_next pointer, until a 109 * NULL pointer is encountered. The three members ai_family, ai_socktype, 110 * and ai_protocol in each returned addrinfo structure contain the 111 * corresponding arguments for a call to socket(2). For each addrinfo 112 * structure in the list, the ai_addr member points to a filled-in socket 113 * address structure of length ai_addrlen. 114 * 115 * All of the information returned by lwres_getaddrinfo() is dynamically 116 * allocated: the addrinfo structures, and the socket address structures 117 * and canonical host name strings pointed to by the addrinfostructures. 118 * Memory allocated for the dynamically allocated structures created by a 119 * successful call to lwres_getaddrinfo() is released by 120 * lwres_freeaddrinfo(). ai is a pointer to a struct addrinfo created by 121 * a call to lwres_getaddrinfo(). 122 * 123 * \section lwresreturn RETURN VALUES 124 * 125 * lwres_getaddrinfo() returns zero on success or one of the error codes 126 * listed in gai_strerror() if an error occurs. If both hostname and 127 * servname are NULL lwres_getaddrinfo() returns #EAI_NONAME. 128 * 129 * \section lwressee SEE ALSO 130 * 131 * lwres(3), lwres_getaddrinfo(), lwres_freeaddrinfo(), 132 * lwres_gai_strerror(), RFC2133, getservbyname(3), connect(2), 133 * sendto(2), sendmsg(2), socket(2). 134 */ 135 136#include <config.h> 137 138#include <errno.h> 139 140#include <isc/string.h> 141 142#include <lwres/lwres.h> 143#include <lwres/net.h> 144#include <lwres/netdb.h> 145#include <lwres/stdlib.h> 146 147#define SA(addr) ((struct sockaddr *)(addr)) 148#define SIN(addr) ((struct sockaddr_in *)(addr)) 149#define SIN6(addr) ((struct sockaddr_in6 *)(addr)) 150#define SLOCAL(addr) ((struct sockaddr_un *)(addr)) 151 152/*! \struct addrinfo 153 */ 154static struct addrinfo 155 *ai_reverse(struct addrinfo *oai), 156 *ai_clone(struct addrinfo *oai, int family), 157 *ai_alloc(int family, int addrlen); 158#ifdef AF_LOCAL 159static int get_local(const char *name, int socktype, struct addrinfo **res); 160#endif 161 162static int add_ipv4(const char *hostname, int flags, struct addrinfo **aip, 163 int socktype, int port); 164static int add_ipv6(const char *hostname, int flags, struct addrinfo **aip, 165 int socktype, int port); 166static void set_order(int, int (**)(const char *, int, struct addrinfo **, 167 int, int)); 168 169#define FOUND_IPV4 0x1 170#define FOUND_IPV6 0x2 171#define FOUND_MAX 2 172 173#define ISC_AI_MASK (AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST) 174/*% Get a list of IP addresses and port numbers for host hostname and service servname. */ 175int 176lwres_getaddrinfo(const char *hostname, const char *servname, 177 const struct addrinfo *hints, struct addrinfo **res) 178{ 179 struct servent *sp; 180 const char *proto; 181 int family, socktype, flags, protocol; 182 struct addrinfo *ai, *ai_list; 183 int port, err, i; 184 int (*net_order[FOUND_MAX+1])(const char *, int, struct addrinfo **, 185 int, int); 186 187 if (hostname == NULL && servname == NULL) 188 return (EAI_NONAME); 189 190 proto = NULL; 191 if (hints != NULL) { 192 if ((hints->ai_flags & ~(ISC_AI_MASK)) != 0) 193 return (EAI_BADFLAGS); 194 if (hints->ai_addrlen || hints->ai_canonname || 195 hints->ai_addr || hints->ai_next) { 196 errno = EINVAL; 197 return (EAI_SYSTEM); 198 } 199 family = hints->ai_family; 200 socktype = hints->ai_socktype; 201 protocol = hints->ai_protocol; 202 flags = hints->ai_flags; 203 switch (family) { 204 case AF_UNSPEC: 205 switch (hints->ai_socktype) { 206 case SOCK_STREAM: 207 proto = "tcp"; 208 break; 209 case SOCK_DGRAM: 210 proto = "udp"; 211 break; 212 } 213 break; 214 case AF_INET: 215 case AF_INET6: 216 switch (hints->ai_socktype) { 217 case 0: 218 break; 219 case SOCK_STREAM: 220 proto = "tcp"; 221 break; 222 case SOCK_DGRAM: 223 proto = "udp"; 224 break; 225 case SOCK_RAW: 226 break; 227 default: 228 return (EAI_SOCKTYPE); 229 } 230 break; 231#ifdef AF_LOCAL 232 case AF_LOCAL: 233 switch (hints->ai_socktype) { 234 case 0: 235 break; 236 case SOCK_STREAM: 237 break; 238 case SOCK_DGRAM: 239 break; 240 default: 241 return (EAI_SOCKTYPE); 242 } 243 break; 244#endif 245 default: 246 return (EAI_FAMILY); 247 } 248 } else { 249 protocol = 0; 250 family = 0; 251 socktype = 0; 252 flags = 0; 253 } 254 255#ifdef AF_LOCAL 256 /*! 257 * First, deal with AF_LOCAL. If the family was not set, 258 * then assume AF_LOCAL if the first character of the 259 * hostname/servname is '/'. 260 */ 261 262 if (hostname != NULL && 263 (family == AF_LOCAL || (family == 0 && *hostname == '/'))) 264 return (get_local(hostname, socktype, res)); 265 266 if (servname != NULL && 267 (family == AF_LOCAL || (family == 0 && *servname == '/'))) 268 return (get_local(servname, socktype, res)); 269#endif 270 271 /* 272 * Ok, only AF_INET and AF_INET6 left. 273 */ 274 ai_list = NULL; 275 276 /* 277 * First, look up the service name (port) if it was 278 * requested. If the socket type wasn't specified, then 279 * try and figure it out. 280 */ 281 if (servname != NULL) { 282 char *e; 283 284 port = strtol(servname, &e, 10); 285 if (*e == '\0') { 286 if (socktype == 0) 287 return (EAI_SOCKTYPE); 288 if (port < 0 || port > 65535) 289 return (EAI_SERVICE); 290 port = htons((unsigned short) port); 291 } else { 292 sp = getservbyname(servname, proto); 293 if (sp == NULL) 294 return (EAI_SERVICE); 295 port = sp->s_port; 296 if (socktype == 0) { 297 if (strcmp(sp->s_proto, "tcp") == 0) 298 socktype = SOCK_STREAM; 299 else if (strcmp(sp->s_proto, "udp") == 0) 300 socktype = SOCK_DGRAM; 301 } 302 } 303 } else 304 port = 0; 305 306 /* 307 * Next, deal with just a service name, and no hostname. 308 * (we verified that one of them was non-null up above). 309 */ 310 if (hostname == NULL && (flags & AI_PASSIVE) != 0) { 311 if (family == AF_INET || family == 0) { 312 ai = ai_alloc(AF_INET, sizeof(struct sockaddr_in)); 313 if (ai == NULL) 314 return (EAI_MEMORY); 315 ai->ai_socktype = socktype; 316 ai->ai_protocol = protocol; 317 SIN(ai->ai_addr)->sin_port = port; 318 ai->ai_next = ai_list; 319 ai_list = ai; 320 } 321 322 if (family == AF_INET6 || family == 0) { 323 ai = ai_alloc(AF_INET6, sizeof(struct sockaddr_in6)); 324 if (ai == NULL) { 325 lwres_freeaddrinfo(ai_list); 326 return (EAI_MEMORY); 327 } 328 ai->ai_socktype = socktype; 329 ai->ai_protocol = protocol; 330 SIN6(ai->ai_addr)->sin6_port = port; 331 ai->ai_next = ai_list; 332 ai_list = ai; 333 } 334 335 *res = ai_list; 336 return (0); 337 } 338 339 /* 340 * If the family isn't specified or AI_NUMERICHOST specified, 341 * check first to see if it is a numeric address. 342 * Though the gethostbyname2() routine 343 * will recognize numeric addresses, it will only recognize 344 * the format that it is being called for. Thus, a numeric 345 * AF_INET address will be treated by the AF_INET6 call as 346 * a domain name, and vice versa. Checking for both numerics 347 * here avoids that. 348 */ 349 if (hostname != NULL && 350 (family == 0 || (flags & AI_NUMERICHOST) != 0)) { 351 char abuf[sizeof(struct in6_addr)]; 352 char nbuf[NI_MAXHOST]; 353 int addrsize, addroff; 354#ifdef LWRES_HAVE_SIN6_SCOPE_ID 355 char *p, *ep; 356 char ntmp[NI_MAXHOST]; 357 lwres_uint32_t scopeid; 358#endif 359 360#ifdef LWRES_HAVE_SIN6_SCOPE_ID 361 /* 362 * Scope identifier portion. 363 */ 364 ntmp[0] = '\0'; 365 if (strchr(hostname, '%') != NULL) { 366 strncpy(ntmp, hostname, sizeof(ntmp) - 1); 367 ntmp[sizeof(ntmp) - 1] = '\0'; 368 p = strchr(ntmp, '%'); 369 ep = NULL; 370 371 /* 372 * Vendors may want to support non-numeric 373 * scopeid around here. 374 */ 375 376 if (p != NULL) 377 scopeid = (lwres_uint32_t)strtoul(p + 1, 378 &ep, 10); 379 if (p != NULL && ep != NULL && ep[0] == '\0') 380 *p = '\0'; 381 else { 382 ntmp[0] = '\0'; 383 scopeid = 0; 384 } 385 } else 386 scopeid = 0; 387#endif 388 389 if (lwres_net_pton(AF_INET, hostname, (struct in_addr *)abuf) 390 == 1) 391 { 392 if (family == AF_INET6) { 393 /* 394 * Convert to a V4 mapped address. 395 */ 396 struct in6_addr *a6 = (struct in6_addr *)abuf; 397 memcpy(&a6->s6_addr[12], &a6->s6_addr[0], 4); 398 memset(&a6->s6_addr[10], 0xff, 2); 399 memset(&a6->s6_addr[0], 0, 10); 400 goto inet6_addr; 401 } 402 addrsize = sizeof(struct in_addr); 403 addroff = offsetof(struct sockaddr_in, sin_addr); 404 family = AF_INET; 405 goto common; 406#ifdef LWRES_HAVE_SIN6_SCOPE_ID 407 } else if (ntmp[0] != '\0' && 408 lwres_net_pton(AF_INET6, ntmp, abuf) == 1) 409 { 410 if (family && family != AF_INET6) 411 return (EAI_NONAME); 412 addrsize = sizeof(struct in6_addr); 413 addroff = offsetof(struct sockaddr_in6, sin6_addr); 414 family = AF_INET6; 415 goto common; 416#endif 417 } else if (lwres_net_pton(AF_INET6, hostname, abuf) == 1) { 418 if (family != 0 && family != AF_INET6) 419 return (EAI_NONAME); 420 inet6_addr: 421 addrsize = sizeof(struct in6_addr); 422 addroff = offsetof(struct sockaddr_in6, sin6_addr); 423 family = AF_INET6; 424 425 common: 426 ai = ai_clone(ai_list, family); 427 if (ai == NULL) 428 return (EAI_MEMORY); 429 ai_list = ai; 430 ai->ai_socktype = socktype; 431 SIN(ai->ai_addr)->sin_port = port; 432 memcpy((char *)ai->ai_addr + addroff, abuf, addrsize); 433 if (flags & AI_CANONNAME) { 434#if defined(LWRES_HAVE_SIN6_SCOPE_ID) 435 if (ai->ai_family == AF_INET6) 436 SIN6(ai->ai_addr)->sin6_scope_id = 437 scopeid; 438#endif 439 if (lwres_getnameinfo(ai->ai_addr, 440 ai->ai_addrlen, nbuf, sizeof(nbuf), 441 NULL, 0, 442 NI_NUMERICHOST) == 0) { 443 ai->ai_canonname = strdup(nbuf); 444 if (ai->ai_canonname == NULL) { 445 lwres_freeaddrinfo(ai_list); 446 return (EAI_MEMORY); 447 } 448 } else { 449 /* XXX raise error? */ 450 ai->ai_canonname = NULL; 451 } 452 } 453 goto done; 454 } else if ((flags & AI_NUMERICHOST) != 0) { 455 return (EAI_NONAME); 456 } 457 } 458 459 set_order(family, net_order); 460 for (i = 0; i < FOUND_MAX; i++) { 461 if (net_order[i] == NULL) 462 break; 463 err = (net_order[i])(hostname, flags, &ai_list, 464 socktype, port); 465 if (err != 0) 466 return (err); 467 } 468 469 if (ai_list == NULL) 470 return (EAI_NODATA); 471 472done: 473 ai_list = ai_reverse(ai_list); 474 475 *res = ai_list; 476 return (0); 477} 478 479static char * 480lwres_strsep(char **stringp, const char *delim) { 481 char *string = *stringp; 482 char *s; 483 const char *d; 484 char sc, dc; 485 486 if (string == NULL) 487 return (NULL); 488 489 for (s = string; *s != '\0'; s++) { 490 sc = *s; 491 for (d = delim; (dc = *d) != '\0'; d++) 492 if (sc == dc) { 493 *s++ = '\0'; 494 *stringp = s; 495 return (string); 496 } 497 } 498 *stringp = NULL; 499 return (string); 500} 501 502static void 503set_order(int family, int (**net_order)(const char *, int, struct addrinfo **, 504 int, int)) 505{ 506 char *order, *tok; 507 int found; 508 509 if (family) { 510 switch (family) { 511 case AF_INET: 512 *net_order++ = add_ipv4; 513 break; 514 case AF_INET6: 515 *net_order++ = add_ipv6; 516 break; 517 } 518 } else { 519 order = getenv("NET_ORDER"); 520 found = 0; 521 while (order != NULL) { 522 /* 523 * We ignore any unknown names. 524 */ 525 tok = lwres_strsep(&order, ":"); 526 if (strcasecmp(tok, "inet6") == 0) { 527 if ((found & FOUND_IPV6) == 0) 528 *net_order++ = add_ipv6; 529 found |= FOUND_IPV6; 530 } else if (strcasecmp(tok, "inet") == 0 || 531 strcasecmp(tok, "inet4") == 0) { 532 if ((found & FOUND_IPV4) == 0) 533 *net_order++ = add_ipv4; 534 found |= FOUND_IPV4; 535 } 536 } 537 538 /* 539 * Add in anything that we didn't find. 540 */ 541 if ((found & FOUND_IPV4) == 0) 542 *net_order++ = add_ipv4; 543 if ((found & FOUND_IPV6) == 0) 544 *net_order++ = add_ipv6; 545 } 546 *net_order = NULL; 547 return; 548} 549 550static char v4_loop[4] = { 127, 0, 0, 1 }; 551 552/* 553 * The test against 0 is there to keep the Solaris compiler 554 * from complaining about "end-of-loop code not reached". 555 */ 556#define SETERROR(code) \ 557 do { result = (code); \ 558 if (result != 0) goto cleanup; \ 559 } while (/*CONSTCOND*/0) 560 561static int 562add_ipv4(const char *hostname, int flags, struct addrinfo **aip, 563 int socktype, int port) 564{ 565 struct addrinfo *ai; 566 lwres_context_t *lwrctx = NULL; 567 lwres_gabnresponse_t *by = NULL; 568 lwres_addr_t *addr; 569 lwres_result_t lwres; 570 int result = 0; 571 572 lwres = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0); 573 if (lwres != LWRES_R_SUCCESS) 574 SETERROR(EAI_FAIL); 575 (void) lwres_conf_parse(lwrctx, lwres_resolv_conf); 576 if (hostname == NULL && (flags & AI_PASSIVE) == 0) { 577 ai = ai_clone(*aip, AF_INET); 578 if (ai == NULL) { 579 lwres_freeaddrinfo(*aip); 580 SETERROR(EAI_MEMORY); 581 } 582 583 *aip = ai; 584 ai->ai_socktype = socktype; 585 SIN(ai->ai_addr)->sin_port = port; 586 memcpy(&SIN(ai->ai_addr)->sin_addr, v4_loop, 4); 587 } else { 588 lwres = lwres_getaddrsbyname(lwrctx, hostname, 589 LWRES_ADDRTYPE_V4, &by); 590 if (lwres != LWRES_R_SUCCESS) { 591 if (lwres == LWRES_R_NOTFOUND) 592 goto cleanup; 593 else 594 SETERROR(EAI_FAIL); 595 } 596 addr = LWRES_LIST_HEAD(by->addrs); 597 while (addr != NULL) { 598 ai = ai_clone(*aip, AF_INET); 599 if (ai == NULL) { 600 lwres_freeaddrinfo(*aip); 601 SETERROR(EAI_MEMORY); 602 } 603 *aip = ai; 604 ai->ai_socktype = socktype; 605 SIN(ai->ai_addr)->sin_port = port; 606 memcpy(&SIN(ai->ai_addr)->sin_addr, 607 addr->address, 4); 608 if (flags & AI_CANONNAME) { 609 ai->ai_canonname = strdup(by->realname); 610 if (ai->ai_canonname == NULL) 611 SETERROR(EAI_MEMORY); 612 } 613 addr = LWRES_LIST_NEXT(addr, link); 614 } 615 } 616 cleanup: 617 if (by != NULL) 618 lwres_gabnresponse_free(lwrctx, &by); 619 if (lwrctx != NULL) { 620 lwres_conf_clear(lwrctx); 621 lwres_context_destroy(&lwrctx); 622 } 623 return (result); 624} 625 626static char v6_loop[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; 627 628static int 629add_ipv6(const char *hostname, int flags, struct addrinfo **aip, 630 int socktype, int port) 631{ 632 struct addrinfo *ai; 633 lwres_context_t *lwrctx = NULL; 634 lwres_gabnresponse_t *by = NULL; 635 lwres_addr_t *addr; 636 lwres_result_t lwres; 637 int result = 0; 638 639 lwres = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0); 640 if (lwres != LWRES_R_SUCCESS) 641 SETERROR(EAI_FAIL); 642 (void) lwres_conf_parse(lwrctx, lwres_resolv_conf); 643 644 if (hostname == NULL && (flags & AI_PASSIVE) == 0) { 645 ai = ai_clone(*aip, AF_INET6); 646 if (ai == NULL) { 647 lwres_freeaddrinfo(*aip); 648 SETERROR(EAI_MEMORY); 649 } 650 651 *aip = ai; 652 ai->ai_socktype = socktype; 653 SIN6(ai->ai_addr)->sin6_port = port; 654 memcpy(&SIN6(ai->ai_addr)->sin6_addr, v6_loop, 16); 655 } else { 656 lwres = lwres_getaddrsbyname(lwrctx, hostname, 657 LWRES_ADDRTYPE_V6, &by); 658 if (lwres != LWRES_R_SUCCESS) { 659 if (lwres == LWRES_R_NOTFOUND) 660 goto cleanup; 661 else 662 SETERROR(EAI_FAIL); 663 } 664 addr = LWRES_LIST_HEAD(by->addrs); 665 while (addr != NULL) { 666 ai = ai_clone(*aip, AF_INET6); 667 if (ai == NULL) { 668 lwres_freeaddrinfo(*aip); 669 SETERROR(EAI_MEMORY); 670 } 671 *aip = ai; 672 ai->ai_socktype = socktype; 673 SIN6(ai->ai_addr)->sin6_port = port; 674 memcpy(&SIN6(ai->ai_addr)->sin6_addr, 675 addr->address, 16); 676 if (flags & AI_CANONNAME) { 677 ai->ai_canonname = strdup(by->realname); 678 if (ai->ai_canonname == NULL) 679 SETERROR(EAI_MEMORY); 680 } 681 addr = LWRES_LIST_NEXT(addr, link); 682 } 683 } 684 cleanup: 685 if (by != NULL) 686 lwres_gabnresponse_free(lwrctx, &by); 687 if (lwrctx != NULL) { 688 lwres_conf_clear(lwrctx); 689 lwres_context_destroy(&lwrctx); 690 } 691 return (result); 692} 693 694/*% Free address info. */ 695void 696lwres_freeaddrinfo(struct addrinfo *ai) { 697 struct addrinfo *ai_next; 698 699 while (ai != NULL) { 700 ai_next = ai->ai_next; 701 if (ai->ai_addr != NULL) 702 free(ai->ai_addr); 703 if (ai->ai_canonname) 704 free(ai->ai_canonname); 705 free(ai); 706 ai = ai_next; 707 } 708} 709 710#ifdef AF_LOCAL 711static int 712get_local(const char *name, int socktype, struct addrinfo **res) { 713 struct addrinfo *ai; 714 struct sockaddr_un *slocal; 715 716 if (socktype == 0) 717 return (EAI_SOCKTYPE); 718 719 ai = ai_alloc(AF_LOCAL, sizeof(*slocal)); 720 if (ai == NULL) 721 return (EAI_MEMORY); 722 723 slocal = SLOCAL(ai->ai_addr); 724 strncpy(slocal->sun_path, name, sizeof(slocal->sun_path)); 725 726 ai->ai_socktype = socktype; 727 /* 728 * ai->ai_flags, ai->ai_protocol, ai->ai_canonname, 729 * and ai->ai_next were initialized to zero. 730 */ 731 732 *res = ai; 733 return (0); 734} 735#endif 736 737/*! 738 * Allocate an addrinfo structure, and a sockaddr structure 739 * of the specificed length. We initialize: 740 * ai_addrlen 741 * ai_family 742 * ai_addr 743 * ai_addr->sa_family 744 * ai_addr->sa_len (LWRES_PLATFORM_HAVESALEN) 745 * and everything else is initialized to zero. 746 */ 747static struct addrinfo * 748ai_alloc(int family, int addrlen) { 749 struct addrinfo *ai; 750 751 ai = (struct addrinfo *)calloc(1, sizeof(*ai)); 752 if (ai == NULL) 753 return (NULL); 754 755 ai->ai_addr = SA(calloc(1, addrlen)); 756 if (ai->ai_addr == NULL) { 757 free(ai); 758 return (NULL); 759 } 760 ai->ai_addrlen = addrlen; 761 ai->ai_family = family; 762 ai->ai_addr->sa_family = family; 763#ifdef LWRES_PLATFORM_HAVESALEN 764 ai->ai_addr->sa_len = addrlen; 765#endif 766 return (ai); 767} 768 769static struct addrinfo * 770ai_clone(struct addrinfo *oai, int family) { 771 struct addrinfo *ai; 772 773 ai = ai_alloc(family, ((family == AF_INET6) ? 774 sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in))); 775 776 if (ai == NULL) { 777 lwres_freeaddrinfo(oai); 778 return (NULL); 779 } 780 if (oai == NULL) 781 return (ai); 782 783 ai->ai_flags = oai->ai_flags; 784 ai->ai_socktype = oai->ai_socktype; 785 ai->ai_protocol = oai->ai_protocol; 786 ai->ai_canonname = NULL; 787 ai->ai_next = oai; 788 return (ai); 789} 790 791static struct addrinfo * 792ai_reverse(struct addrinfo *oai) { 793 struct addrinfo *nai, *tai; 794 795 nai = NULL; 796 797 while (oai != NULL) { 798 /* 799 * Grab one off the old list. 800 */ 801 tai = oai; 802 oai = oai->ai_next; 803 /* 804 * Put it on the front of the new list. 805 */ 806 tai->ai_next = nai; 807 nai = tai; 808 } 809 return (nai); 810} 811