summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoritojun <>2000-02-25 04:41:41 +0000
committeritojun <>2000-02-25 04:41:41 +0000
commitcac3c52dcd8f0b5391bc42185087935b89ab8ab3 (patch)
tree211cba9ecd2d905b0490f6e06d261387b06cde36
parent3b9588da09797abe4aab6d311630b9c5f9425c12 (diff)
downloadopenbsd-cac3c52dcd8f0b5391bc42185087935b89ab8ab3.tar.gz
openbsd-cac3c52dcd8f0b5391bc42185087935b89ab8ab3.tar.bz2
openbsd-cac3c52dcd8f0b5391bc42185087935b89ab8ab3.zip
make getaddrinfo obey search order declared in resolv.conf.
the code duplicate is necessary because there's no low-level resolver function that looks up database against "any address family" query.
-rw-r--r--src/lib/libc/net/getaddrinfo.c1066
1 files changed, 924 insertions, 142 deletions
diff --git a/src/lib/libc/net/getaddrinfo.c b/src/lib/libc/net/getaddrinfo.c
index 823b21b2b3..2c10a02017 100644
--- a/src/lib/libc/net/getaddrinfo.c
+++ b/src/lib/libc/net/getaddrinfo.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: getaddrinfo.c,v 1.14 2000/02/21 04:14:09 itojun Exp $ */ 1/* $OpenBSD: getaddrinfo.c,v 1.15 2000/02/25 04:41:41 itojun Exp $ */
2 2
3/* 3/*
4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -54,21 +54,26 @@
54 * (1) what should we do against numeric hostname (2) what should we do 54 * (1) what should we do against numeric hostname (2) what should we do
55 * against NULL hostname (3) what is AI_ADDRCONFIG itself. AF not ready? 55 * against NULL hostname (3) what is AI_ADDRCONFIG itself. AF not ready?
56 * non-loopback address configured? global address configured? 56 * non-loopback address configured? global address configured?
57 * - The code makes use of following calls when asked to resolver with 57 * - To avoid search order issue, we have a big amount of code duplicate
58 * ai_family = PF_UNSPEC: 58 * from gethnamaddr.c and some other places. The issues that there's no
59 * getipnodebyname(host, AF_INET6); 59 * lower layer function to lookup "IPv4 or IPv6" record. Calling
60 * getipnodebyname(host, AF_INET); 60 * gethostbyname2 from getaddrinfo will end up in wrong search order, as
61 * This will result in the following queries if the node is configure to 61 * follows:
62 * prefer /etc/hosts than DNS: 62 * - The code makes use of following calls when asked to resolver with
63 * lookup /etc/hosts for IPv6 address 63 * ai_family = PF_UNSPEC:
64 * lookup DNS for IPv6 address 64 * getipnodebyname(host, AF_INET6);
65 * lookup /etc/hosts for IPv4 address 65 * getipnodebyname(host, AF_INET);
66 * lookup DNS for IPv4 address 66 * This will result in the following queries if the node is configure to
67 * which may not meet people's requirement. 67 * prefer /etc/hosts than DNS:
68 * The right thing to happen is to have underlying layer which does 68 * lookup /etc/hosts for IPv6 address
69 * PF_UNSPEC lookup (lookup both) and return chain of addrinfos. 69 * lookup DNS for IPv6 address
70 * This would result in a bit of code duplicate with _dns_ghbyname() and 70 * lookup /etc/hosts for IPv4 address
71 * friends. 71 * lookup DNS for IPv4 address
72 * which may not meet people's requirement.
73 * The right thing to happen is to have underlying layer which does
74 * PF_UNSPEC lookup (lookup both) and return chain of addrinfos.
75 * This would result in a bit of code duplicate with _dns_ghbyname() and
76 * friends.
72 */ 77 */
73 78
74#define INET6 79#define INET6
@@ -90,6 +95,15 @@
90#include <stdio.h> 95#include <stdio.h>
91#include <errno.h> 96#include <errno.h>
92 97
98#include <syslog.h>
99#include <stdarg.h>
100
101#ifdef YP
102#include <rpc/rpc.h>
103#include <rpcsvc/yp_prot.h>
104#include <rpcsvc/ypclnt.h>
105#endif
106
93#define SUCCESS 0 107#define SUCCESS 0
94#define ANY 0 108#define ANY 0
95#define YES 1 109#define YES 1
@@ -156,6 +170,9 @@ static const struct explore explore[] = {
156 { PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, 170 { PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
157 { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, 171 { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
158 { PF_INET, SOCK_RAW, ANY, NULL, 0x05 }, 172 { PF_INET, SOCK_RAW, ANY, NULL, 0x05 },
173 { PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
174 { PF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
175 { PF_UNSPEC, SOCK_RAW, ANY, NULL, 0x05 },
159 { -1, 0, 0, NULL, 0 }, 176 { -1, 0, 0, NULL, 0 },
160}; 177};
161 178
@@ -165,6 +182,25 @@ static const struct explore explore[] = {
165#define PTON_MAX 4 182#define PTON_MAX 4
166#endif 183#endif
167 184
185#if PACKETSZ > 1024
186#define MAXPACKET PACKETSZ
187#else
188#define MAXPACKET 1024
189#endif
190
191typedef union {
192 HEADER hdr;
193 u_char buf[MAXPACKET];
194} querybuf;
195
196struct res_target {
197 struct res_target *next;
198 const char *name; /* domain name */
199 int class, type; /* class and type of query */
200 u_char *answer; /* buffer to put answer */
201 int anslen; /* size of answer buffer */
202 int n; /* result length */
203};
168 204
169static int str_isnumber __P((const char *)); 205static int str_isnumber __P((const char *));
170static int explore_fqdn __P((const struct addrinfo *, const char *, 206static int explore_fqdn __P((const struct addrinfo *, const char *,
@@ -189,6 +225,28 @@ static int addrconfig __P((const struct addrinfo *));
189static int ip6_str2scopeid __P((char *, struct sockaddr_in6 *)); 225static int ip6_str2scopeid __P((char *, struct sockaddr_in6 *));
190#endif 226#endif
191 227
228static void _sethtent __P((void));
229static void _endhtent __P((void));
230static struct addrinfo * _gethtent __P((const char *, const struct addrinfo *));
231static struct addrinfo *_files_getaddrinfo __P((const char *,
232 const struct addrinfo *));
233
234#ifdef YP
235static struct addrinfo *_yphostent __P((char *, const struct addrinfo *));
236static struct addrinfo *_yp_getaddrinfo __P((const char *,
237 const struct addrinfo *));
238#endif
239
240static struct addrinfo *getanswer __P((const querybuf *, int, const char *, int,
241 const struct addrinfo *));
242static int res_queryN __P((const char *, struct res_target *));
243static int res_searchN __P((const char *, struct res_target *));
244static int res_querydomainN __P((const char *, const char *,
245 struct res_target *));
246static struct addrinfo *_dns_getaddrinfo __P((const char *,
247 const struct addrinfo *));
248
249
192/* XXX macros that make external reference is BAD. */ 250/* XXX macros that make external reference is BAD. */
193 251
194#define GET_AI(ai, afd, addr) \ 252#define GET_AI(ai, afd, addr) \
@@ -254,10 +312,9 @@ getaddrinfo(hostname, servname, hints, res)
254 struct addrinfo ai; 312 struct addrinfo ai;
255 struct addrinfo ai0; 313 struct addrinfo ai0;
256 struct addrinfo *pai; 314 struct addrinfo *pai;
257 const struct afd *afd;
258 const struct explore *ex; 315 const struct explore *ex;
259 316
260 sentinel.ai_next = NULL; 317 memset(&sentinel, 0, sizeof(sentinel));
261 cur = &sentinel; 318 cur = &sentinel;
262 pai = &ai; 319 pai = &ai;
263 pai->ai_flags = 0; 320 pai->ai_flags = 0;
@@ -342,6 +399,10 @@ getaddrinfo(hostname, servname, hints, res)
342 for (ex = explore; ex->e_af >= 0; ex++) { 399 for (ex = explore; ex->e_af >= 0; ex++) {
343 *pai = ai0; 400 *pai = ai0;
344 401
402 /* PF_UNSPEC entries are prepared for DNS queries only */
403 if (ex->e_af == PF_UNSPEC)
404 continue;
405
345 if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex))) 406 if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
346 continue; 407 continue;
347 if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex))) 408 if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex)))
@@ -386,42 +447,32 @@ getaddrinfo(hostname, servname, hints, res)
386 * we would like to prefer AF_INET6 than AF_INET, so we'll make a 447 * we would like to prefer AF_INET6 than AF_INET, so we'll make a
387 * outer loop by AFs. 448 * outer loop by AFs.
388 */ 449 */
389 for (afd = afdl; afd->a_af; afd++) { 450 for (ex = explore; ex->e_af >= 0; ex++) {
390 *pai = ai0; 451 *pai = ai0;
391 452
392 if (!MATCH_FAMILY(pai->ai_family, afd->a_af, 1)) 453 /* require exact match for family field */
454 if (pai->ai_family != ex->e_af)
393 continue; 455 continue;
394 456
395 for (ex = explore; ex->e_af >= 0; ex++) { 457 if (!MATCH(pai->ai_socktype, ex->e_socktype,
396 *pai = ai0; 458 WILD_SOCKTYPE(ex))) {
397 459 continue;
398 if (pai->ai_family == PF_UNSPEC) 460 }
399 pai->ai_family = afd->a_af; 461 if (!MATCH(pai->ai_protocol, ex->e_protocol,
400 462 WILD_PROTOCOL(ex))) {
401 if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex))) 463 continue;
402 continue; 464 }
403 if (!MATCH(pai->ai_socktype, ex->e_socktype,
404 WILD_SOCKTYPE(ex))) {
405 continue;
406 }
407 if (!MATCH(pai->ai_protocol, ex->e_protocol,
408 WILD_PROTOCOL(ex))) {
409 continue;
410 }
411 465
412 if (pai->ai_family == PF_UNSPEC) 466 if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
413 pai->ai_family = ex->e_af; 467 pai->ai_socktype = ex->e_socktype;
414 if (pai->ai_socktype == ANY && ex->e_socktype != ANY) 468 if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
415 pai->ai_socktype = ex->e_socktype; 469 pai->ai_protocol = ex->e_protocol;
416 if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
417 pai->ai_protocol = ex->e_protocol;
418 470
419 error = explore_fqdn(pai, hostname, servname, 471 error = explore_fqdn(pai, hostname, servname,
420 &cur->ai_next); 472 &cur->ai_next);
421 473
422 while (cur && cur->ai_next) 474 while (cur && cur->ai_next)
423 cur = cur->ai_next; 475 cur = cur->ai_next;
424 }
425 } 476 }
426 477
427 /* XXX */ 478 /* XXX */
@@ -456,20 +507,13 @@ explore_fqdn(pai, hostname, servname, res)
456 const char *servname; 507 const char *servname;
457 struct addrinfo **res; 508 struct addrinfo **res;
458{ 509{
459 struct hostent *hp; 510 struct addrinfo *result;
460 int h_error; 511 struct addrinfo *cur;
461 int af;
462 char **aplist = NULL, *apbuf = NULL;
463 char *ap;
464 struct addrinfo sentinel, *cur;
465 int i;
466 int naddrs;
467 const struct afd *afd;
468 int error = 0; 512 int error = 0;
513 char lookups[MAXDNSLUS];
514 int i;
469 515
470 *res = NULL; 516 result = NULL;
471 sentinel.ai_next = NULL;
472 cur = &sentinel;
473 517
474#ifdef AI_ADDRCONFIG 518#ifdef AI_ADDRCONFIG
475 /* 519 /*
@@ -486,99 +530,41 @@ explore_fqdn(pai, hostname, servname, res)
486 if (get_portmatch(pai, servname) != 0) 530 if (get_portmatch(pai, servname) != 0)
487 return 0; 531 return 0;
488 532
489 afd = find_afd(pai->ai_family); 533 if ((_res.options & RES_INIT) == 0 && res_init() == -1)
490 534 strncpy(lookups, "f", sizeof lookups);
491 hp = gethostbyname2(hostname, pai->ai_family); 535 else {
492 h_error = h_errno; 536 bcopy(_res.lookups, lookups, sizeof lookups);
537 if (lookups[0] == '\0')
538 strncpy(lookups, "bf", sizeof lookups);
539 }
493 540
494 if (hp == NULL) { 541 for (i = 0; i < MAXDNSLUS && result == NULL && lookups[i]; i++) {
495 switch (h_error) { 542 switch (lookups[i]) {
496 case HOST_NOT_FOUND: 543#ifdef YP
497 case NO_DATA: 544 case 'y':
498 error = EAI_NODATA; 545 result = _yp_getaddrinfo(hostname, pai);
499 break; 546 break;
500 case TRY_AGAIN: 547#endif
501 error = EAI_AGAIN; 548 case 'b':
549 result = _dns_getaddrinfo(hostname, pai);
502 break; 550 break;
503 case NO_RECOVERY: 551 case 'f':
504 case NETDB_INTERNAL: 552 result = _files_getaddrinfo(hostname, pai);
505 default:
506 error = EAI_FAIL;
507 break; 553 break;
508 } 554 }
509 } else if ((hp->h_name == NULL) || (hp->h_name[0] == 0)
510 || (hp->h_addr_list[0] == NULL)) {
511 hp = NULL;
512 error = EAI_FAIL;
513 }
514
515 if (hp == NULL)
516 goto free;
517
518 /*
519 * hp will be overwritten if we use gethostbyname2().
520 * always deep copy for simplification.
521 */
522 for (naddrs = 0; hp->h_addr_list[naddrs] != NULL; naddrs++)
523 ;
524 naddrs++;
525 aplist = (char **)malloc(sizeof(aplist[0]) * naddrs);
526 apbuf = (char *)malloc((size_t)hp->h_length * naddrs);
527 if (aplist == NULL || apbuf == NULL) {
528 error = EAI_MEMORY;
529 goto free;
530 }
531 memset(aplist, 0, sizeof(aplist[0]) * naddrs);
532 for (i = 0; i < naddrs; i++) {
533 if (hp->h_addr_list[i] == NULL) {
534 aplist[i] = NULL;
535 continue;
536 }
537 memcpy(&apbuf[i * hp->h_length], hp->h_addr_list[i],
538 (size_t)hp->h_length);
539 aplist[i] = &apbuf[i * hp->h_length];
540 } 555 }
541 556 if (result) {
542 for (i = 0; aplist[i] != NULL; i++) { 557 for (cur = result; cur; cur = cur->ai_next) {
543 af = hp->h_addrtype; 558 GET_PORT(cur, servname);
544 ap = aplist[i]; 559 /* canonname should be filled already */
545#ifdef INET6
546 if (af == AF_INET6
547 && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) {
548 af = AF_INET;
549 ap = ap + sizeof(struct in6_addr)
550 - sizeof(struct in_addr);
551 } 560 }
552#endif 561 *res = result;
553 562 return 0;
554 if (af != pai->ai_family)
555 continue;
556
557 GET_AI(cur->ai_next, afd, ap);
558 GET_PORT(cur->ai_next, servname);
559 if ((pai->ai_flags & AI_CANONNAME) != 0) {
560 /*
561 * RFC2553 says that ai_canonname will be set only for
562 * the first element. we do it for all the elements,
563 * just for convenience.
564 */
565 GET_CANONNAME(cur->ai_next, hp->h_name);
566 }
567
568 while (cur && cur->ai_next)
569 cur = cur->ai_next;
570 } 563 }
571 564
572 *res = sentinel.ai_next;
573 return 0;
574
575free: 565free:
576 if (aplist) 566 if (result)
577 free(aplist); 567 freeaddrinfo(result);
578 if (apbuf)
579 free(apbuf);
580 if (sentinel.ai_next)
581 freeaddrinfo(sentinel.ai_next);
582 return error; 568 return error;
583} 569}
584 570
@@ -998,3 +984,799 @@ ip6_str2scopeid(scope, sin6)
998 return -1; 984 return -1;
999} 985}
1000#endif 986#endif
987
988/* code duplicate with gethnamaddr.c */
989
990static const char AskedForGot[] =
991 "gethostby*.getanswer: asked for \"%s\", got \"%s\"";
992static FILE *hostf = NULL;
993
994static struct addrinfo *
995getanswer(answer, anslen, qname, qtype, pai)
996 const querybuf *answer;
997 int anslen;
998 const char *qname;
999 int qtype;
1000 const struct addrinfo *pai;
1001{
1002 struct addrinfo sentinel, *cur;
1003 struct addrinfo ai;
1004 const struct afd *afd;
1005 char *canonname;
1006 const HEADER *hp;
1007 const u_char *cp;
1008 int n;
1009 const u_char *eom;
1010 char *bp;
1011 int type, class, buflen, ancount, qdcount;
1012 int haveanswer, had_error;
1013 char tbuf[MAXDNAME];
1014 const char *tname;
1015 int (*name_ok) __P((const char *));
1016 char hostbuf[8*1024];
1017
1018 memset(&sentinel, 0, sizeof(sentinel));
1019 cur = &sentinel;
1020
1021 tname = qname;
1022 canonname = NULL;
1023 eom = answer->buf + anslen;
1024 switch (qtype) {
1025 case T_A:
1026 case T_AAAA:
1027 case T_ANY: /*use T_ANY only for T_A/T_AAAA lookup*/
1028 name_ok = res_hnok;
1029 break;
1030 default:
1031 return (NULL); /* XXX should be abort(); */
1032 }
1033 /*
1034 * find first satisfactory answer
1035 */
1036 hp = &answer->hdr;
1037 ancount = ntohs(hp->ancount);
1038 qdcount = ntohs(hp->qdcount);
1039 bp = hostbuf;
1040 buflen = sizeof hostbuf;
1041 cp = answer->buf + HFIXEDSZ;
1042 if (qdcount != 1) {
1043 h_errno = NO_RECOVERY;
1044 return (NULL);
1045 }
1046 n = dn_expand(answer->buf, eom, cp, bp, buflen);
1047 if ((n < 0) || !(*name_ok)(bp)) {
1048 h_errno = NO_RECOVERY;
1049 return (NULL);
1050 }
1051 cp += n + QFIXEDSZ;
1052 if (qtype == T_A || qtype == T_AAAA || qtype == T_ANY) {
1053 /* res_send() has already verified that the query name is the
1054 * same as the one we sent; this just gets the expanded name
1055 * (i.e., with the succeeding search-domain tacked on).
1056 */
1057 n = strlen(bp) + 1; /* for the \0 */
1058 if (n >= MAXHOSTNAMELEN) {
1059 h_errno = NO_RECOVERY;
1060 return (NULL);
1061 }
1062 canonname = bp;
1063 bp += n;
1064 buflen -= n;
1065 /* The qname can be abbreviated, but h_name is now absolute. */
1066 qname = canonname;
1067 }
1068 haveanswer = 0;
1069 had_error = 0;
1070 while (ancount-- > 0 && cp < eom && !had_error) {
1071 n = dn_expand(answer->buf, eom, cp, bp, buflen);
1072 if ((n < 0) || !(*name_ok)(bp)) {
1073 had_error++;
1074 continue;
1075 }
1076 cp += n; /* name */
1077 type = _getshort(cp);
1078 cp += INT16SZ; /* type */
1079 class = _getshort(cp);
1080 cp += INT16SZ + INT32SZ; /* class, TTL */
1081 n = _getshort(cp);
1082 cp += INT16SZ; /* len */
1083 if (class != C_IN) {
1084 /* XXX - debug? syslog? */
1085 cp += n;
1086 continue; /* XXX - had_error++ ? */
1087 }
1088 if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) &&
1089 type == T_CNAME) {
1090 n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
1091 if ((n < 0) || !(*name_ok)(tbuf)) {
1092 had_error++;
1093 continue;
1094 }
1095 cp += n;
1096 /* Get canonical name. */
1097 n = strlen(tbuf) + 1; /* for the \0 */
1098 if (n > buflen || n >= MAXHOSTNAMELEN) {
1099 had_error++;
1100 continue;
1101 }
1102 strcpy(bp, tbuf);
1103 canonname = bp;
1104 bp += n;
1105 buflen -= n;
1106 continue;
1107 }
1108 if (qtype == T_ANY) {
1109 if (!(type == T_A || type == T_AAAA)) {
1110 cp += n;
1111 continue;
1112 }
1113 } else if (type != qtype) {
1114 if (type != T_KEY && type != T_SIG)
1115 syslog(LOG_NOTICE|LOG_AUTH,
1116 "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
1117 qname, p_class(C_IN), p_type(qtype),
1118 p_type(type));
1119 cp += n;
1120 continue; /* XXX - had_error++ ? */
1121 }
1122 switch (type) {
1123 case T_A:
1124 case T_AAAA:
1125 if (strcasecmp(canonname, bp) != 0) {
1126 syslog(LOG_NOTICE|LOG_AUTH,
1127 AskedForGot, canonname, bp);
1128 cp += n;
1129 continue; /* XXX - had_error++ ? */
1130 }
1131 if (type == T_A && n != INADDRSZ) {
1132 cp += n;
1133 continue;
1134 }
1135 if (type == T_AAAA && n != IN6ADDRSZ) {
1136 cp += n;
1137 continue;
1138 }
1139 if (!haveanswer) {
1140 int nn;
1141
1142 canonname = bp;
1143 nn = strlen(bp) + 1; /* for the \0 */
1144 bp += nn;
1145 buflen -= nn;
1146 }
1147
1148 /* don't overwrite pai */
1149 ai = *pai;
1150 ai.ai_family = (type == T_A) ? AF_INET : AF_INET6;
1151 afd = find_afd(ai.ai_family);
1152 if (afd == NULL) {
1153 cp += n;
1154 continue;
1155 }
1156 cur->ai_next = get_ai(&ai, afd, cp);
1157 if (cur->ai_next == NULL)
1158 had_error++;
1159 while (cur && cur->ai_next)
1160 cur = cur->ai_next;
1161 cp += n;
1162 break;
1163 default:
1164 abort();
1165 }
1166 if (!had_error)
1167 haveanswer++;
1168 }
1169 if (haveanswer) {
1170 if (!canonname)
1171 (void)get_canonname(pai, sentinel.ai_next, qname);
1172 else
1173 (void)get_canonname(pai, sentinel.ai_next, canonname);
1174 h_errno = NETDB_SUCCESS;
1175 return sentinel.ai_next;
1176 }
1177
1178 h_errno = NO_RECOVERY;
1179 return NULL;
1180}
1181
1182/*ARGSUSED*/
1183static struct addrinfo *
1184_dns_getaddrinfo(name, pai)
1185 const char *name;
1186 const struct addrinfo *pai;
1187{
1188 struct addrinfo *ai;
1189 querybuf buf, buf2;
1190 struct addrinfo sentinel, *cur;
1191 struct res_target q, q2;
1192 int ancount;
1193
1194 memset(&q, 0, sizeof(q2));
1195 memset(&q2, 0, sizeof(q2));
1196 memset(&sentinel, 0, sizeof(sentinel));
1197 cur = &sentinel;
1198
1199 switch (pai->ai_family) {
1200 case AF_UNSPEC:
1201 /* prefer IPv6 */
1202 q.class = C_IN;
1203 q.type = T_AAAA;
1204 q.answer = buf.buf;
1205 q.anslen = sizeof(buf);
1206 q.next = &q2;
1207 q2.class = C_IN;
1208 q2.type = T_A;
1209 q2.answer = buf2.buf;
1210 q2.anslen = sizeof(buf2);
1211 break;
1212 case AF_INET:
1213 q.class = C_IN;
1214 q.type = T_A;
1215 q.answer = buf.buf;
1216 q.anslen = sizeof(buf);
1217 break;
1218 case AF_INET6:
1219 q.class = C_IN;
1220 q.type = T_AAAA;
1221 q.answer = buf.buf;
1222 q.anslen = sizeof(buf);
1223 break;
1224 default:
1225 return NULL;
1226 }
1227 if ((ancount = res_searchN(name, &q)) < 0)
1228 return NULL;
1229 ai = getanswer(&buf, q.n, q.name, q.type, pai);
1230 if (ai) {
1231 cur->ai_next = ai;
1232 while (cur && cur->ai_next)
1233 cur = cur->ai_next;
1234 }
1235 if (q.next) {
1236 ai = getanswer(&buf2, q2.n, q2.name, q2.type, pai);
1237 if (ai)
1238 cur->ai_next = ai;
1239 }
1240 return sentinel.ai_next;
1241}
1242
1243static FILE *hostf;
1244
1245static void
1246_sethtent()
1247{
1248 if (!hostf)
1249 hostf = fopen(_PATH_HOSTS, "r" );
1250 else
1251 rewind(hostf);
1252}
1253
1254static void
1255_endhtent()
1256{
1257 if (hostf) {
1258 (void) fclose(hostf);
1259 hostf = NULL;
1260 }
1261}
1262
1263static struct addrinfo *
1264_gethtent(name, pai)
1265 const char *name;
1266 const struct addrinfo *pai;
1267{
1268 char *p;
1269 char *cp, *tname;
1270 struct addrinfo hints, *res0, *res;
1271 int error;
1272 const char *addr;
1273 char hostbuf[8*1024];
1274
1275 if (!hostf && !(hostf = fopen(_PATH_HOSTS, "r" )))
1276 return (NULL);
1277 again:
1278 if (!(p = fgets(hostbuf, sizeof hostbuf, hostf)))
1279 return (NULL);
1280 if (*p == '#')
1281 goto again;
1282 if (!(cp = strpbrk(p, "#\n")))
1283 goto again;
1284 *cp = '\0';
1285 if (!(cp = strpbrk(p, " \t")))
1286 goto again;
1287 *cp++ = '\0';
1288 addr = p;
1289 /* if this is not something we're looking for, skip it. */
1290 while (cp && *cp) {
1291 if (*cp == ' ' || *cp == '\t') {
1292 cp++;
1293 continue;
1294 }
1295 tname = cp;
1296 if ((cp = strpbrk(cp, " \t")) != NULL)
1297 *cp++ = '\0';
1298 if (strcasecmp(name, tname) == 0)
1299 goto found;
1300 }
1301 goto again;
1302
1303found:
1304 hints = *pai;
1305 hints.ai_flags = AI_NUMERICHOST;
1306 error = getaddrinfo(addr, NULL, &hints, &res0);
1307 if (error)
1308 goto again;
1309 for (res = res0; res; res = res->ai_next) {
1310 /* cover it up */
1311 res->ai_flags = pai->ai_flags;
1312
1313 if (pai->ai_flags & AI_CANONNAME) {
1314 if (get_canonname(pai, res, name) != 0) {
1315 freeaddrinfo(res0);
1316 goto again;
1317 }
1318 }
1319 }
1320 return res0;
1321}
1322
1323/*ARGSUSED*/
1324static struct addrinfo *
1325_files_getaddrinfo(name, pai)
1326 const char *name;
1327 const struct addrinfo *pai;
1328{
1329 struct addrinfo sentinel, *cur;
1330 struct addrinfo *p;
1331
1332 memset(&sentinel, 0, sizeof(sentinel));
1333 cur = &sentinel;
1334
1335 _sethtent();
1336 while ((p = _gethtent(name, pai)) != NULL) {
1337 cur->ai_next = p;
1338 while (cur && cur->ai_next)
1339 cur = cur->ai_next;
1340 }
1341 _endhtent();
1342
1343 return sentinel.ai_next;
1344}
1345
1346#ifdef YP
1347static char *__ypdomain;
1348
1349/*ARGSUSED*/
1350static struct addrinfo *
1351_yphostent(line, pai)
1352 char *line;
1353 const struct addrinfo *pai;
1354{
1355 struct addrinfo sentinel, *cur;
1356 struct addrinfo hints, *res, *res0;
1357 int error;
1358 char *p = line;
1359 const char *addr, *canonname;
1360 char *nextline;
1361 char *cp;
1362 int more;
1363
1364 addr = canonname = NULL;
1365
1366nextline:
1367 more = 0;
1368
1369 /* terminate line */
1370 cp = strchr(p, '\n');
1371 if (cp) {
1372 *cp++ = '\0';
1373 nextline = cp;
1374 } else
1375 nextline = NULL;
1376
1377 cp = strpbrk(p, " \t");
1378 if (cp == NULL) {
1379 if (canonname == NULL)
1380 return (NULL);
1381 else
1382 goto done;
1383 }
1384 *cp++ = '\0';
1385
1386 addr = p;
1387
1388 while (cp && *cp) {
1389 if (*cp == ' ' || *cp == '\t') {
1390 cp++;
1391 continue;
1392 }
1393 if (!canonname)
1394 canonname = cp;
1395 if ((cp = strpbrk(cp, " \t")) != NULL)
1396 *cp++ = '\0';
1397 }
1398
1399 hints = *pai;
1400 hints.ai_flags = AI_NUMERICHOST;
1401 error = getaddrinfo(addr, NULL, &hints, &res0);
1402 if (error == 0) {
1403 for (res = res0; res; res = res->ai_next) {
1404 /* cover it up */
1405 res->ai_flags = pai->ai_flags;
1406
1407 if (pai->ai_flags & AI_CANONNAME)
1408 (void)get_canonname(pai, res, canonname);
1409 }
1410 }
1411 if (res0) {
1412 cur->ai_next = res0;
1413 while (cur && cur->ai_next)
1414 cur = cur->ai_next;
1415 }
1416
1417 if (nextline) {
1418 p = nextline;
1419 goto nextline;
1420 }
1421
1422done:
1423 return sentinel.ai_next;
1424}
1425
1426/*ARGSUSED*/
1427static struct addrinfo *
1428_yp_getaddrinfo(name, pai)
1429 const char *name;
1430 const struct addrinfo *pai;
1431{
1432 struct addrinfo sentinel, *cur;
1433 struct addrinfo *ai = NULL;
1434 static char *__ypcurrent;
1435 int __ypcurrentlen, r;
1436
1437 memset(&sentinel, 0, sizeof(sentinel));
1438 cur = &sentinel;
1439
1440 if (!__ypdomain) {
1441 if (_yp_check(&__ypdomain) == 0)
1442 return NULL;
1443 }
1444 if (__ypcurrent)
1445 free(__ypcurrent);
1446 __ypcurrent = NULL;
1447
1448 /* hosts.byname is only for IPv4 (Solaris8) */
1449 if (pai->ai_family == PF_UNSPEC || pai->ai_family == PF_INET) {
1450 r = yp_match(__ypdomain, "hosts.byname", name,
1451 (int)strlen(name), &__ypcurrent, &__ypcurrentlen);
1452 if (r == 0) {
1453 struct addrinfo ai4;
1454
1455 ai4 = *pai;
1456 ai4.ai_family = AF_INET;
1457 ai = _yphostent(__ypcurrent, &ai4);
1458 if (ai) {
1459 cur->ai_next = ai;
1460 while (cur && cur->ai_next)
1461 cur = cur->ai_next;
1462 }
1463 }
1464 }
1465
1466 /* ipnodes.byname can hold both IPv4/v6 */
1467 r = yp_match(__ypdomain, "ipnodes.byname", name,
1468 (int)strlen(name), &__ypcurrent, &__ypcurrentlen);
1469 if (r == 0) {
1470 ai = _yphostent(__ypcurrent, pai);
1471 if (ai) {
1472 cur->ai_next = ai;
1473 while (cur && cur->ai_next)
1474 cur = cur->ai_next;
1475 }
1476 }
1477
1478 return sentinel.ai_next;
1479}
1480#endif
1481
1482
1483/* resolver logic */
1484
1485extern const char *__hostalias __P((const char *));
1486extern int h_errno;
1487
1488/*
1489 * Formulate a normal query, send, and await answer.
1490 * Returned answer is placed in supplied buffer "answer".
1491 * Perform preliminary check of answer, returning success only
1492 * if no error is indicated and the answer count is nonzero.
1493 * Return the size of the response on success, -1 on error.
1494 * Error number is left in h_errno.
1495 *
1496 * Caller must parse answer and determine whether it answers the question.
1497 */
1498static int
1499res_queryN(name, target)
1500 const char *name; /* domain name */
1501 struct res_target *target;
1502{
1503 u_char buf[MAXPACKET];
1504 HEADER *hp;
1505 int n;
1506 struct res_target *t;
1507 int rcode;
1508 int ancount;
1509
1510 rcode = NOERROR;
1511 ancount = 0;
1512
1513 if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
1514 h_errno = NETDB_INTERNAL;
1515 return (-1);
1516 }
1517
1518 for (t = target; t; t = t->next) {
1519 int class, type;
1520 u_char *answer;
1521 int anslen;
1522
1523 hp = (HEADER *)(void *)t->answer;
1524 hp->rcode = NOERROR; /* default */
1525
1526 /* make it easier... */
1527 class = t->class;
1528 type = t->type;
1529 answer = t->answer;
1530 anslen = t->anslen;
1531#ifdef DEBUG
1532 if (_res.options & RES_DEBUG)
1533 printf(";; res_query(%s, %d, %d)\n", name, class, type);
1534#endif
1535
1536 n = res_mkquery(QUERY, name, class, type, NULL, 0, NULL,
1537 buf, sizeof(buf));
1538 if (n <= 0) {
1539#ifdef DEBUG
1540 if (_res.options & RES_DEBUG)
1541 printf(";; res_query: mkquery failed\n");
1542#endif
1543 h_errno = NO_RECOVERY;
1544 return (n);
1545 }
1546 n = res_send(buf, n, answer, anslen);
1547 if (n < 0) {
1548#ifdef DEBUG
1549 if (_res.options & RES_DEBUG)
1550 printf(";; res_query: send error\n");
1551#endif
1552 h_errno = TRY_AGAIN;
1553 return (n);
1554 }
1555
1556 if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
1557 rcode = hp->rcode; /* record most recent error */
1558#ifdef DEBUG
1559 if (_res.options & RES_DEBUG)
1560 printf(";; rcode = %d, ancount=%d\n", hp->rcode,
1561 ntohs(hp->ancount));
1562#endif
1563 continue;
1564 }
1565
1566 ancount += ntohs(hp->ancount);
1567
1568 t->n = n;
1569 }
1570
1571 if (ancount == 0) {
1572 switch (rcode) {
1573 case NXDOMAIN:
1574 h_errno = HOST_NOT_FOUND;
1575 break;
1576 case SERVFAIL:
1577 h_errno = TRY_AGAIN;
1578 break;
1579 case NOERROR:
1580 h_errno = NO_DATA;
1581 break;
1582 case FORMERR:
1583 case NOTIMP:
1584 case REFUSED:
1585 default:
1586 h_errno = NO_RECOVERY;
1587 break;
1588 }
1589 return (-1);
1590 }
1591 return (ancount);
1592}
1593
1594/*
1595 * Formulate a normal query, send, and retrieve answer in supplied buffer.
1596 * Return the size of the response on success, -1 on error.
1597 * If enabled, implement search rules until answer or unrecoverable failure
1598 * is detected. Error code, if any, is left in h_errno.
1599 */
1600static int
1601res_searchN(name, target)
1602 const char *name; /* domain name */
1603 struct res_target *target;
1604{
1605 const char *cp, * const *domain;
1606 HEADER *hp = (HEADER *)(void *)target->answer; /*XXX*/
1607 u_int dots;
1608 int trailing_dot, ret, saved_herrno;
1609 int got_nodata = 0, got_servfail = 0, tried_as_is = 0;
1610
1611 if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
1612 h_errno = NETDB_INTERNAL;
1613 return (-1);
1614 }
1615
1616 errno = 0;
1617 h_errno = HOST_NOT_FOUND; /* default, if we never query */
1618 dots = 0;
1619 for (cp = name; *cp; cp++)
1620 dots += (*cp == '.');
1621 trailing_dot = 0;
1622 if (cp > name && *--cp == '.')
1623 trailing_dot++;
1624
1625 /*
1626 * if there aren't any dots, it could be a user-level alias
1627 */
1628 if (!dots && (cp = __hostalias(name)) != NULL)
1629 return (res_queryN(cp, target));
1630
1631 /*
1632 * If there are dots in the name already, let's just give it a try
1633 * 'as is'. The threshold can be set with the "ndots" option.
1634 */
1635 saved_herrno = -1;
1636 if (dots >= _res.ndots) {
1637 ret = res_querydomainN(name, NULL, target);
1638 if (ret > 0)
1639 return (ret);
1640 saved_herrno = h_errno;
1641 tried_as_is++;
1642 }
1643
1644 /*
1645 * We do at least one level of search if
1646 * - there is no dot and RES_DEFNAME is set, or
1647 * - there is at least one dot, there is no trailing dot,
1648 * and RES_DNSRCH is set.
1649 */
1650 if ((!dots && (_res.options & RES_DEFNAMES)) ||
1651 (dots && !trailing_dot && (_res.options & RES_DNSRCH))) {
1652 int done = 0;
1653
1654 for (domain = (const char * const *)_res.dnsrch;
1655 *domain && !done;
1656 domain++) {
1657
1658 ret = res_querydomainN(name, *domain, target);
1659 if (ret > 0)
1660 return (ret);
1661
1662 /*
1663 * If no server present, give up.
1664 * If name isn't found in this domain,
1665 * keep trying higher domains in the search list
1666 * (if that's enabled).
1667 * On a NO_DATA error, keep trying, otherwise
1668 * a wildcard entry of another type could keep us
1669 * from finding this entry higher in the domain.
1670 * If we get some other error (negative answer or
1671 * server failure), then stop searching up,
1672 * but try the input name below in case it's
1673 * fully-qualified.
1674 */
1675 if (errno == ECONNREFUSED) {
1676 h_errno = TRY_AGAIN;
1677 return (-1);
1678 }
1679
1680 switch (h_errno) {
1681 case NO_DATA:
1682 got_nodata++;
1683 /* FALLTHROUGH */
1684 case HOST_NOT_FOUND:
1685 /* keep trying */
1686 break;
1687 case TRY_AGAIN:
1688 if (hp->rcode == SERVFAIL) {
1689 /* try next search element, if any */
1690 got_servfail++;
1691 break;
1692 }
1693 /* FALLTHROUGH */
1694 default:
1695 /* anything else implies that we're done */
1696 done++;
1697 }
1698 /*
1699 * if we got here for some reason other than DNSRCH,
1700 * we only wanted one iteration of the loop, so stop.
1701 */
1702 if (!(_res.options & RES_DNSRCH))
1703 done++;
1704 }
1705 }
1706
1707 /*
1708 * if we have not already tried the name "as is", do that now.
1709 * note that we do this regardless of how many dots were in the
1710 * name or whether it ends with a dot.
1711 */
1712 if (!tried_as_is) {
1713 ret = res_querydomainN(name, NULL, target);
1714 if (ret > 0)
1715 return (ret);
1716 }
1717
1718 /*
1719 * if we got here, we didn't satisfy the search.
1720 * if we did an initial full query, return that query's h_errno
1721 * (note that we wouldn't be here if that query had succeeded).
1722 * else if we ever got a nodata, send that back as the reason.
1723 * else send back meaningless h_errno, that being the one from
1724 * the last DNSRCH we did.
1725 */
1726 if (saved_herrno != -1)
1727 h_errno = saved_herrno;
1728 else if (got_nodata)
1729 h_errno = NO_DATA;
1730 else if (got_servfail)
1731 h_errno = TRY_AGAIN;
1732 return (-1);
1733}
1734
1735/*
1736 * Perform a call on res_query on the concatenation of name and domain,
1737 * removing a trailing dot from name if domain is NULL.
1738 */
1739static int
1740res_querydomainN(name, domain, target)
1741 const char *name, *domain;
1742 struct res_target *target;
1743{
1744 char nbuf[MAXDNAME];
1745 const char *longname = nbuf;
1746 size_t n, d;
1747
1748 if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
1749 h_errno = NETDB_INTERNAL;
1750 return (-1);
1751 }
1752#ifdef DEBUG
1753 if (_res.options & RES_DEBUG)
1754 printf(";; res_querydomain(%s, %s)\n",
1755 name, domain?domain:"<Nil>");
1756#endif
1757 if (domain == NULL) {
1758 /*
1759 * Check for trailing '.';
1760 * copy without '.' if present.
1761 */
1762 n = strlen(name);
1763 if (n >= MAXDNAME) {
1764 h_errno = NO_RECOVERY;
1765 return (-1);
1766 }
1767 if (n-- != 0 && name[n] == '.') {
1768 strncpy(nbuf, name, n);
1769 nbuf[n] = '\0';
1770 } else
1771 longname = name;
1772 } else {
1773 n = strlen(name);
1774 d = strlen(domain);
1775 if (n + d + 1 >= MAXDNAME) {
1776 h_errno = NO_RECOVERY;
1777 return (-1);
1778 }
1779 sprintf(nbuf, "%s.%s", name, domain);
1780 }
1781 return (res_queryN(longname, target));
1782}