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