1224090Sdougb/* 2262706Serwin * Copyright (C) 2009, 2012-2014 Internet Systems Consortium, Inc. ("ISC") 3224090Sdougb * 4224090Sdougb * Permission to use, copy, modify, and/or distribute this software for any 5224090Sdougb * purpose with or without fee is hereby granted, provided that the above 6224090Sdougb * copyright notice and this permission notice appear in all copies. 7224090Sdougb * 8224090Sdougb * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 9224090Sdougb * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10224090Sdougb * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 11224090Sdougb * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12224090Sdougb * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13224090Sdougb * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14224090Sdougb * PERFORMANCE OF THIS SOFTWARE. 15224090Sdougb */ 16224090Sdougb 17234010Sdougb/* $Id: getaddrinfo.c,v 1.3 2009/09/02 23:48:02 tbox Exp $ */ 18224090Sdougb 19224090Sdougb/*! \file */ 20224090Sdougb 21224090Sdougb/** 22224090Sdougb * getaddrinfo() is used to get a list of IP addresses and port 23224090Sdougb * numbers for host hostname and service servname as defined in RFC3493. 24224090Sdougb * hostname and servname are pointers to null-terminated strings 25224090Sdougb * or NULL. hostname is either a host name or a numeric host address 26224090Sdougb * string: a dotted decimal IPv4 address or an IPv6 address. servname is 27224090Sdougb * either a decimal port number or a service name as listed in 28224090Sdougb * /etc/services. 29224090Sdougb * 30224090Sdougb * If the operating system does not provide a struct addrinfo, the 31224090Sdougb * following structure is used: 32224090Sdougb * 33224090Sdougb * \code 34224090Sdougb * struct addrinfo { 35224090Sdougb * int ai_flags; // AI_PASSIVE, AI_CANONNAME 36224090Sdougb * int ai_family; // PF_xxx 37224090Sdougb * int ai_socktype; // SOCK_xxx 38224090Sdougb * int ai_protocol; // 0 or IPPROTO_xxx for IPv4 and IPv6 39224090Sdougb * size_t ai_addrlen; // length of ai_addr 40224090Sdougb * char *ai_canonname; // canonical name for hostname 41224090Sdougb * struct sockaddr *ai_addr; // binary address 42224090Sdougb * struct addrinfo *ai_next; // next structure in linked list 43224090Sdougb * }; 44224090Sdougb * \endcode 45224090Sdougb * 46224090Sdougb * 47224090Sdougb * hints is an optional pointer to a struct addrinfo. This structure can 48224090Sdougb * be used to provide hints concerning the type of socket that the caller 49224090Sdougb * supports or wishes to use. The caller can supply the following 50224090Sdougb * structure elements in *hints: 51224090Sdougb * 52224090Sdougb * <ul> 53224090Sdougb * <li>ai_family: 54224090Sdougb * The protocol family that should be used. When ai_family is set 55224090Sdougb * to PF_UNSPEC, it means the caller will accept any protocol 56224090Sdougb * family supported by the operating system.</li> 57224090Sdougb * 58224090Sdougb * <li>ai_socktype: 59224090Sdougb * denotes the type of socket -- SOCK_STREAM, SOCK_DGRAM or 60224090Sdougb * SOCK_RAW -- that is wanted. When ai_socktype is zero the caller 61224090Sdougb * will accept any socket type.</li> 62224090Sdougb * 63224090Sdougb * <li>ai_protocol: 64224090Sdougb * indicates which transport protocol is wanted: IPPROTO_UDP or 65224090Sdougb * IPPROTO_TCP. If ai_protocol is zero the caller will accept any 66224090Sdougb * protocol.</li> 67224090Sdougb * 68224090Sdougb * <li>ai_flags: 69224090Sdougb * Flag bits. If the AI_CANONNAME bit is set, a successful call to 70224090Sdougb * getaddrinfo() will return a null-terminated string 71224090Sdougb * containing the canonical name of the specified hostname in 72224090Sdougb * ai_canonname of the first addrinfo structure returned. Setting 73224090Sdougb * the AI_PASSIVE bit indicates that the returned socket address 74224090Sdougb * structure is intended for used in a call to bind(2). In this 75224090Sdougb * case, if the hostname argument is a NULL pointer, then the IP 76224090Sdougb * address portion of the socket address structure will be set to 77224090Sdougb * INADDR_ANY for an IPv4 address or IN6ADDR_ANY_INIT for an IPv6 78224090Sdougb * address.<br /><br /> 79224090Sdougb * 80224090Sdougb * When ai_flags does not set the AI_PASSIVE bit, the returned 81224090Sdougb * socket address structure will be ready for use in a call to 82224090Sdougb * connect(2) for a connection-oriented protocol or connect(2), 83224090Sdougb * sendto(2), or sendmsg(2) if a connectionless protocol was 84224090Sdougb * chosen. The IP address portion of the socket address structure 85224090Sdougb * will be set to the loopback address if hostname is a NULL 86224090Sdougb * pointer and AI_PASSIVE is not set in ai_flags.<br /><br /> 87224090Sdougb * 88224090Sdougb * If ai_flags is set to AI_NUMERICHOST it indicates that hostname 89224090Sdougb * should be treated as a numeric string defining an IPv4 or IPv6 90224090Sdougb * address and no name resolution should be attempted. 91224090Sdougb * </li></ul> 92224090Sdougb * 93224090Sdougb * All other elements of the struct addrinfo passed via hints must be 94224090Sdougb * zero. 95224090Sdougb * 96224090Sdougb * A hints of NULL is treated as if the caller provided a struct addrinfo 97224090Sdougb * initialized to zero with ai_familyset to PF_UNSPEC. 98224090Sdougb * 99224090Sdougb * After a successful call to getaddrinfo(), *res is a pointer to a 100224090Sdougb * linked list of one or more addrinfo structures. Each struct addrinfo 101224090Sdougb * in this list cn be processed by following the ai_next pointer, until a 102224090Sdougb * NULL pointer is encountered. The three members ai_family, ai_socktype, 103224090Sdougb * and ai_protocol in each returned addrinfo structure contain the 104224090Sdougb * corresponding arguments for a call to socket(2). For each addrinfo 105224090Sdougb * structure in the list, the ai_addr member points to a filled-in socket 106224090Sdougb * address structure of length ai_addrlen. 107224090Sdougb * 108224090Sdougb * All of the information returned by getaddrinfo() is dynamically 109224090Sdougb * allocated: the addrinfo structures, and the socket address structures 110224090Sdougb * and canonical host name strings pointed to by the addrinfostructures. 111224090Sdougb * Memory allocated for the dynamically allocated structures created by a 112224090Sdougb * successful call to getaddrinfo() is released by freeaddrinfo(). 113224090Sdougb * ai is a pointer to a struct addrinfo created by a call to getaddrinfo(). 114224090Sdougb * 115224090Sdougb * \section irsreturn RETURN VALUES 116224090Sdougb * 117224090Sdougb * getaddrinfo() returns zero on success or one of the error codes 118224090Sdougb * listed in gai_strerror() if an error occurs. If both hostname and 119224090Sdougb * servname are NULL getaddrinfo() returns #EAI_NONAME. 120224090Sdougb * 121224090Sdougb * \section irssee SEE ALSO 122224090Sdougb * 123224090Sdougb * getaddrinfo(), freeaddrinfo(), 124224090Sdougb * gai_strerror(), RFC3493, getservbyname(3), connect(2), 125224090Sdougb * sendto(2), sendmsg(2), socket(2). 126224090Sdougb */ 127224090Sdougb 128224090Sdougb#include <config.h> 129224090Sdougb 130224090Sdougb#include <stdlib.h> 131224090Sdougb#include <string.h> 132224090Sdougb#include <errno.h> 133224090Sdougb 134224090Sdougb#include <isc/app.h> 135224090Sdougb#include <isc/buffer.h> 136224090Sdougb#include <isc/lib.h> 137224090Sdougb#include <isc/mem.h> 138224090Sdougb#include <isc/sockaddr.h> 139254402Serwin#include <isc/string.h> 140224090Sdougb#include <isc/util.h> 141224090Sdougb 142224090Sdougb#include <dns/client.h> 143224090Sdougb#include <dns/fixedname.h> 144224090Sdougb#include <dns/name.h> 145224090Sdougb#include <dns/rdata.h> 146224090Sdougb#include <dns/rdataset.h> 147224090Sdougb#include <dns/rdatastruct.h> 148224090Sdougb#include <dns/rdatatype.h> 149224090Sdougb#include <dns/result.h> 150224090Sdougb 151224090Sdougb#include <irs/context.h> 152224090Sdougb#include <irs/netdb.h> 153224090Sdougb#include <irs/resconf.h> 154224090Sdougb 155224090Sdougb#define SA(addr) ((struct sockaddr *)(addr)) 156224090Sdougb#define SIN(addr) ((struct sockaddr_in *)(addr)) 157224090Sdougb#define SIN6(addr) ((struct sockaddr_in6 *)(addr)) 158224090Sdougb#define SLOCAL(addr) ((struct sockaddr_un *)(addr)) 159224090Sdougb 160224090Sdougb/*! \struct addrinfo 161224090Sdougb */ 162224090Sdougbstatic struct addrinfo 163224090Sdougb *ai_concat(struct addrinfo *ai1, struct addrinfo *ai2), 164224090Sdougb *ai_reverse(struct addrinfo *oai), 165224090Sdougb *ai_clone(struct addrinfo *oai, int family), 166224090Sdougb *ai_alloc(int family, int addrlen); 167224090Sdougb#ifdef AF_LOCAL 168224090Sdougbstatic int get_local(const char *name, int socktype, struct addrinfo **res); 169224090Sdougb#endif 170224090Sdougb 171224090Sdougbstatic int 172224090Sdougbresolve_name(int family, const char *hostname, int flags, 173224090Sdougb struct addrinfo **aip, int socktype, int port); 174224090Sdougb 175224090Sdougbstatic int add_ipv4(const char *hostname, int flags, struct addrinfo **aip, 176224090Sdougb int socktype, int port); 177224090Sdougbstatic int add_ipv6(const char *hostname, int flags, struct addrinfo **aip, 178224090Sdougb int socktype, int port); 179224090Sdougbstatic void set_order(int, int (**)(const char *, int, struct addrinfo **, 180224090Sdougb int, int)); 181224090Sdougb 182224090Sdougb#define FOUND_IPV4 0x1 183224090Sdougb#define FOUND_IPV6 0x2 184224090Sdougb#define FOUND_MAX 2 185224090Sdougb 186224090Sdougb#define ISC_AI_MASK (AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST) 187224090Sdougb/*% 188224090Sdougb * Get a list of IP addresses and port numbers for host hostname and 189224090Sdougb * service servname. 190224090Sdougb */ 191224090Sdougbint 192224090Sdougbgetaddrinfo(const char *hostname, const char *servname, 193224090Sdougb const struct addrinfo *hints, struct addrinfo **res) 194224090Sdougb{ 195224090Sdougb struct servent *sp; 196224090Sdougb const char *proto; 197224090Sdougb int family, socktype, flags, protocol; 198224090Sdougb struct addrinfo *ai, *ai_list; 199224090Sdougb int err = 0; 200224090Sdougb int port, i; 201224090Sdougb int (*net_order[FOUND_MAX+1])(const char *, int, struct addrinfo **, 202224090Sdougb int, int); 203224090Sdougb 204224090Sdougb if (hostname == NULL && servname == NULL) 205224090Sdougb return (EAI_NONAME); 206224090Sdougb 207224090Sdougb proto = NULL; 208224090Sdougb if (hints != NULL) { 209224090Sdougb if ((hints->ai_flags & ~(ISC_AI_MASK)) != 0) 210224090Sdougb return (EAI_BADFLAGS); 211224090Sdougb if (hints->ai_addrlen || hints->ai_canonname || 212224090Sdougb hints->ai_addr || hints->ai_next) { 213224090Sdougb errno = EINVAL; 214224090Sdougb return (EAI_SYSTEM); 215224090Sdougb } 216224090Sdougb family = hints->ai_family; 217224090Sdougb socktype = hints->ai_socktype; 218224090Sdougb protocol = hints->ai_protocol; 219224090Sdougb flags = hints->ai_flags; 220224090Sdougb switch (family) { 221224090Sdougb case AF_UNSPEC: 222224090Sdougb switch (hints->ai_socktype) { 223224090Sdougb case SOCK_STREAM: 224224090Sdougb proto = "tcp"; 225224090Sdougb break; 226224090Sdougb case SOCK_DGRAM: 227224090Sdougb proto = "udp"; 228224090Sdougb break; 229224090Sdougb } 230224090Sdougb break; 231224090Sdougb case AF_INET: 232224090Sdougb case AF_INET6: 233224090Sdougb switch (hints->ai_socktype) { 234224090Sdougb case 0: 235224090Sdougb break; 236224090Sdougb case SOCK_STREAM: 237224090Sdougb proto = "tcp"; 238224090Sdougb break; 239224090Sdougb case SOCK_DGRAM: 240224090Sdougb proto = "udp"; 241224090Sdougb break; 242224090Sdougb case SOCK_RAW: 243224090Sdougb break; 244224090Sdougb default: 245224090Sdougb return (EAI_SOCKTYPE); 246224090Sdougb } 247224090Sdougb break; 248224090Sdougb#ifdef AF_LOCAL 249224090Sdougb case AF_LOCAL: 250224090Sdougb switch (hints->ai_socktype) { 251224090Sdougb case 0: 252224090Sdougb break; 253224090Sdougb case SOCK_STREAM: 254224090Sdougb break; 255224090Sdougb case SOCK_DGRAM: 256224090Sdougb break; 257224090Sdougb default: 258224090Sdougb return (EAI_SOCKTYPE); 259224090Sdougb } 260224090Sdougb break; 261224090Sdougb#endif 262224090Sdougb default: 263224090Sdougb return (EAI_FAMILY); 264224090Sdougb } 265224090Sdougb } else { 266224090Sdougb protocol = 0; 267224090Sdougb family = 0; 268224090Sdougb socktype = 0; 269224090Sdougb flags = 0; 270224090Sdougb } 271224090Sdougb 272224090Sdougb#ifdef AF_LOCAL 273224090Sdougb /*! 274224090Sdougb * First, deal with AF_LOCAL. If the family was not set, 275224090Sdougb * then assume AF_LOCAL if the first character of the 276224090Sdougb * hostname/servname is '/'. 277224090Sdougb */ 278224090Sdougb 279224090Sdougb if (hostname != NULL && 280224090Sdougb (family == AF_LOCAL || (family == 0 && *hostname == '/'))) 281224090Sdougb return (get_local(hostname, socktype, res)); 282224090Sdougb 283224090Sdougb if (servname != NULL && 284224090Sdougb (family == AF_LOCAL || (family == 0 && *servname == '/'))) 285224090Sdougb return (get_local(servname, socktype, res)); 286224090Sdougb#endif 287224090Sdougb 288224090Sdougb /* 289224090Sdougb * Ok, only AF_INET and AF_INET6 left. 290224090Sdougb */ 291224090Sdougb ai_list = NULL; 292224090Sdougb 293224090Sdougb /* 294224090Sdougb * First, look up the service name (port) if it was 295224090Sdougb * requested. If the socket type wasn't specified, then 296224090Sdougb * try and figure it out. 297224090Sdougb */ 298224090Sdougb if (servname != NULL) { 299224090Sdougb char *e; 300224090Sdougb 301224090Sdougb port = strtol(servname, &e, 10); 302224090Sdougb if (*e == '\0') { 303224090Sdougb if (socktype == 0) 304224090Sdougb return (EAI_SOCKTYPE); 305224090Sdougb if (port < 0 || port > 65535) 306224090Sdougb return (EAI_SERVICE); 307224090Sdougb port = htons((unsigned short) port); 308224090Sdougb } else { 309224090Sdougb sp = getservbyname(servname, proto); 310224090Sdougb if (sp == NULL) 311224090Sdougb return (EAI_SERVICE); 312224090Sdougb port = sp->s_port; 313224090Sdougb if (socktype == 0) { 314224090Sdougb if (strcmp(sp->s_proto, "tcp") == 0) 315224090Sdougb socktype = SOCK_STREAM; 316224090Sdougb else if (strcmp(sp->s_proto, "udp") == 0) 317224090Sdougb socktype = SOCK_DGRAM; 318224090Sdougb } 319224090Sdougb } 320224090Sdougb } else 321224090Sdougb port = 0; 322224090Sdougb 323224090Sdougb /* 324224090Sdougb * Next, deal with just a service name, and no hostname. 325224090Sdougb * (we verified that one of them was non-null up above). 326224090Sdougb */ 327224090Sdougb if (hostname == NULL && (flags & AI_PASSIVE) != 0) { 328224090Sdougb if (family == AF_INET || family == 0) { 329224090Sdougb ai = ai_alloc(AF_INET, sizeof(struct sockaddr_in)); 330224090Sdougb if (ai == NULL) 331224090Sdougb return (EAI_MEMORY); 332224090Sdougb ai->ai_socktype = socktype; 333224090Sdougb ai->ai_protocol = protocol; 334224090Sdougb SIN(ai->ai_addr)->sin_port = port; 335224090Sdougb ai->ai_next = ai_list; 336224090Sdougb ai_list = ai; 337224090Sdougb } 338224090Sdougb 339224090Sdougb if (family == AF_INET6 || family == 0) { 340224090Sdougb ai = ai_alloc(AF_INET6, sizeof(struct sockaddr_in6)); 341224090Sdougb if (ai == NULL) { 342224090Sdougb freeaddrinfo(ai_list); 343224090Sdougb return (EAI_MEMORY); 344224090Sdougb } 345224090Sdougb ai->ai_socktype = socktype; 346224090Sdougb ai->ai_protocol = protocol; 347224090Sdougb SIN6(ai->ai_addr)->sin6_port = port; 348224090Sdougb ai->ai_next = ai_list; 349224090Sdougb ai_list = ai; 350224090Sdougb } 351224090Sdougb 352224090Sdougb *res = ai_list; 353224090Sdougb return (0); 354224090Sdougb } 355224090Sdougb 356224090Sdougb /* 357224090Sdougb * If the family isn't specified or AI_NUMERICHOST specified, check 358224090Sdougb * first to see if it is a numeric address. 359224090Sdougb * Though the gethostbyname2() routine will recognize numeric addresses, 360224090Sdougb * it will only recognize the format that it is being called for. Thus, 361224090Sdougb * a numeric AF_INET address will be treated by the AF_INET6 call as 362224090Sdougb * a domain name, and vice versa. Checking for both numerics here 363224090Sdougb * avoids that. 364224090Sdougb */ 365224090Sdougb if (hostname != NULL && 366224090Sdougb (family == 0 || (flags & AI_NUMERICHOST) != 0)) { 367224090Sdougb char abuf[sizeof(struct in6_addr)]; 368224090Sdougb char nbuf[NI_MAXHOST]; 369224090Sdougb int addrsize, addroff; 370224090Sdougb#ifdef IRS_HAVE_SIN6_SCOPE_ID 371224090Sdougb char *p, *ep; 372224090Sdougb char ntmp[NI_MAXHOST]; 373224090Sdougb isc_uint32_t scopeid; 374224090Sdougb#endif 375224090Sdougb 376224090Sdougb#ifdef IRS_HAVE_SIN6_SCOPE_ID 377224090Sdougb /* 378224090Sdougb * Scope identifier portion. 379224090Sdougb */ 380224090Sdougb ntmp[0] = '\0'; 381224090Sdougb if (strchr(hostname, '%') != NULL) { 382224090Sdougb strncpy(ntmp, hostname, sizeof(ntmp) - 1); 383224090Sdougb ntmp[sizeof(ntmp) - 1] = '\0'; 384224090Sdougb p = strchr(ntmp, '%'); 385224090Sdougb ep = NULL; 386224090Sdougb 387224090Sdougb /* 388224090Sdougb * Vendors may want to support non-numeric 389224090Sdougb * scopeid around here. 390224090Sdougb */ 391224090Sdougb 392224090Sdougb if (p != NULL) 393224090Sdougb scopeid = (isc_uint32_t)strtoul(p + 1, 394224090Sdougb &ep, 10); 395224090Sdougb if (p != NULL && ep != NULL && ep[0] == '\0') 396224090Sdougb *p = '\0'; 397224090Sdougb else { 398224090Sdougb ntmp[0] = '\0'; 399224090Sdougb scopeid = 0; 400224090Sdougb } 401224090Sdougb } else 402224090Sdougb scopeid = 0; 403224090Sdougb#endif 404224090Sdougb 405224090Sdougb if (inet_pton(AF_INET, hostname, (struct in_addr *)abuf) 406224090Sdougb == 1) { 407224090Sdougb if (family == AF_INET6) { 408224090Sdougb /* 409224090Sdougb * Convert to a V4 mapped address. 410224090Sdougb */ 411224090Sdougb struct in6_addr *a6 = (struct in6_addr *)abuf; 412262706Serwin memmove(&a6->s6_addr[12], &a6->s6_addr[0], 4); 413224090Sdougb memset(&a6->s6_addr[10], 0xff, 2); 414224090Sdougb memset(&a6->s6_addr[0], 0, 10); 415224090Sdougb goto inet6_addr; 416224090Sdougb } 417224090Sdougb addrsize = sizeof(struct in_addr); 418224090Sdougb addroff = (char *)(&SIN(0)->sin_addr) - (char *)0; 419224090Sdougb family = AF_INET; 420224090Sdougb goto common; 421224090Sdougb#ifdef IRS_HAVE_SIN6_SCOPE_ID 422224090Sdougb } else if (ntmp[0] != '\0' && 423224090Sdougb inet_pton(AF_INET6, ntmp, abuf) == 1) { 424224090Sdougb if (family && family != AF_INET6) 425224090Sdougb return (EAI_NONAME); 426224090Sdougb addrsize = sizeof(struct in6_addr); 427224090Sdougb addroff = (char *)(&SIN6(0)->sin6_addr) - (char *)0; 428224090Sdougb family = AF_INET6; 429224090Sdougb goto common; 430224090Sdougb#endif 431224090Sdougb } else if (inet_pton(AF_INET6, hostname, abuf) == 1) { 432224090Sdougb if (family != 0 && family != AF_INET6) 433224090Sdougb return (EAI_NONAME); 434224090Sdougb inet6_addr: 435224090Sdougb addrsize = sizeof(struct in6_addr); 436224090Sdougb addroff = (char *)(&SIN6(0)->sin6_addr) - (char *)0; 437224090Sdougb family = AF_INET6; 438224090Sdougb 439224090Sdougb common: 440224090Sdougb ai = ai_alloc(family, 441224090Sdougb ((family == AF_INET6) ? 442224090Sdougb sizeof(struct sockaddr_in6) : 443224090Sdougb sizeof(struct sockaddr_in))); 444224090Sdougb if (ai == NULL) 445224090Sdougb return (EAI_MEMORY); 446224090Sdougb ai_list = ai; 447224090Sdougb ai->ai_socktype = socktype; 448224090Sdougb SIN(ai->ai_addr)->sin_port = port; 449262706Serwin memmove((char *)ai->ai_addr + addroff, abuf, addrsize); 450224090Sdougb if ((flags & AI_CANONNAME) != 0) { 451224090Sdougb#ifdef IRS_HAVE_SIN6_SCOPE_ID 452224090Sdougb if (ai->ai_family == AF_INET6) 453224090Sdougb SIN6(ai->ai_addr)->sin6_scope_id = 454224090Sdougb scopeid; 455224090Sdougb#endif 456224090Sdougb if (getnameinfo(ai->ai_addr, ai->ai_addrlen, 457224090Sdougb nbuf, sizeof(nbuf), NULL, 0, 458224090Sdougb NI_NUMERICHOST) == 0) { 459224090Sdougb ai->ai_canonname = strdup(nbuf); 460224090Sdougb if (ai->ai_canonname == NULL) { 461224090Sdougb freeaddrinfo(ai); 462224090Sdougb return (EAI_MEMORY); 463224090Sdougb } 464224090Sdougb } else { 465224090Sdougb /* XXX raise error? */ 466224090Sdougb ai->ai_canonname = NULL; 467224090Sdougb } 468224090Sdougb } 469224090Sdougb goto done; 470224090Sdougb } else if ((flags & AI_NUMERICHOST) != 0) { 471224090Sdougb return (EAI_NONAME); 472224090Sdougb } 473224090Sdougb } 474224090Sdougb 475224090Sdougb if (hostname == NULL && (flags & AI_PASSIVE) == 0) { 476224090Sdougb set_order(family, net_order); 477224090Sdougb for (i = 0; i < FOUND_MAX; i++) { 478224090Sdougb if (net_order[i] == NULL) 479224090Sdougb break; 480224090Sdougb err = (net_order[i])(hostname, flags, &ai_list, 481224090Sdougb socktype, port); 482224090Sdougb if (err != 0) { 483254402Serwin if (ai_list != NULL) { 484224090Sdougb freeaddrinfo(ai_list); 485254402Serwin ai_list = NULL; 486254402Serwin } 487224090Sdougb break; 488224090Sdougb } 489224090Sdougb } 490224090Sdougb } else 491224090Sdougb err = resolve_name(family, hostname, flags, &ai_list, 492224090Sdougb socktype, port); 493224090Sdougb 494224090Sdougb if (ai_list == NULL) { 495224090Sdougb if (err == 0) 496224090Sdougb err = EAI_NONAME; 497224090Sdougb return (err); 498224090Sdougb } 499224090Sdougb 500224090Sdougbdone: 501224090Sdougb ai_list = ai_reverse(ai_list); 502224090Sdougb 503224090Sdougb *res = ai_list; 504224090Sdougb return (0); 505224090Sdougb} 506224090Sdougb 507224090Sdougbtypedef struct gai_restrans { 508224090Sdougb dns_clientrestrans_t *xid; 509224090Sdougb isc_boolean_t is_inprogress; 510224090Sdougb int error; 511224090Sdougb struct addrinfo ai_sentinel; 512224090Sdougb struct gai_resstate *resstate; 513224090Sdougb} gai_restrans_t; 514224090Sdougb 515224090Sdougbtypedef struct gai_resstate { 516224090Sdougb isc_mem_t *mctx; 517224090Sdougb struct gai_statehead *head; 518224090Sdougb dns_fixedname_t fixedname; 519224090Sdougb dns_name_t *qname; 520224090Sdougb gai_restrans_t *trans4; 521224090Sdougb gai_restrans_t *trans6; 522224090Sdougb ISC_LINK(struct gai_resstate) link; 523224090Sdougb} gai_resstate_t; 524224090Sdougb 525224090Sdougbtypedef struct gai_statehead { 526224090Sdougb int ai_family; 527224090Sdougb int ai_flags; 528224090Sdougb int ai_socktype; 529224090Sdougb int ai_port; 530224090Sdougb isc_appctx_t *actx; 531224090Sdougb dns_client_t *dnsclient; 532224090Sdougb ISC_LIST(struct gai_resstate) resstates; 533224090Sdougb unsigned int activestates; 534224090Sdougb} gai_statehead_t; 535224090Sdougb 536224090Sdougbstatic isc_result_t 537224090Sdougbmake_resstate(isc_mem_t *mctx, gai_statehead_t *head, const char *hostname, 538224090Sdougb const char *domain, gai_resstate_t **statep) 539224090Sdougb{ 540224090Sdougb isc_result_t result; 541224090Sdougb gai_resstate_t *state; 542224090Sdougb dns_fixedname_t fixeddomain; 543224090Sdougb dns_name_t *qdomain; 544224090Sdougb size_t namelen; 545224090Sdougb isc_buffer_t b; 546224090Sdougb isc_boolean_t need_v4 = ISC_FALSE; 547224090Sdougb isc_boolean_t need_v6 = ISC_FALSE; 548224090Sdougb 549224090Sdougb state = isc_mem_get(mctx, sizeof(*state)); 550224090Sdougb if (state == NULL) 551224090Sdougb return (ISC_R_NOMEMORY); 552224090Sdougb 553224090Sdougb /* Construct base domain name */ 554224090Sdougb namelen = strlen(domain); 555254402Serwin isc_buffer_constinit(&b, domain, namelen); 556224090Sdougb isc_buffer_add(&b, namelen); 557224090Sdougb dns_fixedname_init(&fixeddomain); 558224090Sdougb qdomain = dns_fixedname_name(&fixeddomain); 559224090Sdougb result = dns_name_fromtext(qdomain, &b, dns_rootname, 0, NULL); 560224090Sdougb if (result != ISC_R_SUCCESS) { 561224090Sdougb isc_mem_put(mctx, state, sizeof(*state)); 562224090Sdougb return (result); 563224090Sdougb } 564224090Sdougb 565224090Sdougb /* Construct query name */ 566224090Sdougb namelen = strlen(hostname); 567254402Serwin isc_buffer_constinit(&b, hostname, namelen); 568224090Sdougb isc_buffer_add(&b, namelen); 569224090Sdougb dns_fixedname_init(&state->fixedname); 570224090Sdougb state->qname = dns_fixedname_name(&state->fixedname); 571224090Sdougb result = dns_name_fromtext(state->qname, &b, qdomain, 0, NULL); 572224090Sdougb if (result != ISC_R_SUCCESS) { 573224090Sdougb isc_mem_put(mctx, state, sizeof(*state)); 574224090Sdougb return (result); 575224090Sdougb } 576224090Sdougb 577224090Sdougb if (head->ai_family == AF_UNSPEC || head->ai_family == AF_INET) 578224090Sdougb need_v4 = ISC_TRUE; 579224090Sdougb if (head->ai_family == AF_UNSPEC || head->ai_family == AF_INET6) 580224090Sdougb need_v6 = ISC_TRUE; 581224090Sdougb 582224090Sdougb state->trans6 = NULL; 583224090Sdougb state->trans4 = NULL; 584224090Sdougb if (need_v4) { 585224090Sdougb state->trans4 = isc_mem_get(mctx, sizeof(gai_restrans_t)); 586224090Sdougb if (state->trans4 == NULL) { 587224090Sdougb isc_mem_put(mctx, state, sizeof(*state)); 588224090Sdougb return (ISC_R_NOMEMORY); 589224090Sdougb } 590224090Sdougb state->trans4->error = 0; 591224090Sdougb state->trans4->xid = NULL; 592224090Sdougb state->trans4->resstate = state; 593224090Sdougb state->trans4->is_inprogress = ISC_TRUE; 594224090Sdougb state->trans4->ai_sentinel.ai_next = NULL; 595224090Sdougb } 596224090Sdougb if (need_v6) { 597224090Sdougb state->trans6 = isc_mem_get(mctx, sizeof(gai_restrans_t)); 598224090Sdougb if (state->trans6 == NULL) { 599224090Sdougb if (state->trans4 != NULL) 600224090Sdougb isc_mem_put(mctx, state->trans4, 601224090Sdougb sizeof(*state->trans4)); 602224090Sdougb isc_mem_put(mctx, state, sizeof(*state)); 603224090Sdougb return (ISC_R_NOMEMORY); 604224090Sdougb } 605224090Sdougb state->trans6->error = 0; 606224090Sdougb state->trans6->xid = NULL; 607224090Sdougb state->trans6->resstate = state; 608224090Sdougb state->trans6->is_inprogress = ISC_TRUE; 609224090Sdougb state->trans6->ai_sentinel.ai_next = NULL; 610224090Sdougb } 611224090Sdougb 612224090Sdougb state->mctx = mctx; 613224090Sdougb state->head = head; 614224090Sdougb ISC_LINK_INIT(state, link); 615224090Sdougb 616224090Sdougb *statep = state; 617224090Sdougb 618224090Sdougb return (ISC_R_SUCCESS); 619224090Sdougb} 620224090Sdougb 621224090Sdougbstatic isc_result_t 622224090Sdougbmake_resstates(isc_mem_t *mctx, const char *hostname, gai_statehead_t *head, 623224090Sdougb irs_resconf_t *resconf) 624224090Sdougb{ 625224090Sdougb isc_result_t result; 626224090Sdougb irs_resconf_searchlist_t *searchlist; 627224090Sdougb irs_resconf_search_t *searchent; 628224090Sdougb gai_resstate_t *resstate, *resstate0; 629224090Sdougb 630224090Sdougb resstate0 = NULL; 631224090Sdougb result = make_resstate(mctx, head, hostname, ".", &resstate0); 632224090Sdougb if (result != ISC_R_SUCCESS) 633224090Sdougb return (result); 634224090Sdougb 635224090Sdougb searchlist = irs_resconf_getsearchlist(resconf); 636224090Sdougb for (searchent = ISC_LIST_HEAD(*searchlist); searchent != NULL; 637224090Sdougb searchent = ISC_LIST_NEXT(searchent, link)) { 638224090Sdougb resstate = NULL; 639224090Sdougb result = make_resstate(mctx, head, hostname, 640224090Sdougb (const char *)searchent->domain, 641224090Sdougb &resstate); 642224090Sdougb if (result != ISC_R_SUCCESS) 643224090Sdougb break; 644224090Sdougb 645224090Sdougb ISC_LIST_APPEND(head->resstates, resstate, link); 646224090Sdougb head->activestates++; 647224090Sdougb } 648224090Sdougb 649224090Sdougb /* 650224090Sdougb * Insert the original hostname either at the head or the tail of the 651224090Sdougb * state list, depending on the number of labels contained in the 652224090Sdougb * original name and the 'ndots' configuration parameter. 653224090Sdougb */ 654224090Sdougb if (dns_name_countlabels(resstate0->qname) > 655224090Sdougb irs_resconf_getndots(resconf) + 1) { 656224090Sdougb ISC_LIST_PREPEND(head->resstates, resstate0, link); 657224090Sdougb } else 658224090Sdougb ISC_LIST_APPEND(head->resstates, resstate0, link); 659224090Sdougb head->activestates++; 660224090Sdougb 661224090Sdougb if (result != ISC_R_SUCCESS) { 662224090Sdougb while ((resstate = ISC_LIST_HEAD(head->resstates)) != NULL) { 663224090Sdougb ISC_LIST_UNLINK(head->resstates, resstate, link); 664224090Sdougb if (resstate->trans4 != NULL) { 665224090Sdougb isc_mem_put(mctx, resstate->trans4, 666224090Sdougb sizeof(*resstate->trans4)); 667224090Sdougb } 668224090Sdougb if (resstate->trans6 != NULL) { 669224090Sdougb isc_mem_put(mctx, resstate->trans6, 670224090Sdougb sizeof(*resstate->trans6)); 671224090Sdougb } 672224090Sdougb 673224090Sdougb isc_mem_put(mctx, resstate, sizeof(*resstate)); 674224090Sdougb } 675224090Sdougb } 676224090Sdougb 677224090Sdougb return (result); 678224090Sdougb} 679224090Sdougb 680224090Sdougbstatic void 681224090Sdougbprocess_answer(isc_task_t *task, isc_event_t *event) { 682224090Sdougb int error = 0, family; 683224090Sdougb gai_restrans_t *trans = event->ev_arg; 684224090Sdougb gai_resstate_t *resstate; 685224090Sdougb dns_clientresevent_t *rev = (dns_clientresevent_t *)event; 686224090Sdougb dns_rdatatype_t qtype; 687224090Sdougb dns_name_t *name; 688224090Sdougb 689224090Sdougb REQUIRE(trans != NULL); 690224090Sdougb resstate = trans->resstate; 691224090Sdougb REQUIRE(resstate != NULL); 692224090Sdougb REQUIRE(task != NULL); 693224090Sdougb 694224090Sdougb if (trans == resstate->trans4) { 695224090Sdougb family = AF_INET; 696224090Sdougb qtype = dns_rdatatype_a; 697224090Sdougb } else { 698224090Sdougb INSIST(trans == resstate->trans6); 699224090Sdougb family = AF_INET6; 700224090Sdougb qtype = dns_rdatatype_aaaa; 701224090Sdougb } 702224090Sdougb 703224090Sdougb INSIST(trans->is_inprogress); 704224090Sdougb trans->is_inprogress = ISC_FALSE; 705224090Sdougb 706224090Sdougb switch (rev->result) { 707224090Sdougb case ISC_R_SUCCESS: 708224090Sdougb case DNS_R_NCACHENXDOMAIN: /* treat this as a fatal error? */ 709224090Sdougb case DNS_R_NCACHENXRRSET: 710224090Sdougb break; 711224090Sdougb default: 712224090Sdougb switch (rev->vresult) { 713224090Sdougb case DNS_R_SIGINVALID: 714224090Sdougb case DNS_R_SIGEXPIRED: 715224090Sdougb case DNS_R_SIGFUTURE: 716224090Sdougb case DNS_R_KEYUNAUTHORIZED: 717224090Sdougb case DNS_R_MUSTBESECURE: 718224090Sdougb case DNS_R_COVERINGNSEC: 719224090Sdougb case DNS_R_NOTAUTHORITATIVE: 720224090Sdougb case DNS_R_NOVALIDKEY: 721224090Sdougb case DNS_R_NOVALIDDS: 722224090Sdougb case DNS_R_NOVALIDSIG: 723224090Sdougb error = EAI_INSECUREDATA; 724224090Sdougb break; 725224090Sdougb default: 726224090Sdougb error = EAI_FAIL; 727224090Sdougb } 728224090Sdougb goto done; 729224090Sdougb } 730224090Sdougb 731224090Sdougb /* Parse the response and construct the addrinfo chain */ 732224090Sdougb for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL; 733224090Sdougb name = ISC_LIST_NEXT(name, link)) { 734224090Sdougb isc_result_t result; 735224090Sdougb dns_rdataset_t *rdataset; 736224090Sdougb isc_buffer_t b; 737224090Sdougb isc_region_t r; 738224090Sdougb char t[1024]; 739224090Sdougb 740224090Sdougb for (rdataset = ISC_LIST_HEAD(name->list); 741224090Sdougb rdataset != NULL; 742224090Sdougb rdataset = ISC_LIST_NEXT(rdataset, link)) { 743224090Sdougb if (!dns_rdataset_isassociated(rdataset)) 744224090Sdougb continue; 745224090Sdougb if (rdataset->type != qtype) 746224090Sdougb continue; 747224090Sdougb 748224090Sdougb if ((resstate->head->ai_flags & AI_CANONNAME) != 0) { 749224090Sdougb isc_buffer_init(&b, t, sizeof(t)); 750224090Sdougb result = dns_name_totext(name, ISC_TRUE, &b); 751224090Sdougb if (result != ISC_R_SUCCESS) { 752224090Sdougb error = EAI_FAIL; 753224090Sdougb goto done; 754224090Sdougb } 755224090Sdougb isc_buffer_putuint8(&b, '\0'); 756224090Sdougb isc_buffer_usedregion(&b, &r); 757224090Sdougb } 758224090Sdougb 759224090Sdougb for (result = dns_rdataset_first(rdataset); 760224090Sdougb result == ISC_R_SUCCESS; 761224090Sdougb result = dns_rdataset_next(rdataset)) { 762224090Sdougb struct addrinfo *ai; 763224090Sdougb dns_rdata_t rdata; 764224090Sdougb dns_rdata_in_a_t rdata_a; 765224090Sdougb dns_rdata_in_aaaa_t rdata_aaaa; 766224090Sdougb 767224090Sdougb ai = ai_alloc(family, 768224090Sdougb ((family == AF_INET6) ? 769224090Sdougb sizeof(struct sockaddr_in6) : 770224090Sdougb sizeof(struct sockaddr_in))); 771224090Sdougb if (ai == NULL) { 772224090Sdougb error = EAI_MEMORY; 773224090Sdougb goto done; 774224090Sdougb } 775224090Sdougb ai->ai_socktype = resstate->head->ai_socktype; 776224090Sdougb ai->ai_next = trans->ai_sentinel.ai_next; 777224090Sdougb trans->ai_sentinel.ai_next = ai; 778224090Sdougb 779224090Sdougb /* 780224090Sdougb * Set AF-specific parameters 781224090Sdougb * (IPv4/v6 address/port) 782224090Sdougb */ 783224090Sdougb dns_rdata_init(&rdata); 784224090Sdougb switch (family) { 785224090Sdougb case AF_INET: 786224090Sdougb dns_rdataset_current(rdataset, &rdata); 787254402Serwin result = dns_rdata_tostruct(&rdata, &rdata_a, 788254402Serwin NULL); 789254402Serwin RUNTIME_CHECK(result == ISC_R_SUCCESS); 790224090Sdougb SIN(ai->ai_addr)->sin_port = 791224090Sdougb resstate->head->ai_port; 792262706Serwin memmove(&SIN(ai->ai_addr)->sin_addr, 793262706Serwin &rdata_a.in_addr, 4); 794224090Sdougb dns_rdata_freestruct(&rdata_a); 795224090Sdougb break; 796224090Sdougb case AF_INET6: 797224090Sdougb dns_rdataset_current(rdataset, &rdata); 798254402Serwin result = dns_rdata_tostruct(&rdata, &rdata_aaaa, 799254402Serwin NULL); 800254402Serwin RUNTIME_CHECK(result == ISC_R_SUCCESS); 801224090Sdougb SIN6(ai->ai_addr)->sin6_port = 802224090Sdougb resstate->head->ai_port; 803262706Serwin memmove(&SIN6(ai->ai_addr)->sin6_addr, 804262706Serwin &rdata_aaaa.in6_addr, 16); 805224090Sdougb dns_rdata_freestruct(&rdata_aaaa); 806224090Sdougb break; 807224090Sdougb } 808224090Sdougb 809224090Sdougb if ((resstate->head->ai_flags & AI_CANONNAME) 810224090Sdougb != 0) { 811224090Sdougb ai->ai_canonname = 812224090Sdougb strdup((const char *)r.base); 813224090Sdougb if (ai->ai_canonname == NULL) { 814224090Sdougb error = EAI_MEMORY; 815224090Sdougb goto done; 816224090Sdougb } 817224090Sdougb } 818224090Sdougb } 819224090Sdougb } 820224090Sdougb } 821224090Sdougb 822224090Sdougb done: 823224090Sdougb dns_client_freeresanswer(resstate->head->dnsclient, &rev->answerlist); 824224090Sdougb dns_client_destroyrestrans(&trans->xid); 825224090Sdougb 826224090Sdougb isc_event_free(&event); 827224090Sdougb 828224090Sdougb /* Make sure that error == 0 iff we have a non-empty list */ 829224090Sdougb if (error == 0) { 830224090Sdougb if (trans->ai_sentinel.ai_next == NULL) 831224090Sdougb error = EAI_NONAME; 832224090Sdougb } else { 833224090Sdougb if (trans->ai_sentinel.ai_next != NULL) { 834224090Sdougb freeaddrinfo(trans->ai_sentinel.ai_next); 835224090Sdougb trans->ai_sentinel.ai_next = NULL; 836224090Sdougb } 837224090Sdougb } 838224090Sdougb trans->error = error; 839224090Sdougb 840224090Sdougb /* Check whether we are done */ 841224090Sdougb if ((resstate->trans4 == NULL || !resstate->trans4->is_inprogress) && 842224090Sdougb (resstate->trans6 == NULL || !resstate->trans6->is_inprogress)) { 843224090Sdougb /* 844224090Sdougb * We're done for this state. If there is no other outstanding 845224090Sdougb * state, we can exit. 846224090Sdougb */ 847224090Sdougb resstate->head->activestates--; 848224090Sdougb if (resstate->head->activestates == 0) { 849224090Sdougb isc_app_ctxsuspend(resstate->head->actx); 850224090Sdougb return; 851224090Sdougb } 852224090Sdougb 853224090Sdougb /* 854224090Sdougb * There are outstanding states, but if we are at the head 855224090Sdougb * of the state list (i.e., at the highest search priority) 856224090Sdougb * and have any answer, we can stop now by canceling the 857224090Sdougb * others. 858224090Sdougb */ 859224090Sdougb if (resstate == ISC_LIST_HEAD(resstate->head->resstates)) { 860224090Sdougb if ((resstate->trans4 != NULL && 861224090Sdougb resstate->trans4->ai_sentinel.ai_next != NULL) || 862224090Sdougb (resstate->trans6 != NULL && 863224090Sdougb resstate->trans6->ai_sentinel.ai_next != NULL)) { 864224090Sdougb gai_resstate_t *rest; 865224090Sdougb 866224090Sdougb for (rest = ISC_LIST_NEXT(resstate, link); 867224090Sdougb rest != NULL; 868224090Sdougb rest = ISC_LIST_NEXT(rest, link)) { 869224090Sdougb if (rest->trans4 != NULL && 870224090Sdougb rest->trans4->xid != NULL) 871224090Sdougb dns_client_cancelresolve( 872224090Sdougb rest->trans4->xid); 873224090Sdougb if (rest->trans6 != NULL && 874224090Sdougb rest->trans6->xid != NULL) 875224090Sdougb dns_client_cancelresolve( 876224090Sdougb rest->trans6->xid); 877224090Sdougb } 878224090Sdougb } else { 879224090Sdougb /* 880224090Sdougb * This search fails, so we move to the tail 881224090Sdougb * of the list so that the next entry will 882224090Sdougb * have the highest priority. 883224090Sdougb */ 884224090Sdougb ISC_LIST_UNLINK(resstate->head->resstates, 885224090Sdougb resstate, link); 886224090Sdougb ISC_LIST_APPEND(resstate->head->resstates, 887224090Sdougb resstate, link); 888224090Sdougb } 889224090Sdougb } 890224090Sdougb } 891224090Sdougb} 892224090Sdougb 893224090Sdougbstatic int 894224090Sdougbresolve_name(int family, const char *hostname, int flags, 895224090Sdougb struct addrinfo **aip, int socktype, int port) 896224090Sdougb{ 897224090Sdougb isc_result_t result; 898224090Sdougb irs_context_t *irsctx; 899224090Sdougb irs_resconf_t *conf; 900224090Sdougb isc_mem_t *mctx; 901224090Sdougb isc_appctx_t *actx; 902224090Sdougb isc_task_t *task; 903224090Sdougb int terror = 0; 904224090Sdougb int error = 0; 905224090Sdougb dns_client_t *client; 906224090Sdougb gai_resstate_t *resstate; 907224090Sdougb gai_statehead_t head; 908224090Sdougb isc_boolean_t all_fail = ISC_TRUE; 909224090Sdougb 910224090Sdougb /* get IRS context and the associated parameters */ 911224090Sdougb irsctx = NULL; 912224090Sdougb result = irs_context_get(&irsctx); 913224090Sdougb if (result != ISC_R_SUCCESS) 914224090Sdougb return (EAI_FAIL); 915224090Sdougb actx = irs_context_getappctx(irsctx); 916224090Sdougb 917224090Sdougb mctx = irs_context_getmctx(irsctx); 918224090Sdougb task = irs_context_gettask(irsctx); 919224090Sdougb conf = irs_context_getresconf(irsctx); 920224090Sdougb client = irs_context_getdnsclient(irsctx); 921224090Sdougb 922224090Sdougb /* construct resolution states */ 923224090Sdougb head.activestates = 0; 924224090Sdougb head.ai_family = family; 925224090Sdougb head.ai_socktype = socktype; 926224090Sdougb head.ai_flags = flags; 927224090Sdougb head.ai_port = port; 928224090Sdougb head.actx = actx; 929224090Sdougb head.dnsclient = client; 930224090Sdougb ISC_LIST_INIT(head.resstates); 931224090Sdougb result = make_resstates(mctx, hostname, &head, conf); 932224090Sdougb if (result != ISC_R_SUCCESS) 933224090Sdougb return (EAI_FAIL); 934224090Sdougb 935224090Sdougb for (resstate = ISC_LIST_HEAD(head.resstates); 936224090Sdougb resstate != NULL; resstate = ISC_LIST_NEXT(resstate, link)) { 937224090Sdougb if (resstate->trans4 != NULL) { 938224090Sdougb result = dns_client_startresolve(client, 939224090Sdougb resstate->qname, 940224090Sdougb dns_rdataclass_in, 941224090Sdougb dns_rdatatype_a, 942224090Sdougb 0, task, 943224090Sdougb process_answer, 944224090Sdougb resstate->trans4, 945224090Sdougb &resstate->trans4->xid); 946224090Sdougb if (result == ISC_R_SUCCESS) { 947224090Sdougb resstate->trans4->is_inprogress = ISC_TRUE; 948224090Sdougb all_fail = ISC_FALSE; 949224090Sdougb } else 950224090Sdougb resstate->trans4->is_inprogress = ISC_FALSE; 951224090Sdougb } 952224090Sdougb if (resstate->trans6 != NULL) { 953224090Sdougb result = dns_client_startresolve(client, 954224090Sdougb resstate->qname, 955224090Sdougb dns_rdataclass_in, 956224090Sdougb dns_rdatatype_aaaa, 957224090Sdougb 0, task, 958224090Sdougb process_answer, 959224090Sdougb resstate->trans6, 960224090Sdougb &resstate->trans6->xid); 961224090Sdougb if (result == ISC_R_SUCCESS) { 962224090Sdougb resstate->trans6->is_inprogress = ISC_TRUE; 963224090Sdougb all_fail = ISC_FALSE; 964224090Sdougb } else 965224090Sdougb resstate->trans6->is_inprogress= ISC_FALSE; 966224090Sdougb } 967224090Sdougb } 968224090Sdougb if (!all_fail) { 969224090Sdougb /* Start all the events */ 970224090Sdougb isc_app_ctxrun(actx); 971224090Sdougb } else 972224090Sdougb error = EAI_FAIL; 973224090Sdougb 974224090Sdougb /* Cleanup */ 975224090Sdougb while ((resstate = ISC_LIST_HEAD(head.resstates)) != NULL) { 976224090Sdougb int terror4 = 0, terror6 = 0; 977224090Sdougb 978224090Sdougb ISC_LIST_UNLINK(head.resstates, resstate, link); 979224090Sdougb 980224090Sdougb if (*aip == NULL) { 981224090Sdougb struct addrinfo *sentinel4 = NULL; 982224090Sdougb struct addrinfo *sentinel6 = NULL; 983224090Sdougb 984224090Sdougb if (resstate->trans4 != NULL) { 985224090Sdougb sentinel4 = 986224090Sdougb resstate->trans4->ai_sentinel.ai_next; 987224090Sdougb resstate->trans4->ai_sentinel.ai_next = NULL; 988224090Sdougb } 989224090Sdougb if (resstate->trans6 != NULL) { 990224090Sdougb sentinel6 = 991224090Sdougb resstate->trans6->ai_sentinel.ai_next; 992224090Sdougb resstate->trans6->ai_sentinel.ai_next = NULL; 993224090Sdougb } 994224090Sdougb *aip = ai_concat(sentinel4, sentinel6); 995224090Sdougb } 996224090Sdougb 997224090Sdougb if (resstate->trans4 != NULL) { 998224090Sdougb INSIST(resstate->trans4->xid == NULL); 999224090Sdougb terror4 = resstate->trans4->error; 1000224090Sdougb isc_mem_put(mctx, resstate->trans4, 1001224090Sdougb sizeof(*resstate->trans4)); 1002224090Sdougb } 1003224090Sdougb if (resstate->trans6 != NULL) { 1004224090Sdougb INSIST(resstate->trans6->xid == NULL); 1005224090Sdougb terror6 = resstate->trans6->error; 1006224090Sdougb isc_mem_put(mctx, resstate->trans6, 1007224090Sdougb sizeof(*resstate->trans6)); 1008224090Sdougb } 1009224090Sdougb 1010224090Sdougb /* 1011224090Sdougb * If the entire lookup fails, we need to choose an appropriate 1012224090Sdougb * error code from individual codes. We'll try to provide as 1013224090Sdougb * specific a code as possible. In general, we are going to 1014224090Sdougb * find an error code other than EAI_NONAME (which is too 1015224090Sdougb * generic and may actually not be problematic in some cases). 1016224090Sdougb * EAI_NONAME will be set below if no better code is found. 1017224090Sdougb */ 1018224090Sdougb if (terror == 0 || terror == EAI_NONAME) { 1019224090Sdougb if (terror4 != 0 && terror4 != EAI_NONAME) 1020224090Sdougb terror = terror4; 1021224090Sdougb else if (terror6 != 0 && terror6 != EAI_NONAME) 1022224090Sdougb terror = terror6; 1023224090Sdougb } 1024224090Sdougb 1025224090Sdougb isc_mem_put(mctx, resstate, sizeof(*resstate)); 1026224090Sdougb } 1027224090Sdougb 1028224090Sdougb if (*aip == NULL) { 1029224090Sdougb error = terror; 1030224090Sdougb if (error == 0) 1031224090Sdougb error = EAI_NONAME; 1032224090Sdougb } 1033224090Sdougb 1034224090Sdougb#if 1 /* XXX: enabled for finding leaks. should be cleaned up later. */ 1035224090Sdougb isc_app_ctxfinish(actx); 1036224090Sdougb irs_context_destroy(&irsctx); 1037224090Sdougb#endif 1038224090Sdougb 1039224090Sdougb return (error); 1040224090Sdougb} 1041224090Sdougb 1042224090Sdougbstatic char * 1043224090Sdougbirs_strsep(char **stringp, const char *delim) { 1044224090Sdougb char *string = *stringp; 1045224090Sdougb char *s; 1046224090Sdougb const char *d; 1047224090Sdougb char sc, dc; 1048224090Sdougb 1049224090Sdougb if (string == NULL) 1050224090Sdougb return (NULL); 1051224090Sdougb 1052224090Sdougb for (s = string; *s != '\0'; s++) { 1053224090Sdougb sc = *s; 1054224090Sdougb for (d = delim; (dc = *d) != '\0'; d++) 1055224090Sdougb if (sc == dc) { 1056224090Sdougb *s++ = '\0'; 1057224090Sdougb *stringp = s; 1058224090Sdougb return (string); 1059224090Sdougb } 1060224090Sdougb } 1061224090Sdougb *stringp = NULL; 1062224090Sdougb return (string); 1063224090Sdougb} 1064224090Sdougb 1065224090Sdougbstatic void 1066224090Sdougbset_order(int family, int (**net_order)(const char *, int, struct addrinfo **, 1067224090Sdougb int, int)) 1068224090Sdougb{ 1069224090Sdougb char *order, *tok; 1070224090Sdougb int found; 1071224090Sdougb 1072224090Sdougb if (family) { 1073224090Sdougb switch (family) { 1074224090Sdougb case AF_INET: 1075224090Sdougb *net_order++ = add_ipv4; 1076224090Sdougb break; 1077224090Sdougb case AF_INET6: 1078224090Sdougb *net_order++ = add_ipv6; 1079224090Sdougb break; 1080224090Sdougb } 1081224090Sdougb } else { 1082224090Sdougb order = getenv("NET_ORDER"); 1083224090Sdougb found = 0; 1084224090Sdougb while (order != NULL) { 1085224090Sdougb /* 1086224090Sdougb * We ignore any unknown names. 1087224090Sdougb */ 1088224090Sdougb tok = irs_strsep(&order, ":"); 1089224090Sdougb if (strcasecmp(tok, "inet6") == 0) { 1090224090Sdougb if ((found & FOUND_IPV6) == 0) 1091224090Sdougb *net_order++ = add_ipv6; 1092224090Sdougb found |= FOUND_IPV6; 1093224090Sdougb } else if (strcasecmp(tok, "inet") == 0 || 1094224090Sdougb strcasecmp(tok, "inet4") == 0) { 1095224090Sdougb if ((found & FOUND_IPV4) == 0) 1096224090Sdougb *net_order++ = add_ipv4; 1097224090Sdougb found |= FOUND_IPV4; 1098224090Sdougb } 1099224090Sdougb } 1100224090Sdougb 1101224090Sdougb /* 1102224090Sdougb * Add in anything that we didn't find. 1103224090Sdougb */ 1104224090Sdougb if ((found & FOUND_IPV4) == 0) 1105224090Sdougb *net_order++ = add_ipv4; 1106224090Sdougb if ((found & FOUND_IPV6) == 0) 1107224090Sdougb *net_order++ = add_ipv6; 1108224090Sdougb } 1109224090Sdougb *net_order = NULL; 1110224090Sdougb return; 1111224090Sdougb} 1112224090Sdougb 1113224090Sdougbstatic char v4_loop[4] = { 127, 0, 0, 1 }; 1114224090Sdougb 1115224090Sdougbstatic int 1116224090Sdougbadd_ipv4(const char *hostname, int flags, struct addrinfo **aip, 1117224090Sdougb int socktype, int port) 1118224090Sdougb{ 1119224090Sdougb struct addrinfo *ai; 1120224090Sdougb 1121224090Sdougb UNUSED(hostname); 1122224090Sdougb UNUSED(flags); 1123224090Sdougb 1124224090Sdougb ai = ai_clone(*aip, AF_INET); /* don't use ai_clone() */ 1125224090Sdougb if (ai == NULL) { 1126224090Sdougb freeaddrinfo(*aip); 1127224090Sdougb return (EAI_MEMORY); 1128224090Sdougb } 1129224090Sdougb 1130224090Sdougb *aip = ai; 1131224090Sdougb ai->ai_socktype = socktype; 1132224090Sdougb SIN(ai->ai_addr)->sin_port = port; 1133262706Serwin memmove(&SIN(ai->ai_addr)->sin_addr, v4_loop, 4); 1134224090Sdougb 1135224090Sdougb return (0); 1136224090Sdougb} 1137224090Sdougb 1138224090Sdougbstatic char v6_loop[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; 1139224090Sdougb 1140224090Sdougbstatic int 1141224090Sdougbadd_ipv6(const char *hostname, int flags, struct addrinfo **aip, 1142224090Sdougb int socktype, int port) 1143224090Sdougb{ 1144224090Sdougb struct addrinfo *ai; 1145224090Sdougb 1146224090Sdougb UNUSED(hostname); 1147224090Sdougb UNUSED(flags); 1148224090Sdougb 1149224090Sdougb ai = ai_clone(*aip, AF_INET6); /* don't use ai_clone() */ 1150254402Serwin if (ai == NULL) 1151224090Sdougb return (EAI_MEMORY); 1152224090Sdougb 1153224090Sdougb *aip = ai; 1154224090Sdougb ai->ai_socktype = socktype; 1155224090Sdougb SIN6(ai->ai_addr)->sin6_port = port; 1156262706Serwin memmove(&SIN6(ai->ai_addr)->sin6_addr, v6_loop, 16); 1157224090Sdougb 1158224090Sdougb return (0); 1159224090Sdougb} 1160224090Sdougb 1161224090Sdougb/*% Free address info. */ 1162224090Sdougbvoid 1163224090Sdougbfreeaddrinfo(struct addrinfo *ai) { 1164224090Sdougb struct addrinfo *ai_next; 1165224090Sdougb 1166224090Sdougb while (ai != NULL) { 1167224090Sdougb ai_next = ai->ai_next; 1168224090Sdougb if (ai->ai_addr != NULL) 1169224090Sdougb free(ai->ai_addr); 1170224090Sdougb if (ai->ai_canonname) 1171224090Sdougb free(ai->ai_canonname); 1172224090Sdougb free(ai); 1173224090Sdougb ai = ai_next; 1174224090Sdougb } 1175224090Sdougb} 1176224090Sdougb 1177224090Sdougb#ifdef AF_LOCAL 1178224090Sdougbstatic int 1179224090Sdougbget_local(const char *name, int socktype, struct addrinfo **res) { 1180224090Sdougb struct addrinfo *ai; 1181224090Sdougb struct sockaddr_un *slocal; 1182224090Sdougb 1183224090Sdougb if (socktype == 0) 1184224090Sdougb return (EAI_SOCKTYPE); 1185224090Sdougb 1186224090Sdougb ai = ai_alloc(AF_LOCAL, sizeof(*slocal)); 1187224090Sdougb if (ai == NULL) 1188224090Sdougb return (EAI_MEMORY); 1189224090Sdougb 1190224090Sdougb slocal = SLOCAL(ai->ai_addr); 1191254402Serwin strlcpy(slocal->sun_path, name, sizeof(slocal->sun_path)); 1192224090Sdougb 1193224090Sdougb ai->ai_socktype = socktype; 1194224090Sdougb /* 1195224090Sdougb * ai->ai_flags, ai->ai_protocol, ai->ai_canonname, 1196224090Sdougb * and ai->ai_next were initialized to zero. 1197224090Sdougb */ 1198224090Sdougb 1199224090Sdougb *res = ai; 1200224090Sdougb return (0); 1201224090Sdougb} 1202224090Sdougb#endif 1203224090Sdougb 1204224090Sdougb/*! 1205224090Sdougb * Allocate an addrinfo structure, and a sockaddr structure 1206224090Sdougb * of the specificed length. We initialize: 1207224090Sdougb * ai_addrlen 1208224090Sdougb * ai_family 1209224090Sdougb * ai_addr 1210224090Sdougb * ai_addr->sa_family 1211224090Sdougb * ai_addr->sa_len (IRS_PLATFORM_HAVESALEN) 1212224090Sdougb * and everything else is initialized to zero. 1213224090Sdougb */ 1214224090Sdougbstatic struct addrinfo * 1215224090Sdougbai_alloc(int family, int addrlen) { 1216224090Sdougb struct addrinfo *ai; 1217224090Sdougb 1218224090Sdougb ai = (struct addrinfo *)calloc(1, sizeof(*ai)); 1219224090Sdougb if (ai == NULL) 1220224090Sdougb return (NULL); 1221224090Sdougb 1222224090Sdougb ai->ai_addr = SA(calloc(1, addrlen)); 1223224090Sdougb if (ai->ai_addr == NULL) { 1224224090Sdougb free(ai); 1225224090Sdougb return (NULL); 1226224090Sdougb } 1227224090Sdougb ai->ai_addrlen = addrlen; 1228224090Sdougb ai->ai_family = family; 1229224090Sdougb ai->ai_addr->sa_family = family; 1230224090Sdougb#ifdef IRS_PLATFORM_HAVESALEN 1231224090Sdougb ai->ai_addr->sa_len = addrlen; 1232224090Sdougb#endif 1233224090Sdougb return (ai); 1234224090Sdougb} 1235224090Sdougb 1236224090Sdougbstatic struct addrinfo * 1237224090Sdougbai_clone(struct addrinfo *oai, int family) { 1238224090Sdougb struct addrinfo *ai; 1239224090Sdougb 1240224090Sdougb ai = ai_alloc(family, ((family == AF_INET6) ? 1241224090Sdougb sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in))); 1242224090Sdougb 1243224090Sdougb if (ai == NULL) { 1244224090Sdougb if (oai != NULL) 1245224090Sdougb freeaddrinfo(oai); 1246224090Sdougb return (NULL); 1247224090Sdougb } 1248224090Sdougb if (oai == NULL) 1249224090Sdougb return (ai); 1250224090Sdougb 1251224090Sdougb ai->ai_flags = oai->ai_flags; 1252224090Sdougb ai->ai_socktype = oai->ai_socktype; 1253224090Sdougb ai->ai_protocol = oai->ai_protocol; 1254224090Sdougb ai->ai_canonname = NULL; 1255224090Sdougb ai->ai_next = oai; 1256224090Sdougb return (ai); 1257224090Sdougb} 1258224090Sdougb 1259224090Sdougbstatic struct addrinfo * 1260224090Sdougbai_reverse(struct addrinfo *oai) { 1261224090Sdougb struct addrinfo *nai, *tai; 1262224090Sdougb 1263224090Sdougb nai = NULL; 1264224090Sdougb 1265224090Sdougb while (oai != NULL) { 1266224090Sdougb /* 1267224090Sdougb * Grab one off the old list. 1268224090Sdougb */ 1269224090Sdougb tai = oai; 1270224090Sdougb oai = oai->ai_next; 1271224090Sdougb /* 1272224090Sdougb * Put it on the front of the new list. 1273224090Sdougb */ 1274224090Sdougb tai->ai_next = nai; 1275224090Sdougb nai = tai; 1276224090Sdougb } 1277224090Sdougb return (nai); 1278224090Sdougb} 1279224090Sdougb 1280224090Sdougb 1281224090Sdougbstatic struct addrinfo * 1282224090Sdougbai_concat(struct addrinfo *ai1, struct addrinfo *ai2) { 1283224090Sdougb struct addrinfo *ai_tmp; 1284224090Sdougb 1285224090Sdougb if (ai1 == NULL) 1286224090Sdougb return (ai2); 1287224090Sdougb else if (ai2 == NULL) 1288224090Sdougb return (ai1); 1289224090Sdougb 1290224090Sdougb for (ai_tmp = ai1; ai_tmp != NULL && ai_tmp->ai_next != NULL; 1291224090Sdougb ai_tmp = ai_tmp->ai_next) 1292224090Sdougb ; 1293224090Sdougb 1294224090Sdougb ai_tmp->ai_next = ai2; 1295224090Sdougb 1296224090Sdougb return (ai1); 1297224090Sdougb} 1298