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