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