Annotation of src/lib/libc/net/getaddrinfo.c, Revision 1.77
1.77 ! ginsbach 1: /* $NetBSD: getaddrinfo.c,v 1.76 2006/02/13 17:16:20 ginsbach Exp $ */
1.48 itojun 2: /* $KAME: getaddrinfo.c,v 1.29 2000/08/31 17:26:57 itojun Exp $ */
1.6 itojun 3:
1.1 itojun 4: /*
5: * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6: * All rights reserved.
1.42 itojun 7: *
1.1 itojun 8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. Neither the name of the project nor the names of its contributors
17: * may be used to endorse or promote products derived from this software
18: * without specific prior written permission.
1.42 itojun 19: *
1.1 itojun 20: * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23: * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30: * SUCH DAMAGE.
31: */
32:
33: /*
34: * Issues to be discussed:
35: * - Thread safe-ness must be checked.
36: * - Return values. There are nonstandard return values defined and used
1.14 itojun 37: * in the source code. This is because RFC2553 is silent about which error
1.1 itojun 38: * code must be returned for which situation.
1.27 itojun 39: * - IPv4 classful (shortened) form. RFC2553 is silent about it. XNET 5.2
40: * says to use inet_aton() to convert IPv4 numeric to binary (alows
41: * classful form as a result).
42: * current code - disallow classful form for IPv4 (due to use of inet_pton).
43: * - freeaddrinfo(NULL). RFC2553 is silent about it. XNET 5.2 says it is
44: * invalid.
45: * current code - SEGV on freeaddrinfo(NULL)
1.14 itojun 46: * Note:
47: * - We use getipnodebyname() just for thread-safeness. There's no intent
48: * to let it do PF_UNSPEC (actually we never pass PF_UNSPEC to
49: * getipnodebyname().
50: * - The code filters out AFs that are not supported by the kernel,
1.22 itojun 51: * when globbing NULL hostname (to loopback, or wildcard). Is it the right
1.14 itojun 52: * thing to do? What is the relationship with post-RFC2553 AI_ADDRCONFIG
53: * in ai_flags?
1.30 itojun 54: * - (post-2553) semantics of AI_ADDRCONFIG itself is too vague.
55: * (1) what should we do against numeric hostname (2) what should we do
56: * against NULL hostname (3) what is AI_ADDRCONFIG itself. AF not ready?
57: * non-loopback address configured? global address configured?
1.32 itojun 58: * - To avoid search order issue, we have a big amount of code duplicate
59: * from gethnamaddr.c and some other places. The issues that there's no
60: * lower layer function to lookup "IPv4 or IPv6" record. Calling
61: * gethostbyname2 from getaddrinfo will end up in wrong search order, as
62: * follows:
63: * - The code makes use of following calls when asked to resolver with
64: * ai_family = PF_UNSPEC:
65: * getipnodebyname(host, AF_INET6);
66: * getipnodebyname(host, AF_INET);
67: * This will result in the following queries if the node is configure to
68: * prefer /etc/hosts than DNS:
69: * lookup /etc/hosts for IPv6 address
70: * lookup DNS for IPv6 address
71: * lookup /etc/hosts for IPv4 address
72: * lookup DNS for IPv4 address
73: * which may not meet people's requirement.
74: * The right thing to happen is to have underlying layer which does
75: * PF_UNSPEC lookup (lookup both) and return chain of addrinfos.
76: * This would result in a bit of code duplicate with _dns_ghbyname() and
77: * friends.
1.1 itojun 78: */
1.39 itojun 79:
80: #include <sys/cdefs.h>
81: #if defined(LIBC_SCCS) && !defined(lint)
1.77 ! ginsbach 82: __RCSID("$NetBSD: getaddrinfo.c,v 1.76 2006/02/13 17:16:20 ginsbach Exp $");
1.39 itojun 83: #endif /* LIBC_SCCS and not lint */
1.1 itojun 84:
1.38 itojun 85: #include "namespace.h"
1.14 itojun 86: #include <sys/types.h>
1.1 itojun 87: #include <sys/param.h>
88: #include <sys/socket.h>
1.14 itojun 89: #include <net/if.h>
1.1 itojun 90: #include <netinet/in.h>
91: #include <arpa/inet.h>
92: #include <arpa/nameser.h>
1.51 lukem 93: #include <assert.h>
94: #include <ctype.h>
95: #include <errno.h>
1.1 itojun 96: #include <netdb.h>
97: #include <resolv.h>
1.51 lukem 98: #include <stddef.h>
99: #include <stdio.h>
100: #include <stdlib.h>
1.14 itojun 101: #include <string.h>
1.1 itojun 102: #include <unistd.h>
1.14 itojun 103:
1.32 itojun 104: #include <syslog.h>
105: #include <stdarg.h>
106: #include <nsswitch.h>
107:
108: #ifdef YP
109: #include <rpc/rpc.h>
110: #include <rpcsvc/yp_prot.h>
111: #include <rpcsvc/ypclnt.h>
1.38 itojun 112: #endif
113:
114: #ifdef __weak_alias
115: __weak_alias(getaddrinfo,_getaddrinfo)
116: __weak_alias(freeaddrinfo,_freeaddrinfo)
117: __weak_alias(gai_strerror,_gai_strerror)
1.32 itojun 118: #endif
119:
1.1 itojun 120: #define SUCCESS 0
121: #define ANY 0
122: #define YES 1
123: #define NO 0
124:
125: static const char in_addrany[] = { 0, 0, 0, 0 };
1.49 lukem 126: static const char in_loopback[] = { 127, 0, 0, 1 };
127: #ifdef INET6
1.1 itojun 128: static const char in6_addrany[] = {
129: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
130: };
131: static const char in6_loopback[] = {
132: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
133: };
1.49 lukem 134: #endif
1.1 itojun 135:
1.14 itojun 136: static const struct afd {
1.1 itojun 137: int a_af;
138: int a_addrlen;
139: int a_socklen;
140: int a_off;
141: const char *a_addrany;
142: const char *a_loopback;
1.14 itojun 143: int a_scoped;
1.1 itojun 144: } afdl [] = {
145: #ifdef INET6
146: {PF_INET6, sizeof(struct in6_addr),
147: sizeof(struct sockaddr_in6),
148: offsetof(struct sockaddr_in6, sin6_addr),
1.14 itojun 149: in6_addrany, in6_loopback, 1},
1.1 itojun 150: #endif
151: {PF_INET, sizeof(struct in_addr),
152: sizeof(struct sockaddr_in),
153: offsetof(struct sockaddr_in, sin_addr),
1.14 itojun 154: in_addrany, in_loopback, 0},
155: {0, 0, 0, 0, NULL, NULL, 0},
156: };
157:
158: struct explore {
159: int e_af;
160: int e_socktype;
161: int e_protocol;
162: const char *e_protostr;
163: int e_wild;
164: #define WILD_AF(ex) ((ex)->e_wild & 0x01)
165: #define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02)
166: #define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04)
167: };
168:
169: static const struct explore explore[] = {
170: #if 0
171: { PF_LOCAL, 0, ANY, ANY, NULL, 0x01 },
172: #endif
173: #ifdef INET6
174: { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
175: { PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
176: { PF_INET6, SOCK_RAW, ANY, NULL, 0x05 },
177: #endif
178: { PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
179: { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
180: { PF_INET, SOCK_RAW, ANY, NULL, 0x05 },
1.32 itojun 181: { PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
182: { PF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
183: { PF_UNSPEC, SOCK_RAW, ANY, NULL, 0x05 },
1.14 itojun 184: { -1, 0, 0, NULL, 0 },
1.1 itojun 185: };
186:
187: #ifdef INET6
188: #define PTON_MAX 16
189: #else
190: #define PTON_MAX 4
191: #endif
192:
1.32 itojun 193: static const ns_src default_dns_files[] = {
194: { NSSRC_FILES, NS_SUCCESS },
195: { NSSRC_DNS, NS_SUCCESS },
196: { 0 }
197: };
198:
1.63 itojun 199: #define MAXPACKET (64*1024)
1.32 itojun 200:
201: typedef union {
202: HEADER hdr;
203: u_char buf[MAXPACKET];
204: } querybuf;
205:
206: struct res_target {
207: struct res_target *next;
208: const char *name; /* domain name */
1.43 itojun 209: int qclass, qtype; /* class and type of query */
1.32 itojun 210: u_char *answer; /* buffer to put answer */
211: int anslen; /* size of answer buffer */
212: int n; /* result length */
213: };
1.1 itojun 214:
1.70 christos 215: static int str2number(const char *);
216: static int explore_fqdn(const struct addrinfo *, const char *,
217: const char *, struct addrinfo **);
218: static int explore_null(const struct addrinfo *,
219: const char *, struct addrinfo **);
220: static int explore_numeric(const struct addrinfo *, const char *,
221: const char *, struct addrinfo **, const char *);
222: static int explore_numeric_scope(const struct addrinfo *, const char *,
223: const char *, struct addrinfo **);
224: static int get_canonname(const struct addrinfo *,
225: struct addrinfo *, const char *);
226: static struct addrinfo *get_ai(const struct addrinfo *,
227: const struct afd *, const char *);
228: static int get_portmatch(const struct addrinfo *, const char *);
1.75 yamt 229: static int get_port(const struct addrinfo *, const char *, int);
1.70 christos 230: static const struct afd *find_afd(int);
1.27 itojun 231: #ifdef INET6
1.70 christos 232: static int ip6_str2scopeid(char *, struct sockaddr_in6 *, u_int32_t *);
1.42 itojun 233: #endif
1.14 itojun 234:
1.70 christos 235: static struct addrinfo *getanswer(const querybuf *, int, const char *, int,
236: const struct addrinfo *);
1.73 tsarna 237: static void aisort(struct addrinfo *s, res_state res);
1.70 christos 238: static int _dns_getaddrinfo(void *, void *, va_list);
239: static void _sethtent(FILE **);
240: static void _endhtent(FILE **);
241: static struct addrinfo *_gethtent(FILE **, const char *,
242: const struct addrinfo *);
243: static int _files_getaddrinfo(void *, void *, va_list);
1.32 itojun 244: #ifdef YP
1.70 christos 245: static struct addrinfo *_yphostent(char *, const struct addrinfo *);
246: static int _yp_getaddrinfo(void *, void *, va_list);
1.32 itojun 247: #endif
248:
1.70 christos 249: static int res_queryN(const char *, struct res_target *, res_state);
1.73 tsarna 250: static int res_searchN(const char *, struct res_target *, res_state);
1.70 christos 251: static int res_querydomainN(const char *, const char *,
252: struct res_target *, res_state);
1.32 itojun 253:
1.53 jdolecek 254: static const char * const ai_errlist[] = {
1.7 lukem 255: "Success",
256: "Address family for hostname not supported", /* EAI_ADDRFAMILY */
257: "Temporary failure in name resolution", /* EAI_AGAIN */
258: "Invalid value for ai_flags", /* EAI_BADFLAGS */
259: "Non-recoverable failure in name resolution", /* EAI_FAIL */
1.2 lukem 260: "ai_family not supported", /* EAI_FAMILY */
1.7 lukem 261: "Memory allocation failure", /* EAI_MEMORY */
262: "No address associated with hostname", /* EAI_NODATA */
1.14 itojun 263: "hostname nor servname provided, or not known", /* EAI_NONAME */
1.2 lukem 264: "servname not supported for ai_socktype", /* EAI_SERVICE */
265: "ai_socktype not supported", /* EAI_SOCKTYPE */
1.7 lukem 266: "System error returned in errno", /* EAI_SYSTEM */
267: "Invalid value for hints", /* EAI_BADHINTS */
268: "Resolved protocol is unknown", /* EAI_PROTOCOL */
1.77 ! ginsbach 269: "Argument buffer overflow", /* EAI_OVERFLOW */
1.7 lukem 270: "Unknown error", /* EAI_MAX */
1.1 itojun 271: };
272:
1.14 itojun 273: /* XXX macros that make external reference is BAD. */
274:
275: #define GET_AI(ai, afd, addr) \
276: do { \
277: /* external reference: pai, error, and label free */ \
278: (ai) = get_ai(pai, (afd), (addr)); \
279: if ((ai) == NULL) { \
280: error = EAI_MEMORY; \
281: goto free; \
282: } \
1.20 mycroft 283: } while (/*CONSTCOND*/0)
1.14 itojun 284:
285: #define GET_PORT(ai, serv) \
286: do { \
287: /* external reference: error and label free */ \
288: error = get_port((ai), (serv), 0); \
289: if (error != 0) \
290: goto free; \
1.20 mycroft 291: } while (/*CONSTCOND*/0)
1.14 itojun 292:
1.1 itojun 293: #define GET_CANONNAME(ai, str) \
1.14 itojun 294: do { \
295: /* external reference: pai, error and label free */ \
296: error = get_canonname(pai, (ai), (str)); \
297: if (error != 0) \
298: goto free; \
1.20 mycroft 299: } while (/*CONSTCOND*/0)
1.14 itojun 300:
301: #define ERR(err) \
302: do { \
303: /* external reference: error, and label bad */ \
304: error = (err); \
305: goto bad; \
1.36 christos 306: /*NOTREACHED*/ \
1.20 mycroft 307: } while (/*CONSTCOND*/0)
1.14 itojun 308:
309: #define MATCH_FAMILY(x, y, w) \
1.20 mycroft 310: ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC)))
1.14 itojun 311: #define MATCH(x, y, w) \
1.20 mycroft 312: ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY)))
1.1 itojun 313:
1.70 christos 314: const char *
315: gai_strerror(int ecode)
1.1 itojun 316: {
317: if (ecode < 0 || ecode > EAI_MAX)
318: ecode = EAI_MAX;
1.70 christos 319: return ai_errlist[ecode];
1.1 itojun 320: }
321:
322: void
1.70 christos 323: freeaddrinfo(struct addrinfo *ai)
1.1 itojun 324: {
325: struct addrinfo *next;
326:
1.51 lukem 327: _DIAGASSERT(ai != NULL);
328:
1.26 itojun 329: do {
1.1 itojun 330: next = ai->ai_next;
331: if (ai->ai_canonname)
332: free(ai->ai_canonname);
333: /* no need to free(ai->ai_addr) */
334: free(ai);
1.27 itojun 335: ai = next;
336: } while (ai);
1.1 itojun 337: }
338:
339: static int
1.70 christos 340: str2number(const char *p)
1.1 itojun 341: {
1.45 itojun 342: char *ep;
1.67 itojun 343: unsigned long v;
1.45 itojun 344:
1.51 lukem 345: _DIAGASSERT(p != NULL);
346:
1.46 itojun 347: if (*p == '\0')
1.67 itojun 348: return -1;
1.45 itojun 349: ep = NULL;
1.59 itojun 350: errno = 0;
1.67 itojun 351: v = strtoul(p, &ep, 10);
352: if (errno == 0 && ep && *ep == '\0' && v <= UINT_MAX)
353: return v;
1.45 itojun 354: else
1.67 itojun 355: return -1;
1.1 itojun 356: }
357:
358: int
1.70 christos 359: getaddrinfo(const char *hostname, const char *servname,
360: const struct addrinfo *hints, struct addrinfo **res)
1.1 itojun 361: {
362: struct addrinfo sentinel;
363: struct addrinfo *cur;
1.14 itojun 364: int error = 0;
1.1 itojun 365: struct addrinfo ai;
1.14 itojun 366: struct addrinfo ai0;
1.1 itojun 367: struct addrinfo *pai;
1.14 itojun 368: const struct explore *ex;
1.1 itojun 369:
1.51 lukem 370: /* hostname is allowed to be NULL */
371: /* servname is allowed to be NULL */
372: /* hints is allowed to be NULL */
373: _DIAGASSERT(res != NULL);
374:
1.32 itojun 375: memset(&sentinel, 0, sizeof(sentinel));
1.1 itojun 376: cur = &sentinel;
377: pai = &ai;
378: pai->ai_flags = 0;
379: pai->ai_family = PF_UNSPEC;
380: pai->ai_socktype = ANY;
381: pai->ai_protocol = ANY;
382: pai->ai_addrlen = 0;
383: pai->ai_canonname = NULL;
384: pai->ai_addr = NULL;
385: pai->ai_next = NULL;
386:
387: if (hostname == NULL && servname == NULL)
388: return EAI_NONAME;
389: if (hints) {
390: /* error check for hints */
391: if (hints->ai_addrlen || hints->ai_canonname ||
392: hints->ai_addr || hints->ai_next)
393: ERR(EAI_BADHINTS); /* xxx */
394: if (hints->ai_flags & ~AI_MASK)
395: ERR(EAI_BADFLAGS);
396: switch (hints->ai_family) {
397: case PF_UNSPEC:
398: case PF_INET:
399: #ifdef INET6
400: case PF_INET6:
401: #endif
402: break;
403: default:
404: ERR(EAI_FAMILY);
405: }
406: memcpy(pai, hints, sizeof(*pai));
1.14 itojun 407:
408: /*
409: * if both socktype/protocol are specified, check if they
410: * are meaningful combination.
411: */
412: if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) {
413: for (ex = explore; ex->e_af >= 0; ex++) {
414: if (pai->ai_family != ex->e_af)
415: continue;
416: if (ex->e_socktype == ANY)
417: continue;
418: if (ex->e_protocol == ANY)
419: continue;
420: if (pai->ai_socktype == ex->e_socktype
421: && pai->ai_protocol != ex->e_protocol) {
422: ERR(EAI_BADHINTS);
423: }
1.1 itojun 424: }
425: }
426: }
427:
428: /*
1.14 itojun 429: * check for special cases. (1) numeric servname is disallowed if
430: * socktype/protocol are left unspecified. (2) servname is disallowed
431: * for raw and other inet{,6} sockets.
1.1 itojun 432: */
1.14 itojun 433: if (MATCH_FAMILY(pai->ai_family, PF_INET, 1)
1.27 itojun 434: #ifdef PF_INET6
435: || MATCH_FAMILY(pai->ai_family, PF_INET6, 1)
436: #endif
437: ) {
1.23 itojun 438: ai0 = *pai; /* backup *pai */
1.21 mycroft 439:
1.27 itojun 440: if (pai->ai_family == PF_UNSPEC) {
441: #ifdef PF_INET6
1.14 itojun 442: pai->ai_family = PF_INET6;
1.27 itojun 443: #else
444: pai->ai_family = PF_INET;
445: #endif
446: }
1.14 itojun 447: error = get_portmatch(pai, servname);
448: if (error)
449: ERR(error);
1.21 mycroft 450:
451: *pai = ai0;
1.14 itojun 452: }
453:
454: ai0 = *pai;
455:
456: /* NULL hostname, or numeric hostname */
457: for (ex = explore; ex->e_af >= 0; ex++) {
458: *pai = ai0;
459:
1.32 itojun 460: /* PF_UNSPEC entries are prepared for DNS queries only */
461: if (ex->e_af == PF_UNSPEC)
462: continue;
463:
1.14 itojun 464: if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
465: continue;
466: if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex)))
467: continue;
468: if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex)))
469: continue;
470:
471: if (pai->ai_family == PF_UNSPEC)
472: pai->ai_family = ex->e_af;
473: if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
474: pai->ai_socktype = ex->e_socktype;
475: if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
476: pai->ai_protocol = ex->e_protocol;
477:
478: if (hostname == NULL)
1.20 mycroft 479: error = explore_null(pai, servname, &cur->ai_next);
1.14 itojun 480: else
1.65 itojun 481: error = explore_numeric_scope(pai, hostname, servname,
482: &cur->ai_next);
1.14 itojun 483:
484: if (error)
485: goto free;
486:
487: while (cur && cur->ai_next)
488: cur = cur->ai_next;
489: }
490:
491: /*
492: * XXX
1.76 ginsbach 493: * If numeric representation of AF1 can be interpreted as FQDN
1.14 itojun 494: * representation of AF2, we need to think again about the code below.
495: */
496: if (sentinel.ai_next)
497: goto good;
498:
499: if (hostname == NULL)
1.43 itojun 500: ERR(EAI_NODATA);
1.64 itojun 501: if (pai->ai_flags & AI_NUMERICHOST)
502: ERR(EAI_NONAME);
1.14 itojun 503:
504: /*
505: * hostname as alphabetical name.
506: * we would like to prefer AF_INET6 than AF_INET, so we'll make a
507: * outer loop by AFs.
508: */
1.32 itojun 509: for (ex = explore; ex->e_af >= 0; ex++) {
1.14 itojun 510: *pai = ai0;
511:
1.32 itojun 512: /* require exact match for family field */
513: if (pai->ai_family != ex->e_af)
1.14 itojun 514: continue;
515:
1.32 itojun 516: if (!MATCH(pai->ai_socktype, ex->e_socktype,
517: WILD_SOCKTYPE(ex))) {
518: continue;
519: }
520: if (!MATCH(pai->ai_protocol, ex->e_protocol,
521: WILD_PROTOCOL(ex))) {
522: continue;
523: }
1.14 itojun 524:
1.32 itojun 525: if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
526: pai->ai_socktype = ex->e_socktype;
527: if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
528: pai->ai_protocol = ex->e_protocol;
1.1 itojun 529:
1.32 itojun 530: error = explore_fqdn(pai, hostname, servname,
531: &cur->ai_next);
1.14 itojun 532:
1.32 itojun 533: while (cur && cur->ai_next)
534: cur = cur->ai_next;
1.1 itojun 535: }
1.14 itojun 536:
537: /* XXX */
538: if (sentinel.ai_next)
539: error = 0;
540:
541: if (error)
542: goto free;
543: if (error == 0) {
544: if (sentinel.ai_next) {
545: good:
546: *res = sentinel.ai_next;
547: return SUCCESS;
548: } else
549: error = EAI_FAIL;
550: }
551: free:
552: bad:
553: if (sentinel.ai_next)
554: freeaddrinfo(sentinel.ai_next);
555: *res = NULL;
556: return error;
557: }
558:
559: /*
560: * FQDN hostname, DNS lookup
561: */
562: static int
1.70 christos 563: explore_fqdn(const struct addrinfo *pai, const char *hostname,
564: const char *servname, struct addrinfo **res)
1.14 itojun 565: {
1.32 itojun 566: struct addrinfo *result;
567: struct addrinfo *cur;
1.27 itojun 568: int error = 0;
1.32 itojun 569: static const ns_dtab dtab[] = {
570: NS_FILES_CB(_files_getaddrinfo, NULL)
571: { NSSRC_DNS, _dns_getaddrinfo, NULL }, /* force -DHESIOD */
572: NS_NIS_CB(_yp_getaddrinfo, NULL)
573: { 0 }
574: };
1.14 itojun 575:
1.51 lukem 576: _DIAGASSERT(pai != NULL);
577: /* hostname may be NULL */
578: /* servname may be NULL */
579: _DIAGASSERT(res != NULL);
580:
1.32 itojun 581: result = NULL;
1.14 itojun 582:
583: /*
584: * if the servname does not match socktype/protocol, ignore it.
585: */
586: if (get_portmatch(pai, servname) != 0)
587: return 0;
588:
1.32 itojun 589: switch (nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo",
590: default_dns_files, hostname, pai)) {
591: case NS_TRYAGAIN:
592: error = EAI_AGAIN;
593: goto free;
594: case NS_UNAVAIL:
1.14 itojun 595: error = EAI_FAIL;
596: goto free;
1.32 itojun 597: case NS_NOTFOUND:
598: error = EAI_NODATA;
1.15 itojun 599: goto free;
1.32 itojun 600: case NS_SUCCESS:
601: error = 0;
602: for (cur = result; cur; cur = cur->ai_next) {
603: GET_PORT(cur, servname);
604: /* canonname should be filled already */
1.16 itojun 605: }
1.32 itojun 606: break;
1.16 itojun 607: }
1.15 itojun 608:
1.32 itojun 609: *res = result;
1.14 itojun 610:
611: return 0;
612:
613: free:
1.34 itojun 614: if (result)
615: freeaddrinfo(result);
1.14 itojun 616: return error;
617: }
618:
619: /*
620: * hostname == NULL.
621: * passive socket -> anyaddr (0.0.0.0 or ::)
622: * non-passive socket -> localhost (127.0.0.1 or ::1)
623: */
624: static int
1.70 christos 625: explore_null(const struct addrinfo *pai, const char *servname,
626: struct addrinfo **res)
1.14 itojun 627: {
628: int s;
629: const struct afd *afd;
630: struct addrinfo *cur;
631: struct addrinfo sentinel;
632: int error;
633:
1.51 lukem 634: _DIAGASSERT(pai != NULL);
635: /* servname may be NULL */
636: _DIAGASSERT(res != NULL);
637:
1.14 itojun 638: *res = NULL;
639: sentinel.ai_next = NULL;
640: cur = &sentinel;
641:
642: /*
643: * filter out AFs that are not supported by the kernel
644: * XXX errno?
645: */
646: s = socket(pai->ai_family, SOCK_DGRAM, 0);
647: if (s < 0) {
648: if (errno != EMFILE)
649: return 0;
650: } else
651: close(s);
652:
653: /*
654: * if the servname does not match socktype/protocol, ignore it.
655: */
656: if (get_portmatch(pai, servname) != 0)
657: return 0;
658:
659: afd = find_afd(pai->ai_family);
1.42 itojun 660: if (afd == NULL)
661: return 0;
1.14 itojun 662:
663: if (pai->ai_flags & AI_PASSIVE) {
664: GET_AI(cur->ai_next, afd, afd->a_addrany);
665: /* xxx meaningless?
666: * GET_CANONNAME(cur->ai_next, "anyaddr");
667: */
668: GET_PORT(cur->ai_next, servname);
669: } else {
670: GET_AI(cur->ai_next, afd, afd->a_loopback);
671: /* xxx meaningless?
672: * GET_CANONNAME(cur->ai_next, "localhost");
673: */
674: GET_PORT(cur->ai_next, servname);
675: }
676: cur = cur->ai_next;
677:
678: *res = sentinel.ai_next;
679: return 0;
680:
681: free:
682: if (sentinel.ai_next)
683: freeaddrinfo(sentinel.ai_next);
684: return error;
685: }
686:
687: /*
688: * numeric hostname
689: */
690: static int
1.70 christos 691: explore_numeric(const struct addrinfo *pai, const char *hostname,
692: const char *servname, struct addrinfo **res, const char *canonname)
1.14 itojun 693: {
694: const struct afd *afd;
695: struct addrinfo *cur;
696: struct addrinfo sentinel;
697: int error;
698: char pton[PTON_MAX];
699:
1.51 lukem 700: _DIAGASSERT(pai != NULL);
701: /* hostname may be NULL */
702: /* servname may be NULL */
703: _DIAGASSERT(res != NULL);
704:
1.14 itojun 705: *res = NULL;
706: sentinel.ai_next = NULL;
707: cur = &sentinel;
708:
709: /*
710: * if the servname does not match socktype/protocol, ignore it.
711: */
712: if (get_portmatch(pai, servname) != 0)
713: return 0;
714:
715: afd = find_afd(pai->ai_family);
1.42 itojun 716: if (afd == NULL)
717: return 0;
1.14 itojun 718:
1.27 itojun 719: switch (afd->a_af) {
720: #if 0 /*X/Open spec*/
721: case AF_INET:
722: if (inet_aton(hostname, (struct in_addr *)pton) == 1) {
723: if (pai->ai_family == afd->a_af ||
724: pai->ai_family == PF_UNSPEC /*?*/) {
725: GET_AI(cur->ai_next, afd, pton);
726: GET_PORT(cur->ai_next, servname);
1.65 itojun 727: if ((pai->ai_flags & AI_CANONNAME)) {
728: /*
729: * Set the numeric address itself as
730: * the canonical name, based on a
731: * clarification in rfc2553bis-03.
732: */
733: GET_CANONNAME(cur->ai_next, canonname);
734: }
1.27 itojun 735: while (cur && cur->ai_next)
736: cur = cur->ai_next;
1.42 itojun 737: } else
1.27 itojun 738: ERR(EAI_FAMILY); /*xxx*/
739: }
740: break;
741: #endif
742: default:
743: if (inet_pton(afd->a_af, hostname, pton) == 1) {
744: if (pai->ai_family == afd->a_af ||
745: pai->ai_family == PF_UNSPEC /*?*/) {
746: GET_AI(cur->ai_next, afd, pton);
747: GET_PORT(cur->ai_next, servname);
1.65 itojun 748: if ((pai->ai_flags & AI_CANONNAME)) {
749: /*
750: * Set the numeric address itself as
751: * the canonical name, based on a
752: * clarification in rfc2553bis-03.
753: */
754: GET_CANONNAME(cur->ai_next, canonname);
755: }
1.27 itojun 756: while (cur && cur->ai_next)
757: cur = cur->ai_next;
1.42 itojun 758: } else
1.27 itojun 759: ERR(EAI_FAMILY); /*xxx*/
760: }
761: break;
1.1 itojun 762: }
763:
1.14 itojun 764: *res = sentinel.ai_next;
765: return 0;
766:
767: free:
768: bad:
769: if (sentinel.ai_next)
770: freeaddrinfo(sentinel.ai_next);
771: return error;
772: }
773:
774: /*
775: * numeric hostname with scope
776: */
777: static int
1.70 christos 778: explore_numeric_scope(const struct addrinfo *pai, const char *hostname,
779: const char *servname, struct addrinfo **res)
1.14 itojun 780: {
1.29 itojun 781: #if !defined(SCOPE_DELIMITER) || !defined(INET6)
1.65 itojun 782: return explore_numeric(pai, hostname, servname, res, hostname);
1.14 itojun 783: #else
784: const struct afd *afd;
785: struct addrinfo *cur;
786: int error;
1.30 itojun 787: char *cp, *hostname2 = NULL, *scope, *addr;
1.14 itojun 788: struct sockaddr_in6 *sin6;
789:
1.51 lukem 790: _DIAGASSERT(pai != NULL);
791: /* hostname may be NULL */
792: /* servname may be NULL */
793: _DIAGASSERT(res != NULL);
794:
1.14 itojun 795: /*
796: * if the servname does not match socktype/protocol, ignore it.
797: */
798: if (get_portmatch(pai, servname) != 0)
799: return 0;
800:
801: afd = find_afd(pai->ai_family);
1.42 itojun 802: if (afd == NULL)
803: return 0;
804:
1.14 itojun 805: if (!afd->a_scoped)
1.65 itojun 806: return explore_numeric(pai, hostname, servname, res, hostname);
1.14 itojun 807:
808: cp = strchr(hostname, SCOPE_DELIMITER);
809: if (cp == NULL)
1.65 itojun 810: return explore_numeric(pai, hostname, servname, res, hostname);
1.14 itojun 811:
1.30 itojun 812: /*
813: * Handle special case of <scoped_address><delimiter><scope id>
814: */
815: hostname2 = strdup(hostname);
816: if (hostname2 == NULL)
817: return EAI_MEMORY;
818: /* terminate at the delimiter */
819: hostname2[cp - hostname] = '\0';
820: addr = hostname2;
821: scope = cp + 1;
1.1 itojun 822:
1.65 itojun 823: error = explore_numeric(pai, addr, servname, res, hostname);
1.1 itojun 824: if (error == 0) {
1.59 itojun 825: u_int32_t scopeid;
1.27 itojun 826:
1.14 itojun 827: for (cur = *res; cur; cur = cur->ai_next) {
828: if (cur->ai_family != AF_INET6)
829: continue;
1.36 christos 830: sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr;
1.60 itojun 831: if (ip6_str2scopeid(scope, sin6, &scopeid) == -1) {
1.27 itojun 832: free(hostname2);
1.43 itojun 833: return(EAI_NODATA); /* XXX: is return OK? */
1.27 itojun 834: }
835: sin6->sin6_scope_id = scopeid;
1.14 itojun 836: }
1.1 itojun 837: }
1.14 itojun 838:
839: free(hostname2);
840:
1.1 itojun 841: return error;
1.14 itojun 842: #endif
1.1 itojun 843: }
844:
845: static int
1.70 christos 846: get_canonname(const struct addrinfo *pai, struct addrinfo *ai, const char *str)
1.1 itojun 847: {
1.51 lukem 848:
849: _DIAGASSERT(pai != NULL);
850: _DIAGASSERT(ai != NULL);
851: _DIAGASSERT(str != NULL);
852:
1.14 itojun 853: if ((pai->ai_flags & AI_CANONNAME) != 0) {
1.66 itojun 854: ai->ai_canonname = strdup(str);
1.14 itojun 855: if (ai->ai_canonname == NULL)
856: return EAI_MEMORY;
857: }
858: return 0;
859: }
1.1 itojun 860:
1.14 itojun 861: static struct addrinfo *
1.70 christos 862: get_ai(const struct addrinfo *pai, const struct afd *afd, const char *addr)
1.14 itojun 863: {
864: char *p;
865: struct addrinfo *ai;
1.12 lukem 866:
1.51 lukem 867: _DIAGASSERT(pai != NULL);
868: _DIAGASSERT(afd != NULL);
869: _DIAGASSERT(addr != NULL);
870:
1.14 itojun 871: ai = (struct addrinfo *)malloc(sizeof(struct addrinfo)
872: + (afd->a_socklen));
873: if (ai == NULL)
874: return NULL;
875:
876: memcpy(ai, pai, sizeof(struct addrinfo));
1.36 christos 877: ai->ai_addr = (struct sockaddr *)(void *)(ai + 1);
1.20 mycroft 878: memset(ai->ai_addr, 0, (size_t)afd->a_socklen);
1.14 itojun 879: ai->ai_addr->sa_len = afd->a_socklen;
880: ai->ai_addrlen = afd->a_socklen;
1.55 kleink 881: #if defined (__alpha__) || (defined(__i386__) && defined(_LP64)) || defined(__sparc64__)
882: ai->__ai_pad0 = 0;
883: #endif
1.14 itojun 884: ai->ai_addr->sa_family = ai->ai_family = afd->a_af;
1.36 christos 885: p = (char *)(void *)(ai->ai_addr);
1.20 mycroft 886: memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen);
1.14 itojun 887: return ai;
888: }
1.1 itojun 889:
1.14 itojun 890: static int
1.70 christos 891: get_portmatch(const struct addrinfo *ai, const char *servname)
1.14 itojun 892: {
1.4 itojun 893:
1.51 lukem 894: _DIAGASSERT(ai != NULL);
895: /* servname may be NULL */
896:
1.75 yamt 897: return get_port(ai, servname, 1);
1.1 itojun 898: }
899:
900: static int
1.75 yamt 901: get_port(const struct addrinfo *ai, const char *servname, int matchonly)
1.1 itojun 902: {
1.14 itojun 903: const char *proto;
904: struct servent *sp;
905: int port;
906: int allownumeric;
1.12 lukem 907:
1.51 lukem 908: _DIAGASSERT(ai != NULL);
909: /* servname may be NULL */
910:
1.14 itojun 911: if (servname == NULL)
912: return 0;
1.23 itojun 913: switch (ai->ai_family) {
914: case AF_INET:
1.27 itojun 915: #ifdef AF_INET6
1.23 itojun 916: case AF_INET6:
1.27 itojun 917: #endif
1.23 itojun 918: break;
919: default:
1.14 itojun 920: return 0;
1.23 itojun 921: }
1.1 itojun 922:
1.14 itojun 923: switch (ai->ai_socktype) {
924: case SOCK_RAW:
925: return EAI_SERVICE;
926: case SOCK_DGRAM:
927: case SOCK_STREAM:
928: allownumeric = 1;
929: break;
930: case ANY:
931: allownumeric = 0;
932: break;
933: default:
934: return EAI_SOCKTYPE;
1.1 itojun 935: }
1.14 itojun 936:
1.67 itojun 937: port = str2number(servname);
938: if (port >= 0) {
1.14 itojun 939: if (!allownumeric)
940: return EAI_SERVICE;
941: if (port < 0 || port > 65535)
942: return EAI_SERVICE;
1.58 itojun 943: port = htons(port);
1.14 itojun 944: } else {
1.67 itojun 945: if (ai->ai_flags & AI_NUMERICSERV)
946: return EAI_NONAME;
947:
1.14 itojun 948: switch (ai->ai_socktype) {
949: case SOCK_DGRAM:
950: proto = "udp";
1.1 itojun 951: break;
1.14 itojun 952: case SOCK_STREAM:
953: proto = "tcp";
1.1 itojun 954: break;
955: default:
1.14 itojun 956: proto = NULL;
1.1 itojun 957: break;
958: }
1.14 itojun 959:
960: if ((sp = getservbyname(servname, proto)) == NULL)
961: return EAI_SERVICE;
962: port = sp->s_port;
1.1 itojun 963: }
964:
1.14 itojun 965: if (!matchonly) {
966: switch (ai->ai_family) {
1.1 itojun 967: case AF_INET:
1.36 christos 968: ((struct sockaddr_in *)(void *)
969: ai->ai_addr)->sin_port = port;
1.1 itojun 970: break;
971: #ifdef INET6
1.14 itojun 972: case AF_INET6:
1.36 christos 973: ((struct sockaddr_in6 *)(void *)
974: ai->ai_addr)->sin6_port = port;
1.1 itojun 975: break;
976: #endif
977: }
1.14 itojun 978: }
979:
980: return 0;
981: }
982:
983: static const struct afd *
1.70 christos 984: find_afd(int af)
1.14 itojun 985: {
986: const struct afd *afd;
1.1 itojun 987:
1.14 itojun 988: if (af == PF_UNSPEC)
989: return NULL;
990: for (afd = afdl; afd->a_af; afd++) {
991: if (afd->a_af == af)
992: return afd;
1.1 itojun 993: }
1.14 itojun 994: return NULL;
1.1 itojun 995: }
1.27 itojun 996:
997: #ifdef INET6
998: /* convert a string to a scope identifier. XXX: IPv6 specific */
1.60 itojun 999: static int
1.70 christos 1000: ip6_str2scopeid(char *scope, struct sockaddr_in6 *sin6, u_int32_t *scopeid)
1.27 itojun 1001: {
1.59 itojun 1002: u_long lscopeid;
1.51 lukem 1003: struct in6_addr *a6;
1.27 itojun 1004: char *ep;
1.46 itojun 1005:
1.51 lukem 1006: _DIAGASSERT(scope != NULL);
1007: _DIAGASSERT(sin6 != NULL);
1.60 itojun 1008: _DIAGASSERT(scopeid != NULL);
1.51 lukem 1009:
1010: a6 = &sin6->sin6_addr;
1011:
1.46 itojun 1012: /* empty scopeid portion is invalid */
1013: if (*scope == '\0')
1014: return -1;
1.27 itojun 1015:
1016: if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) {
1017: /*
1018: * We currently assume a one-to-one mapping between links
1019: * and interfaces, so we simply use interface indices for
1020: * like-local scopes.
1021: */
1.60 itojun 1022: *scopeid = if_nametoindex(scope);
1023: if (*scopeid == 0)
1.27 itojun 1024: goto trynumeric;
1.60 itojun 1025: return 0;
1.27 itojun 1026: }
1027:
1028: /* still unclear about literal, allow numeric only - placeholder */
1029: if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6))
1030: goto trynumeric;
1031: if (IN6_IS_ADDR_MC_ORGLOCAL(a6))
1032: goto trynumeric;
1033: else
1034: goto trynumeric; /* global */
1035:
1036: /* try to convert to a numeric id as a last resort */
1037: trynumeric:
1.59 itojun 1038: errno = 0;
1039: lscopeid = strtoul(scope, &ep, 10);
1.61 itojun 1040: *scopeid = (u_int32_t)(lscopeid & 0xffffffffUL);
1.60 itojun 1041: if (errno == 0 && ep && *ep == '\0' && *scopeid == lscopeid)
1042: return 0;
1.27 itojun 1043: else
1044: return -1;
1045: }
1.42 itojun 1046: #endif
1.32 itojun 1047:
1048: /* code duplicate with gethnamaddr.c */
1049:
1050: static const char AskedForGot[] =
1051: "gethostby*.getanswer: asked for \"%s\", got \"%s\"";
1052:
1053: static struct addrinfo *
1.70 christos 1054: getanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
1055: const struct addrinfo *pai)
1.32 itojun 1056: {
1057: struct addrinfo sentinel, *cur;
1058: struct addrinfo ai;
1059: const struct afd *afd;
1060: char *canonname;
1061: const HEADER *hp;
1062: const u_char *cp;
1063: int n;
1064: const u_char *eom;
1.56 itojun 1065: char *bp, *ep;
1066: int type, class, ancount, qdcount;
1.32 itojun 1067: int haveanswer, had_error;
1068: char tbuf[MAXDNAME];
1.70 christos 1069: int (*name_ok) (const char *);
1.32 itojun 1070: char hostbuf[8*1024];
1071:
1.51 lukem 1072: _DIAGASSERT(answer != NULL);
1073: _DIAGASSERT(qname != NULL);
1074: _DIAGASSERT(pai != NULL);
1075:
1.32 itojun 1076: memset(&sentinel, 0, sizeof(sentinel));
1077: cur = &sentinel;
1078:
1079: canonname = NULL;
1080: eom = answer->buf + anslen;
1081: switch (qtype) {
1082: case T_A:
1083: case T_AAAA:
1084: case T_ANY: /*use T_ANY only for T_A/T_AAAA lookup*/
1085: name_ok = res_hnok;
1086: break;
1087: default:
1.70 christos 1088: return NULL; /* XXX should be abort(); */
1.32 itojun 1089: }
1090: /*
1091: * find first satisfactory answer
1092: */
1093: hp = &answer->hdr;
1094: ancount = ntohs(hp->ancount);
1095: qdcount = ntohs(hp->qdcount);
1096: bp = hostbuf;
1.56 itojun 1097: ep = hostbuf + sizeof hostbuf;
1.32 itojun 1098: cp = answer->buf + HFIXEDSZ;
1099: if (qdcount != 1) {
1100: h_errno = NO_RECOVERY;
1101: return (NULL);
1102: }
1.56 itojun 1103: n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
1.32 itojun 1104: if ((n < 0) || !(*name_ok)(bp)) {
1105: h_errno = NO_RECOVERY;
1106: return (NULL);
1107: }
1108: cp += n + QFIXEDSZ;
1109: if (qtype == T_A || qtype == T_AAAA || qtype == T_ANY) {
1110: /* res_send() has already verified that the query name is the
1111: * same as the one we sent; this just gets the expanded name
1112: * (i.e., with the succeeding search-domain tacked on).
1113: */
1114: n = strlen(bp) + 1; /* for the \0 */
1115: if (n >= MAXHOSTNAMELEN) {
1116: h_errno = NO_RECOVERY;
1117: return (NULL);
1118: }
1119: canonname = bp;
1120: bp += n;
1121: /* The qname can be abbreviated, but h_name is now absolute. */
1122: qname = canonname;
1123: }
1124: haveanswer = 0;
1125: had_error = 0;
1126: while (ancount-- > 0 && cp < eom && !had_error) {
1.56 itojun 1127: n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
1.32 itojun 1128: if ((n < 0) || !(*name_ok)(bp)) {
1129: had_error++;
1130: continue;
1131: }
1132: cp += n; /* name */
1133: type = _getshort(cp);
1134: cp += INT16SZ; /* type */
1135: class = _getshort(cp);
1136: cp += INT16SZ + INT32SZ; /* class, TTL */
1137: n = _getshort(cp);
1138: cp += INT16SZ; /* len */
1139: if (class != C_IN) {
1140: /* XXX - debug? syslog? */
1141: cp += n;
1142: continue; /* XXX - had_error++ ? */
1143: }
1144: if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) &&
1145: type == T_CNAME) {
1146: n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
1147: if ((n < 0) || !(*name_ok)(tbuf)) {
1148: had_error++;
1149: continue;
1150: }
1151: cp += n;
1152: /* Get canonical name. */
1153: n = strlen(tbuf) + 1; /* for the \0 */
1.56 itojun 1154: if (n > ep - bp || n >= MAXHOSTNAMELEN) {
1.32 itojun 1155: had_error++;
1156: continue;
1157: }
1.66 itojun 1158: strlcpy(bp, tbuf, (size_t)(ep - bp));
1.32 itojun 1159: canonname = bp;
1160: bp += n;
1161: continue;
1162: }
1163: if (qtype == T_ANY) {
1164: if (!(type == T_A || type == T_AAAA)) {
1165: cp += n;
1166: continue;
1167: }
1168: } else if (type != qtype) {
1169: if (type != T_KEY && type != T_SIG)
1170: syslog(LOG_NOTICE|LOG_AUTH,
1171: "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
1172: qname, p_class(C_IN), p_type(qtype),
1173: p_type(type));
1174: cp += n;
1175: continue; /* XXX - had_error++ ? */
1176: }
1177: switch (type) {
1178: case T_A:
1179: case T_AAAA:
1180: if (strcasecmp(canonname, bp) != 0) {
1181: syslog(LOG_NOTICE|LOG_AUTH,
1182: AskedForGot, canonname, bp);
1183: cp += n;
1184: continue; /* XXX - had_error++ ? */
1185: }
1186: if (type == T_A && n != INADDRSZ) {
1187: cp += n;
1188: continue;
1189: }
1190: if (type == T_AAAA && n != IN6ADDRSZ) {
1191: cp += n;
1192: continue;
1.62 itojun 1193: }
1194: if (type == T_AAAA) {
1195: struct in6_addr in6;
1196: memcpy(&in6, cp, IN6ADDRSZ);
1197: if (IN6_IS_ADDR_V4MAPPED(&in6)) {
1198: cp += n;
1199: continue;
1200: }
1.32 itojun 1201: }
1202: if (!haveanswer) {
1203: int nn;
1204:
1205: canonname = bp;
1206: nn = strlen(bp) + 1; /* for the \0 */
1207: bp += nn;
1208: }
1209:
1210: /* don't overwrite pai */
1211: ai = *pai;
1212: ai.ai_family = (type == T_A) ? AF_INET : AF_INET6;
1213: afd = find_afd(ai.ai_family);
1214: if (afd == NULL) {
1215: cp += n;
1216: continue;
1217: }
1.36 christos 1218: cur->ai_next = get_ai(&ai, afd, (const char *)cp);
1.32 itojun 1219: if (cur->ai_next == NULL)
1220: had_error++;
1221: while (cur && cur->ai_next)
1222: cur = cur->ai_next;
1223: cp += n;
1224: break;
1225: default:
1226: abort();
1227: }
1228: if (!had_error)
1229: haveanswer++;
1230: }
1231: if (haveanswer) {
1232: if (!canonname)
1233: (void)get_canonname(pai, sentinel.ai_next, qname);
1234: else
1235: (void)get_canonname(pai, sentinel.ai_next, canonname);
1236: h_errno = NETDB_SUCCESS;
1237: return sentinel.ai_next;
1238: }
1239:
1240: h_errno = NO_RECOVERY;
1241: return NULL;
1242: }
1243:
1.73 tsarna 1244: #define SORTEDADDR(p) (((struct sockaddr_in *)(void *)(p->ai_next->ai_addr))->sin_addr.s_addr)
1245: #define SORTMATCH(p, s) ((SORTEDADDR(p) & (s).mask) == (s).addr.s_addr)
1246:
1247: static void
1248: aisort(struct addrinfo *s, res_state res)
1249: {
1250: struct addrinfo head, *t, *p;
1251: int i;
1252:
1253: head.ai_next = NULL;
1254: t = &head;
1255:
1256: for (i = 0; i < res->nsort; i++) {
1257: p = s;
1258: while (p->ai_next) {
1259: if ((p->ai_next->ai_family != AF_INET)
1260: || SORTMATCH(p, res->sort_list[i])) {
1261: t->ai_next = p->ai_next;
1262: t = t->ai_next;
1263: p->ai_next = p->ai_next->ai_next;
1264: } else {
1265: p = p->ai_next;
1266: }
1267: }
1268: }
1269:
1270: /* add rest of list and reset s to the new list*/
1271: t->ai_next = s->ai_next;
1272: s->ai_next = head.ai_next;
1273: }
1274:
1.32 itojun 1275: /*ARGSUSED*/
1276: static int
1.70 christos 1277: _dns_getaddrinfo(void *rv, void *cb_data, va_list ap)
1.32 itojun 1278: {
1279: struct addrinfo *ai;
1.63 itojun 1280: querybuf *buf, *buf2;
1.32 itojun 1281: const char *name;
1282: const struct addrinfo *pai;
1283: struct addrinfo sentinel, *cur;
1284: struct res_target q, q2;
1.73 tsarna 1285: res_state res;
1.32 itojun 1286:
1287: name = va_arg(ap, char *);
1288: pai = va_arg(ap, const struct addrinfo *);
1289:
1290: memset(&q, 0, sizeof(q2));
1291: memset(&q2, 0, sizeof(q2));
1292: memset(&sentinel, 0, sizeof(sentinel));
1293: cur = &sentinel;
1294:
1.63 itojun 1295: buf = malloc(sizeof(*buf));
1296: if (buf == NULL) {
1297: h_errno = NETDB_INTERNAL;
1298: return NS_NOTFOUND;
1299: }
1300: buf2 = malloc(sizeof(*buf2));
1301: if (buf2 == NULL) {
1302: free(buf);
1303: h_errno = NETDB_INTERNAL;
1304: return NS_NOTFOUND;
1305: }
1306:
1.32 itojun 1307: switch (pai->ai_family) {
1308: case AF_UNSPEC:
1309: /* prefer IPv6 */
1.52 itojun 1310: q.name = name;
1.43 itojun 1311: q.qclass = C_IN;
1312: q.qtype = T_AAAA;
1.63 itojun 1313: q.answer = buf->buf;
1314: q.anslen = sizeof(buf->buf);
1.32 itojun 1315: q.next = &q2;
1.52 itojun 1316: q2.name = name;
1.43 itojun 1317: q2.qclass = C_IN;
1318: q2.qtype = T_A;
1.63 itojun 1319: q2.answer = buf2->buf;
1320: q2.anslen = sizeof(buf2->buf);
1.32 itojun 1321: break;
1322: case AF_INET:
1.52 itojun 1323: q.name = name;
1.43 itojun 1324: q.qclass = C_IN;
1325: q.qtype = T_A;
1.63 itojun 1326: q.answer = buf->buf;
1327: q.anslen = sizeof(buf->buf);
1.32 itojun 1328: break;
1329: case AF_INET6:
1.52 itojun 1330: q.name = name;
1.43 itojun 1331: q.qclass = C_IN;
1332: q.qtype = T_AAAA;
1.63 itojun 1333: q.answer = buf->buf;
1334: q.anslen = sizeof(buf->buf);
1.32 itojun 1335: break;
1336: default:
1.63 itojun 1337: free(buf);
1338: free(buf2);
1.32 itojun 1339: return NS_UNAVAIL;
1340: }
1.73 tsarna 1341:
1342: res = __res_get_state();
1343: if (res == NULL) {
1344: free(buf);
1345: free(buf2);
1346: return NS_NOTFOUND;
1347: }
1348:
1349: if (res_searchN(name, &q, res) < 0) {
1350: __res_put_state(res);
1.63 itojun 1351: free(buf);
1352: free(buf2);
1.32 itojun 1353: return NS_NOTFOUND;
1.63 itojun 1354: }
1355: ai = getanswer(buf, q.n, q.name, q.qtype, pai);
1.32 itojun 1356: if (ai) {
1357: cur->ai_next = ai;
1358: while (cur && cur->ai_next)
1359: cur = cur->ai_next;
1360: }
1361: if (q.next) {
1.63 itojun 1362: ai = getanswer(buf2, q2.n, q2.name, q2.qtype, pai);
1.32 itojun 1363: if (ai)
1364: cur->ai_next = ai;
1365: }
1.63 itojun 1366: free(buf);
1367: free(buf2);
1.73 tsarna 1368: if (sentinel.ai_next == NULL) {
1369: __res_put_state(res);
1.32 itojun 1370: switch (h_errno) {
1371: case HOST_NOT_FOUND:
1372: return NS_NOTFOUND;
1373: case TRY_AGAIN:
1374: return NS_TRYAGAIN;
1375: default:
1376: return NS_UNAVAIL;
1377: }
1.73 tsarna 1378: }
1379:
1380: if (res->nsort)
1381: aisort(&sentinel, res);
1382:
1383: __res_put_state(res);
1384:
1.32 itojun 1385: *((struct addrinfo **)rv) = sentinel.ai_next;
1386: return NS_SUCCESS;
1387: }
1388:
1389: static void
1.70 christos 1390: _sethtent(FILE **hostf)
1.32 itojun 1391: {
1.51 lukem 1392:
1.70 christos 1393: if (!*hostf)
1394: *hostf = fopen(_PATH_HOSTS, "r" );
1.32 itojun 1395: else
1.70 christos 1396: rewind(*hostf);
1.32 itojun 1397: }
1398:
1399: static void
1.70 christos 1400: _endhtent(FILE **hostf)
1.32 itojun 1401: {
1.51 lukem 1402:
1.70 christos 1403: if (*hostf) {
1404: (void) fclose(*hostf);
1405: *hostf = NULL;
1.32 itojun 1406: }
1407: }
1408:
1409: static struct addrinfo *
1.70 christos 1410: _gethtent(FILE **hostf, const char *name, const struct addrinfo *pai)
1.32 itojun 1411: {
1412: char *p;
1.48 itojun 1413: char *cp, *tname, *cname;
1.32 itojun 1414: struct addrinfo hints, *res0, *res;
1415: int error;
1416: const char *addr;
1417: char hostbuf[8*1024];
1418:
1.51 lukem 1419: _DIAGASSERT(name != NULL);
1420: _DIAGASSERT(pai != NULL);
1421:
1.70 christos 1422: if (!*hostf && !(*hostf = fopen(_PATH_HOSTS, "r" )))
1.32 itojun 1423: return (NULL);
1424: again:
1.70 christos 1425: if (!(p = fgets(hostbuf, sizeof hostbuf, *hostf)))
1.32 itojun 1426: return (NULL);
1427: if (*p == '#')
1428: goto again;
1429: if (!(cp = strpbrk(p, "#\n")))
1430: goto again;
1431: *cp = '\0';
1432: if (!(cp = strpbrk(p, " \t")))
1433: goto again;
1434: *cp++ = '\0';
1435: addr = p;
1436: /* if this is not something we're looking for, skip it. */
1.48 itojun 1437: cname = NULL;
1.32 itojun 1438: while (cp && *cp) {
1439: if (*cp == ' ' || *cp == '\t') {
1440: cp++;
1441: continue;
1442: }
1.48 itojun 1443: if (!cname)
1444: cname = cp;
1.32 itojun 1445: tname = cp;
1446: if ((cp = strpbrk(cp, " \t")) != NULL)
1447: *cp++ = '\0';
1448: if (strcasecmp(name, tname) == 0)
1449: goto found;
1450: }
1451: goto again;
1452:
1453: found:
1454: hints = *pai;
1455: hints.ai_flags = AI_NUMERICHOST;
1456: error = getaddrinfo(addr, NULL, &hints, &res0);
1457: if (error)
1458: goto again;
1459: for (res = res0; res; res = res->ai_next) {
1460: /* cover it up */
1461: res->ai_flags = pai->ai_flags;
1462:
1463: if (pai->ai_flags & AI_CANONNAME) {
1.48 itojun 1464: if (get_canonname(pai, res, cname) != 0) {
1.32 itojun 1465: freeaddrinfo(res0);
1466: goto again;
1467: }
1468: }
1469: }
1470: return res0;
1471: }
1472:
1473: /*ARGSUSED*/
1474: static int
1.70 christos 1475: _files_getaddrinfo(void *rv, void *cb_data, va_list ap)
1.32 itojun 1476: {
1477: const char *name;
1478: const struct addrinfo *pai;
1479: struct addrinfo sentinel, *cur;
1480: struct addrinfo *p;
1.70 christos 1481: #ifndef _REENTRANT
1482: static
1483: #endif
1484: FILE *hostf = NULL;
1.32 itojun 1485:
1486: name = va_arg(ap, char *);
1487: pai = va_arg(ap, struct addrinfo *);
1488:
1489: memset(&sentinel, 0, sizeof(sentinel));
1490: cur = &sentinel;
1491:
1.70 christos 1492: _sethtent(&hostf);
1493: while ((p = _gethtent(&hostf, name, pai)) != NULL) {
1.32 itojun 1494: cur->ai_next = p;
1495: while (cur && cur->ai_next)
1496: cur = cur->ai_next;
1497: }
1.70 christos 1498: _endhtent(&hostf);
1.32 itojun 1499:
1500: *((struct addrinfo **)rv) = sentinel.ai_next;
1501: if (sentinel.ai_next == NULL)
1502: return NS_NOTFOUND;
1503: return NS_SUCCESS;
1504: }
1505:
1506: #ifdef YP
1507: /*ARGSUSED*/
1508: static struct addrinfo *
1.70 christos 1509: _yphostent(char *line, const struct addrinfo *pai)
1.32 itojun 1510: {
1511: struct addrinfo sentinel, *cur;
1512: struct addrinfo hints, *res, *res0;
1513: int error;
1.51 lukem 1514: char *p;
1.32 itojun 1515: const char *addr, *canonname;
1516: char *nextline;
1517: char *cp;
1518:
1.51 lukem 1519: _DIAGASSERT(line != NULL);
1520: _DIAGASSERT(pai != NULL);
1521:
1522: p = line;
1.32 itojun 1523: addr = canonname = NULL;
1524:
1.36 christos 1525: memset(&sentinel, 0, sizeof(sentinel));
1526: cur = &sentinel;
1527:
1.32 itojun 1528: nextline:
1529: /* terminate line */
1530: cp = strchr(p, '\n');
1531: if (cp) {
1532: *cp++ = '\0';
1533: nextline = cp;
1534: } else
1535: nextline = NULL;
1536:
1537: cp = strpbrk(p, " \t");
1538: if (cp == NULL) {
1539: if (canonname == NULL)
1540: return (NULL);
1541: else
1542: goto done;
1543: }
1544: *cp++ = '\0';
1545:
1546: addr = p;
1547:
1548: while (cp && *cp) {
1549: if (*cp == ' ' || *cp == '\t') {
1550: cp++;
1551: continue;
1552: }
1553: if (!canonname)
1554: canonname = cp;
1555: if ((cp = strpbrk(cp, " \t")) != NULL)
1556: *cp++ = '\0';
1557: }
1558:
1559: hints = *pai;
1560: hints.ai_flags = AI_NUMERICHOST;
1561: error = getaddrinfo(addr, NULL, &hints, &res0);
1562: if (error == 0) {
1563: for (res = res0; res; res = res->ai_next) {
1564: /* cover it up */
1565: res->ai_flags = pai->ai_flags;
1566:
1567: if (pai->ai_flags & AI_CANONNAME)
1568: (void)get_canonname(pai, res, canonname);
1569: }
1.37 itojun 1570: } else
1571: res0 = NULL;
1.32 itojun 1572: if (res0) {
1573: cur->ai_next = res0;
1574: while (cur && cur->ai_next)
1575: cur = cur->ai_next;
1576: }
1577:
1578: if (nextline) {
1579: p = nextline;
1580: goto nextline;
1581: }
1582:
1583: done:
1584: return sentinel.ai_next;
1585: }
1586:
1587: /*ARGSUSED*/
1588: static int
1.70 christos 1589: _yp_getaddrinfo(void *rv, void *cb_data, va_list ap)
1.32 itojun 1590: {
1591: struct addrinfo sentinel, *cur;
1592: struct addrinfo *ai = NULL;
1.72 christos 1593: char *ypbuf;
1594: int ypbuflen, r;
1.32 itojun 1595: const char *name;
1596: const struct addrinfo *pai;
1.72 christos 1597: char *ypdomain;
1598:
1599: if (_yp_check(&ypdomain) == 0)
1600: return NS_UNAVAIL;
1.32 itojun 1601:
1602: name = va_arg(ap, char *);
1603: pai = va_arg(ap, const struct addrinfo *);
1604:
1605: memset(&sentinel, 0, sizeof(sentinel));
1606: cur = &sentinel;
1607:
1608: /* hosts.byname is only for IPv4 (Solaris8) */
1.33 itojun 1609: if (pai->ai_family == PF_UNSPEC || pai->ai_family == PF_INET) {
1.72 christos 1610: r = yp_match(ypdomain, "hosts.byname", name,
1611: (int)strlen(name), &ypbuf, &ypbuflen);
1.33 itojun 1612: if (r == 0) {
1613: struct addrinfo ai4;
1614:
1615: ai4 = *pai;
1616: ai4.ai_family = AF_INET;
1.72 christos 1617: ai = _yphostent(ypbuf, &ai4);
1.33 itojun 1618: if (ai) {
1619: cur->ai_next = ai;
1620: while (cur && cur->ai_next)
1621: cur = cur->ai_next;
1622: }
1.32 itojun 1623: }
1.72 christos 1624: free(ypbuf);
1.32 itojun 1625: }
1626:
1627: /* ipnodes.byname can hold both IPv4/v6 */
1.72 christos 1628: r = yp_match(ypdomain, "ipnodes.byname", name,
1629: (int)strlen(name), &ypbuf, &ypbuflen);
1.32 itojun 1630: if (r == 0) {
1.72 christos 1631: ai = _yphostent(ypbuf, pai);
1632: if (ai)
1.32 itojun 1633: cur->ai_next = ai;
1.72 christos 1634: free(ypbuf);
1.32 itojun 1635: }
1636:
1637: if (sentinel.ai_next == NULL) {
1638: h_errno = HOST_NOT_FOUND;
1639: return NS_NOTFOUND;
1640: }
1641: *((struct addrinfo **)rv) = sentinel.ai_next;
1642: return NS_SUCCESS;
1643: }
1644: #endif
1645:
1646: /* resolver logic */
1647:
1648: /*
1649: * Formulate a normal query, send, and await answer.
1650: * Returned answer is placed in supplied buffer "answer".
1651: * Perform preliminary check of answer, returning success only
1652: * if no error is indicated and the answer count is nonzero.
1653: * Return the size of the response on success, -1 on error.
1654: * Error number is left in h_errno.
1655: *
1656: * Caller must parse answer and determine whether it answers the question.
1657: */
1658: static int
1.70 christos 1659: res_queryN(const char *name, /* domain name */ struct res_target *target,
1660: res_state res)
1.32 itojun 1661: {
1662: u_char buf[MAXPACKET];
1663: HEADER *hp;
1664: int n;
1665: struct res_target *t;
1666: int rcode;
1667: int ancount;
1668:
1.51 lukem 1669: _DIAGASSERT(name != NULL);
1670: /* XXX: target may be NULL??? */
1671:
1.32 itojun 1672: rcode = NOERROR;
1673: ancount = 0;
1674:
1675: for (t = target; t; t = t->next) {
1676: int class, type;
1677: u_char *answer;
1678: int anslen;
1679:
1680: hp = (HEADER *)(void *)t->answer;
1681: hp->rcode = NOERROR; /* default */
1682:
1683: /* make it easier... */
1.43 itojun 1684: class = t->qclass;
1685: type = t->qtype;
1.32 itojun 1686: answer = t->answer;
1687: anslen = t->anslen;
1688: #ifdef DEBUG
1.70 christos 1689: if (res->options & RES_DEBUG)
1690: printf(";; res_nquery(%s, %d, %d)\n", name, class, type);
1.32 itojun 1691: #endif
1692:
1.70 christos 1693: n = res_nmkquery(res, QUERY, name, class, type, NULL, 0, NULL,
1.32 itojun 1694: buf, sizeof(buf));
1.47 itojun 1695: #ifdef RES_USE_EDNS0
1.70 christos 1696: if (n > 0 && (res->options & RES_USE_EDNS0) != 0)
1697: n = res_nopt(res, n, buf, sizeof(buf), anslen);
1.47 itojun 1698: #endif
1.32 itojun 1699: if (n <= 0) {
1700: #ifdef DEBUG
1.70 christos 1701: if (res->options & RES_DEBUG)
1702: printf(";; res_nquery: mkquery failed\n");
1.32 itojun 1703: #endif
1704: h_errno = NO_RECOVERY;
1.70 christos 1705: return n;
1.32 itojun 1706: }
1.70 christos 1707: n = res_nsend(res, buf, n, answer, anslen);
1.35 itojun 1708: #if 0
1.32 itojun 1709: if (n < 0) {
1710: #ifdef DEBUG
1.70 christos 1711: if (res->options & RES_DEBUG)
1.32 itojun 1712: printf(";; res_query: send error\n");
1713: #endif
1714: h_errno = TRY_AGAIN;
1.70 christos 1715: return n;
1.32 itojun 1716: }
1.35 itojun 1717: #endif
1.32 itojun 1718:
1.35 itojun 1719: if (n < 0 || hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
1.32 itojun 1720: rcode = hp->rcode; /* record most recent error */
1721: #ifdef DEBUG
1.70 christos 1722: if (res->options & RES_DEBUG)
1.57 itojun 1723: printf(";; rcode = %u, ancount=%u\n", hp->rcode,
1.32 itojun 1724: ntohs(hp->ancount));
1725: #endif
1726: continue;
1727: }
1728:
1729: ancount += ntohs(hp->ancount);
1730:
1731: t->n = n;
1732: }
1733:
1734: if (ancount == 0) {
1735: switch (rcode) {
1736: case NXDOMAIN:
1737: h_errno = HOST_NOT_FOUND;
1738: break;
1739: case SERVFAIL:
1740: h_errno = TRY_AGAIN;
1741: break;
1742: case NOERROR:
1743: h_errno = NO_DATA;
1744: break;
1745: case FORMERR:
1746: case NOTIMP:
1747: case REFUSED:
1748: default:
1749: h_errno = NO_RECOVERY;
1750: break;
1751: }
1.70 christos 1752: return -1;
1.32 itojun 1753: }
1.70 christos 1754: return ancount;
1.32 itojun 1755: }
1756:
1757: /*
1758: * Formulate a normal query, send, and retrieve answer in supplied buffer.
1759: * Return the size of the response on success, -1 on error.
1760: * If enabled, implement search rules until answer or unrecoverable failure
1761: * is detected. Error code, if any, is left in h_errno.
1762: */
1763: static int
1.73 tsarna 1764: res_searchN(const char *name, struct res_target *target, res_state res)
1.32 itojun 1765: {
1766: const char *cp, * const *domain;
1.51 lukem 1767: HEADER *hp;
1.32 itojun 1768: u_int dots;
1769: int trailing_dot, ret, saved_herrno;
1770: int got_nodata = 0, got_servfail = 0, tried_as_is = 0;
1.71 christos 1771:
1.51 lukem 1772: _DIAGASSERT(name != NULL);
1773: _DIAGASSERT(target != NULL);
1774:
1775: hp = (HEADER *)(void *)target->answer; /*XXX*/
1776:
1.32 itojun 1777: errno = 0;
1778: h_errno = HOST_NOT_FOUND; /* default, if we never query */
1779: dots = 0;
1780: for (cp = name; *cp; cp++)
1781: dots += (*cp == '.');
1782: trailing_dot = 0;
1783: if (cp > name && *--cp == '.')
1784: trailing_dot++;
1785:
1786: /*
1787: * if there aren't any dots, it could be a user-level alias
1788: */
1.70 christos 1789: if (!dots && (cp = __hostalias(name)) != NULL) {
1790: ret = res_queryN(cp, target, res);
1791: return ret;
1792: }
1.32 itojun 1793:
1794: /*
1795: * If there are dots in the name already, let's just give it a try
1796: * 'as is'. The threshold can be set with the "ndots" option.
1797: */
1798: saved_herrno = -1;
1.70 christos 1799: if (dots >= res->ndots) {
1800: ret = res_querydomainN(name, NULL, target, res);
1.73 tsarna 1801: if (ret > 0)
1.32 itojun 1802: return (ret);
1803: saved_herrno = h_errno;
1804: tried_as_is++;
1805: }
1806:
1807: /*
1808: * We do at least one level of search if
1809: * - there is no dot and RES_DEFNAME is set, or
1810: * - there is at least one dot, there is no trailing dot,
1811: * and RES_DNSRCH is set.
1812: */
1.70 christos 1813: if ((!dots && (res->options & RES_DEFNAMES)) ||
1814: (dots && !trailing_dot && (res->options & RES_DNSRCH))) {
1.32 itojun 1815: int done = 0;
1816:
1.70 christos 1817: for (domain = (const char * const *)res->dnsrch;
1.32 itojun 1818: *domain && !done;
1819: domain++) {
1820:
1.70 christos 1821: ret = res_querydomainN(name, *domain, target, res);
1.73 tsarna 1822: if (ret > 0)
1.70 christos 1823: return ret;
1.32 itojun 1824:
1825: /*
1826: * If no server present, give up.
1827: * If name isn't found in this domain,
1828: * keep trying higher domains in the search list
1829: * (if that's enabled).
1830: * On a NO_DATA error, keep trying, otherwise
1831: * a wildcard entry of another type could keep us
1832: * from finding this entry higher in the domain.
1833: * If we get some other error (negative answer or
1834: * server failure), then stop searching up,
1835: * but try the input name below in case it's
1836: * fully-qualified.
1837: */
1838: if (errno == ECONNREFUSED) {
1839: h_errno = TRY_AGAIN;
1.70 christos 1840: return -1;
1.32 itojun 1841: }
1842:
1843: switch (h_errno) {
1844: case NO_DATA:
1845: got_nodata++;
1846: /* FALLTHROUGH */
1847: case HOST_NOT_FOUND:
1848: /* keep trying */
1849: break;
1850: case TRY_AGAIN:
1851: if (hp->rcode == SERVFAIL) {
1852: /* try next search element, if any */
1853: got_servfail++;
1854: break;
1855: }
1856: /* FALLTHROUGH */
1857: default:
1858: /* anything else implies that we're done */
1859: done++;
1860: }
1861: /*
1862: * if we got here for some reason other than DNSRCH,
1863: * we only wanted one iteration of the loop, so stop.
1864: */
1.70 christos 1865: if (!(res->options & RES_DNSRCH))
1.32 itojun 1866: done++;
1867: }
1868: }
1869:
1870: /*
1871: * if we have not already tried the name "as is", do that now.
1872: * note that we do this regardless of how many dots were in the
1873: * name or whether it ends with a dot.
1874: */
1875: if (!tried_as_is) {
1.70 christos 1876: ret = res_querydomainN(name, NULL, target, res);
1.73 tsarna 1877: if (ret > 0)
1.70 christos 1878: return ret;
1.32 itojun 1879: }
1880:
1881: /*
1882: * if we got here, we didn't satisfy the search.
1883: * if we did an initial full query, return that query's h_errno
1884: * (note that we wouldn't be here if that query had succeeded).
1885: * else if we ever got a nodata, send that back as the reason.
1886: * else send back meaningless h_errno, that being the one from
1887: * the last DNSRCH we did.
1888: */
1889: if (saved_herrno != -1)
1890: h_errno = saved_herrno;
1891: else if (got_nodata)
1892: h_errno = NO_DATA;
1893: else if (got_servfail)
1894: h_errno = TRY_AGAIN;
1.70 christos 1895: return -1;
1.32 itojun 1896: }
1897:
1898: /*
1899: * Perform a call on res_query on the concatenation of name and domain,
1900: * removing a trailing dot from name if domain is NULL.
1901: */
1902: static int
1.73 tsarna 1903: res_querydomainN(const char *name, const char *domain,
1.70 christos 1904: struct res_target *target, res_state res)
1.32 itojun 1905: {
1906: char nbuf[MAXDNAME];
1907: const char *longname = nbuf;
1908: size_t n, d;
1.51 lukem 1909:
1910: _DIAGASSERT(name != NULL);
1911: /* XXX: target may be NULL??? */
1.32 itojun 1912:
1913: #ifdef DEBUG
1.70 christos 1914: if (res->options & RES_DEBUG)
1.32 itojun 1915: printf(";; res_querydomain(%s, %s)\n",
1916: name, domain?domain:"<Nil>");
1917: #endif
1918: if (domain == NULL) {
1919: /*
1920: * Check for trailing '.';
1921: * copy without '.' if present.
1922: */
1923: n = strlen(name);
1.63 itojun 1924: if (n + 1 > sizeof(nbuf)) {
1.32 itojun 1925: h_errno = NO_RECOVERY;
1.70 christos 1926: return -1;
1.32 itojun 1927: }
1.40 itojun 1928: if (n > 0 && name[--n] == '.') {
1.32 itojun 1929: strncpy(nbuf, name, n);
1930: nbuf[n] = '\0';
1931: } else
1932: longname = name;
1933: } else {
1934: n = strlen(name);
1935: d = strlen(domain);
1.63 itojun 1936: if (n + 1 + d + 1 > sizeof(nbuf)) {
1.32 itojun 1937: h_errno = NO_RECOVERY;
1.70 christos 1938: return -1;
1.32 itojun 1939: }
1.54 itojun 1940: snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain);
1.32 itojun 1941: }
1.70 christos 1942: return res_queryN(longname, target, res);
1.32 itojun 1943: }
CVSweb <webmaster@jp.NetBSD.org>