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