getaddrinfo.c revision 224090
1275072Semaste/* 2275072Semaste * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") 3275072Semaste * 4275072Semaste * Permission to use, copy, modify, and/or distribute this software for any 5275072Semaste * purpose with or without fee is hereby granted, provided that the above 6275072Semaste * copyright notice and this permission notice appear in all copies. 7275072Semaste * 8275072Semaste * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 9275072Semaste * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10275072Semaste * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 11275072Semaste * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12275072Semaste * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13275072Semaste * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14275072Semaste * PERFORMANCE OF THIS SOFTWARE. 15275072Semaste */ 16275072Semaste 17275072Semaste/* $Id: getaddrinfo.c,v 1.3 2009-09-02 23:48:02 tbox Exp $ */ 18275072Semaste 19275072Semaste/*! \file */ 20275072Semaste 21275072Semaste/** 22275072Semaste * getaddrinfo() is used to get a list of IP addresses and port 23275072Semaste * numbers for host hostname and service servname as defined in RFC3493. 24275072Semaste * hostname and servname are pointers to null-terminated strings 25275072Semaste * or NULL. hostname is either a host name or a numeric host address 26275072Semaste * string: a dotted decimal IPv4 address or an IPv6 address. servname is 27275072Semaste * either a decimal port number or a service name as listed in 28275072Semaste * /etc/services. 29275072Semaste * 30275072Semaste * If the operating system does not provide a struct addrinfo, the 31275072Semaste * following structure is used: 32275072Semaste * 33275072Semaste * \code 34275072Semaste * struct addrinfo { 35275072Semaste * int ai_flags; // AI_PASSIVE, AI_CANONNAME 36275072Semaste * int ai_family; // PF_xxx 37275072Semaste * int ai_socktype; // SOCK_xxx 38275072Semaste * int ai_protocol; // 0 or IPPROTO_xxx for IPv4 and IPv6 39275072Semaste * size_t ai_addrlen; // length of ai_addr 40275072Semaste * char *ai_canonname; // canonical name for hostname 41275072Semaste * struct sockaddr *ai_addr; // binary address 42275072Semaste * struct addrinfo *ai_next; // next structure in linked list 43275072Semaste * }; 44275072Semaste * \endcode 45275072Semaste * 46275072Semaste * 47275072Semaste * hints is an optional pointer to a struct addrinfo. This structure can 48275072Semaste * be used to provide hints concerning the type of socket that the caller 49275072Semaste * supports or wishes to use. The caller can supply the following 50275072Semaste * structure elements in *hints: 51275072Semaste * 52275072Semaste * <ul> 53275072Semaste * <li>ai_family: 54275072Semaste * The protocol family that should be used. When ai_family is set 55275072Semaste * to PF_UNSPEC, it means the caller will accept any protocol 56275072Semaste * family supported by the operating system.</li> 57275072Semaste * 58275072Semaste * <li>ai_socktype: 59275072Semaste * denotes the type of socket -- SOCK_STREAM, SOCK_DGRAM or 60275072Semaste * SOCK_RAW -- that is wanted. When ai_socktype is zero the caller 61275072Semaste * will accept any socket type.</li> 62275072Semaste * 63275072Semaste * <li>ai_protocol: 64275072Semaste * indicates which transport protocol is wanted: IPPROTO_UDP or 65275072Semaste * IPPROTO_TCP. If ai_protocol is zero the caller will accept any 66275072Semaste * protocol.</li> 67275072Semaste * 68275072Semaste * <li>ai_flags: 69275072Semaste * Flag bits. If the AI_CANONNAME bit is set, a successful call to 70275072Semaste * getaddrinfo() will return a null-terminated string 71275072Semaste * containing the canonical name of the specified hostname in 72275072Semaste * ai_canonname of the first addrinfo structure returned. Setting 73275072Semaste * the AI_PASSIVE bit indicates that the returned socket address 74275072Semaste * structure is intended for used in a call to bind(2). In this 75275072Semaste * case, if the hostname argument is a NULL pointer, then the IP 76275072Semaste * address portion of the socket address structure will be set to 77275072Semaste * INADDR_ANY for an IPv4 address or IN6ADDR_ANY_INIT for an IPv6 78275072Semaste * address.<br /><br /> 79275072Semaste * 80275072Semaste * When ai_flags does not set the AI_PASSIVE bit, the returned 81275072Semaste * socket address structure will be ready for use in a call to 82275072Semaste * connect(2) for a connection-oriented protocol or connect(2), 83275072Semaste * sendto(2), or sendmsg(2) if a connectionless protocol was 84275072Semaste * chosen. The IP address portion of the socket address structure 85275072Semaste * will be set to the loopback address if hostname is a NULL 86275072Semaste * pointer and AI_PASSIVE is not set in ai_flags.<br /><br /> 87275072Semaste * 88275072Semaste * If ai_flags is set to AI_NUMERICHOST it indicates that hostname 89275072Semaste * should be treated as a numeric string defining an IPv4 or IPv6 90275072Semaste * address and no name resolution should be attempted. 91275072Semaste * </li></ul> 92275072Semaste * 93275072Semaste * All other elements of the struct addrinfo passed via hints must be 94275072Semaste * zero. 95275072Semaste * 96275072Semaste * A hints of NULL is treated as if the caller provided a struct addrinfo 97275072Semaste * initialized to zero with ai_familyset to PF_UNSPEC. 98275072Semaste * 99275072Semaste * After a successful call to getaddrinfo(), *res is a pointer to a 100275072Semaste * linked list of one or more addrinfo structures. Each struct addrinfo 101275072Semaste * in this list cn be processed by following the ai_next pointer, until a 102275072Semaste * NULL pointer is encountered. The three members ai_family, ai_socktype, 103275072Semaste * and ai_protocol in each returned addrinfo structure contain the 104275072Semaste * corresponding arguments for a call to socket(2). For each addrinfo 105275072Semaste * structure in the list, the ai_addr member points to a filled-in socket 106275072Semaste * address structure of length ai_addrlen. 107275072Semaste * 108275072Semaste * All of the information returned by getaddrinfo() is dynamically 109275072Semaste * allocated: the addrinfo structures, and the socket address structures 110275072Semaste * and canonical host name strings pointed to by the addrinfostructures. 111275072Semaste * Memory allocated for the dynamically allocated structures created by a 112275072Semaste * successful call to getaddrinfo() is released by freeaddrinfo(). 113275072Semaste * ai is a pointer to a struct addrinfo created by a call to getaddrinfo(). 114275072Semaste * 115275072Semaste * \section irsreturn RETURN VALUES 116275072Semaste * 117275072Semaste * getaddrinfo() returns zero on success or one of the error codes 118275072Semaste * listed in gai_strerror() if an error occurs. If both hostname and 119275072Semaste * servname are NULL getaddrinfo() returns #EAI_NONAME. 120275072Semaste * 121275072Semaste * \section irssee SEE ALSO 122275072Semaste * 123275072Semaste * getaddrinfo(), freeaddrinfo(), 124275072Semaste * gai_strerror(), RFC3493, getservbyname(3), connect(2), 125275072Semaste * sendto(2), sendmsg(2), socket(2). 126275072Semaste */ 127275072Semaste 128275072Semaste#include <config.h> 129275072Semaste 130275072Semaste#include <stdlib.h> 131275072Semaste#include <string.h> 132275072Semaste#include <errno.h> 133275072Semaste 134275072Semaste#include <isc/app.h> 135275072Semaste#include <isc/buffer.h> 136275072Semaste#include <isc/lib.h> 137275072Semaste#include <isc/mem.h> 138275072Semaste#include <isc/sockaddr.h> 139275072Semaste#include <isc/util.h> 140275072Semaste 141275072Semaste#include <dns/client.h> 142275072Semaste#include <dns/fixedname.h> 143275072Semaste#include <dns/name.h> 144275072Semaste#include <dns/rdata.h> 145275072Semaste#include <dns/rdataset.h> 146275072Semaste#include <dns/rdatastruct.h> 147275072Semaste#include <dns/rdatatype.h> 148275072Semaste#include <dns/result.h> 149275072Semaste 150275072Semaste#include <irs/context.h> 151275072Semaste#include <irs/netdb.h> 152275072Semaste#include <irs/resconf.h> 153275072Semaste 154275072Semaste#define SA(addr) ((struct sockaddr *)(addr)) 155275072Semaste#define SIN(addr) ((struct sockaddr_in *)(addr)) 156275072Semaste#define SIN6(addr) ((struct sockaddr_in6 *)(addr)) 157275072Semaste#define SLOCAL(addr) ((struct sockaddr_un *)(addr)) 158275072Semaste 159275072Semaste/*! \struct addrinfo 160275072Semaste */ 161275072Semastestatic struct addrinfo 162275072Semaste *ai_concat(struct addrinfo *ai1, struct addrinfo *ai2), 163275072Semaste *ai_reverse(struct addrinfo *oai), 164275072Semaste *ai_clone(struct addrinfo *oai, int family), 165275072Semaste *ai_alloc(int family, int addrlen); 166275072Semaste#ifdef AF_LOCAL 167275072Semastestatic int get_local(const char *name, int socktype, struct addrinfo **res); 168275072Semaste#endif 169275072Semaste 170275072Semastestatic int 171275072Semasteresolve_name(int family, const char *hostname, int flags, 172275072Semaste struct addrinfo **aip, int socktype, int port); 173275072Semaste 174275072Semastestatic int add_ipv4(const char *hostname, int flags, struct addrinfo **aip, 175275072Semaste int socktype, int port); 176275072Semastestatic int add_ipv6(const char *hostname, int flags, struct addrinfo **aip, 177275072Semaste int socktype, int port); 178275072Semastestatic void set_order(int, int (**)(const char *, int, struct addrinfo **, 179275072Semaste int, int)); 180275072Semaste 181275072Semaste#define FOUND_IPV4 0x1 182275072Semaste#define FOUND_IPV6 0x2 183275072Semaste#define FOUND_MAX 2 184275072Semaste 185275072Semaste#define ISC_AI_MASK (AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST) 186275072Semaste/*% 187275072Semaste * Get a list of IP addresses and port numbers for host hostname and 188275072Semaste * service servname. 189275072Semaste */ 190275072Semasteint 191275072Semastegetaddrinfo(const char *hostname, const char *servname, 192275072Semaste const struct addrinfo *hints, struct addrinfo **res) 193275072Semaste{ 194275072Semaste struct servent *sp; 195275072Semaste const char *proto; 196275072Semaste int family, socktype, flags, protocol; 197275072Semaste struct addrinfo *ai, *ai_list; 198275072Semaste int err = 0; 199275072Semaste int port, i; 200275072Semaste int (*net_order[FOUND_MAX+1])(const char *, int, struct addrinfo **, 201275072Semaste int, int); 202275072Semaste 203275072Semaste if (hostname == NULL && servname == NULL) 204275072Semaste return (EAI_NONAME); 205275072Semaste 206275072Semaste proto = NULL; 207275072Semaste if (hints != NULL) { 208275072Semaste if ((hints->ai_flags & ~(ISC_AI_MASK)) != 0) 209275072Semaste return (EAI_BADFLAGS); 210275072Semaste if (hints->ai_addrlen || hints->ai_canonname || 211275072Semaste hints->ai_addr || hints->ai_next) { 212275072Semaste errno = EINVAL; 213275072Semaste return (EAI_SYSTEM); 214275072Semaste } 215275072Semaste family = hints->ai_family; 216275072Semaste socktype = hints->ai_socktype; 217275072Semaste protocol = hints->ai_protocol; 218275072Semaste flags = hints->ai_flags; 219275072Semaste switch (family) { 220275072Semaste case AF_UNSPEC: 221275072Semaste switch (hints->ai_socktype) { 222275072Semaste case SOCK_STREAM: 223275072Semaste proto = "tcp"; 224275072Semaste break; 225275072Semaste case SOCK_DGRAM: 226275072Semaste proto = "udp"; 227275072Semaste break; 228275072Semaste } 229275072Semaste break; 230275072Semaste case AF_INET: 231275072Semaste case AF_INET6: 232275072Semaste switch (hints->ai_socktype) { 233275072Semaste case 0: 234275072Semaste break; 235275072Semaste case SOCK_STREAM: 236275072Semaste proto = "tcp"; 237275072Semaste break; 238275072Semaste case SOCK_DGRAM: 239275072Semaste proto = "udp"; 240275072Semaste break; 241275072Semaste case SOCK_RAW: 242275072Semaste break; 243275072Semaste default: 244275072Semaste return (EAI_SOCKTYPE); 245275072Semaste } 246275072Semaste break; 247275072Semaste#ifdef AF_LOCAL 248275072Semaste case AF_LOCAL: 249275072Semaste switch (hints->ai_socktype) { 250275072Semaste case 0: 251275072Semaste break; 252275072Semaste case SOCK_STREAM: 253275072Semaste break; 254275072Semaste case SOCK_DGRAM: 255275072Semaste break; 256275072Semaste default: 257275072Semaste return (EAI_SOCKTYPE); 258275072Semaste } 259275072Semaste break; 260275072Semaste#endif 261275072Semaste default: 262275072Semaste return (EAI_FAMILY); 263275072Semaste } 264275072Semaste } else { 265275072Semaste protocol = 0; 266275072Semaste family = 0; 267275072Semaste socktype = 0; 268275072Semaste flags = 0; 269275072Semaste } 270275072Semaste 271275072Semaste#ifdef AF_LOCAL 272275072Semaste /*! 273275072Semaste * First, deal with AF_LOCAL. If the family was not set, 274275072Semaste * then assume AF_LOCAL if the first character of the 275275072Semaste * hostname/servname is '/'. 276275072Semaste */ 277275072Semaste 278275072Semaste if (hostname != NULL && 279275072Semaste (family == AF_LOCAL || (family == 0 && *hostname == '/'))) 280 return (get_local(hostname, socktype, res)); 281 282 if (servname != NULL && 283 (family == AF_LOCAL || (family == 0 && *servname == '/'))) 284 return (get_local(servname, socktype, res)); 285#endif 286 287 /* 288 * Ok, only AF_INET and AF_INET6 left. 289 */ 290 ai_list = NULL; 291 292 /* 293 * First, look up the service name (port) if it was 294 * requested. If the socket type wasn't specified, then 295 * try and figure it out. 296 */ 297 if (servname != NULL) { 298 char *e; 299 300 port = strtol(servname, &e, 10); 301 if (*e == '\0') { 302 if (socktype == 0) 303 return (EAI_SOCKTYPE); 304 if (port < 0 || port > 65535) 305 return (EAI_SERVICE); 306 port = htons((unsigned short) port); 307 } else { 308 sp = getservbyname(servname, proto); 309 if (sp == NULL) 310 return (EAI_SERVICE); 311 port = sp->s_port; 312 if (socktype == 0) { 313 if (strcmp(sp->s_proto, "tcp") == 0) 314 socktype = SOCK_STREAM; 315 else if (strcmp(sp->s_proto, "udp") == 0) 316 socktype = SOCK_DGRAM; 317 } 318 } 319 } else 320 port = 0; 321 322 /* 323 * Next, deal with just a service name, and no hostname. 324 * (we verified that one of them was non-null up above). 325 */ 326 if (hostname == NULL && (flags & AI_PASSIVE) != 0) { 327 if (family == AF_INET || family == 0) { 328 ai = ai_alloc(AF_INET, sizeof(struct sockaddr_in)); 329 if (ai == NULL) 330 return (EAI_MEMORY); 331 ai->ai_socktype = socktype; 332 ai->ai_protocol = protocol; 333 SIN(ai->ai_addr)->sin_port = port; 334 ai->ai_next = ai_list; 335 ai_list = ai; 336 } 337 338 if (family == AF_INET6 || family == 0) { 339 ai = ai_alloc(AF_INET6, sizeof(struct sockaddr_in6)); 340 if (ai == NULL) { 341 freeaddrinfo(ai_list); 342 return (EAI_MEMORY); 343 } 344 ai->ai_socktype = socktype; 345 ai->ai_protocol = protocol; 346 SIN6(ai->ai_addr)->sin6_port = port; 347 ai->ai_next = ai_list; 348 ai_list = ai; 349 } 350 351 *res = ai_list; 352 return (0); 353 } 354 355 /* 356 * If the family isn't specified or AI_NUMERICHOST specified, check 357 * first to see if it is a numeric address. 358 * Though the gethostbyname2() routine will recognize numeric addresses, 359 * it will only recognize the format that it is being called for. Thus, 360 * a numeric AF_INET address will be treated by the AF_INET6 call as 361 * a domain name, and vice versa. Checking for both numerics here 362 * avoids that. 363 */ 364 if (hostname != NULL && 365 (family == 0 || (flags & AI_NUMERICHOST) != 0)) { 366 char abuf[sizeof(struct in6_addr)]; 367 char nbuf[NI_MAXHOST]; 368 int addrsize, addroff; 369#ifdef IRS_HAVE_SIN6_SCOPE_ID 370 char *p, *ep; 371 char ntmp[NI_MAXHOST]; 372 isc_uint32_t scopeid; 373#endif 374 375#ifdef IRS_HAVE_SIN6_SCOPE_ID 376 /* 377 * Scope identifier portion. 378 */ 379 ntmp[0] = '\0'; 380 if (strchr(hostname, '%') != NULL) { 381 strncpy(ntmp, hostname, sizeof(ntmp) - 1); 382 ntmp[sizeof(ntmp) - 1] = '\0'; 383 p = strchr(ntmp, '%'); 384 ep = NULL; 385 386 /* 387 * Vendors may want to support non-numeric 388 * scopeid around here. 389 */ 390 391 if (p != NULL) 392 scopeid = (isc_uint32_t)strtoul(p + 1, 393 &ep, 10); 394 if (p != NULL && ep != NULL && ep[0] == '\0') 395 *p = '\0'; 396 else { 397 ntmp[0] = '\0'; 398 scopeid = 0; 399 } 400 } else 401 scopeid = 0; 402#endif 403 404 if (inet_pton(AF_INET, hostname, (struct in_addr *)abuf) 405 == 1) { 406 if (family == AF_INET6) { 407 /* 408 * Convert to a V4 mapped address. 409 */ 410 struct in6_addr *a6 = (struct in6_addr *)abuf; 411 memcpy(&a6->s6_addr[12], &a6->s6_addr[0], 4); 412 memset(&a6->s6_addr[10], 0xff, 2); 413 memset(&a6->s6_addr[0], 0, 10); 414 goto inet6_addr; 415 } 416 addrsize = sizeof(struct in_addr); 417 addroff = (char *)(&SIN(0)->sin_addr) - (char *)0; 418 family = AF_INET; 419 goto common; 420#ifdef IRS_HAVE_SIN6_SCOPE_ID 421 } else if (ntmp[0] != '\0' && 422 inet_pton(AF_INET6, ntmp, abuf) == 1) { 423 if (family && family != AF_INET6) 424 return (EAI_NONAME); 425 addrsize = sizeof(struct in6_addr); 426 addroff = (char *)(&SIN6(0)->sin6_addr) - (char *)0; 427 family = AF_INET6; 428 goto common; 429#endif 430 } else if (inet_pton(AF_INET6, hostname, abuf) == 1) { 431 if (family != 0 && family != AF_INET6) 432 return (EAI_NONAME); 433 inet6_addr: 434 addrsize = sizeof(struct in6_addr); 435 addroff = (char *)(&SIN6(0)->sin6_addr) - (char *)0; 436 family = AF_INET6; 437 438 common: 439 ai = ai_alloc(family, 440 ((family == AF_INET6) ? 441 sizeof(struct sockaddr_in6) : 442 sizeof(struct sockaddr_in))); 443 if (ai == NULL) 444 return (EAI_MEMORY); 445 ai_list = ai; 446 ai->ai_socktype = socktype; 447 SIN(ai->ai_addr)->sin_port = port; 448 memcpy((char *)ai->ai_addr + addroff, abuf, addrsize); 449 if ((flags & AI_CANONNAME) != 0) { 450#ifdef IRS_HAVE_SIN6_SCOPE_ID 451 if (ai->ai_family == AF_INET6) 452 SIN6(ai->ai_addr)->sin6_scope_id = 453 scopeid; 454#endif 455 if (getnameinfo(ai->ai_addr, ai->ai_addrlen, 456 nbuf, sizeof(nbuf), NULL, 0, 457 NI_NUMERICHOST) == 0) { 458 ai->ai_canonname = strdup(nbuf); 459 if (ai->ai_canonname == NULL) { 460 freeaddrinfo(ai); 461 return (EAI_MEMORY); 462 } 463 } else { 464 /* XXX raise error? */ 465 ai->ai_canonname = NULL; 466 } 467 } 468 goto done; 469 } else if ((flags & AI_NUMERICHOST) != 0) { 470 return (EAI_NONAME); 471 } 472 } 473 474 if (hostname == NULL && (flags & AI_PASSIVE) == 0) { 475 set_order(family, net_order); 476 for (i = 0; i < FOUND_MAX; i++) { 477 if (net_order[i] == NULL) 478 break; 479 err = (net_order[i])(hostname, flags, &ai_list, 480 socktype, port); 481 if (err != 0) { 482 if (ai_list != NULL) 483 freeaddrinfo(ai_list); 484 break; 485 } 486 } 487 } else 488 err = resolve_name(family, hostname, flags, &ai_list, 489 socktype, port); 490 491 if (ai_list == NULL) { 492 if (err == 0) 493 err = EAI_NONAME; 494 return (err); 495 } 496 497done: 498 ai_list = ai_reverse(ai_list); 499 500 *res = ai_list; 501 return (0); 502} 503 504typedef struct gai_restrans { 505 dns_clientrestrans_t *xid; 506 isc_boolean_t is_inprogress; 507 int error; 508 struct addrinfo ai_sentinel; 509 struct gai_resstate *resstate; 510} gai_restrans_t; 511 512typedef struct gai_resstate { 513 isc_mem_t *mctx; 514 struct gai_statehead *head; 515 dns_fixedname_t fixedname; 516 dns_name_t *qname; 517 gai_restrans_t *trans4; 518 gai_restrans_t *trans6; 519 ISC_LINK(struct gai_resstate) link; 520} gai_resstate_t; 521 522typedef struct gai_statehead { 523 int ai_family; 524 int ai_flags; 525 int ai_socktype; 526 int ai_port; 527 isc_appctx_t *actx; 528 dns_client_t *dnsclient; 529 ISC_LIST(struct gai_resstate) resstates; 530 unsigned int activestates; 531} gai_statehead_t; 532 533static isc_result_t 534make_resstate(isc_mem_t *mctx, gai_statehead_t *head, const char *hostname, 535 const char *domain, gai_resstate_t **statep) 536{ 537 isc_result_t result; 538 gai_resstate_t *state; 539 dns_fixedname_t fixeddomain; 540 dns_name_t *qdomain; 541 size_t namelen; 542 isc_buffer_t b; 543 isc_boolean_t need_v4 = ISC_FALSE; 544 isc_boolean_t need_v6 = ISC_FALSE; 545 546 state = isc_mem_get(mctx, sizeof(*state)); 547 if (state == NULL) 548 return (ISC_R_NOMEMORY); 549 550 /* Construct base domain name */ 551 namelen = strlen(domain); 552 isc_buffer_init(&b, domain, namelen); 553 isc_buffer_add(&b, namelen); 554 dns_fixedname_init(&fixeddomain); 555 qdomain = dns_fixedname_name(&fixeddomain); 556 result = dns_name_fromtext(qdomain, &b, dns_rootname, 0, NULL); 557 if (result != ISC_R_SUCCESS) { 558 isc_mem_put(mctx, state, sizeof(*state)); 559 return (result); 560 } 561 562 /* Construct query name */ 563 namelen = strlen(hostname); 564 isc_buffer_init(&b, hostname, namelen); 565 isc_buffer_add(&b, namelen); 566 dns_fixedname_init(&state->fixedname); 567 state->qname = dns_fixedname_name(&state->fixedname); 568 result = dns_name_fromtext(state->qname, &b, qdomain, 0, NULL); 569 if (result != ISC_R_SUCCESS) { 570 isc_mem_put(mctx, state, sizeof(*state)); 571 return (result); 572 } 573 574 if (head->ai_family == AF_UNSPEC || head->ai_family == AF_INET) 575 need_v4 = ISC_TRUE; 576 if (head->ai_family == AF_UNSPEC || head->ai_family == AF_INET6) 577 need_v6 = ISC_TRUE; 578 579 state->trans6 = NULL; 580 state->trans4 = NULL; 581 if (need_v4) { 582 state->trans4 = isc_mem_get(mctx, sizeof(gai_restrans_t)); 583 if (state->trans4 == NULL) { 584 isc_mem_put(mctx, state, sizeof(*state)); 585 return (ISC_R_NOMEMORY); 586 } 587 state->trans4->error = 0; 588 state->trans4->xid = NULL; 589 state->trans4->resstate = state; 590 state->trans4->is_inprogress = ISC_TRUE; 591 state->trans4->ai_sentinel.ai_next = NULL; 592 } 593 if (need_v6) { 594 state->trans6 = isc_mem_get(mctx, sizeof(gai_restrans_t)); 595 if (state->trans6 == NULL) { 596 if (state->trans4 != NULL) 597 isc_mem_put(mctx, state->trans4, 598 sizeof(*state->trans4)); 599 isc_mem_put(mctx, state, sizeof(*state)); 600 return (ISC_R_NOMEMORY); 601 } 602 state->trans6->error = 0; 603 state->trans6->xid = NULL; 604 state->trans6->resstate = state; 605 state->trans6->is_inprogress = ISC_TRUE; 606 state->trans6->ai_sentinel.ai_next = NULL; 607 } 608 609 state->mctx = mctx; 610 state->head = head; 611 ISC_LINK_INIT(state, link); 612 613 *statep = state; 614 615 return (ISC_R_SUCCESS); 616} 617 618static isc_result_t 619make_resstates(isc_mem_t *mctx, const char *hostname, gai_statehead_t *head, 620 irs_resconf_t *resconf) 621{ 622 isc_result_t result; 623 irs_resconf_searchlist_t *searchlist; 624 irs_resconf_search_t *searchent; 625 gai_resstate_t *resstate, *resstate0; 626 627 resstate0 = NULL; 628 result = make_resstate(mctx, head, hostname, ".", &resstate0); 629 if (result != ISC_R_SUCCESS) 630 return (result); 631 632 searchlist = irs_resconf_getsearchlist(resconf); 633 for (searchent = ISC_LIST_HEAD(*searchlist); searchent != NULL; 634 searchent = ISC_LIST_NEXT(searchent, link)) { 635 resstate = NULL; 636 result = make_resstate(mctx, head, hostname, 637 (const char *)searchent->domain, 638 &resstate); 639 if (result != ISC_R_SUCCESS) 640 break; 641 642 ISC_LIST_APPEND(head->resstates, resstate, link); 643 head->activestates++; 644 } 645 646 /* 647 * Insert the original hostname either at the head or the tail of the 648 * state list, depending on the number of labels contained in the 649 * original name and the 'ndots' configuration parameter. 650 */ 651 if (dns_name_countlabels(resstate0->qname) > 652 irs_resconf_getndots(resconf) + 1) { 653 ISC_LIST_PREPEND(head->resstates, resstate0, link); 654 } else 655 ISC_LIST_APPEND(head->resstates, resstate0, link); 656 head->activestates++; 657 658 if (result != ISC_R_SUCCESS) { 659 while ((resstate = ISC_LIST_HEAD(head->resstates)) != NULL) { 660 ISC_LIST_UNLINK(head->resstates, resstate, link); 661 if (resstate->trans4 != NULL) { 662 isc_mem_put(mctx, resstate->trans4, 663 sizeof(*resstate->trans4)); 664 } 665 if (resstate->trans6 != NULL) { 666 isc_mem_put(mctx, resstate->trans6, 667 sizeof(*resstate->trans6)); 668 } 669 670 isc_mem_put(mctx, resstate, sizeof(*resstate)); 671 } 672 } 673 674 return (result); 675} 676 677static void 678process_answer(isc_task_t *task, isc_event_t *event) { 679 int error = 0, family; 680 gai_restrans_t *trans = event->ev_arg; 681 gai_resstate_t *resstate; 682 dns_clientresevent_t *rev = (dns_clientresevent_t *)event; 683 dns_rdatatype_t qtype; 684 dns_name_t *name; 685 686 REQUIRE(trans != NULL); 687 resstate = trans->resstate; 688 REQUIRE(resstate != NULL); 689 REQUIRE(task != NULL); 690 691 if (trans == resstate->trans4) { 692 family = AF_INET; 693 qtype = dns_rdatatype_a; 694 } else { 695 INSIST(trans == resstate->trans6); 696 family = AF_INET6; 697 qtype = dns_rdatatype_aaaa; 698 } 699 700 INSIST(trans->is_inprogress); 701 trans->is_inprogress = ISC_FALSE; 702 703 switch (rev->result) { 704 case ISC_R_SUCCESS: 705 case DNS_R_NCACHENXDOMAIN: /* treat this as a fatal error? */ 706 case DNS_R_NCACHENXRRSET: 707 break; 708 default: 709 switch (rev->vresult) { 710 case DNS_R_SIGINVALID: 711 case DNS_R_SIGEXPIRED: 712 case DNS_R_SIGFUTURE: 713 case DNS_R_KEYUNAUTHORIZED: 714 case DNS_R_MUSTBESECURE: 715 case DNS_R_COVERINGNSEC: 716 case DNS_R_NOTAUTHORITATIVE: 717 case DNS_R_NOVALIDKEY: 718 case DNS_R_NOVALIDDS: 719 case DNS_R_NOVALIDSIG: 720 error = EAI_INSECUREDATA; 721 break; 722 default: 723 error = EAI_FAIL; 724 } 725 goto done; 726 } 727 728 /* Parse the response and construct the addrinfo chain */ 729 for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL; 730 name = ISC_LIST_NEXT(name, link)) { 731 isc_result_t result; 732 dns_rdataset_t *rdataset; 733 isc_buffer_t b; 734 isc_region_t r; 735 char t[1024]; 736 737 for (rdataset = ISC_LIST_HEAD(name->list); 738 rdataset != NULL; 739 rdataset = ISC_LIST_NEXT(rdataset, link)) { 740 if (!dns_rdataset_isassociated(rdataset)) 741 continue; 742 if (rdataset->type != qtype) 743 continue; 744 745 if ((resstate->head->ai_flags & AI_CANONNAME) != 0) { 746 isc_buffer_init(&b, t, sizeof(t)); 747 result = dns_name_totext(name, ISC_TRUE, &b); 748 if (result != ISC_R_SUCCESS) { 749 error = EAI_FAIL; 750 goto done; 751 } 752 isc_buffer_putuint8(&b, '\0'); 753 isc_buffer_usedregion(&b, &r); 754 } 755 756 for (result = dns_rdataset_first(rdataset); 757 result == ISC_R_SUCCESS; 758 result = dns_rdataset_next(rdataset)) { 759 struct addrinfo *ai; 760 dns_rdata_t rdata; 761 dns_rdata_in_a_t rdata_a; 762 dns_rdata_in_aaaa_t rdata_aaaa; 763 764 ai = ai_alloc(family, 765 ((family == AF_INET6) ? 766 sizeof(struct sockaddr_in6) : 767 sizeof(struct sockaddr_in))); 768 if (ai == NULL) { 769 error = EAI_MEMORY; 770 goto done; 771 } 772 ai->ai_socktype = resstate->head->ai_socktype; 773 ai->ai_next = trans->ai_sentinel.ai_next; 774 trans->ai_sentinel.ai_next = ai; 775 776 /* 777 * Set AF-specific parameters 778 * (IPv4/v6 address/port) 779 */ 780 dns_rdata_init(&rdata); 781 switch (family) { 782 case AF_INET: 783 dns_rdataset_current(rdataset, &rdata); 784 dns_rdata_tostruct(&rdata, &rdata_a, 785 NULL); 786 787 SIN(ai->ai_addr)->sin_port = 788 resstate->head->ai_port; 789 memcpy(&SIN(ai->ai_addr)->sin_addr, 790 &rdata_a.in_addr, 4); 791 dns_rdata_freestruct(&rdata_a); 792 break; 793 case AF_INET6: 794 dns_rdataset_current(rdataset, &rdata); 795 dns_rdata_tostruct(&rdata, &rdata_aaaa, 796 NULL); 797 SIN6(ai->ai_addr)->sin6_port = 798 resstate->head->ai_port; 799 memcpy(&SIN6(ai->ai_addr)->sin6_addr, 800 &rdata_aaaa.in6_addr, 16); 801 dns_rdata_freestruct(&rdata_aaaa); 802 break; 803 } 804 805 if ((resstate->head->ai_flags & AI_CANONNAME) 806 != 0) { 807 ai->ai_canonname = 808 strdup((const char *)r.base); 809 if (ai->ai_canonname == NULL) { 810 error = EAI_MEMORY; 811 goto done; 812 } 813 } 814 } 815 } 816 } 817 818 done: 819 dns_client_freeresanswer(resstate->head->dnsclient, &rev->answerlist); 820 dns_client_destroyrestrans(&trans->xid); 821 822 isc_event_free(&event); 823 824 /* Make sure that error == 0 iff we have a non-empty list */ 825 if (error == 0) { 826 if (trans->ai_sentinel.ai_next == NULL) 827 error = EAI_NONAME; 828 } else { 829 if (trans->ai_sentinel.ai_next != NULL) { 830 freeaddrinfo(trans->ai_sentinel.ai_next); 831 trans->ai_sentinel.ai_next = NULL; 832 } 833 } 834 trans->error = error; 835 836 /* Check whether we are done */ 837 if ((resstate->trans4 == NULL || !resstate->trans4->is_inprogress) && 838 (resstate->trans6 == NULL || !resstate->trans6->is_inprogress)) { 839 /* 840 * We're done for this state. If there is no other outstanding 841 * state, we can exit. 842 */ 843 resstate->head->activestates--; 844 if (resstate->head->activestates == 0) { 845 isc_app_ctxsuspend(resstate->head->actx); 846 return; 847 } 848 849 /* 850 * There are outstanding states, but if we are at the head 851 * of the state list (i.e., at the highest search priority) 852 * and have any answer, we can stop now by canceling the 853 * others. 854 */ 855 if (resstate == ISC_LIST_HEAD(resstate->head->resstates)) { 856 if ((resstate->trans4 != NULL && 857 resstate->trans4->ai_sentinel.ai_next != NULL) || 858 (resstate->trans6 != NULL && 859 resstate->trans6->ai_sentinel.ai_next != NULL)) { 860 gai_resstate_t *rest; 861 862 for (rest = ISC_LIST_NEXT(resstate, link); 863 rest != NULL; 864 rest = ISC_LIST_NEXT(rest, link)) { 865 if (rest->trans4 != NULL && 866 rest->trans4->xid != NULL) 867 dns_client_cancelresolve( 868 rest->trans4->xid); 869 if (rest->trans6 != NULL && 870 rest->trans6->xid != NULL) 871 dns_client_cancelresolve( 872 rest->trans6->xid); 873 } 874 } else { 875 /* 876 * This search fails, so we move to the tail 877 * of the list so that the next entry will 878 * have the highest priority. 879 */ 880 ISC_LIST_UNLINK(resstate->head->resstates, 881 resstate, link); 882 ISC_LIST_APPEND(resstate->head->resstates, 883 resstate, link); 884 } 885 } 886 } 887} 888 889static int 890resolve_name(int family, const char *hostname, int flags, 891 struct addrinfo **aip, int socktype, int port) 892{ 893 isc_result_t result; 894 irs_context_t *irsctx; 895 irs_resconf_t *conf; 896 isc_mem_t *mctx; 897 isc_appctx_t *actx; 898 isc_task_t *task; 899 int terror = 0; 900 int error = 0; 901 dns_client_t *client; 902 gai_resstate_t *resstate; 903 gai_statehead_t head; 904 isc_boolean_t all_fail = ISC_TRUE; 905 906 /* get IRS context and the associated parameters */ 907 irsctx = NULL; 908 result = irs_context_get(&irsctx); 909 if (result != ISC_R_SUCCESS) 910 return (EAI_FAIL); 911 actx = irs_context_getappctx(irsctx); 912 913 mctx = irs_context_getmctx(irsctx); 914 task = irs_context_gettask(irsctx); 915 conf = irs_context_getresconf(irsctx); 916 client = irs_context_getdnsclient(irsctx); 917 918 /* construct resolution states */ 919 head.activestates = 0; 920 head.ai_family = family; 921 head.ai_socktype = socktype; 922 head.ai_flags = flags; 923 head.ai_port = port; 924 head.actx = actx; 925 head.dnsclient = client; 926 ISC_LIST_INIT(head.resstates); 927 result = make_resstates(mctx, hostname, &head, conf); 928 if (result != ISC_R_SUCCESS) 929 return (EAI_FAIL); 930 931 for (resstate = ISC_LIST_HEAD(head.resstates); 932 resstate != NULL; resstate = ISC_LIST_NEXT(resstate, link)) { 933 if (resstate->trans4 != NULL) { 934 result = dns_client_startresolve(client, 935 resstate->qname, 936 dns_rdataclass_in, 937 dns_rdatatype_a, 938 0, task, 939 process_answer, 940 resstate->trans4, 941 &resstate->trans4->xid); 942 if (result == ISC_R_SUCCESS) { 943 resstate->trans4->is_inprogress = ISC_TRUE; 944 all_fail = ISC_FALSE; 945 } else 946 resstate->trans4->is_inprogress = ISC_FALSE; 947 } 948 if (resstate->trans6 != NULL) { 949 result = dns_client_startresolve(client, 950 resstate->qname, 951 dns_rdataclass_in, 952 dns_rdatatype_aaaa, 953 0, task, 954 process_answer, 955 resstate->trans6, 956 &resstate->trans6->xid); 957 if (result == ISC_R_SUCCESS) { 958 resstate->trans6->is_inprogress = ISC_TRUE; 959 all_fail = ISC_FALSE; 960 } else 961 resstate->trans6->is_inprogress= ISC_FALSE; 962 } 963 } 964 if (!all_fail) { 965 /* Start all the events */ 966 isc_app_ctxrun(actx); 967 } else 968 error = EAI_FAIL; 969 970 /* Cleanup */ 971 while ((resstate = ISC_LIST_HEAD(head.resstates)) != NULL) { 972 int terror4 = 0, terror6 = 0; 973 974 ISC_LIST_UNLINK(head.resstates, resstate, link); 975 976 if (*aip == NULL) { 977 struct addrinfo *sentinel4 = NULL; 978 struct addrinfo *sentinel6 = NULL; 979 980 if (resstate->trans4 != NULL) { 981 sentinel4 = 982 resstate->trans4->ai_sentinel.ai_next; 983 resstate->trans4->ai_sentinel.ai_next = NULL; 984 } 985 if (resstate->trans6 != NULL) { 986 sentinel6 = 987 resstate->trans6->ai_sentinel.ai_next; 988 resstate->trans6->ai_sentinel.ai_next = NULL; 989 } 990 *aip = ai_concat(sentinel4, sentinel6); 991 } 992 993 if (resstate->trans4 != NULL) { 994 INSIST(resstate->trans4->xid == NULL); 995 terror4 = resstate->trans4->error; 996 isc_mem_put(mctx, resstate->trans4, 997 sizeof(*resstate->trans4)); 998 } 999 if (resstate->trans6 != NULL) { 1000 INSIST(resstate->trans6->xid == NULL); 1001 terror6 = resstate->trans6->error; 1002 isc_mem_put(mctx, resstate->trans6, 1003 sizeof(*resstate->trans6)); 1004 } 1005 1006 /* 1007 * If the entire lookup fails, we need to choose an appropriate 1008 * error code from individual codes. We'll try to provide as 1009 * specific a code as possible. In general, we are going to 1010 * find an error code other than EAI_NONAME (which is too 1011 * generic and may actually not be problematic in some cases). 1012 * EAI_NONAME will be set below if no better code is found. 1013 */ 1014 if (terror == 0 || terror == EAI_NONAME) { 1015 if (terror4 != 0 && terror4 != EAI_NONAME) 1016 terror = terror4; 1017 else if (terror6 != 0 && terror6 != EAI_NONAME) 1018 terror = terror6; 1019 } 1020 1021 isc_mem_put(mctx, resstate, sizeof(*resstate)); 1022 } 1023 1024 if (*aip == NULL) { 1025 error = terror; 1026 if (error == 0) 1027 error = EAI_NONAME; 1028 } 1029 1030#if 1 /* XXX: enabled for finding leaks. should be cleaned up later. */ 1031 isc_app_ctxfinish(actx); 1032 irs_context_destroy(&irsctx); 1033#endif 1034 1035 return (error); 1036} 1037 1038static char * 1039irs_strsep(char **stringp, const char *delim) { 1040 char *string = *stringp; 1041 char *s; 1042 const char *d; 1043 char sc, dc; 1044 1045 if (string == NULL) 1046 return (NULL); 1047 1048 for (s = string; *s != '\0'; s++) { 1049 sc = *s; 1050 for (d = delim; (dc = *d) != '\0'; d++) 1051 if (sc == dc) { 1052 *s++ = '\0'; 1053 *stringp = s; 1054 return (string); 1055 } 1056 } 1057 *stringp = NULL; 1058 return (string); 1059} 1060 1061static void 1062set_order(int family, int (**net_order)(const char *, int, struct addrinfo **, 1063 int, int)) 1064{ 1065 char *order, *tok; 1066 int found; 1067 1068 if (family) { 1069 switch (family) { 1070 case AF_INET: 1071 *net_order++ = add_ipv4; 1072 break; 1073 case AF_INET6: 1074 *net_order++ = add_ipv6; 1075 break; 1076 } 1077 } else { 1078 order = getenv("NET_ORDER"); 1079 found = 0; 1080 while (order != NULL) { 1081 /* 1082 * We ignore any unknown names. 1083 */ 1084 tok = irs_strsep(&order, ":"); 1085 if (strcasecmp(tok, "inet6") == 0) { 1086 if ((found & FOUND_IPV6) == 0) 1087 *net_order++ = add_ipv6; 1088 found |= FOUND_IPV6; 1089 } else if (strcasecmp(tok, "inet") == 0 || 1090 strcasecmp(tok, "inet4") == 0) { 1091 if ((found & FOUND_IPV4) == 0) 1092 *net_order++ = add_ipv4; 1093 found |= FOUND_IPV4; 1094 } 1095 } 1096 1097 /* 1098 * Add in anything that we didn't find. 1099 */ 1100 if ((found & FOUND_IPV4) == 0) 1101 *net_order++ = add_ipv4; 1102 if ((found & FOUND_IPV6) == 0) 1103 *net_order++ = add_ipv6; 1104 } 1105 *net_order = NULL; 1106 return; 1107} 1108 1109static char v4_loop[4] = { 127, 0, 0, 1 }; 1110 1111static int 1112add_ipv4(const char *hostname, int flags, struct addrinfo **aip, 1113 int socktype, int port) 1114{ 1115 struct addrinfo *ai; 1116 1117 UNUSED(hostname); 1118 UNUSED(flags); 1119 1120 ai = ai_clone(*aip, AF_INET); /* don't use ai_clone() */ 1121 if (ai == NULL) { 1122 freeaddrinfo(*aip); 1123 return (EAI_MEMORY); 1124 } 1125 1126 *aip = ai; 1127 ai->ai_socktype = socktype; 1128 SIN(ai->ai_addr)->sin_port = port; 1129 memcpy(&SIN(ai->ai_addr)->sin_addr, v4_loop, 4); 1130 1131 return (0); 1132} 1133 1134static char v6_loop[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; 1135 1136static int 1137add_ipv6(const char *hostname, int flags, struct addrinfo **aip, 1138 int socktype, int port) 1139{ 1140 struct addrinfo *ai; 1141 1142 UNUSED(hostname); 1143 UNUSED(flags); 1144 1145 ai = ai_clone(*aip, AF_INET6); /* don't use ai_clone() */ 1146 if (ai == NULL) { 1147 freeaddrinfo(*aip); 1148 return (EAI_MEMORY); 1149 } 1150 1151 *aip = ai; 1152 ai->ai_socktype = socktype; 1153 SIN6(ai->ai_addr)->sin6_port = port; 1154 memcpy(&SIN6(ai->ai_addr)->sin6_addr, v6_loop, 16); 1155 1156 return (0); 1157} 1158 1159/*% Free address info. */ 1160void 1161freeaddrinfo(struct addrinfo *ai) { 1162 struct addrinfo *ai_next; 1163 1164 while (ai != NULL) { 1165 ai_next = ai->ai_next; 1166 if (ai->ai_addr != NULL) 1167 free(ai->ai_addr); 1168 if (ai->ai_canonname) 1169 free(ai->ai_canonname); 1170 free(ai); 1171 ai = ai_next; 1172 } 1173} 1174 1175#ifdef AF_LOCAL 1176static int 1177get_local(const char *name, int socktype, struct addrinfo **res) { 1178 struct addrinfo *ai; 1179 struct sockaddr_un *slocal; 1180 1181 if (socktype == 0) 1182 return (EAI_SOCKTYPE); 1183 1184 ai = ai_alloc(AF_LOCAL, sizeof(*slocal)); 1185 if (ai == NULL) 1186 return (EAI_MEMORY); 1187 1188 slocal = SLOCAL(ai->ai_addr); 1189 strncpy(slocal->sun_path, name, sizeof(slocal->sun_path)); 1190 1191 ai->ai_socktype = socktype; 1192 /* 1193 * ai->ai_flags, ai->ai_protocol, ai->ai_canonname, 1194 * and ai->ai_next were initialized to zero. 1195 */ 1196 1197 *res = ai; 1198 return (0); 1199} 1200#endif 1201 1202/*! 1203 * Allocate an addrinfo structure, and a sockaddr structure 1204 * of the specificed length. We initialize: 1205 * ai_addrlen 1206 * ai_family 1207 * ai_addr 1208 * ai_addr->sa_family 1209 * ai_addr->sa_len (IRS_PLATFORM_HAVESALEN) 1210 * and everything else is initialized to zero. 1211 */ 1212static struct addrinfo * 1213ai_alloc(int family, int addrlen) { 1214 struct addrinfo *ai; 1215 1216 ai = (struct addrinfo *)calloc(1, sizeof(*ai)); 1217 if (ai == NULL) 1218 return (NULL); 1219 1220 ai->ai_addr = SA(calloc(1, addrlen)); 1221 if (ai->ai_addr == NULL) { 1222 free(ai); 1223 return (NULL); 1224 } 1225 ai->ai_addrlen = addrlen; 1226 ai->ai_family = family; 1227 ai->ai_addr->sa_family = family; 1228#ifdef IRS_PLATFORM_HAVESALEN 1229 ai->ai_addr->sa_len = addrlen; 1230#endif 1231 return (ai); 1232} 1233 1234static struct addrinfo * 1235ai_clone(struct addrinfo *oai, int family) { 1236 struct addrinfo *ai; 1237 1238 ai = ai_alloc(family, ((family == AF_INET6) ? 1239 sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in))); 1240 1241 if (ai == NULL) { 1242 if (oai != NULL) 1243 freeaddrinfo(oai); 1244 return (NULL); 1245 } 1246 if (oai == NULL) 1247 return (ai); 1248 1249 ai->ai_flags = oai->ai_flags; 1250 ai->ai_socktype = oai->ai_socktype; 1251 ai->ai_protocol = oai->ai_protocol; 1252 ai->ai_canonname = NULL; 1253 ai->ai_next = oai; 1254 return (ai); 1255} 1256 1257static struct addrinfo * 1258ai_reverse(struct addrinfo *oai) { 1259 struct addrinfo *nai, *tai; 1260 1261 nai = NULL; 1262 1263 while (oai != NULL) { 1264 /* 1265 * Grab one off the old list. 1266 */ 1267 tai = oai; 1268 oai = oai->ai_next; 1269 /* 1270 * Put it on the front of the new list. 1271 */ 1272 tai->ai_next = nai; 1273 nai = tai; 1274 } 1275 return (nai); 1276} 1277 1278 1279static struct addrinfo * 1280ai_concat(struct addrinfo *ai1, struct addrinfo *ai2) { 1281 struct addrinfo *ai_tmp; 1282 1283 if (ai1 == NULL) 1284 return (ai2); 1285 else if (ai2 == NULL) 1286 return (ai1); 1287 1288 for (ai_tmp = ai1; ai_tmp != NULL && ai_tmp->ai_next != NULL; 1289 ai_tmp = ai_tmp->ai_next) 1290 ; 1291 1292 ai_tmp->ai_next = ai2; 1293 1294 return (ai1); 1295} 1296