res_init.c revision 160965
1/*
2 * Copyright (c) 1985, 1989, 1993
3 *    The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 * 	This product includes software developed by the University of
16 * 	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34/*
35 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
36 *
37 * Permission to use, copy, modify, and distribute this software for any
38 * purpose with or without fee is hereby granted, provided that the above
39 * copyright notice and this permission notice appear in all copies, and that
40 * the name of Digital Equipment Corporation not be used in advertising or
41 * publicity pertaining to distribution of the document or software without
42 * specific, written prior permission.
43 *
44 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
45 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
46 * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
47 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
48 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
49 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
50 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
51 * SOFTWARE.
52 */
53
54/*
55 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
56 * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
57 *
58 * Permission to use, copy, modify, and distribute this software for any
59 * purpose with or without fee is hereby granted, provided that the above
60 * copyright notice and this permission notice appear in all copies.
61 *
62 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
63 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
64 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
65 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
66 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
67 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
68 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
69 */
70
71#if defined(LIBC_SCCS) && !defined(lint)
72static const char sccsid[] = "@(#)res_init.c	8.1 (Berkeley) 6/7/93";
73static const char rcsid[] = "$Id: res_init.c,v 1.9.2.5.4.5 2005/11/03 00:00:52 marka Exp $";
74#endif /* LIBC_SCCS and not lint */
75#include <sys/cdefs.h>
76__FBSDID("$FreeBSD: head/lib/libc/resolv/res_init.c 160965 2006-08-04 10:21:11Z ume $");
77
78#include "port_before.h"
79
80#include "namespace.h"
81
82#include <sys/types.h>
83#include <sys/param.h>
84#include <sys/socket.h>
85#include <sys/time.h>
86
87#include <netinet/in.h>
88#include <arpa/inet.h>
89#include <arpa/nameser.h>
90
91#include <ctype.h>
92#include <stdio.h>
93#include <stdlib.h>
94#include <string.h>
95#include <unistd.h>
96#include <netdb.h>
97
98#include "un-namespace.h"
99
100#include "port_after.h"
101
102/* ensure that sockaddr_in6 and IN6ADDR_ANY_INIT are declared / defined */
103#include <resolv.h>
104
105#include "res_private.h"
106
107/* Options.  Should all be left alone. */
108#define RESOLVSORT
109#define DEBUG
110
111#ifdef SOLARIS2
112#include <sys/systeminfo.h>
113#endif
114
115static void res_setoptions(res_state, const char *, const char *);
116
117#ifdef RESOLVSORT
118static const char sort_mask[] = "/&";
119#define ISSORTMASK(ch) (strchr(sort_mask, ch) != NULL)
120static u_int32_t net_mask(struct in_addr);
121#endif
122
123#if !defined(isascii)	/* XXX - could be a function */
124# define isascii(c) (!(c & 0200))
125#endif
126
127/*
128 * Resolver state default settings.
129 */
130
131/*
132 * Set up default settings.  If the configuration file exist, the values
133 * there will have precedence.  Otherwise, the server address is set to
134 * INADDR_ANY and the default domain name comes from the gethostname().
135 *
136 * An interrim version of this code (BIND 4.9, pre-4.4BSD) used 127.0.0.1
137 * rather than INADDR_ANY ("0.0.0.0") as the default name server address
138 * since it was noted that INADDR_ANY actually meant ``the first interface
139 * you "ifconfig"'d at boot time'' and if this was a SLIP or PPP interface,
140 * it had to be "up" in order for you to reach your own name server.  It
141 * was later decided that since the recommended practice is to always
142 * install local static routes through 127.0.0.1 for all your network
143 * interfaces, that we could solve this problem without a code change.
144 *
145 * The configuration file should always be used, since it is the only way
146 * to specify a default domain.  If you are running a server on your local
147 * machine, you should say "nameserver 0.0.0.0" or "nameserver 127.0.0.1"
148 * in the configuration file.
149 *
150 * Return 0 if completes successfully, -1 on error
151 */
152int
153res_ninit(res_state statp) {
154	extern int __res_vinit(res_state, int);
155
156	return (__res_vinit(statp, 0));
157}
158
159/* This function has to be reachable by res_data.c but not publically. */
160int
161__res_vinit(res_state statp, int preinit) {
162	FILE *fp;
163	char *cp, **pp;
164	int n;
165	char buf[BUFSIZ];
166	int nserv = 0;    /* number of nameserver records read from file */
167	int haveenv = 0;
168	int havesearch = 0;
169#ifdef RESOLVSORT
170	int nsort = 0;
171	char *net;
172#endif
173	int dots;
174	union res_sockaddr_union u[2];
175
176	if (statp->_u._ext.ext != NULL)
177		res_ndestroy(statp);
178
179	if (!preinit) {
180		statp->retrans = RES_TIMEOUT;
181		statp->retry = RES_DFLRETRY;
182		statp->options = RES_DEFAULT;
183		statp->id = res_randomid();
184	}
185
186	memset(u, 0, sizeof(u));
187#ifdef USELOOPBACK
188	u[nserv].sin.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1);
189#else
190	u[nserv].sin.sin_addr.s_addr = INADDR_ANY;
191#endif
192	u[nserv].sin.sin_family = AF_INET;
193	u[nserv].sin.sin_port = htons(NAMESERVER_PORT);
194#ifdef HAVE_SA_LEN
195	u[nserv].sin.sin_len = sizeof(struct sockaddr_in);
196#endif
197	nserv++;
198#ifdef HAS_INET6_STRUCTS
199#ifdef USELOOPBACK
200	u[nserv].sin6.sin6_addr = in6addr_loopback;
201#else
202	u[nserv].sin6.sin6_addr = in6addr_any;
203#endif
204	u[nserv].sin6.sin6_family = AF_INET6;
205	u[nserv].sin6.sin6_port = htons(NAMESERVER_PORT);
206#ifdef HAVE_SA_LEN
207	u[nserv].sin6.sin6_len = sizeof(struct sockaddr_in6);
208#endif
209	nserv++;
210#endif
211	statp->nscount = 0;
212	statp->ndots = 1;
213	statp->pfcode = 0;
214	statp->_vcsock = -1;
215	statp->_flags = 0;
216	statp->qhook = NULL;
217	statp->rhook = NULL;
218	statp->_u._ext.nscount = 0;
219	statp->_u._ext.ext = malloc(sizeof(*statp->_u._ext.ext));
220	if (statp->_u._ext.ext != NULL) {
221	        memset(statp->_u._ext.ext, 0, sizeof(*statp->_u._ext.ext));
222		statp->_u._ext.ext->nsaddrs[0].sin = statp->nsaddr;
223		strcpy(statp->_u._ext.ext->nsuffix, "ip6.arpa");
224		strcpy(statp->_u._ext.ext->nsuffix2, "ip6.int");
225	} else
226		return (-1);
227#ifdef RESOLVSORT
228	statp->nsort = 0;
229#endif
230	res_setservers(statp, u, nserv);
231
232#ifdef	SOLARIS2
233	/*
234	 * The old libresolv derived the defaultdomain from NIS/NIS+.
235	 * We want to keep this behaviour
236	 */
237	{
238		char buf[sizeof(statp->defdname)], *cp;
239		int ret;
240
241		if ((ret = sysinfo(SI_SRPC_DOMAIN, buf, sizeof(buf))) > 0 &&
242			(unsigned int)ret <= sizeof(buf)) {
243			if (buf[0] == '+')
244				buf[0] = '.';
245			cp = strchr(buf, '.');
246			if (cp == NULL) {
247				if (strlcpy(statp->defdname, buf,
248					sizeof(statp->defdname))
249					>= sizeof(statp->defdname))
250					goto freedata;
251			} else {
252				if (strlcpy(statp->defdname, cp+1,
253					sizeof(statp->defdname))
254					 >= sizeof(statp->defdname))
255					goto freedata;
256			}
257		}
258	}
259#endif	/* SOLARIS2 */
260
261	/* Allow user to override the local domain definition */
262	if (issetugid() == 0 && (cp = getenv("LOCALDOMAIN")) != NULL) {
263		(void)strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
264		statp->defdname[sizeof(statp->defdname) - 1] = '\0';
265		haveenv++;
266
267		/*
268		 * Set search list to be blank-separated strings
269		 * from rest of env value.  Permits users of LOCALDOMAIN
270		 * to still have a search list, and anyone to set the
271		 * one that they want to use as an individual (even more
272		 * important now that the rfc1535 stuff restricts searches)
273		 */
274		cp = statp->defdname;
275		pp = statp->dnsrch;
276		*pp++ = cp;
277		for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) {
278			if (*cp == '\n')	/* silly backwards compat */
279				break;
280			else if (*cp == ' ' || *cp == '\t') {
281				*cp = 0;
282				n = 1;
283			} else if (n) {
284				*pp++ = cp;
285				n = 0;
286				havesearch = 1;
287			}
288		}
289		/* null terminate last domain if there are excess */
290		while (*cp != '\0' && *cp != ' ' && *cp != '\t' && *cp != '\n')
291			cp++;
292		*cp = '\0';
293		*pp++ = 0;
294	}
295
296#define	MATCH(line, name) \
297	(!strncmp(line, name, sizeof(name) - 1) && \
298	(line[sizeof(name) - 1] == ' ' || \
299	 line[sizeof(name) - 1] == '\t'))
300
301	nserv = 0;
302	if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) {
303	    /* read the config file */
304	    while (fgets(buf, sizeof(buf), fp) != NULL) {
305		/* skip comments */
306		if (*buf == ';' || *buf == '#')
307			continue;
308		/* read default domain name */
309		if (MATCH(buf, "domain")) {
310		    if (haveenv)	/* skip if have from environ */
311			    continue;
312		    cp = buf + sizeof("domain") - 1;
313		    while (*cp == ' ' || *cp == '\t')
314			    cp++;
315		    if ((*cp == '\0') || (*cp == '\n'))
316			    continue;
317		    strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
318		    statp->defdname[sizeof(statp->defdname) - 1] = '\0';
319		    if ((cp = strpbrk(statp->defdname, " \t\n")) != NULL)
320			    *cp = '\0';
321		    havesearch = 0;
322		    continue;
323		}
324		/* set search list */
325		if (MATCH(buf, "search")) {
326		    if (haveenv)	/* skip if have from environ */
327			    continue;
328		    cp = buf + sizeof("search") - 1;
329		    while (*cp == ' ' || *cp == '\t')
330			    cp++;
331		    if ((*cp == '\0') || (*cp == '\n'))
332			    continue;
333		    strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
334		    statp->defdname[sizeof(statp->defdname) - 1] = '\0';
335		    if ((cp = strchr(statp->defdname, '\n')) != NULL)
336			    *cp = '\0';
337		    /*
338		     * Set search list to be blank-separated strings
339		     * on rest of line.
340		     */
341		    cp = statp->defdname;
342		    pp = statp->dnsrch;
343		    *pp++ = cp;
344		    for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) {
345			    if (*cp == ' ' || *cp == '\t') {
346				    *cp = 0;
347				    n = 1;
348			    } else if (n) {
349				    *pp++ = cp;
350				    n = 0;
351			    }
352		    }
353		    /* null terminate last domain if there are excess */
354		    while (*cp != '\0' && *cp != ' ' && *cp != '\t')
355			    cp++;
356		    *cp = '\0';
357		    *pp++ = 0;
358		    havesearch = 1;
359		    continue;
360		}
361		/* read nameservers to query */
362		if (MATCH(buf, "nameserver") && nserv < MAXNS) {
363		    struct addrinfo hints, *ai;
364		    char sbuf[NI_MAXSERV];
365		    const size_t minsiz =
366		        sizeof(statp->_u._ext.ext->nsaddrs[0]);
367
368		    cp = buf + sizeof("nameserver") - 1;
369		    while (*cp == ' ' || *cp == '\t')
370			cp++;
371		    cp[strcspn(cp, ";# \t\n")] = '\0';
372		    if ((*cp != '\0') && (*cp != '\n')) {
373			memset(&hints, 0, sizeof(hints));
374			hints.ai_family = PF_UNSPEC;
375			hints.ai_socktype = SOCK_DGRAM;	/*dummy*/
376			hints.ai_flags = AI_NUMERICHOST;
377			sprintf(sbuf, "%u", NAMESERVER_PORT);
378			if (getaddrinfo(cp, sbuf, &hints, &ai) == 0 &&
379			    ai->ai_addrlen <= minsiz) {
380			    if (statp->_u._ext.ext != NULL) {
381				memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
382				    ai->ai_addr, ai->ai_addrlen);
383			    }
384			    if (ai->ai_addrlen <=
385			        sizeof(statp->nsaddr_list[nserv])) {
386				memcpy(&statp->nsaddr_list[nserv],
387				    ai->ai_addr, ai->ai_addrlen);
388			    } else
389				statp->nsaddr_list[nserv].sin_family = 0;
390			    freeaddrinfo(ai);
391			    nserv++;
392			}
393		    }
394		    continue;
395		}
396#ifdef RESOLVSORT
397		if (MATCH(buf, "sortlist")) {
398		    struct in_addr a;
399		    struct in6_addr a6;
400		    int m, i;
401		    u_char *u;
402		    struct __res_state_ext *ext = statp->_u._ext.ext;
403
404		    cp = buf + sizeof("sortlist") - 1;
405		    while (nsort < MAXRESOLVSORT) {
406			while (*cp == ' ' || *cp == '\t')
407			    cp++;
408			if (*cp == '\0' || *cp == '\n' || *cp == ';')
409			    break;
410			net = cp;
411			while (*cp && !ISSORTMASK(*cp) && *cp != ';' &&
412			       isascii(*cp) && !isspace((unsigned char)*cp))
413				cp++;
414			n = *cp;
415			*cp = 0;
416			if (inet_aton(net, &a)) {
417			    statp->sort_list[nsort].addr = a;
418			    if (ISSORTMASK(n)) {
419				*cp++ = n;
420				net = cp;
421				while (*cp && *cp != ';' &&
422					isascii(*cp) &&
423					!isspace((unsigned char)*cp))
424				    cp++;
425				n = *cp;
426				*cp = 0;
427				if (inet_aton(net, &a)) {
428				    statp->sort_list[nsort].mask = a.s_addr;
429				} else {
430				    statp->sort_list[nsort].mask =
431					net_mask(statp->sort_list[nsort].addr);
432				}
433			    } else {
434				statp->sort_list[nsort].mask =
435				    net_mask(statp->sort_list[nsort].addr);
436			    }
437			    ext->sort_list[nsort].af = AF_INET;
438			    ext->sort_list[nsort].addr.ina =
439				statp->sort_list[nsort].addr;
440			    ext->sort_list[nsort].mask.ina.s_addr =
441				statp->sort_list[nsort].mask;
442			    nsort++;
443			}
444			else if (inet_pton(AF_INET6, net, &a6) == 1) {
445
446			    ext->sort_list[nsort].af = AF_INET6;
447			    ext->sort_list[nsort].addr.in6a = a6;
448			    u = (u_char *)&ext->sort_list[nsort].mask.in6a;
449			    *cp++ = n;
450			    net = cp;
451			    while (*cp && *cp != ';' &&
452				    isascii(*cp) && !isspace(*cp))
453				cp++;
454			    m = n;
455			    n = *cp;
456			    *cp = 0;
457			    switch (m) {
458			    case '/':
459				m = atoi(net);
460				break;
461			    case '&':
462				if (inet_pton(AF_INET6, net, u) == 1) {
463				    m = -1;
464				    break;
465				}
466				/*FALLTHROUGH*/
467			    default:
468				m = sizeof(struct in6_addr) * CHAR_BIT;
469				break;
470			    }
471			    if (m >= 0) {
472				for (i = 0; i < sizeof(struct in6_addr); i++) {
473				    if (m <= 0) {
474					*u = 0;
475				    } else {
476					m -= CHAR_BIT;
477					*u = (u_char)~0;
478					if (m < 0)
479					    *u <<= -m;
480				    }
481				    u++;
482				}
483			    }
484			    statp->sort_list[nsort].addr.s_addr =
485				(u_int32_t)0xffffffff;
486			    statp->sort_list[nsort].mask =
487				(u_int32_t)0xffffffff;
488			    nsort++;
489			}
490			*cp = n;
491		    }
492		    continue;
493		}
494#endif
495		if (MATCH(buf, "options")) {
496		    res_setoptions(statp, buf + sizeof("options") - 1, "conf");
497		    continue;
498		}
499	    }
500	    if (nserv > 0)
501		statp->nscount = nserv;
502#ifdef RESOLVSORT
503	    statp->nsort = nsort;
504#endif
505	    (void) fclose(fp);
506	}
507/*
508 * Last chance to get a nameserver.  This should not normally
509 * be necessary
510 */
511#ifdef NO_RESOLV_CONF
512	if(nserv == 0)
513		nserv = get_nameservers(statp);
514#endif
515
516	if (statp->defdname[0] == 0 &&
517	    gethostname(buf, sizeof(statp->defdname) - 1) == 0 &&
518	    (cp = strchr(buf, '.')) != NULL)
519		strcpy(statp->defdname, cp + 1);
520
521	/* find components of local domain that might be searched */
522	if (havesearch == 0) {
523		pp = statp->dnsrch;
524		*pp++ = statp->defdname;
525		*pp = NULL;
526
527		dots = 0;
528		for (cp = statp->defdname; *cp; cp++)
529			dots += (*cp == '.');
530
531		cp = statp->defdname;
532		while (pp < statp->dnsrch + MAXDFLSRCH) {
533			if (dots < LOCALDOMAINPARTS)
534				break;
535			cp = strchr(cp, '.') + 1;    /* we know there is one */
536			*pp++ = cp;
537			dots--;
538		}
539		*pp = NULL;
540#ifdef DEBUG
541		if (statp->options & RES_DEBUG) {
542			printf(";; res_init()... default dnsrch list:\n");
543			for (pp = statp->dnsrch; *pp; pp++)
544				printf(";;\t%s\n", *pp);
545			printf(";;\t..END..\n");
546		}
547#endif
548	}
549
550	if (issetugid())
551		statp->options |= RES_NOALIASES;
552	else if ((cp = getenv("RES_OPTIONS")) != NULL)
553		res_setoptions(statp, cp, "env");
554	statp->options |= RES_INIT;
555	return (0);
556
557#ifdef	SOLARIS2
558 freedata:
559	if (statp->_u._ext.ext != NULL) {
560		free(statp->_u._ext.ext);
561		statp->_u._ext.ext = NULL;
562	}
563	return (-1);
564#endif
565}
566
567static void
568res_setoptions(res_state statp, const char *options, const char *source)
569{
570	const char *cp = options;
571	int i;
572#ifndef _LIBC
573	struct __res_state_ext *ext = statp->_u._ext.ext;
574#endif
575
576#ifdef DEBUG
577	if (statp->options & RES_DEBUG)
578		printf(";; res_setoptions(\"%s\", \"%s\")...\n",
579		       options, source);
580#endif
581	while (*cp) {
582		/* skip leading and inner runs of spaces */
583		while (*cp == ' ' || *cp == '\t')
584			cp++;
585		/* search for and process individual options */
586		if (!strncmp(cp, "ndots:", sizeof("ndots:") - 1)) {
587			i = atoi(cp + sizeof("ndots:") - 1);
588			if (i <= RES_MAXNDOTS)
589				statp->ndots = i;
590			else
591				statp->ndots = RES_MAXNDOTS;
592#ifdef DEBUG
593			if (statp->options & RES_DEBUG)
594				printf(";;\tndots=%d\n", statp->ndots);
595#endif
596		} else if (!strncmp(cp, "timeout:", sizeof("timeout:") - 1)) {
597			i = atoi(cp + sizeof("timeout:") - 1);
598			if (i <= RES_MAXRETRANS)
599				statp->retrans = i;
600			else
601				statp->retrans = RES_MAXRETRANS;
602#ifdef DEBUG
603			if (statp->options & RES_DEBUG)
604				printf(";;\ttimeout=%d\n", statp->retrans);
605#endif
606#ifdef	SOLARIS2
607		} else if (!strncmp(cp, "retrans:", sizeof("retrans:") - 1)) {
608			/*
609		 	 * For backward compatibility, 'retrans' is
610		 	 * supported as an alias for 'timeout', though
611		 	 * without an imposed maximum.
612		 	 */
613			statp->retrans = atoi(cp + sizeof("retrans:") - 1);
614		} else if (!strncmp(cp, "retry:", sizeof("retry:") - 1)){
615			/*
616			 * For backward compatibility, 'retry' is
617			 * supported as an alias for 'attempts', though
618			 * without an imposed maximum.
619			 */
620			statp->retry = atoi(cp + sizeof("retry:") - 1);
621#endif	/* SOLARIS2 */
622		} else if (!strncmp(cp, "attempts:", sizeof("attempts:") - 1)){
623			i = atoi(cp + sizeof("attempts:") - 1);
624			if (i <= RES_MAXRETRY)
625				statp->retry = i;
626			else
627				statp->retry = RES_MAXRETRY;
628#ifdef DEBUG
629			if (statp->options & RES_DEBUG)
630				printf(";;\tattempts=%d\n", statp->retry);
631#endif
632		} else if (!strncmp(cp, "debug", sizeof("debug") - 1)) {
633#ifdef DEBUG
634			if (!(statp->options & RES_DEBUG)) {
635				printf(";; res_setoptions(\"%s\", \"%s\")..\n",
636				       options, source);
637				statp->options |= RES_DEBUG;
638			}
639			printf(";;\tdebug\n");
640#endif
641		} else if (!strncmp(cp, "no_tld_query",
642				    sizeof("no_tld_query") - 1) ||
643			   !strncmp(cp, "no-tld-query",
644				    sizeof("no-tld-query") - 1)) {
645			statp->options |= RES_NOTLDQUERY;
646		} else if (!strncmp(cp, "inet6", sizeof("inet6") - 1)) {
647			statp->options |= RES_USE_INET6;
648		} else if (!strncmp(cp, "insecure1", sizeof("insecure1") - 1)) {
649		       statp->options |= RES_INSECURE1;
650		} else if (!strncmp(cp, "insecure2", sizeof("insecure2") - 1)) {
651		       statp->options |= RES_INSECURE2;
652		} else if (!strncmp(cp, "rotate", sizeof("rotate") - 1)) {
653			statp->options |= RES_ROTATE;
654		} else if (!strncmp(cp, "no-check-names",
655				    sizeof("no-check-names") - 1)) {
656			statp->options |= RES_NOCHECKNAME;
657		}
658#ifdef RES_USE_EDNS0
659		else if (!strncmp(cp, "edns0", sizeof("edns0") - 1)) {
660			statp->options |= RES_USE_EDNS0;
661		}
662#endif
663#ifndef _LIBC
664		else if (!strncmp(cp, "dname", sizeof("dname") - 1)) {
665			statp->options |= RES_USE_DNAME;
666		}
667		else if (!strncmp(cp, "nibble:", sizeof("nibble:") - 1)) {
668			if (ext == NULL)
669				goto skip;
670			cp += sizeof("nibble:") - 1;
671			i = MIN(strcspn(cp, " \t"), sizeof(ext->nsuffix) - 1);
672			strncpy(ext->nsuffix, cp, i);
673			ext->nsuffix[i] = '\0';
674		}
675		else if (!strncmp(cp, "nibble2:", sizeof("nibble2:") - 1)) {
676			if (ext == NULL)
677				goto skip;
678			cp += sizeof("nibble2:") - 1;
679			i = MIN(strcspn(cp, " \t"), sizeof(ext->nsuffix2) - 1);
680			strncpy(ext->nsuffix2, cp, i);
681			ext->nsuffix2[i] = '\0';
682		}
683		else if (!strncmp(cp, "v6revmode:", sizeof("v6revmode:") - 1)) {
684			cp += sizeof("v6revmode:") - 1;
685			/* "nibble" and "bitstring" used to be valid */
686			if (!strncmp(cp, "single", sizeof("single") - 1)) {
687				statp->options |= RES_NO_NIBBLE2;
688			} else if (!strncmp(cp, "both", sizeof("both") - 1)) {
689				statp->options &=
690					 ~RES_NO_NIBBLE2;
691			}
692		}
693#endif
694		else {
695			/* XXX - print a warning here? */
696		}
697#ifndef _LIBC
698   skip:
699#endif
700		/* skip to next run of spaces */
701		while (*cp && *cp != ' ' && *cp != '\t')
702			cp++;
703	}
704}
705
706#ifdef RESOLVSORT
707/* XXX - should really support CIDR which means explicit masks always. */
708static u_int32_t
709net_mask(in)		/* XXX - should really use system's version of this */
710	struct in_addr in;
711{
712	u_int32_t i = ntohl(in.s_addr);
713
714	if (IN_CLASSA(i))
715		return (htonl(IN_CLASSA_NET));
716	else if (IN_CLASSB(i))
717		return (htonl(IN_CLASSB_NET));
718	return (htonl(IN_CLASSC_NET));
719}
720#endif
721
722u_int
723res_randomid(void) {
724	struct timeval now;
725
726	gettimeofday(&now, NULL);
727	return (0xffff & (now.tv_sec ^ now.tv_usec ^ getpid()));
728}
729
730/*
731 * This routine is for closing the socket if a virtual circuit is used and
732 * the program wants to close it.  This provides support for endhostent()
733 * which expects to close the socket.
734 *
735 * This routine is not expected to be user visible.
736 */
737void
738res_nclose(res_state statp) {
739	int ns;
740
741	if (statp->_vcsock >= 0) {
742		(void) _close(statp->_vcsock);
743		statp->_vcsock = -1;
744		statp->_flags &= ~(RES_F_VC | RES_F_CONN);
745	}
746	for (ns = 0; ns < statp->_u._ext.nscount; ns++) {
747		if (statp->_u._ext.nssocks[ns] != -1) {
748			(void) _close(statp->_u._ext.nssocks[ns]);
749			statp->_u._ext.nssocks[ns] = -1;
750		}
751	}
752}
753
754void
755res_ndestroy(res_state statp) {
756	res_nclose(statp);
757	if (statp->_u._ext.ext != NULL)
758		free(statp->_u._ext.ext);
759	statp->options &= ~RES_INIT;
760	statp->_u._ext.ext = NULL;
761}
762
763#ifndef _LIBC
764const char *
765res_get_nibblesuffix(res_state statp) {
766	if (statp->_u._ext.ext)
767		return (statp->_u._ext.ext->nsuffix);
768	return ("ip6.arpa");
769}
770
771const char *
772res_get_nibblesuffix2(res_state statp) {
773	if (statp->_u._ext.ext)
774		return (statp->_u._ext.ext->nsuffix2);
775	return ("ip6.int");
776}
777#endif
778
779void
780res_setservers(res_state statp, const union res_sockaddr_union *set, int cnt) {
781	int i, nserv;
782	size_t size;
783
784	/* close open servers */
785	res_nclose(statp);
786
787	/* cause rtt times to be forgotten */
788	statp->_u._ext.nscount = 0;
789
790	nserv = 0;
791	for (i = 0; i < cnt && nserv < MAXNS; i++) {
792		switch (set->sin.sin_family) {
793		case AF_INET:
794			size = sizeof(set->sin);
795			if (statp->_u._ext.ext)
796				memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
797					&set->sin, size);
798			if (size <= sizeof(statp->nsaddr_list[nserv]))
799				memcpy(&statp->nsaddr_list[nserv],
800					&set->sin, size);
801			else
802				statp->nsaddr_list[nserv].sin_family = 0;
803			nserv++;
804			break;
805
806#ifdef HAS_INET6_STRUCTS
807		case AF_INET6:
808			size = sizeof(set->sin6);
809			if (statp->_u._ext.ext)
810				memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
811					&set->sin6, size);
812			if (size <= sizeof(statp->nsaddr_list[nserv]))
813				memcpy(&statp->nsaddr_list[nserv],
814					&set->sin6, size);
815			else
816				statp->nsaddr_list[nserv].sin_family = 0;
817			nserv++;
818			break;
819#endif
820
821		default:
822			break;
823		}
824		set++;
825	}
826	statp->nscount = nserv;
827
828}
829
830int
831res_getservers(res_state statp, union res_sockaddr_union *set, int cnt) {
832	int i;
833	size_t size;
834	u_int16_t family;
835
836	for (i = 0; i < statp->nscount && i < cnt; i++) {
837		if (statp->_u._ext.ext)
838			family = statp->_u._ext.ext->nsaddrs[i].sin.sin_family;
839		else
840			family = statp->nsaddr_list[i].sin_family;
841
842		switch (family) {
843		case AF_INET:
844			size = sizeof(set->sin);
845			if (statp->_u._ext.ext)
846				memcpy(&set->sin,
847				       &statp->_u._ext.ext->nsaddrs[i],
848				       size);
849			else
850				memcpy(&set->sin, &statp->nsaddr_list[i],
851				       size);
852			break;
853
854#ifdef HAS_INET6_STRUCTS
855		case AF_INET6:
856			size = sizeof(set->sin6);
857			if (statp->_u._ext.ext)
858				memcpy(&set->sin6,
859				       &statp->_u._ext.ext->nsaddrs[i],
860				       size);
861			else
862				memcpy(&set->sin6, &statp->nsaddr_list[i],
863				       size);
864			break;
865#endif
866
867		default:
868			set->sin.sin_family = 0;
869			break;
870		}
871		set++;
872	}
873	return (statp->nscount);
874}
875