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