1 /* $OpenBSD: getaddrinfo_async.c,v 1.45 2015/09/20 14:19:21 eric Exp $ */ 2 /* 3 * Copyright (c) 2012 Eric Faurot <eric@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/types.h> 19 #include <sys/socket.h> 20 #include <sys/uio.h> 21 #include <netinet/in.h> 22 #include <arpa/nameser.h> 23 #include <net/if.h> 24 #include <netdb.h> 25 26 #include <asr.h> 27 #include <errno.h> 28 #include <ifaddrs.h> 29 #include <resolv.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <unistd.h> 33 #include <limits.h> 34 35 #ifdef YP 36 #include <rpc/rpc.h> 37 #include <rpcsvc/yp.h> 38 #include <rpcsvc/ypclnt.h> 39 #include "ypinternal.h" 40 #endif 41 42 #include "asr_private.h" 43 44 struct match { 45 int family; 46 int socktype; 47 int protocol; 48 }; 49 50 static int getaddrinfo_async_run(struct asr_query *, struct asr_result *); 51 static int get_port(const char *, const char *, int); 52 static int iter_family(struct asr_query *, int); 53 static int addrinfo_add(struct asr_query *, const struct sockaddr *, const char *); 54 static int addrinfo_from_file(struct asr_query *, int, FILE *); 55 static int addrinfo_from_pkt(struct asr_query *, char *, size_t); 56 static int addrconfig_setup(struct asr_query *); 57 #ifdef YP 58 static int addrinfo_from_yp(struct asr_query *, int, char *); 59 #endif 60 61 static const struct match matches[] = { 62 { PF_INET, SOCK_DGRAM, IPPROTO_UDP }, 63 { PF_INET, SOCK_STREAM, IPPROTO_TCP }, 64 { PF_INET, SOCK_RAW, 0 }, 65 { PF_INET6, SOCK_DGRAM, IPPROTO_UDP }, 66 { PF_INET6, SOCK_STREAM, IPPROTO_TCP }, 67 { PF_INET6, SOCK_RAW, 0 }, 68 { -1, 0, 0, }, 69 }; 70 71 #define MATCH_FAMILY(a, b) ((a) == matches[(b)].family || (a) == PF_UNSPEC) 72 #define MATCH_PROTO(a, b) ((a) == matches[(b)].protocol || (a) == 0 || matches[(b)].protocol == 0) 73 /* Do not match SOCK_RAW unless explicitely specified */ 74 #define MATCH_SOCKTYPE(a, b) ((a) == matches[(b)].socktype || ((a) == 0 && \ 75 matches[(b)].socktype != SOCK_RAW)) 76 77 enum { 78 DOM_INIT, 79 DOM_DOMAIN, 80 DOM_DONE 81 }; 82 83 struct asr_query * 84 getaddrinfo_async(const char *hostname, const char *servname, 85 const struct addrinfo *hints, void *asr) 86 { 87 struct asr_ctx *ac; 88 struct asr_query *as; 89 char alias[MAXDNAME]; 90 91 ac = _asr_use_resolver(asr); 92 if ((as = _asr_async_new(ac, ASR_GETADDRINFO)) == NULL) 93 goto abort; /* errno set */ 94 as->as_run = getaddrinfo_async_run; 95 96 if (hostname) { 97 if (_asr_hostalias(ac, hostname, alias, sizeof(alias))) 98 hostname = alias; 99 if ((as->as.ai.hostname = strdup(hostname)) == NULL) 100 goto abort; /* errno set */ 101 } 102 if (servname && (as->as.ai.servname = strdup(servname)) == NULL) 103 goto abort; /* errno set */ 104 if (hints) 105 memmove(&as->as.ai.hints, hints, sizeof *hints); 106 else { 107 memset(&as->as.ai.hints, 0, sizeof as->as.ai.hints); 108 as->as.ai.hints.ai_family = PF_UNSPEC; 109 as->as.ai.hints.ai_flags = AI_ADDRCONFIG; 110 } 111 112 _asr_ctx_unref(ac); 113 return (as); 114 abort: 115 if (as) 116 _asr_async_free(as); 117 _asr_ctx_unref(ac); 118 return (NULL); 119 } 120 DEF_WEAK(getaddrinfo_async); 121 122 static int 123 getaddrinfo_async_run(struct asr_query *as, struct asr_result *ar) 124 { 125 #ifdef YP 126 static char *domain = NULL; 127 char *res; 128 int len; 129 char *name; 130 #endif 131 char fqdn[MAXDNAME]; 132 const char *str; 133 struct addrinfo *ai; 134 int i, family, r; 135 FILE *f; 136 union { 137 struct sockaddr sa; 138 struct sockaddr_in sain; 139 struct sockaddr_in6 sain6; 140 } sa; 141 142 next: 143 switch (as->as_state) { 144 145 case ASR_STATE_INIT: 146 147 /* 148 * First, make sure the parameters are valid. 149 */ 150 151 as->as_count = 0; 152 153 if (as->as.ai.hostname == NULL && 154 as->as.ai.servname == NULL) { 155 ar->ar_gai_errno = EAI_NONAME; 156 async_set_state(as, ASR_STATE_HALT); 157 break; 158 } 159 160 if (as->as.ai.hostname && as->as.ai.hostname[0] == '\0') { 161 ar->ar_gai_errno = EAI_NODATA; 162 async_set_state(as, ASR_STATE_HALT); 163 break; 164 } 165 166 ai = &as->as.ai.hints; 167 168 if (ai->ai_addrlen || 169 ai->ai_canonname || 170 ai->ai_addr || 171 ai->ai_next) { 172 ar->ar_gai_errno = EAI_BADHINTS; 173 async_set_state(as, ASR_STATE_HALT); 174 break; 175 } 176 177 if (ai->ai_flags & ~AI_MASK || 178 (ai->ai_flags & AI_CANONNAME && ai->ai_flags & AI_FQDN)) { 179 ar->ar_gai_errno = EAI_BADFLAGS; 180 async_set_state(as, ASR_STATE_HALT); 181 break; 182 } 183 184 if (ai->ai_family != PF_UNSPEC && 185 ai->ai_family != PF_INET && 186 ai->ai_family != PF_INET6) { 187 ar->ar_gai_errno = EAI_FAMILY; 188 async_set_state(as, ASR_STATE_HALT); 189 break; 190 } 191 192 if (ai->ai_socktype && 193 ai->ai_socktype != SOCK_DGRAM && 194 ai->ai_socktype != SOCK_STREAM && 195 ai->ai_socktype != SOCK_RAW) { 196 ar->ar_gai_errno = EAI_SOCKTYPE; 197 async_set_state(as, ASR_STATE_HALT); 198 break; 199 } 200 201 if (ai->ai_socktype == SOCK_RAW && 202 get_port(as->as.ai.servname, NULL, 1) != 0) { 203 ar->ar_gai_errno = EAI_SERVICE; 204 async_set_state(as, ASR_STATE_HALT); 205 break; 206 } 207 208 /* Restrict result set to configured address families */ 209 if (ai->ai_flags & AI_ADDRCONFIG) { 210 if (addrconfig_setup(as) != 0) { 211 ar->ar_gai_errno = EAI_FAIL; 212 async_set_state(as, ASR_STATE_HALT); 213 break; 214 } 215 } 216 217 /* Make sure there is at least a valid combination */ 218 for (i = 0; matches[i].family != -1; i++) 219 if (MATCH_FAMILY(ai->ai_family, i) && 220 MATCH_SOCKTYPE(ai->ai_socktype, i) && 221 MATCH_PROTO(ai->ai_protocol, i)) 222 break; 223 if (matches[i].family == -1) { 224 ar->ar_gai_errno = EAI_BADHINTS; 225 async_set_state(as, ASR_STATE_HALT); 226 break; 227 } 228 229 if (ai->ai_protocol == 0 || ai->ai_protocol == IPPROTO_UDP) 230 as->as.ai.port_udp = get_port(as->as.ai.servname, "udp", 231 as->as.ai.hints.ai_flags & AI_NUMERICSERV); 232 if (ai->ai_protocol == 0 || ai->ai_protocol == IPPROTO_TCP) 233 as->as.ai.port_tcp = get_port(as->as.ai.servname, "tcp", 234 as->as.ai.hints.ai_flags & AI_NUMERICSERV); 235 if (as->as.ai.port_tcp == -2 || as->as.ai.port_udp == -2 || 236 (as->as.ai.port_tcp == -1 && as->as.ai.port_udp == -1) || 237 (ai->ai_protocol && (as->as.ai.port_udp == -1 || 238 as->as.ai.port_tcp == -1))) { 239 ar->ar_gai_errno = EAI_SERVICE; 240 async_set_state(as, ASR_STATE_HALT); 241 break; 242 } 243 244 ar->ar_gai_errno = 0; 245 246 /* If hostname is NULL, use local address */ 247 if (as->as.ai.hostname == NULL) { 248 for (family = iter_family(as, 1); 249 family != -1; 250 family = iter_family(as, 0)) { 251 /* 252 * We could use statically built sockaddrs for 253 * those, rather than parsing over and over. 254 */ 255 if (family == PF_INET) 256 str = (ai->ai_flags & AI_PASSIVE) ? \ 257 "0.0.0.0" : "127.0.0.1"; 258 else /* PF_INET6 */ 259 str = (ai->ai_flags & AI_PASSIVE) ? \ 260 "::" : "::1"; 261 /* This can't fail */ 262 _asr_sockaddr_from_str(&sa.sa, family, str); 263 if ((r = addrinfo_add(as, &sa.sa, NULL))) { 264 ar->ar_gai_errno = r; 265 break; 266 } 267 } 268 if (ar->ar_gai_errno == 0 && as->as_count == 0) { 269 ar->ar_gai_errno = EAI_NODATA; 270 } 271 async_set_state(as, ASR_STATE_HALT); 272 break; 273 } 274 275 /* Try numeric addresses first */ 276 for (family = iter_family(as, 1); 277 family != -1; 278 family = iter_family(as, 0)) { 279 280 if (_asr_sockaddr_from_str(&sa.sa, family, 281 as->as.ai.hostname) == -1) 282 continue; 283 284 if ((r = addrinfo_add(as, &sa.sa, NULL))) 285 ar->ar_gai_errno = r; 286 break; 287 } 288 if (ar->ar_gai_errno || as->as_count) { 289 async_set_state(as, ASR_STATE_HALT); 290 break; 291 } 292 293 if (ai->ai_flags & AI_NUMERICHOST) { 294 ar->ar_gai_errno = EAI_NONAME; 295 async_set_state(as, ASR_STATE_HALT); 296 break; 297 } 298 299 async_set_state(as, ASR_STATE_NEXT_DB); 300 break; 301 302 case ASR_STATE_NEXT_DB: 303 if (_asr_iter_db(as) == -1) { 304 async_set_state(as, ASR_STATE_NOT_FOUND); 305 break; 306 } 307 as->as_family_idx = 0; 308 async_set_state(as, ASR_STATE_SAME_DB); 309 break; 310 311 case ASR_STATE_NEXT_FAMILY: 312 as->as_family_idx += 1; 313 if (as->as.ai.hints.ai_family != AF_UNSPEC || 314 AS_FAMILY(as) == -1) { 315 /* The family was specified, or we have tried all 316 * families with this DB. 317 */ 318 if (as->as_count) { 319 ar->ar_gai_errno = 0; 320 async_set_state(as, ASR_STATE_HALT); 321 } else 322 async_set_state(as, ASR_STATE_NEXT_DOMAIN); 323 break; 324 } 325 async_set_state(as, ASR_STATE_SAME_DB); 326 break; 327 328 case ASR_STATE_NEXT_DOMAIN: 329 /* domain search is only for dns */ 330 if (AS_DB(as) != ASR_DB_DNS) { 331 async_set_state(as, ASR_STATE_NEXT_DB); 332 break; 333 } 334 as->as_family_idx = 0; 335 336 free(as->as.ai.fqdn); 337 as->as.ai.fqdn = NULL; 338 r = _asr_iter_domain(as, as->as.ai.hostname, fqdn, sizeof(fqdn)); 339 if (r == -1) { 340 async_set_state(as, ASR_STATE_NEXT_DB); 341 break; 342 } 343 if (r == 0) { 344 ar->ar_gai_errno = EAI_FAIL; 345 async_set_state(as, ASR_STATE_HALT); 346 break; 347 } 348 as->as.ai.fqdn = strdup(fqdn); 349 if (as->as.ai.fqdn == NULL) { 350 ar->ar_gai_errno = EAI_MEMORY; 351 async_set_state(as, ASR_STATE_HALT); 352 } 353 354 async_set_state(as, ASR_STATE_SAME_DB); 355 break; 356 357 case ASR_STATE_SAME_DB: 358 /* query the current DB again */ 359 switch (AS_DB(as)) { 360 case ASR_DB_DNS: 361 if (as->as.ai.fqdn == NULL) { 362 /* First try, initialize domain iteration */ 363 as->as_dom_flags = 0; 364 as->as_dom_step = DOM_INIT; 365 async_set_state(as, ASR_STATE_NEXT_DOMAIN); 366 break; 367 } 368 369 family = (as->as.ai.hints.ai_family == AF_UNSPEC) ? 370 AS_FAMILY(as) : as->as.ai.hints.ai_family; 371 372 if (family == AF_INET && 373 as->as.ai.flags & ASYNC_NO_INET) { 374 async_set_state(as, ASR_STATE_NEXT_FAMILY); 375 break; 376 } else if (family == AF_INET6 && 377 as->as.ai.flags & ASYNC_NO_INET6) { 378 async_set_state(as, ASR_STATE_NEXT_FAMILY); 379 break; 380 } 381 382 as->as.ai.subq = _res_query_async_ctx(as->as.ai.fqdn, 383 C_IN, (family == AF_INET6) ? T_AAAA : T_A, 384 as->as_ctx); 385 386 if (as->as.ai.subq == NULL) { 387 if (errno == ENOMEM) 388 ar->ar_gai_errno = EAI_MEMORY; 389 else 390 ar->ar_gai_errno = EAI_FAIL; 391 async_set_state(as, ASR_STATE_HALT); 392 break; 393 } 394 async_set_state(as, ASR_STATE_SUBQUERY); 395 break; 396 397 case ASR_DB_FILE: 398 f = fopen(_PATH_HOSTS, "re"); 399 if (f == NULL) { 400 async_set_state(as, ASR_STATE_NEXT_DB); 401 break; 402 } 403 family = (as->as.ai.hints.ai_family == AF_UNSPEC) ? 404 AS_FAMILY(as) : as->as.ai.hints.ai_family; 405 406 r = addrinfo_from_file(as, family, f); 407 if (r == -1) { 408 if (errno == ENOMEM) 409 ar->ar_gai_errno = EAI_MEMORY; 410 else 411 ar->ar_gai_errno = EAI_FAIL; 412 async_set_state(as, ASR_STATE_HALT); 413 } else 414 async_set_state(as, ASR_STATE_NEXT_FAMILY); 415 fclose(f); 416 break; 417 418 #ifdef YP 419 case ASR_DB_YP: 420 if (!domain && _yp_check(&domain) == 0) { 421 async_set_state(as, ASR_STATE_NEXT_DB); 422 break; 423 } 424 family = (as->as.ai.hints.ai_family == AF_UNSPEC) ? 425 AS_FAMILY(as) : as->as.ai.hints.ai_family; 426 427 name = as->as.ai.hostname; 428 429 /* XXX 430 * ipnodes.byname could also contain IPv4 address 431 */ 432 r = yp_match(domain, (family == AF_INET6) ? 433 "ipnodes.byname" : "hosts.byname", 434 name, strlen(name), &res, &len); 435 if (r == 0) { 436 r = addrinfo_from_yp(as, family, res); 437 free(res); 438 if (r == -1) { 439 if (errno == ENOMEM) 440 ar->ar_gai_errno = EAI_MEMORY; 441 else 442 ar->ar_gai_errno = EAI_FAIL; 443 async_set_state(as, ASR_STATE_HALT); 444 break; 445 } 446 } 447 async_set_state(as, ASR_STATE_NEXT_FAMILY); 448 break; 449 #endif 450 default: 451 async_set_state(as, ASR_STATE_NEXT_DB); 452 } 453 break; 454 455 case ASR_STATE_SUBQUERY: 456 if ((r = asr_run(as->as.ai.subq, ar)) == ASYNC_COND) 457 return (ASYNC_COND); 458 459 as->as.ai.subq = NULL; 460 461 if (ar->ar_datalen == -1) { 462 async_set_state(as, ASR_STATE_NEXT_FAMILY); 463 break; 464 } 465 466 r = addrinfo_from_pkt(as, ar->ar_data, ar->ar_datalen); 467 if (r == -1) { 468 if (errno == ENOMEM) 469 ar->ar_gai_errno = EAI_MEMORY; 470 else 471 ar->ar_gai_errno = EAI_FAIL; 472 async_set_state(as, ASR_STATE_HALT); 473 } else 474 async_set_state(as, ASR_STATE_NEXT_FAMILY); 475 free(ar->ar_data); 476 break; 477 478 case ASR_STATE_NOT_FOUND: 479 /* No result found. Maybe we can try again. */ 480 if (as->as.ai.flags & ASYNC_AGAIN) 481 ar->ar_gai_errno = EAI_AGAIN; 482 else 483 ar->ar_gai_errno = EAI_NODATA; 484 async_set_state(as, ASR_STATE_HALT); 485 break; 486 487 case ASR_STATE_HALT: 488 if (ar->ar_gai_errno == 0) { 489 ar->ar_count = as->as_count; 490 ar->ar_addrinfo = as->as.ai.aifirst; 491 as->as.ai.aifirst = NULL; 492 } else { 493 ar->ar_count = 0; 494 ar->ar_addrinfo = NULL; 495 } 496 return (ASYNC_DONE); 497 498 default: 499 ar->ar_errno = EOPNOTSUPP; 500 ar->ar_gai_errno = EAI_SYSTEM; 501 async_set_state(as, ASR_STATE_HALT); 502 break; 503 } 504 goto next; 505 } 506 507 /* 508 * Retreive the port number for the service name "servname" and 509 * the protocol "proto". 510 */ 511 static int 512 get_port(const char *servname, const char *proto, int numonly) 513 { 514 struct servent se; 515 struct servent_data sed; 516 int port, r; 517 const char *e; 518 519 if (servname == NULL) 520 return (0); 521 522 e = NULL; 523 port = strtonum(servname, 0, USHRT_MAX, &e); 524 if (e == NULL) 525 return (port); 526 if (errno == ERANGE) 527 return (-2); /* invalid */ 528 if (numonly) 529 return (-2); 530 531 memset(&sed, 0, sizeof(sed)); 532 r = getservbyname_r(servname, proto, &se, &sed); 533 port = ntohs(se.s_port); 534 endservent_r(&sed); 535 536 if (r == -1) 537 return (-1); /* not found */ 538 539 return (port); 540 } 541 542 /* 543 * Iterate over the address families that are to be queried. Use the 544 * list on the async context, unless a specific family was given in hints. 545 */ 546 static int 547 iter_family(struct asr_query *as, int first) 548 { 549 if (first) { 550 as->as_family_idx = 0; 551 if (as->as.ai.hints.ai_family != PF_UNSPEC) 552 return as->as.ai.hints.ai_family; 553 return AS_FAMILY(as); 554 } 555 556 if (as->as.ai.hints.ai_family != PF_UNSPEC) 557 return (-1); 558 559 as->as_family_idx++; 560 561 return AS_FAMILY(as); 562 } 563 564 /* 565 * Use the sockaddr at "sa" to extend the result list on the "as" context, 566 * with the specified canonical name "cname". This function adds one 567 * entry per protocol/socktype match. 568 */ 569 static int 570 addrinfo_add(struct asr_query *as, const struct sockaddr *sa, const char *cname) 571 { 572 struct addrinfo *ai; 573 int i, port, proto; 574 575 for (i = 0; matches[i].family != -1; i++) { 576 if (matches[i].family != sa->sa_family || 577 !MATCH_SOCKTYPE(as->as.ai.hints.ai_socktype, i) || 578 !MATCH_PROTO(as->as.ai.hints.ai_protocol, i)) 579 continue; 580 581 proto = as->as.ai.hints.ai_protocol; 582 if (!proto) 583 proto = matches[i].protocol; 584 585 if (proto == IPPROTO_TCP) 586 port = as->as.ai.port_tcp; 587 else if (proto == IPPROTO_UDP) 588 port = as->as.ai.port_udp; 589 else 590 port = 0; 591 592 /* servname specified, but not defined for this protocol */ 593 if (port == -1) 594 continue; 595 596 ai = calloc(1, sizeof(*ai) + sa->sa_len); 597 if (ai == NULL) 598 return (EAI_MEMORY); 599 ai->ai_family = sa->sa_family; 600 ai->ai_socktype = matches[i].socktype; 601 ai->ai_protocol = proto; 602 ai->ai_flags = as->as.ai.hints.ai_flags; 603 ai->ai_addrlen = sa->sa_len; 604 ai->ai_addr = (void *)(ai + 1); 605 if (cname && 606 as->as.ai.hints.ai_flags & (AI_CANONNAME | AI_FQDN)) { 607 if ((ai->ai_canonname = strdup(cname)) == NULL) { 608 free(ai); 609 return (EAI_MEMORY); 610 } 611 } 612 memmove(ai->ai_addr, sa, sa->sa_len); 613 if (sa->sa_family == PF_INET) 614 ((struct sockaddr_in *)ai->ai_addr)->sin_port = 615 htons(port); 616 else if (sa->sa_family == PF_INET6) 617 ((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = 618 htons(port); 619 620 if (as->as.ai.aifirst == NULL) 621 as->as.ai.aifirst = ai; 622 if (as->as.ai.ailast) 623 as->as.ai.ailast->ai_next = ai; 624 as->as.ai.ailast = ai; 625 as->as_count += 1; 626 } 627 628 return (0); 629 } 630 631 static int 632 addrinfo_from_file(struct asr_query *as, int family, FILE *f) 633 { 634 char *tokens[MAXTOKEN], *c, buf[BUFSIZ + 1]; 635 int n, i; 636 union { 637 struct sockaddr sa; 638 struct sockaddr_in sain; 639 struct sockaddr_in6 sain6; 640 } u; 641 642 for (;;) { 643 n = _asr_parse_namedb_line(f, tokens, MAXTOKEN, buf, sizeof(buf)); 644 if (n == -1) 645 break; /* ignore errors reading the file */ 646 647 for (i = 1; i < n; i++) { 648 if (strcasecmp(as->as.ai.hostname, tokens[i])) 649 continue; 650 if (_asr_sockaddr_from_str(&u.sa, family, tokens[0]) == -1) 651 continue; 652 break; 653 } 654 if (i == n) 655 continue; 656 657 if (as->as.ai.hints.ai_flags & (AI_CANONNAME | AI_FQDN)) 658 c = tokens[1]; 659 else 660 c = NULL; 661 662 if (addrinfo_add(as, &u.sa, c)) 663 return (-1); /* errno set */ 664 } 665 return (0); 666 } 667 668 static int 669 addrinfo_from_pkt(struct asr_query *as, char *pkt, size_t pktlen) 670 { 671 struct asr_unpack p; 672 struct asr_dns_header h; 673 struct asr_dns_query q; 674 struct asr_dns_rr rr; 675 int i; 676 union { 677 struct sockaddr sa; 678 struct sockaddr_in sain; 679 struct sockaddr_in6 sain6; 680 } u; 681 char buf[MAXDNAME], *c; 682 683 _asr_unpack_init(&p, pkt, pktlen); 684 _asr_unpack_header(&p, &h); 685 for (; h.qdcount; h.qdcount--) 686 _asr_unpack_query(&p, &q); 687 688 for (i = 0; i < h.ancount; i++) { 689 _asr_unpack_rr(&p, &rr); 690 if (rr.rr_type != q.q_type || 691 rr.rr_class != q.q_class) 692 continue; 693 694 memset(&u, 0, sizeof u); 695 if (rr.rr_type == T_A) { 696 u.sain.sin_len = sizeof u.sain; 697 u.sain.sin_family = AF_INET; 698 u.sain.sin_addr = rr.rr.in_a.addr; 699 u.sain.sin_port = 0; 700 } else if (rr.rr_type == T_AAAA) { 701 u.sain6.sin6_len = sizeof u.sain6; 702 u.sain6.sin6_family = AF_INET6; 703 u.sain6.sin6_addr = rr.rr.in_aaaa.addr6; 704 u.sain6.sin6_port = 0; 705 } else 706 continue; 707 708 if (as->as.ai.hints.ai_flags & AI_CANONNAME) { 709 _asr_strdname(rr.rr_dname, buf, sizeof buf); 710 buf[strlen(buf) - 1] = '\0'; 711 c = res_hnok(buf) ? buf : NULL; 712 } else if (as->as.ai.hints.ai_flags & AI_FQDN) 713 c = as->as.ai.fqdn; 714 else 715 c = NULL; 716 717 if (addrinfo_add(as, &u.sa, c)) 718 return (-1); /* errno set */ 719 } 720 return (0); 721 } 722 723 static int 724 addrconfig_setup(struct asr_query *as) 725 { 726 struct ifaddrs *ifa, *ifa0; 727 struct sockaddr_in *sinp; 728 struct sockaddr_in6 *sin6p; 729 730 if (getifaddrs(&ifa0) != 0) 731 return (-1); 732 733 as->as.ai.flags |= ASYNC_NO_INET | ASYNC_NO_INET6; 734 735 for (ifa = ifa0; ifa != NULL; ifa = ifa->ifa_next) { 736 if (ifa->ifa_addr == NULL) 737 continue; 738 739 switch (ifa->ifa_addr->sa_family) { 740 case PF_INET: 741 sinp = (struct sockaddr_in *)ifa->ifa_addr; 742 743 if (sinp->sin_addr.s_addr == htonl(INADDR_LOOPBACK)) 744 continue; 745 746 as->as.ai.flags &= ~ASYNC_NO_INET; 747 break; 748 case PF_INET6: 749 sin6p = (struct sockaddr_in6 *)ifa->ifa_addr; 750 751 if (IN6_IS_ADDR_LOOPBACK(&sin6p->sin6_addr)) 752 continue; 753 754 if (IN6_IS_ADDR_LINKLOCAL(&sin6p->sin6_addr)) 755 continue; 756 757 as->as.ai.flags &= ~ASYNC_NO_INET6; 758 break; 759 } 760 } 761 762 freeifaddrs(ifa0); 763 764 return (0); 765 } 766 767 #ifdef YP 768 static int 769 strsplit(char *line, char **tokens, int ntokens) 770 { 771 int ntok; 772 char *cp, **tp; 773 774 for (cp = line, tp = tokens, ntok = 0; 775 ntok < ntokens && (*tp = strsep(&cp, " \t")) != NULL; ) 776 if (**tp != '\0') { 777 tp++; 778 ntok++; 779 } 780 781 return (ntok); 782 } 783 784 static int 785 addrinfo_from_yp(struct asr_query *as, int family, char *line) 786 { 787 char *next, *tokens[MAXTOKEN], *c; 788 int ntok; 789 union { 790 struct sockaddr sa; 791 struct sockaddr_in sain; 792 struct sockaddr_in6 sain6; 793 } u; 794 795 for (next = line; line; line = next) { 796 if ((next = strchr(line, '\n'))) { 797 *next = '\0'; 798 next += 1; 799 } 800 ntok = strsplit(line, tokens, MAXTOKEN); 801 if (ntok < 2) 802 continue; 803 804 if (_asr_sockaddr_from_str(&u.sa, family, tokens[0]) == -1) 805 continue; 806 807 if (as->as.ai.hints.ai_flags & (AI_CANONNAME | AI_FQDN)) 808 c = tokens[1]; 809 else 810 c = NULL; 811 812 if (addrinfo_add(as, &u.sa, c)) 813 return (-1); /* errno set */ 814 } 815 return (0); 816 } 817 #endif 818