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