1 /* $NetBSD: getaddrinfo.c,v 1.1 2024/02/18 20:57:47 christos Exp $ */ 2 3 /* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * SPDX-License-Identifier: MPL-2.0 7 * 8 * This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 * 12 * See the COPYRIGHT file distributed with this work for additional 13 * information regarding copyright ownership. 14 */ 15 16 /*! \file */ 17 18 /** 19 * getaddrinfo() is used to get a list of IP addresses and port 20 * numbers for host hostname and service servname as defined in RFC3493. 21 * hostname and servname are pointers to null-terminated strings 22 * or NULL. hostname is either a host name or a numeric host address 23 * string: a dotted decimal IPv4 address or an IPv6 address. servname is 24 * either a decimal port number or a service name as listed in 25 * /etc/services. 26 * 27 * If the operating system does not provide a struct addrinfo, the 28 * following structure is used: 29 * 30 * \code 31 * struct addrinfo { 32 * int ai_flags; // AI_PASSIVE, AI_CANONNAME 33 * int ai_family; // PF_xxx 34 * int ai_socktype; // SOCK_xxx 35 * int ai_protocol; // 0 or IPPROTO_xxx for IPv4 and IPv6 36 * size_t ai_addrlen; // length of ai_addr 37 * char *ai_canonname; // canonical name for hostname 38 * struct sockaddr *ai_addr; // binary address 39 * struct addrinfo *ai_next; // next structure in linked list 40 * }; 41 * \endcode 42 * 43 * 44 * hints is an optional pointer to a struct addrinfo. This structure can 45 * be used to provide hints concerning the type of socket that the caller 46 * supports or wishes to use. The caller can supply the following 47 * structure elements in *hints: 48 * 49 * <ul> 50 * <li>ai_family: 51 * The protocol family that should be used. When ai_family is set 52 * to PF_UNSPEC, it means the caller will accept any protocol 53 * family supported by the operating system.</li> 54 * 55 * <li>ai_socktype: 56 * denotes the type of socket -- SOCK_STREAM, SOCK_DGRAM or 57 * SOCK_RAW -- that is wanted. When ai_socktype is zero the caller 58 * will accept any socket type.</li> 59 * 60 * <li>ai_protocol: 61 * indicates which transport protocol is wanted: IPPROTO_UDP or 62 * IPPROTO_TCP. If ai_protocol is zero the caller will accept any 63 * protocol.</li> 64 * 65 * <li>ai_flags: 66 * Flag bits. If the AI_CANONNAME bit is set, a successful call to 67 * getaddrinfo() will return a null-terminated string 68 * containing the canonical name of the specified hostname in 69 * ai_canonname of the first addrinfo structure returned. Setting 70 * the AI_PASSIVE bit indicates that the returned socket address 71 * structure is intended for used in a call to bind(2). In this 72 * case, if the hostname argument is a NULL pointer, then the IP 73 * address portion of the socket address structure will be set to 74 * INADDR_ANY for an IPv4 address or IN6ADDR_ANY_INIT for an IPv6 75 * address.<br /><br /> 76 * 77 * When ai_flags does not set the AI_PASSIVE bit, the returned 78 * socket address structure will be ready for use in a call to 79 * connect(2) for a connection-oriented protocol or connect(2), 80 * sendto(2), or sendmsg(2) if a connectionless protocol was 81 * chosen. The IP address portion of the socket address structure 82 * will be set to the loopback address if hostname is a NULL 83 * pointer and AI_PASSIVE is not set in ai_flags.<br /><br /> 84 * 85 * If ai_flags is set to AI_NUMERICHOST it indicates that hostname 86 * should be treated as a numeric string defining an IPv4 or IPv6 87 * address and no name resolution should be attempted. 88 * </li></ul> 89 * 90 * All other elements of the struct addrinfo passed via hints must be 91 * zero. 92 * 93 * A hints of NULL is treated as if the caller provided a struct addrinfo 94 * initialized to zero with ai_familyset to PF_UNSPEC. 95 * 96 * After a successful call to getaddrinfo(), *res is a pointer to a 97 * linked list of one or more addrinfo structures. Each struct addrinfo 98 * in this list cn be processed by following the ai_next pointer, until a 99 * NULL pointer is encountered. The three members ai_family, ai_socktype, 100 * and ai_protocol in each returned addrinfo structure contain the 101 * corresponding arguments for a call to socket(2). For each addrinfo 102 * structure in the list, the ai_addr member points to a filled-in socket 103 * address structure of length ai_addrlen. 104 * 105 * All of the information returned by getaddrinfo() is dynamically 106 * allocated: the addrinfo structures, and the socket address structures 107 * and canonical host name strings pointed to by the addrinfostructures. 108 * Memory allocated for the dynamically allocated structures created by a 109 * successful call to getaddrinfo() is released by freeaddrinfo(). 110 * ai is a pointer to a struct addrinfo created by a call to getaddrinfo(). 111 * 112 * \section irsreturn RETURN VALUES 113 * 114 * getaddrinfo() returns zero on success or one of the error codes 115 * listed in gai_strerror() if an error occurs. If both hostname and 116 * servname are NULL getaddrinfo() returns #EAI_NONAME. 117 * 118 * \section irssee SEE ALSO 119 * 120 * getaddrinfo(), freeaddrinfo(), 121 * gai_strerror(), RFC3493, getservbyname(3), connect(2), 122 * sendto(2), sendmsg(2), socket(2). 123 */ 124 125 #include <errno.h> 126 #include <inttypes.h> 127 #include <stdbool.h> 128 #include <stdlib.h> 129 #include <string.h> 130 131 #ifdef _WIN32 132 #include <windows.h> 133 #include <winsock2.h> 134 #include <ws2tcpip.h> 135 #endif /* ifdef _WIN32 */ 136 137 #include <isc/app.h> 138 #include <isc/buffer.h> 139 #include <isc/lib.h> 140 #include <isc/mem.h> 141 #include <isc/mutex.h> 142 #include <isc/print.h> 143 #include <isc/sockaddr.h> 144 #include <isc/string.h> 145 #include <isc/util.h> 146 147 #include <dns/client.h> 148 #include <dns/fixedname.h> 149 #include <dns/name.h> 150 #include <dns/rdata.h> 151 #include <dns/rdataset.h> 152 #include <dns/rdatastruct.h> 153 #include <dns/rdatatype.h> 154 #include <dns/result.h> 155 156 #include <irs/context.h> 157 #include <irs/netdb.h> 158 #include <irs/resconf.h> 159 160 #define SA(addr) ((struct sockaddr *)(addr)) 161 #define SIN(addr) ((struct sockaddr_in *)(addr)) 162 #define SIN6(addr) ((struct sockaddr_in6 *)(addr)) 163 #define SLOCAL(addr) ((struct sockaddr_un *)(addr)) 164 165 /*! \struct addrinfo 166 */ 167 static struct addrinfo * 168 ai_concat(struct addrinfo *ai1, struct addrinfo *ai2), 169 *ai_reverse(struct addrinfo *oai), 170 *ai_clone(struct addrinfo *oai, int family), 171 *ai_alloc(int family, int addrlen); 172 #ifdef AF_LOCAL 173 static int 174 get_local(const char *name, int socktype, struct addrinfo **res); 175 #endif /* ifdef AF_LOCAL */ 176 177 static int 178 resolve_name(int family, const char *hostname, int flags, struct addrinfo **aip, 179 int socktype, int port); 180 181 static int 182 add_ipv4(const char *hostname, int flags, struct addrinfo **aip, int socktype, 183 int port); 184 static int 185 add_ipv6(const char *hostname, int flags, struct addrinfo **aip, int socktype, 186 int port); 187 static void 188 set_order(int, int (**)(const char *, int, struct addrinfo **, int, int)); 189 static void 190 _freeaddrinfo(struct addrinfo *ai); 191 192 #define FOUND_IPV4 0x1 193 #define FOUND_IPV6 0x2 194 #define FOUND_MAX 2 195 196 /*% 197 * Try converting the scope identifier in 'src' to a network interface index. 198 * Upon success, return true and store the resulting index in 'dst'. Upon 199 * failure, return false. 200 */ 201 static bool 202 parse_scopeid(const char *src, uint32_t *dst) { 203 uint32_t scopeid = 0; 204 205 REQUIRE(src != NULL); 206 REQUIRE(dst != NULL); 207 208 #ifdef HAVE_IF_NAMETOINDEX 209 /* 210 * Try using if_nametoindex() first if it is available. As it does not 211 * handle numeric scopes, we do not simply return if it fails. 212 */ 213 scopeid = (uint32_t)if_nametoindex(src); 214 #endif /* ifdef HAVE_IF_NAMETOINDEX */ 215 216 /* 217 * Fall back to numeric scope processing if if_nametoindex() either 218 * fails or is unavailable. 219 */ 220 if (scopeid == 0) { 221 char *endptr = NULL; 222 scopeid = (uint32_t)strtoul(src, &endptr, 10); 223 /* 224 * The scope identifier must not be empty and no trailing 225 * characters are allowed after it. 226 */ 227 if (src == endptr || endptr == NULL || *endptr != '\0') { 228 return (false); 229 } 230 } 231 232 *dst = scopeid; 233 234 return (true); 235 } 236 237 #define ISC_AI_MASK (AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST) 238 /*% 239 * Get a list of IP addresses and port numbers for host hostname and 240 * service servname. 241 */ 242 int 243 getaddrinfo(const char *hostname, const char *servname, 244 const struct addrinfo *hints, struct addrinfo **res) { 245 struct servent *sp; 246 const char *proto; 247 int family, socktype, flags, protocol; 248 struct addrinfo *ai, *ai_list; 249 int err = 0; 250 int port, i; 251 int (*net_order[FOUND_MAX + 1])(const char *, int, struct addrinfo **, 252 int, int); 253 254 if (hostname == NULL && servname == NULL) { 255 return (EAI_NONAME); 256 } 257 258 proto = NULL; 259 if (hints != NULL) { 260 if ((hints->ai_flags & ~(ISC_AI_MASK)) != 0) { 261 return (EAI_BADFLAGS); 262 } 263 if (hints->ai_addrlen || hints->ai_canonname || 264 hints->ai_addr || hints->ai_next) 265 { 266 errno = EINVAL; 267 return (EAI_SYSTEM); 268 } 269 family = hints->ai_family; 270 socktype = hints->ai_socktype; 271 protocol = hints->ai_protocol; 272 flags = hints->ai_flags; 273 switch (family) { 274 case AF_UNSPEC: 275 switch (hints->ai_socktype) { 276 case SOCK_STREAM: 277 proto = "tcp"; 278 break; 279 case SOCK_DGRAM: 280 proto = "udp"; 281 break; 282 } 283 break; 284 case AF_INET: 285 case AF_INET6: 286 switch (hints->ai_socktype) { 287 case 0: 288 break; 289 case SOCK_STREAM: 290 proto = "tcp"; 291 break; 292 case SOCK_DGRAM: 293 proto = "udp"; 294 break; 295 case SOCK_RAW: 296 break; 297 default: 298 return (EAI_SOCKTYPE); 299 } 300 break; 301 #ifdef AF_LOCAL 302 case AF_LOCAL: 303 switch (hints->ai_socktype) { 304 case 0: 305 break; 306 case SOCK_STREAM: 307 break; 308 case SOCK_DGRAM: 309 break; 310 default: 311 return (EAI_SOCKTYPE); 312 } 313 break; 314 #endif /* ifdef AF_LOCAL */ 315 default: 316 return (EAI_FAMILY); 317 } 318 } else { 319 protocol = 0; 320 family = 0; 321 socktype = 0; 322 flags = 0; 323 } 324 325 #ifdef AF_LOCAL 326 /*! 327 * First, deal with AF_LOCAL. If the family was not set, 328 * then assume AF_LOCAL if the first character of the 329 * hostname/servname is '/'. 330 */ 331 332 if (hostname != NULL && 333 (family == AF_LOCAL || (family == 0 && *hostname == '/'))) 334 { 335 return (get_local(hostname, socktype, res)); 336 } 337 338 if (servname != NULL && 339 (family == AF_LOCAL || (family == 0 && *servname == '/'))) 340 { 341 return (get_local(servname, socktype, res)); 342 } 343 #endif /* ifdef AF_LOCAL */ 344 345 /* 346 * Ok, only AF_INET and AF_INET6 left. 347 */ 348 ai_list = NULL; 349 350 /* 351 * First, look up the service name (port) if it was 352 * requested. If the socket type wasn't specified, then 353 * try and figure it out. 354 */ 355 if (servname != NULL) { 356 char *e; 357 358 port = strtol(servname, &e, 10); 359 if (*e == '\0') { 360 if (socktype == 0) { 361 return (EAI_SOCKTYPE); 362 } 363 if (port < 0 || port > 65535) { 364 return (EAI_SERVICE); 365 } 366 port = htons((unsigned short)port); 367 } else { 368 #ifdef _WIN32 369 WORD wVersionRequested; 370 WSADATA wsaData; 371 372 wVersionRequested = MAKEWORD(2, 0); 373 374 err = WSAStartup(wVersionRequested, &wsaData); 375 if (err != 0) { 376 return (EAI_FAIL); 377 } 378 #endif /* ifdef _WIN32 */ 379 sp = getservbyname(servname, proto); 380 if (sp != NULL) { 381 port = sp->s_port; 382 } 383 #ifdef _WIN32 384 WSACleanup(); 385 #endif /* ifdef _WIN32 */ 386 if (sp == NULL) { 387 return (EAI_SERVICE); 388 } 389 if (socktype == 0) { 390 if (strcmp(sp->s_proto, "tcp") == 0) { 391 socktype = SOCK_STREAM; 392 } else if (strcmp(sp->s_proto, "udp") == 0) { 393 socktype = SOCK_DGRAM; 394 } 395 } 396 } 397 } else { 398 port = 0; 399 } 400 401 /* 402 * Next, deal with just a service name, and no hostname. 403 * (we verified that one of them was non-null up above). 404 */ 405 if (hostname == NULL && (flags & AI_PASSIVE) != 0) { 406 if (family == AF_INET || family == 0) { 407 ai = ai_alloc(AF_INET, sizeof(struct sockaddr_in)); 408 if (ai == NULL) { 409 return (EAI_MEMORY); 410 } 411 ai->ai_socktype = socktype; 412 ai->ai_protocol = protocol; 413 SIN(ai->ai_addr)->sin_port = port; 414 ai->ai_next = ai_list; 415 ai_list = ai; 416 } 417 418 if (family == AF_INET6 || family == 0) { 419 ai = ai_alloc(AF_INET6, sizeof(struct sockaddr_in6)); 420 if (ai == NULL) { 421 _freeaddrinfo(ai_list); 422 return (EAI_MEMORY); 423 } 424 ai->ai_socktype = socktype; 425 ai->ai_protocol = protocol; 426 SIN6(ai->ai_addr)->sin6_port = port; 427 ai->ai_next = ai_list; 428 ai_list = ai; 429 } 430 431 *res = ai_list; 432 return (0); 433 } 434 435 /* 436 * If the family isn't specified or AI_NUMERICHOST specified, check 437 * first to see if it is a numeric address. 438 * Though the gethostbyname2() routine will recognize numeric addresses, 439 * it will only recognize the format that it is being called for. Thus, 440 * a numeric AF_INET address will be treated by the AF_INET6 call as 441 * a domain name, and vice versa. Checking for both numerics here 442 * avoids that. 443 */ 444 if (hostname != NULL && (family == 0 || (flags & AI_NUMERICHOST) != 0)) 445 { 446 char abuf[sizeof(struct in6_addr)]; 447 char nbuf[NI_MAXHOST]; 448 int addrsize, addroff; 449 char ntmp[NI_MAXHOST]; 450 uint32_t scopeid = 0; 451 452 /* 453 * Scope identifier portion. 454 */ 455 ntmp[0] = '\0'; 456 if (strchr(hostname, '%') != NULL) { 457 char *p; 458 strlcpy(ntmp, hostname, sizeof(ntmp)); 459 p = strchr(ntmp, '%'); 460 461 if (p != NULL && parse_scopeid(p + 1, &scopeid)) { 462 *p = '\0'; 463 } else { 464 ntmp[0] = '\0'; 465 } 466 } 467 468 if (inet_pton(AF_INET, hostname, (struct in_addr *)abuf) == 1) { 469 if (family == AF_INET6) { 470 /* 471 * Convert to a V4 mapped address. 472 */ 473 struct in6_addr *a6 = (struct in6_addr *)abuf; 474 memmove(&a6->s6_addr[12], &a6->s6_addr[0], 4); 475 memset(&a6->s6_addr[10], 0xff, 2); 476 memset(&a6->s6_addr[0], 0, 10); 477 goto inet6_addr; 478 } 479 addrsize = sizeof(struct in_addr); 480 addroff = offsetof(struct sockaddr_in, sin_addr); 481 family = AF_INET; 482 goto common; 483 } else if (ntmp[0] != '\0' && 484 inet_pton(AF_INET6, ntmp, abuf) == 1) 485 { 486 if (family && family != AF_INET6) { 487 return (EAI_NONAME); 488 } 489 addrsize = sizeof(struct in6_addr); 490 addroff = offsetof(struct sockaddr_in6, sin6_addr); 491 family = AF_INET6; 492 goto common; 493 } else if (inet_pton(AF_INET6, hostname, abuf) == 1) { 494 if (family != 0 && family != AF_INET6) { 495 return (EAI_NONAME); 496 } 497 inet6_addr: 498 addrsize = sizeof(struct in6_addr); 499 addroff = offsetof(struct sockaddr_in6, sin6_addr); 500 family = AF_INET6; 501 502 common: 503 ai = ai_alloc(family, 504 ((family == AF_INET6) 505 ? sizeof(struct sockaddr_in6) 506 : sizeof(struct sockaddr_in))); 507 if (ai == NULL) { 508 return (EAI_MEMORY); 509 } 510 ai_list = ai; 511 ai->ai_socktype = socktype; 512 SIN(ai->ai_addr)->sin_port = port; 513 memmove((char *)ai->ai_addr + addroff, abuf, addrsize); 514 if (ai->ai_family == AF_INET6) { 515 SIN6(ai->ai_addr)->sin6_scope_id = scopeid; 516 } 517 if ((flags & AI_CANONNAME) != 0) { 518 if (getnameinfo(ai->ai_addr, 519 (socklen_t)ai->ai_addrlen, nbuf, 520 sizeof(nbuf), NULL, 0, 521 NI_NUMERICHOST) == 0) 522 { 523 ai->ai_canonname = strdup(nbuf); 524 if (ai->ai_canonname == NULL) { 525 _freeaddrinfo(ai); 526 return (EAI_MEMORY); 527 } 528 } else { 529 /* XXX raise error? */ 530 ai->ai_canonname = NULL; 531 } 532 } 533 goto done; 534 } else if ((flags & AI_NUMERICHOST) != 0) { 535 return (EAI_NONAME); 536 } 537 } 538 539 if (hostname == NULL && (flags & AI_PASSIVE) == 0) { 540 set_order(family, net_order); 541 for (i = 0; i < FOUND_MAX; i++) { 542 if (net_order[i] == NULL) { 543 break; 544 } 545 err = (net_order[i])(hostname, flags, &ai_list, 546 socktype, port); 547 if (err != 0) { 548 if (ai_list != NULL) { 549 _freeaddrinfo(ai_list); 550 ai_list = NULL; 551 } 552 break; 553 } 554 } 555 } else { 556 err = resolve_name(family, hostname, flags, &ai_list, socktype, 557 port); 558 } 559 560 if (ai_list == NULL) { 561 if (err == 0) { 562 err = EAI_NONAME; 563 } 564 return (err); 565 } 566 567 done: 568 ai_list = ai_reverse(ai_list); 569 570 *res = ai_list; 571 return (0); 572 } 573 574 typedef struct gai_restrans { 575 dns_clientrestrans_t *xid; 576 bool is_inprogress; 577 int error; 578 struct addrinfo ai_sentinel; 579 struct gai_resstate *resstate; 580 } gai_restrans_t; 581 582 typedef struct gai_resstate { 583 isc_mem_t *mctx; 584 struct gai_statehead *head; 585 dns_fixedname_t fixedname; 586 dns_name_t *qname; 587 gai_restrans_t *trans4; 588 gai_restrans_t *trans6; 589 ISC_LINK(struct gai_resstate) link; 590 } gai_resstate_t; 591 592 typedef struct gai_statehead { 593 int ai_family; 594 int ai_flags; 595 int ai_socktype; 596 int ai_port; 597 isc_appctx_t *actx; 598 dns_client_t *dnsclient; 599 isc_mutex_t list_lock; 600 ISC_LIST(struct gai_resstate) resstates; 601 unsigned int activestates; 602 } gai_statehead_t; 603 604 static isc_result_t 605 make_resstate(isc_mem_t *mctx, gai_statehead_t *head, const char *hostname, 606 const char *domain, gai_resstate_t **statep) { 607 isc_result_t result; 608 gai_resstate_t *state; 609 dns_fixedname_t fixeddomain; 610 dns_name_t *qdomain; 611 unsigned int namelen; 612 isc_buffer_t b; 613 bool need_v4 = false; 614 bool need_v6 = false; 615 616 state = isc_mem_get(mctx, sizeof(*state)); 617 618 /* Construct base domain name */ 619 namelen = strlen(domain); 620 isc_buffer_constinit(&b, domain, namelen); 621 isc_buffer_add(&b, namelen); 622 qdomain = dns_fixedname_initname(&fixeddomain); 623 result = dns_name_fromtext(qdomain, &b, dns_rootname, 0, NULL); 624 if (result != ISC_R_SUCCESS) { 625 isc_mem_put(mctx, state, sizeof(*state)); 626 return (result); 627 } 628 629 /* Construct query name */ 630 namelen = strlen(hostname); 631 isc_buffer_constinit(&b, hostname, namelen); 632 isc_buffer_add(&b, namelen); 633 state->qname = dns_fixedname_initname(&state->fixedname); 634 result = dns_name_fromtext(state->qname, &b, qdomain, 0, NULL); 635 if (result != ISC_R_SUCCESS) { 636 isc_mem_put(mctx, state, sizeof(*state)); 637 return (result); 638 } 639 640 if (head->ai_family == AF_UNSPEC || head->ai_family == AF_INET) { 641 need_v4 = true; 642 } 643 if (head->ai_family == AF_UNSPEC || head->ai_family == AF_INET6) { 644 need_v6 = true; 645 } 646 647 state->trans6 = NULL; 648 state->trans4 = NULL; 649 if (need_v4) { 650 state->trans4 = isc_mem_get(mctx, sizeof(gai_restrans_t)); 651 state->trans4->error = 0; 652 state->trans4->xid = NULL; 653 state->trans4->resstate = state; 654 state->trans4->is_inprogress = true; 655 state->trans4->ai_sentinel.ai_next = NULL; 656 } 657 if (need_v6) { 658 state->trans6 = isc_mem_get(mctx, sizeof(gai_restrans_t)); 659 state->trans6->error = 0; 660 state->trans6->xid = NULL; 661 state->trans6->resstate = state; 662 state->trans6->is_inprogress = true; 663 state->trans6->ai_sentinel.ai_next = NULL; 664 } 665 666 state->mctx = mctx; 667 state->head = head; 668 ISC_LINK_INIT(state, link); 669 670 *statep = state; 671 672 return (ISC_R_SUCCESS); 673 } 674 675 static isc_result_t 676 make_resstates(isc_mem_t *mctx, const char *hostname, gai_statehead_t *head, 677 irs_resconf_t *resconf) { 678 isc_result_t result; 679 irs_resconf_searchlist_t *searchlist; 680 irs_resconf_search_t *searchent; 681 gai_resstate_t *resstate, *resstate0; 682 683 resstate0 = NULL; 684 result = make_resstate(mctx, head, hostname, ".", &resstate0); 685 if (result != ISC_R_SUCCESS) { 686 return (result); 687 } 688 689 searchlist = irs_resconf_getsearchlist(resconf); 690 for (searchent = ISC_LIST_HEAD(*searchlist); searchent != NULL; 691 searchent = ISC_LIST_NEXT(searchent, link)) 692 { 693 resstate = NULL; 694 result = make_resstate(mctx, head, hostname, 695 (const char *)searchent->domain, 696 &resstate); 697 if (result != ISC_R_SUCCESS) { 698 break; 699 } 700 701 ISC_LIST_APPEND(head->resstates, resstate, link); 702 head->activestates++; 703 } 704 705 /* 706 * Insert the original hostname either at the head or the tail of the 707 * state list, depending on the number of labels contained in the 708 * original name and the 'ndots' configuration parameter. 709 */ 710 if (dns_name_countlabels(resstate0->qname) > 711 irs_resconf_getndots(resconf) + 1) 712 { 713 ISC_LIST_PREPEND(head->resstates, resstate0, link); 714 } else { 715 ISC_LIST_APPEND(head->resstates, resstate0, link); 716 } 717 head->activestates++; 718 719 if (result != ISC_R_SUCCESS) { 720 while ((resstate = ISC_LIST_HEAD(head->resstates)) != NULL) { 721 ISC_LIST_UNLINK(head->resstates, resstate, link); 722 if (resstate->trans4 != NULL) { 723 isc_mem_put(mctx, resstate->trans4, 724 sizeof(*resstate->trans4)); 725 } 726 if (resstate->trans6 != NULL) { 727 isc_mem_put(mctx, resstate->trans6, 728 sizeof(*resstate->trans6)); 729 } 730 731 isc_mem_put(mctx, resstate, sizeof(*resstate)); 732 } 733 } 734 735 return (result); 736 } 737 738 static void 739 process_answer(isc_task_t *task, isc_event_t *event) { 740 int error = 0, family; 741 gai_restrans_t *trans = event->ev_arg; 742 gai_resstate_t *resstate; 743 dns_clientresevent_t *rev = (dns_clientresevent_t *)event; 744 dns_rdatatype_t qtype; 745 dns_name_t *name; 746 bool wantcname; 747 748 REQUIRE(trans != NULL); 749 resstate = trans->resstate; 750 REQUIRE(resstate != NULL); 751 REQUIRE(task != NULL); 752 753 if (trans == resstate->trans4) { 754 family = AF_INET; 755 qtype = dns_rdatatype_a; 756 } else { 757 INSIST(trans == resstate->trans6); 758 family = AF_INET6; 759 qtype = dns_rdatatype_aaaa; 760 } 761 762 INSIST(trans->is_inprogress); 763 trans->is_inprogress = false; 764 765 switch (rev->result) { 766 case ISC_R_SUCCESS: 767 case DNS_R_NCACHENXDOMAIN: /* treat this as a fatal error? */ 768 case DNS_R_NCACHENXRRSET: 769 break; 770 default: 771 switch (rev->vresult) { 772 case DNS_R_SIGINVALID: 773 case DNS_R_SIGEXPIRED: 774 case DNS_R_SIGFUTURE: 775 case DNS_R_KEYUNAUTHORIZED: 776 case DNS_R_MUSTBESECURE: 777 case DNS_R_COVERINGNSEC: 778 case DNS_R_NOTAUTHORITATIVE: 779 case DNS_R_NOVALIDKEY: 780 case DNS_R_NOVALIDDS: 781 case DNS_R_NOVALIDSIG: 782 error = EAI_INSECUREDATA; 783 break; 784 default: 785 error = EAI_FAIL; 786 } 787 goto done; 788 } 789 790 wantcname = ((resstate->head->ai_flags & AI_CANONNAME) != 0); 791 792 /* Parse the response and construct the addrinfo chain */ 793 for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL; 794 name = ISC_LIST_NEXT(name, link)) 795 { 796 isc_result_t result; 797 dns_rdataset_t *rdataset; 798 char cname[1024]; 799 800 if (wantcname) { 801 isc_buffer_t b; 802 803 isc_buffer_init(&b, cname, sizeof(cname)); 804 result = dns_name_totext(name, true, &b); 805 if (result != ISC_R_SUCCESS) { 806 error = EAI_FAIL; 807 goto done; 808 } 809 isc_buffer_putuint8(&b, '\0'); 810 } 811 812 for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; 813 rdataset = ISC_LIST_NEXT(rdataset, link)) 814 { 815 if (!dns_rdataset_isassociated(rdataset)) { 816 continue; 817 } 818 if (rdataset->type != qtype) { 819 continue; 820 } 821 822 for (result = dns_rdataset_first(rdataset); 823 result == ISC_R_SUCCESS; 824 result = dns_rdataset_next(rdataset)) 825 { 826 struct addrinfo *ai; 827 dns_rdata_t rdata; 828 dns_rdata_in_a_t rdata_a; 829 dns_rdata_in_aaaa_t rdata_aaaa; 830 831 ai = ai_alloc( 832 family, 833 ((family == AF_INET6) 834 ? sizeof(struct sockaddr_in6) 835 : sizeof(struct sockaddr_in))); 836 if (ai == NULL) { 837 error = EAI_MEMORY; 838 goto done; 839 } 840 ai->ai_socktype = resstate->head->ai_socktype; 841 ai->ai_next = trans->ai_sentinel.ai_next; 842 trans->ai_sentinel.ai_next = ai; 843 844 /* 845 * Set AF-specific parameters 846 * (IPv4/v6 address/port) 847 */ 848 dns_rdata_init(&rdata); 849 switch (family) { 850 case AF_INET: 851 dns_rdataset_current(rdataset, &rdata); 852 result = dns_rdata_tostruct( 853 &rdata, &rdata_a, NULL); 854 RUNTIME_CHECK(result == ISC_R_SUCCESS); 855 SIN(ai->ai_addr)->sin_port = 856 resstate->head->ai_port; 857 memmove(&SIN(ai->ai_addr)->sin_addr, 858 &rdata_a.in_addr, 4); 859 dns_rdata_freestruct(&rdata_a); 860 break; 861 case AF_INET6: 862 dns_rdataset_current(rdataset, &rdata); 863 result = dns_rdata_tostruct( 864 &rdata, &rdata_aaaa, NULL); 865 RUNTIME_CHECK(result == ISC_R_SUCCESS); 866 SIN6(ai->ai_addr)->sin6_port = 867 resstate->head->ai_port; 868 memmove(&SIN6(ai->ai_addr)->sin6_addr, 869 &rdata_aaaa.in6_addr, 16); 870 dns_rdata_freestruct(&rdata_aaaa); 871 break; 872 } 873 874 if (wantcname) { 875 ai->ai_canonname = strdup(cname); 876 if (ai->ai_canonname == NULL) { 877 error = EAI_MEMORY; 878 goto done; 879 } 880 } 881 } 882 } 883 } 884 885 done: 886 dns_client_freeresanswer(resstate->head->dnsclient, &rev->answerlist); 887 dns_client_destroyrestrans(&trans->xid); 888 889 isc_event_free(&event); 890 891 /* Make sure that error == 0 iff we have a non-empty list */ 892 if (error == 0) { 893 if (trans->ai_sentinel.ai_next == NULL) { 894 error = EAI_NONAME; 895 } 896 } else { 897 if (trans->ai_sentinel.ai_next != NULL) { 898 _freeaddrinfo(trans->ai_sentinel.ai_next); 899 trans->ai_sentinel.ai_next = NULL; 900 } 901 } 902 trans->error = error; 903 904 /* Check whether we are done */ 905 if ((resstate->trans4 == NULL || !resstate->trans4->is_inprogress) && 906 (resstate->trans6 == NULL || !resstate->trans6->is_inprogress)) 907 { 908 /* 909 * We're done for this state. If there is no other outstanding 910 * state, we can exit. 911 */ 912 resstate->head->activestates--; 913 if (resstate->head->activestates == 0) { 914 isc_app_ctxsuspend(resstate->head->actx); 915 return; 916 } 917 918 /* 919 * There are outstanding states, but if we are at the head 920 * of the state list (i.e., at the highest search priority) 921 * and have any answer, we can stop now by canceling the 922 * others. 923 */ 924 LOCK(&resstate->head->list_lock); 925 if (resstate == ISC_LIST_HEAD(resstate->head->resstates)) { 926 if ((resstate->trans4 != NULL && 927 resstate->trans4->ai_sentinel.ai_next != NULL) || 928 (resstate->trans6 != NULL && 929 resstate->trans6->ai_sentinel.ai_next != NULL)) 930 { 931 gai_resstate_t *rest; 932 933 for (rest = ISC_LIST_NEXT(resstate, link); 934 rest != NULL; 935 rest = ISC_LIST_NEXT(rest, link)) 936 { 937 if (rest->trans4 != NULL && 938 rest->trans4->xid != NULL) 939 { 940 dns_client_cancelresolve( 941 rest->trans4->xid); 942 } 943 if (rest->trans6 != NULL && 944 rest->trans6->xid != NULL) 945 { 946 dns_client_cancelresolve( 947 rest->trans6->xid); 948 } 949 } 950 } else { 951 /* 952 * This search fails, so we move to the tail 953 * of the list so that the next entry will 954 * have the highest priority. 955 */ 956 ISC_LIST_UNLINK(resstate->head->resstates, 957 resstate, link); 958 ISC_LIST_APPEND(resstate->head->resstates, 959 resstate, link); 960 } 961 } 962 UNLOCK(&resstate->head->list_lock); 963 } 964 } 965 966 static int 967 resolve_name(int family, const char *hostname, int flags, struct addrinfo **aip, 968 int socktype, int port) { 969 isc_result_t result; 970 irs_context_t *irsctx; 971 irs_resconf_t *conf; 972 isc_mem_t *mctx; 973 isc_appctx_t *actx; 974 isc_task_t *task; 975 int terror = 0; 976 int error = 0; 977 dns_client_t *client; 978 gai_resstate_t *resstate; 979 gai_statehead_t head; 980 bool all_fail = true; 981 982 /* get IRS context and the associated parameters */ 983 irsctx = NULL; 984 result = irs_context_get(&irsctx); 985 if (result != ISC_R_SUCCESS) { 986 return (EAI_FAIL); 987 } 988 actx = irs_context_getappctx(irsctx); 989 990 mctx = irs_context_getmctx(irsctx); 991 task = irs_context_gettask(irsctx); 992 conf = irs_context_getresconf(irsctx); 993 client = irs_context_getdnsclient(irsctx); 994 995 /* construct resolution states */ 996 head.activestates = 0; 997 head.ai_family = family; 998 head.ai_socktype = socktype; 999 head.ai_flags = flags; 1000 head.ai_port = port; 1001 head.actx = actx; 1002 head.dnsclient = client; 1003 isc_mutex_init(&head.list_lock); 1004 1005 ISC_LIST_INIT(head.resstates); 1006 result = make_resstates(mctx, hostname, &head, conf); 1007 if (result != ISC_R_SUCCESS) { 1008 isc_mutex_destroy(&head.list_lock); 1009 return (EAI_FAIL); 1010 } 1011 1012 LOCK(&head.list_lock); 1013 for (resstate = ISC_LIST_HEAD(head.resstates); resstate != NULL; 1014 resstate = ISC_LIST_NEXT(resstate, link)) 1015 { 1016 if (resstate->trans4 != NULL) { 1017 result = dns_client_startresolve( 1018 client, resstate->qname, dns_rdataclass_in, 1019 dns_rdatatype_a, 0, task, process_answer, 1020 resstate->trans4, &resstate->trans4->xid); 1021 if (result == ISC_R_SUCCESS) { 1022 resstate->trans4->is_inprogress = true; 1023 all_fail = false; 1024 } else { 1025 resstate->trans4->is_inprogress = false; 1026 } 1027 } 1028 if (resstate->trans6 != NULL) { 1029 result = dns_client_startresolve( 1030 client, resstate->qname, dns_rdataclass_in, 1031 dns_rdatatype_aaaa, 0, task, process_answer, 1032 resstate->trans6, &resstate->trans6->xid); 1033 if (result == ISC_R_SUCCESS) { 1034 resstate->trans6->is_inprogress = true; 1035 all_fail = false; 1036 } else { 1037 resstate->trans6->is_inprogress = false; 1038 } 1039 } 1040 } 1041 UNLOCK(&head.list_lock); 1042 1043 if (!all_fail) { 1044 /* Start all the events */ 1045 isc_app_ctxrun(actx); 1046 } else { 1047 error = EAI_FAIL; 1048 } 1049 1050 /* Cleanup */ 1051 while ((resstate = ISC_LIST_HEAD(head.resstates)) != NULL) { 1052 int terror4 = 0, terror6 = 0; 1053 1054 ISC_LIST_UNLINK(head.resstates, resstate, link); 1055 1056 if (*aip == NULL) { 1057 struct addrinfo *sentinel4 = NULL; 1058 struct addrinfo *sentinel6 = NULL; 1059 1060 if (resstate->trans4 != NULL) { 1061 sentinel4 = 1062 resstate->trans4->ai_sentinel.ai_next; 1063 resstate->trans4->ai_sentinel.ai_next = NULL; 1064 } 1065 if (resstate->trans6 != NULL) { 1066 sentinel6 = 1067 resstate->trans6->ai_sentinel.ai_next; 1068 resstate->trans6->ai_sentinel.ai_next = NULL; 1069 } 1070 *aip = ai_concat(sentinel4, sentinel6); 1071 } 1072 1073 if (resstate->trans4 != NULL) { 1074 INSIST(resstate->trans4->xid == NULL); 1075 terror4 = resstate->trans4->error; 1076 isc_mem_put(mctx, resstate->trans4, 1077 sizeof(*resstate->trans4)); 1078 } 1079 if (resstate->trans6 != NULL) { 1080 INSIST(resstate->trans6->xid == NULL); 1081 terror6 = resstate->trans6->error; 1082 isc_mem_put(mctx, resstate->trans6, 1083 sizeof(*resstate->trans6)); 1084 } 1085 1086 /* 1087 * If the entire lookup fails, we need to choose an appropriate 1088 * error code from individual codes. We'll try to provide as 1089 * specific a code as possible. In general, we are going to 1090 * find an error code other than EAI_NONAME (which is too 1091 * generic and may actually not be problematic in some cases). 1092 * EAI_NONAME will be set below if no better code is found. 1093 */ 1094 if (terror == 0 || terror == EAI_NONAME) { 1095 if (terror4 != 0 && terror4 != EAI_NONAME) { 1096 terror = terror4; 1097 } else if (terror6 != 0 && terror6 != EAI_NONAME) { 1098 terror = terror6; 1099 } 1100 } 1101 1102 isc_mem_put(mctx, resstate, sizeof(*resstate)); 1103 } 1104 1105 if (*aip == NULL) { 1106 error = terror; 1107 if (error == 0) { 1108 error = EAI_NONAME; 1109 } 1110 } 1111 1112 #if 1 /* XXX: enabled for finding leaks. should be cleaned up later. */ 1113 isc_app_ctxfinish(actx); 1114 irs_context_destroy(&irsctx); 1115 #endif /* if 1 */ 1116 1117 isc_mutex_destroy(&head.list_lock); 1118 return (error); 1119 } 1120 1121 static void 1122 set_order(int family, 1123 int (**net_order)(const char *, int, struct addrinfo **, int, int)) { 1124 char *order, *tok, *last; 1125 int found; 1126 1127 if (family) { 1128 switch (family) { 1129 case AF_INET: 1130 *net_order++ = add_ipv4; 1131 break; 1132 case AF_INET6: 1133 *net_order++ = add_ipv6; 1134 break; 1135 } 1136 } else { 1137 order = getenv("NET_ORDER"); 1138 found = 0; 1139 if (order != NULL) { 1140 last = NULL; 1141 for (tok = strtok_r(order, ":", &last); tok; 1142 tok = strtok_r(NULL, ":", &last)) 1143 { 1144 if (strcasecmp(tok, "inet6") == 0) { 1145 if ((found & FOUND_IPV6) == 0) { 1146 *net_order++ = add_ipv6; 1147 } 1148 found |= FOUND_IPV6; 1149 } else if (strcasecmp(tok, "inet") == 0 || 1150 strcasecmp(tok, "inet4") == 0) 1151 { 1152 if ((found & FOUND_IPV4) == 0) { 1153 *net_order++ = add_ipv4; 1154 } 1155 found |= FOUND_IPV4; 1156 } 1157 } 1158 } 1159 1160 /* 1161 * Add in anything that we didn't find. 1162 */ 1163 if ((found & FOUND_IPV4) == 0) { 1164 *net_order++ = add_ipv4; 1165 } 1166 if ((found & FOUND_IPV6) == 0) { 1167 *net_order++ = add_ipv6; 1168 } 1169 } 1170 *net_order = NULL; 1171 return; 1172 } 1173 1174 static char v4_loop[4] = { 127, 0, 0, 1 }; 1175 1176 static int 1177 add_ipv4(const char *hostname, int flags, struct addrinfo **aip, int socktype, 1178 int port) { 1179 struct addrinfo *ai; 1180 1181 UNUSED(hostname); 1182 UNUSED(flags); 1183 1184 ai = ai_clone(*aip, AF_INET); /* don't use ai_clone() */ 1185 if (ai == NULL) { 1186 return (EAI_MEMORY); 1187 } 1188 1189 *aip = ai; 1190 ai->ai_socktype = socktype; 1191 SIN(ai->ai_addr)->sin_port = port; 1192 memmove(&SIN(ai->ai_addr)->sin_addr, v4_loop, 4); 1193 1194 return (0); 1195 } 1196 1197 static char v6_loop[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; 1198 1199 static int 1200 add_ipv6(const char *hostname, int flags, struct addrinfo **aip, int socktype, 1201 int port) { 1202 struct addrinfo *ai; 1203 1204 UNUSED(hostname); 1205 UNUSED(flags); 1206 1207 ai = ai_clone(*aip, AF_INET6); /* don't use ai_clone() */ 1208 if (ai == NULL) { 1209 return (EAI_MEMORY); 1210 } 1211 1212 *aip = ai; 1213 ai->ai_socktype = socktype; 1214 SIN6(ai->ai_addr)->sin6_port = port; 1215 memmove(&SIN6(ai->ai_addr)->sin6_addr, v6_loop, 16); 1216 1217 return (0); 1218 } 1219 1220 /*% Free address info. */ 1221 void 1222 freeaddrinfo(struct addrinfo *ai) { 1223 _freeaddrinfo(ai); 1224 } 1225 1226 static void 1227 _freeaddrinfo(struct addrinfo *ai) { 1228 struct addrinfo *ai_next; 1229 1230 while (ai != NULL) { 1231 ai_next = ai->ai_next; 1232 if (ai->ai_addr != NULL) { 1233 free(ai->ai_addr); 1234 } 1235 if (ai->ai_canonname) { 1236 free(ai->ai_canonname); 1237 } 1238 free(ai); 1239 ai = ai_next; 1240 } 1241 } 1242 1243 #ifdef AF_LOCAL 1244 static int 1245 get_local(const char *name, int socktype, struct addrinfo **res) { 1246 struct addrinfo *ai; 1247 struct sockaddr_un *slocal; 1248 1249 if (socktype == 0) { 1250 return (EAI_SOCKTYPE); 1251 } 1252 1253 ai = ai_alloc(AF_LOCAL, sizeof(*slocal)); 1254 if (ai == NULL) { 1255 return (EAI_MEMORY); 1256 } 1257 1258 slocal = SLOCAL(ai->ai_addr); 1259 strlcpy(slocal->sun_path, name, sizeof(slocal->sun_path)); 1260 1261 ai->ai_socktype = socktype; 1262 /* 1263 * ai->ai_flags, ai->ai_protocol, ai->ai_canonname, 1264 * and ai->ai_next were initialized to zero. 1265 */ 1266 1267 *res = ai; 1268 return (0); 1269 } 1270 #endif /* ifdef AF_LOCAL */ 1271 1272 /*! 1273 * Allocate an addrinfo structure, and a sockaddr structure 1274 * of the specified length. We initialize: 1275 * ai_addrlen 1276 * ai_family 1277 * ai_addr 1278 * ai_addr->sa_family 1279 * ai_addr->sa_len (IRS_PLATFORM_HAVESALEN) 1280 * and everything else is initialized to zero. 1281 */ 1282 static struct addrinfo * 1283 ai_alloc(int family, int addrlen) { 1284 struct addrinfo *ai; 1285 1286 ai = (struct addrinfo *)calloc(1, sizeof(*ai)); 1287 if (ai == NULL) { 1288 return (NULL); 1289 } 1290 1291 ai->ai_addr = SA(calloc(1, addrlen)); 1292 if (ai->ai_addr == NULL) { 1293 free(ai); 1294 return (NULL); 1295 } 1296 ai->ai_addrlen = addrlen; 1297 ai->ai_family = family; 1298 ai->ai_addr->sa_family = family; 1299 #ifdef IRS_PLATFORM_HAVESALEN 1300 ai->ai_addr->sa_len = addrlen; 1301 #endif /* ifdef IRS_PLATFORM_HAVESALEN */ 1302 return (ai); 1303 } 1304 1305 static struct addrinfo * 1306 ai_clone(struct addrinfo *oai, int family) { 1307 struct addrinfo *ai; 1308 1309 ai = ai_alloc(family, 1310 ((family == AF_INET6) ? sizeof(struct sockaddr_in6) 1311 : sizeof(struct sockaddr_in))); 1312 1313 if (ai == NULL) { 1314 return (NULL); 1315 } 1316 if (oai == NULL) { 1317 return (ai); 1318 } 1319 1320 ai->ai_flags = oai->ai_flags; 1321 ai->ai_socktype = oai->ai_socktype; 1322 ai->ai_protocol = oai->ai_protocol; 1323 ai->ai_canonname = NULL; 1324 ai->ai_next = oai; 1325 return (ai); 1326 } 1327 1328 static struct addrinfo * 1329 ai_reverse(struct addrinfo *oai) { 1330 struct addrinfo *nai, *tai; 1331 1332 nai = NULL; 1333 1334 while (oai != NULL) { 1335 /* 1336 * Grab one off the old list. 1337 */ 1338 tai = oai; 1339 oai = oai->ai_next; 1340 /* 1341 * Put it on the front of the new list. 1342 */ 1343 tai->ai_next = nai; 1344 nai = tai; 1345 } 1346 return (nai); 1347 } 1348 1349 static struct addrinfo * 1350 ai_concat(struct addrinfo *ai1, struct addrinfo *ai2) { 1351 struct addrinfo *ai_tmp; 1352 1353 if (ai1 == NULL) { 1354 return (ai2); 1355 } else if (ai2 == NULL) { 1356 return (ai1); 1357 } 1358 1359 for (ai_tmp = ai1; ai_tmp != NULL && ai_tmp->ai_next != NULL; 1360 ai_tmp = ai_tmp->ai_next) 1361 { 1362 } 1363 1364 ai_tmp->ai_next = ai2; 1365 1366 return (ai1); 1367 } 1368