1122394Sharti/*
2122394Sharti * Copyright (c) 1985, 1989, 1993
3122394Sharti *    The Regents of the University of California.  All rights reserved.
4122394Sharti *
5122394Sharti * Redistribution and use in source and binary forms, with or without
6159063Sharti * modification, are permitted provided that the following conditions
7133211Sharti * are met:
8133211Sharti * 1. Redistributions of source code must retain the above copyright
9133211Sharti *    notice, this list of conditions and the following disclaimer.
10122394Sharti * 2. Redistributions in binary form must reproduce the above copyright
11133211Sharti *    notice, this list of conditions and the following disclaimer in the
12133211Sharti *    documentation and/or other materials provided with the distribution.
13133211Sharti * 4. Neither the name of the University nor the names of its contributors
14133211Sharti *    may be used to endorse or promote products derived from this software
15133211Sharti *    without specific prior written permission.
16133211Sharti *
17122394Sharti * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18122394Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19122394Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20133211Sharti * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21133211Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22133211Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23133211Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24133211Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25133211Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26133211Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27133211Sharti * SUCH DAMAGE.
28133211Sharti */
29133211Sharti
30133211Sharti/*
31133211Sharti * Portions Copyright (c) 1993 by Digital Equipment Corporation.
32122394Sharti *
33159063Sharti * Permission to use, copy, modify, and distribute this software for any
34122394Sharti * purpose with or without fee is hereby granted, provided that the above
35122394Sharti * copyright notice and this permission notice appear in all copies, and that
36122394Sharti * the name of Digital Equipment Corporation not be used in advertising or
37122394Sharti * publicity pertaining to distribution of the document or software without
38122394Sharti * specific, written prior permission.
39159063Sharti *
40133211Sharti * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
41159063Sharti * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
42159063Sharti * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
43122394Sharti * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
44122394Sharti * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
45122394Sharti * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
46122394Sharti * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
47159063Sharti * SOFTWARE.
48122394Sharti */
49159063Sharti
50122394Sharti/*
51159063Sharti * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
52159063Sharti * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
53159063Sharti *
54159063Sharti * Permission to use, copy, modify, and distribute this software for any
55159063Sharti * purpose with or without fee is hereby granted, provided that the above
56159063Sharti * copyright notice and this permission notice appear in all copies.
57159063Sharti *
58159063Sharti * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
59159063Sharti * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
60159063Sharti * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
61159063Sharti * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
62159063Sharti * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
63122394Sharti * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
64122394Sharti * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
65122394Sharti */
66122394Sharti
67142810Sharti#if defined(LIBC_SCCS) && !defined(lint)
68122394Shartistatic const char sccsid[] = "@(#)res_init.c	8.1 (Berkeley) 6/7/93";
69159063Shartistatic const char rcsid[] = "$Id: res_init.c,v 1.16.18.7 2007/07/09 01:52:58 marka Exp $";
70122394Sharti#endif /* LIBC_SCCS and not lint */
71159063Sharti#include <sys/cdefs.h>
72159063Sharti__FBSDID("$FreeBSD$");
73159063Sharti
74159063Sharti#include "port_before.h"
75159063Sharti
76122394Sharti#include "namespace.h"
77122394Sharti
78122394Sharti#include <sys/types.h>
79122394Sharti#include <sys/param.h>
80122394Sharti#include <sys/socket.h>
81122394Sharti#include <sys/time.h>
82122394Sharti
83122394Sharti#include <netinet/in.h>
84122394Sharti#include <arpa/inet.h>
85133429Sharti#include <arpa/nameser.h>
86133211Sharti
87133211Sharti#include <ctype.h>
88122394Sharti#include <stdio.h>
89133211Sharti#include <stdlib.h>
90122394Sharti#include <string.h>
91133211Sharti#include <unistd.h>
92122394Sharti#include <netdb.h>
93122394Sharti
94122394Sharti#include "un-namespace.h"
95122394Sharti
96122394Sharti#include "port_after.h"
97122394Sharti
98122394Sharti/* ensure that sockaddr_in6 and IN6ADDR_ANY_INIT are declared / defined */
99122394Sharti#include <resolv.h>
100122394Sharti
101122394Sharti#include "res_private.h"
102122394Sharti
103122394Sharti/*% Options.  Should all be left alone. */
104122394Sharti#define RESOLVSORT
105122394Sharti#define DEBUG
106122394Sharti
107122394Sharti#ifdef SOLARIS2
108159063Sharti#include <sys/systeminfo.h>
109159063Sharti#endif
110159063Sharti
111122394Shartistatic void res_setoptions(res_state, const char *, const char *);
112159063Sharti
113159063Sharti#ifdef RESOLVSORT
114159063Shartistatic const char sort_mask[] = "/&";
115122394Sharti#define ISSORTMASK(ch) (strchr(sort_mask, ch) != NULL)
116159063Shartistatic u_int32_t net_mask(struct in_addr);
117159063Sharti#endif
118159063Sharti
119122394Sharti#if !defined(isascii)	/*%< XXX - could be a function */
120159063Sharti# define isascii(c) (!(c & 0200))
121159063Sharti#endif
122122394Sharti
123122394Sharti/*
124159063Sharti * Resolver state default settings.
125122394Sharti */
126122394Sharti
127122394Sharti/*%
128122394Sharti * Set up default settings.  If the configuration file exist, the values
129122394Sharti * there will have precedence.  Otherwise, the server address is set to
130122394Sharti * INADDR_ANY and the default domain name comes from the gethostname().
131122394Sharti *
132122394Sharti * An interrim version of this code (BIND 4.9, pre-4.4BSD) used 127.0.0.1
133122394Sharti * rather than INADDR_ANY ("0.0.0.0") as the default name server address
134122394Sharti * since it was noted that INADDR_ANY actually meant ``the first interface
135122394Sharti * you "ifconfig"'d at boot time'' and if this was a SLIP or PPP interface,
136122394Sharti * it had to be "up" in order for you to reach your own name server.  It
137122394Sharti * was later decided that since the recommended practice is to always
138122394Sharti * install local static routes through 127.0.0.1 for all your network
139122394Sharti * interfaces, that we could solve this problem without a code change.
140122394Sharti *
141122394Sharti * The configuration file should always be used, since it is the only way
142122394Sharti * to specify a default domain.  If you are running a server on your local
143122394Sharti * machine, you should say "nameserver 0.0.0.0" or "nameserver 127.0.0.1"
144122394Sharti * in the configuration file.
145122394Sharti *
146122394Sharti * Return 0 if completes successfully, -1 on error
147122394Sharti */
148122394Shartiint
149122394Shartires_ninit(res_state statp) {
150122394Sharti	extern int __res_vinit(res_state, int);
151122394Sharti
152122394Sharti	return (__res_vinit(statp, 0));
153122394Sharti}
154122394Sharti
155122394Sharti/*% This function has to be reachable by res_data.c but not publically. */
156122394Shartiint
157122394Sharti__res_vinit(res_state statp, int preinit) {
158122394Sharti	FILE *fp;
159133211Sharti	char *cp, **pp;
160122394Sharti	int n;
161122394Sharti	char buf[BUFSIZ];
162122394Sharti	int nserv = 0;    /*%< number of nameserver records read from file */
163122394Sharti	int haveenv = 0;
164122394Sharti	int havesearch = 0;
165122394Sharti#ifdef RESOLVSORT
166122394Sharti	int nsort = 0;
167122394Sharti	char *net;
168122394Sharti#endif
169122394Sharti	int dots;
170122394Sharti	union res_sockaddr_union u[2];
171122394Sharti	int maxns = MAXNS;
172122394Sharti
173122394Sharti	RES_SET_H_ERRNO(statp, 0);
174122394Sharti	if (statp->_u._ext.ext != NULL)
175122394Sharti		res_ndestroy(statp);
176122394Sharti
177122394Sharti	if (!preinit) {
178122394Sharti		statp->retrans = RES_TIMEOUT;
179122394Sharti		statp->retry = RES_DFLRETRY;
180122394Sharti		statp->options = RES_DEFAULT;
181122394Sharti		statp->id = res_randomid();
182159063Sharti	}
183159063Sharti
184159063Sharti	memset(u, 0, sizeof(u));
185159063Sharti#ifdef USELOOPBACK
186159063Sharti	u[nserv].sin.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1);
187159063Sharti#else
188159063Sharti	u[nserv].sin.sin_addr.s_addr = INADDR_ANY;
189159063Sharti#endif
190159063Sharti	u[nserv].sin.sin_family = AF_INET;
191159063Sharti	u[nserv].sin.sin_port = htons(NAMESERVER_PORT);
192159063Sharti#ifdef HAVE_SA_LEN
193159063Sharti	u[nserv].sin.sin_len = sizeof(struct sockaddr_in);
194159063Sharti#endif
195159063Sharti	nserv++;
196159063Sharti#ifdef HAS_INET6_STRUCTS
197159063Sharti#ifdef USELOOPBACK
198159063Sharti	u[nserv].sin6.sin6_addr = in6addr_loopback;
199159063Sharti#else
200159063Sharti	u[nserv].sin6.sin6_addr = in6addr_any;
201159063Sharti#endif
202159063Sharti	u[nserv].sin6.sin6_family = AF_INET6;
203159063Sharti	u[nserv].sin6.sin6_port = htons(NAMESERVER_PORT);
204159063Sharti#ifdef HAVE_SA_LEN
205122394Sharti	u[nserv].sin6.sin6_len = sizeof(struct sockaddr_in6);
206122394Sharti#endif
207122394Sharti	nserv++;
208122394Sharti#endif
209122394Sharti	statp->nscount = 0;
210122394Sharti	statp->ndots = 1;
211122394Sharti	statp->pfcode = 0;
212122394Sharti	statp->_vcsock = -1;
213122394Sharti	statp->_flags = 0;
214122394Sharti	statp->qhook = NULL;
215145557Sharti	statp->rhook = NULL;
216122394Sharti	statp->_u._ext.nscount = 0;
217122394Sharti	statp->_u._ext.ext = malloc(sizeof(*statp->_u._ext.ext));
218122394Sharti	if (statp->_u._ext.ext != NULL) {
219122394Sharti	        memset(statp->_u._ext.ext, 0, sizeof(*statp->_u._ext.ext));
220159063Sharti		statp->_u._ext.ext->nsaddrs[0].sin = statp->nsaddr;
221159063Sharti		strcpy(statp->_u._ext.ext->nsuffix, "ip6.arpa");
222159063Sharti		strcpy(statp->_u._ext.ext->nsuffix2, "ip6.int");
223159063Sharti	} else {
224159063Sharti		/*
225159063Sharti		 * Historically res_init() rarely, if at all, failed.
226159063Sharti		 * Examples and applications exist which do not check
227159063Sharti		 * our return code.  Furthermore several applications
228159063Sharti		 * simply call us to get the systems domainname.  So
229122394Sharti		 * rather then immediately fail here we store the
230122394Sharti		 * failure, which is returned later, in h_errno.  And
231159063Sharti		 * prevent the collection of 'nameserver' information
232159063Sharti		 * by setting maxns to 0.  Thus applications that fail
233159063Sharti		 * to check our return code wont be able to make
234159063Sharti		 * queries anyhow.
235159063Sharti		 */
236159063Sharti		RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
237159063Sharti		maxns = 0;
238159063Sharti	}
239159063Sharti#ifdef RESOLVSORT
240159063Sharti	statp->nsort = 0;
241159063Sharti#endif
242159063Sharti	res_setservers(statp, u, nserv);
243159063Sharti
244159063Sharti#ifdef	SOLARIS2
245159063Sharti	/*
246159063Sharti	 * The old libresolv derived the defaultdomain from NIS/NIS+.
247159063Sharti	 * We want to keep this behaviour
248159063Sharti	 */
249159063Sharti	{
250159063Sharti		char buf[sizeof(statp->defdname)], *cp;
251159063Sharti		int ret;
252159063Sharti
253159063Sharti		if ((ret = sysinfo(SI_SRPC_DOMAIN, buf, sizeof(buf))) > 0 &&
254159063Sharti			(unsigned int)ret <= sizeof(buf)) {
255159063Sharti			if (buf[0] == '+')
256159063Sharti				buf[0] = '.';
257159063Sharti			cp = strchr(buf, '.');
258159063Sharti			cp = (cp == NULL) ? buf : (cp + 1);
259159063Sharti			strncpy(statp->defdname, cp,
260159063Sharti				sizeof(statp->defdname) - 1);
261159063Sharti			statp->defdname[sizeof(statp->defdname) - 1] = '\0';
262159063Sharti		}
263159063Sharti	}
264159063Sharti#endif	/* SOLARIS2 */
265159063Sharti
266159063Sharti	/* Allow user to override the local domain definition */
267159063Sharti	if (issetugid() == 0 && (cp = getenv("LOCALDOMAIN")) != NULL) {
268159063Sharti		(void)strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
269159063Sharti		statp->defdname[sizeof(statp->defdname) - 1] = '\0';
270159063Sharti		haveenv++;
271159063Sharti
272159063Sharti		/*
273159063Sharti		 * Set search list to be blank-separated strings
274159063Sharti		 * from rest of env value.  Permits users of LOCALDOMAIN
275159063Sharti		 * to still have a search list, and anyone to set the
276159063Sharti		 * one that they want to use as an individual (even more
277159063Sharti		 * important now that the rfc1535 stuff restricts searches)
278159063Sharti		 */
279159063Sharti		cp = statp->defdname;
280159063Sharti		pp = statp->dnsrch;
281159063Sharti		*pp++ = cp;
282159063Sharti		for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) {
283159063Sharti			if (*cp == '\n')	/*%< silly backwards compat */
284159063Sharti				break;
285159063Sharti			else if (*cp == ' ' || *cp == '\t') {
286159063Sharti				*cp = 0;
287159063Sharti				n = 1;
288159063Sharti			} else if (n) {
289159063Sharti				*pp++ = cp;
290159063Sharti				n = 0;
291159063Sharti				havesearch = 1;
292159063Sharti			}
293159063Sharti		}
294159063Sharti		/* null terminate last domain if there are excess */
295159063Sharti		while (*cp != '\0' && *cp != ' ' && *cp != '\t' && *cp != '\n')
296159063Sharti			cp++;
297159063Sharti		*cp = '\0';
298159063Sharti		*pp++ = 0;
299159063Sharti	}
300159063Sharti
301159063Sharti#define	MATCH(line, name) \
302159063Sharti	(!strncmp(line, name, sizeof(name) - 1) && \
303159063Sharti	(line[sizeof(name) - 1] == ' ' || \
304159063Sharti	 line[sizeof(name) - 1] == '\t'))
305159063Sharti
306159063Sharti	nserv = 0;
307159063Sharti	if ((fp = fopen(_PATH_RESCONF, "re")) != NULL) {
308159063Sharti	    /* read the config file */
309159063Sharti	    while (fgets(buf, sizeof(buf), fp) != NULL) {
310159063Sharti		/* skip comments */
311159063Sharti		if (*buf == ';' || *buf == '#')
312159063Sharti			continue;
313159063Sharti		/* read default domain name */
314159063Sharti		if (MATCH(buf, "domain")) {
315159063Sharti		    if (haveenv)	/*%< skip if have from environ */
316159063Sharti			    continue;
317159063Sharti		    cp = buf + sizeof("domain") - 1;
318159063Sharti		    while (*cp == ' ' || *cp == '\t')
319159063Sharti			    cp++;
320159063Sharti		    if ((*cp == '\0') || (*cp == '\n'))
321159063Sharti			    continue;
322159063Sharti		    strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
323159063Sharti		    statp->defdname[sizeof(statp->defdname) - 1] = '\0';
324159063Sharti		    if ((cp = strpbrk(statp->defdname, " \t\n")) != NULL)
325159063Sharti			    *cp = '\0';
326159063Sharti		    havesearch = 0;
327159063Sharti		    continue;
328159063Sharti		}
329159063Sharti		/* set search list */
330159063Sharti		if (MATCH(buf, "search")) {
331159063Sharti		    if (haveenv)	/*%< skip if have from environ */
332159063Sharti			    continue;
333159063Sharti		    cp = buf + sizeof("search") - 1;
334159063Sharti		    while (*cp == ' ' || *cp == '\t')
335159063Sharti			    cp++;
336159063Sharti		    if ((*cp == '\0') || (*cp == '\n'))
337159063Sharti			    continue;
338159063Sharti		    strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
339159063Sharti		    statp->defdname[sizeof(statp->defdname) - 1] = '\0';
340159063Sharti		    if ((cp = strchr(statp->defdname, '\n')) != NULL)
341159063Sharti			    *cp = '\0';
342159063Sharti		    /*
343159063Sharti		     * Set search list to be blank-separated strings
344159063Sharti		     * on rest of line.
345159063Sharti		     */
346159063Sharti		    cp = statp->defdname;
347159063Sharti		    pp = statp->dnsrch;
348159063Sharti		    *pp++ = cp;
349159063Sharti		    for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) {
350159063Sharti			    if (*cp == ' ' || *cp == '\t') {
351159063Sharti				    *cp = 0;
352159063Sharti				    n = 1;
353159063Sharti			    } else if (n) {
354159063Sharti				    *pp++ = cp;
355159063Sharti				    n = 0;
356159063Sharti			    }
357159063Sharti		    }
358159063Sharti		    /* null terminate last domain if there are excess */
359159063Sharti		    while (*cp != '\0' && *cp != ' ' && *cp != '\t')
360159063Sharti			    cp++;
361159063Sharti		    *cp = '\0';
362159063Sharti		    *pp++ = 0;
363159063Sharti		    havesearch = 1;
364159063Sharti		    continue;
365159063Sharti		}
366159063Sharti		/* read nameservers to query */
367159063Sharti		if (MATCH(buf, "nameserver") && nserv < maxns) {
368159063Sharti		    struct addrinfo hints, *ai;
369159063Sharti		    char sbuf[NI_MAXSERV];
370159063Sharti		    const size_t minsiz =
371159063Sharti		        sizeof(statp->_u._ext.ext->nsaddrs[0]);
372159063Sharti
373159063Sharti		    cp = buf + sizeof("nameserver") - 1;
374159063Sharti		    while (*cp == ' ' || *cp == '\t')
375159063Sharti			cp++;
376159063Sharti		    cp[strcspn(cp, ";# \t\n")] = '\0';
377159063Sharti		    if ((*cp != '\0') && (*cp != '\n')) {
378159063Sharti			memset(&hints, 0, sizeof(hints));
379159063Sharti			hints.ai_family = PF_UNSPEC;
380122394Sharti			hints.ai_socktype = SOCK_DGRAM;	/*dummy*/
381122394Sharti			hints.ai_flags = AI_NUMERICHOST;
382122394Sharti			sprintf(sbuf, "%u", NAMESERVER_PORT);
383122394Sharti			if (getaddrinfo(cp, sbuf, &hints, &ai) == 0 &&
384122394Sharti			    ai->ai_addrlen <= minsiz) {
385122394Sharti			    if (statp->_u._ext.ext != NULL) {
386122394Sharti				memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
387122394Sharti				    ai->ai_addr, ai->ai_addrlen);
388159063Sharti			    }
389159063Sharti			    if (ai->ai_addrlen <=
390159063Sharti			        sizeof(statp->nsaddr_list[nserv])) {
391159063Sharti				memcpy(&statp->nsaddr_list[nserv],
392159063Sharti				    ai->ai_addr, ai->ai_addrlen);
393159063Sharti			    } else
394122394Sharti				statp->nsaddr_list[nserv].sin_family = 0;
395122394Sharti			    freeaddrinfo(ai);
396122394Sharti			    nserv++;
397122394Sharti			}
398122394Sharti		    }
399122394Sharti		    continue;
400122394Sharti		}
401122394Sharti#ifdef RESOLVSORT
402122394Sharti		if (MATCH(buf, "sortlist")) {
403122394Sharti		    struct in_addr a;
404122394Sharti		    struct in6_addr a6;
405122394Sharti		    int m, i;
406122394Sharti		    u_char *u;
407122394Sharti		    struct __res_state_ext *ext = statp->_u._ext.ext;
408122394Sharti
409122394Sharti		    cp = buf + sizeof("sortlist") - 1;
410122394Sharti		    while (nsort < MAXRESOLVSORT) {
411122394Sharti			while (*cp == ' ' || *cp == '\t')
412122394Sharti			    cp++;
413122394Sharti			if (*cp == '\0' || *cp == '\n' || *cp == ';')
414159063Sharti			    break;
415159063Sharti			net = cp;
416159063Sharti			while (*cp && !ISSORTMASK(*cp) && *cp != ';' &&
417159063Sharti			       isascii(*cp) && !isspace((unsigned char)*cp))
418122394Sharti				cp++;
419122394Sharti			n = *cp;
420122394Sharti			*cp = 0;
421122394Sharti			if (inet_aton(net, &a)) {
422122394Sharti			    statp->sort_list[nsort].addr = a;
423122394Sharti			    if (ISSORTMASK(n)) {
424122394Sharti				*cp++ = n;
425133211Sharti				net = cp;
426159063Sharti				while (*cp && *cp != ';' &&
427122394Sharti					isascii(*cp) &&
428122394Sharti					!isspace((unsigned char)*cp))
429122394Sharti				    cp++;
430122394Sharti				n = *cp;
431122394Sharti				*cp = 0;
432122394Sharti				if (inet_aton(net, &a)) {
433122394Sharti				    statp->sort_list[nsort].mask = a.s_addr;
434122394Sharti				} else {
435122394Sharti				    statp->sort_list[nsort].mask =
436122394Sharti					net_mask(statp->sort_list[nsort].addr);
437122394Sharti				}
438159063Sharti			    } else {
439122394Sharti				statp->sort_list[nsort].mask =
440122394Sharti				    net_mask(statp->sort_list[nsort].addr);
441122394Sharti			    }
442159063Sharti			    ext->sort_list[nsort].af = AF_INET;
443122394Sharti			    ext->sort_list[nsort].addr.ina =
444122394Sharti				statp->sort_list[nsort].addr;
445122394Sharti			    ext->sort_list[nsort].mask.ina.s_addr =
446122394Sharti				statp->sort_list[nsort].mask;
447122394Sharti			    nsort++;
448122394Sharti			}
449122394Sharti			else if (inet_pton(AF_INET6, net, &a6) == 1) {
450122394Sharti
451122394Sharti			    ext->sort_list[nsort].af = AF_INET6;
452122394Sharti			    ext->sort_list[nsort].addr.in6a = a6;
453122394Sharti			    u = (u_char *)&ext->sort_list[nsort].mask.in6a;
454122394Sharti			    *cp++ = n;
455122394Sharti			    net = cp;
456122394Sharti			    while (*cp && *cp != ';' &&
457122394Sharti				    isascii(*cp) && !isspace(*cp))
458122394Sharti				cp++;
459122394Sharti			    m = n;
460122394Sharti			    n = *cp;
461122394Sharti			    *cp = 0;
462122394Sharti			    switch (m) {
463122394Sharti			    case '/':
464122394Sharti				m = atoi(net);
465122394Sharti				break;
466122394Sharti			    case '&':
467159063Sharti				if (inet_pton(AF_INET6, net, u) == 1) {
468122394Sharti				    m = -1;
469122394Sharti				    break;
470122394Sharti				}
471122394Sharti				/*FALLTHROUGH*/
472122394Sharti			    default:
473122394Sharti				m = sizeof(struct in6_addr) * CHAR_BIT;
474159063Sharti				break;
475122394Sharti			    }
476122394Sharti			    if (m >= 0) {
477159063Sharti				for (i = 0; i < sizeof(struct in6_addr); i++) {
478122394Sharti				    if (m <= 0) {
479159063Sharti					*u = 0;
480159063Sharti				    } else {
481159063Sharti					m -= CHAR_BIT;
482159063Sharti					*u = (u_char)~0;
483159063Sharti					if (m < 0)
484159063Sharti					    *u <<= -m;
485122394Sharti				    }
486122394Sharti				    u++;
487122394Sharti				}
488122394Sharti			    }
489159063Sharti			    statp->sort_list[nsort].addr.s_addr =
490122394Sharti				(u_int32_t)0xffffffff;
491159063Sharti			    statp->sort_list[nsort].mask =
492122394Sharti				(u_int32_t)0xffffffff;
493122394Sharti			    nsort++;
494122394Sharti			}
495122394Sharti			*cp = n;
496122394Sharti		    }
497122394Sharti		    continue;
498122394Sharti		}
499122394Sharti#endif
500122394Sharti		if (MATCH(buf, "options")) {
501122394Sharti		    res_setoptions(statp, buf + sizeof("options") - 1, "conf");
502122394Sharti		    continue;
503122394Sharti		}
504159063Sharti	    }
505122394Sharti	    if (nserv > 0)
506159063Sharti		statp->nscount = nserv;
507122394Sharti#ifdef RESOLVSORT
508122394Sharti	    statp->nsort = nsort;
509122394Sharti#endif
510122394Sharti	    (void) fclose(fp);
511122394Sharti	}
512122394Sharti/*
513122394Sharti * Last chance to get a nameserver.  This should not normally
514122394Sharti * be necessary
515122394Sharti */
516159063Sharti#ifdef NO_RESOLV_CONF
517122394Sharti	if(nserv == 0)
518122394Sharti		nserv = get_nameservers(statp);
519159063Sharti#endif
520159063Sharti
521159063Sharti	if (statp->defdname[0] == 0 &&
522159063Sharti	    gethostname(buf, sizeof(statp->defdname) - 1) == 0 &&
523159063Sharti	    (cp = strchr(buf, '.')) != NULL)
524159063Sharti		strcpy(statp->defdname, cp + 1);
525159063Sharti
526159063Sharti	/* find components of local domain that might be searched */
527159063Sharti	if (havesearch == 0) {
528159063Sharti		pp = statp->dnsrch;
529159063Sharti		*pp++ = statp->defdname;
530159063Sharti		*pp = NULL;
531159063Sharti
532159063Sharti		dots = 0;
533159063Sharti		for (cp = statp->defdname; *cp; cp++)
534159063Sharti			dots += (*cp == '.');
535159063Sharti
536159063Sharti		cp = statp->defdname;
537159063Sharti		while (pp < statp->dnsrch + MAXDFLSRCH) {
538159063Sharti			if (dots < LOCALDOMAINPARTS)
539159063Sharti				break;
540159063Sharti			cp = strchr(cp, '.') + 1;    /*%< we know there is one */
541159063Sharti			*pp++ = cp;
542122394Sharti			dots--;
543122394Sharti		}
544122394Sharti		*pp = NULL;
545122394Sharti#ifdef DEBUG
546159063Sharti		if (statp->options & RES_DEBUG) {
547159063Sharti			printf(";; res_init()... default dnsrch list:\n");
548159063Sharti			for (pp = statp->dnsrch; *pp; pp++)
549159063Sharti				printf(";;\t%s\n", *pp);
550159063Sharti			printf(";;\t..END..\n");
551159063Sharti		}
552159063Sharti#endif
553159063Sharti	}
554159063Sharti
555159063Sharti	if (issetugid())
556159063Sharti		statp->options |= RES_NOALIASES;
557159063Sharti	else if ((cp = getenv("RES_OPTIONS")) != NULL)
558159063Sharti		res_setoptions(statp, cp, "env");
559159063Sharti	statp->options |= RES_INIT;
560159063Sharti	return (statp->res_h_errno);
561122394Sharti}
562122394Sharti
563122394Shartistatic void
564122394Shartires_setoptions(res_state statp, const char *options, const char *source)
565122394Sharti{
566122394Sharti	const char *cp = options;
567122394Sharti	int i;
568122394Sharti#ifndef _LIBC
569122394Sharti	struct __res_state_ext *ext = statp->_u._ext.ext;
570159063Sharti#endif
571159063Sharti
572159063Sharti#ifdef DEBUG
573122394Sharti	if (statp->options & RES_DEBUG)
574122394Sharti		printf(";; res_setoptions(\"%s\", \"%s\")...\n",
575122394Sharti		       options, source);
576122394Sharti#endif
577122394Sharti	while (*cp) {
578122394Sharti		/* skip leading and inner runs of spaces */
579122394Sharti		while (*cp == ' ' || *cp == '\t')
580122394Sharti			cp++;
581122394Sharti		/* search for and process individual options */
582122394Sharti		if (!strncmp(cp, "ndots:", sizeof("ndots:") - 1)) {
583122394Sharti			i = atoi(cp + sizeof("ndots:") - 1);
584122394Sharti			if (i <= RES_MAXNDOTS)
585122394Sharti				statp->ndots = i;
586122394Sharti			else
587122394Sharti				statp->ndots = RES_MAXNDOTS;
588122394Sharti#ifdef DEBUG
589122394Sharti			if (statp->options & RES_DEBUG)
590122394Sharti				printf(";;\tndots=%d\n", statp->ndots);
591122394Sharti#endif
592159063Sharti		} else if (!strncmp(cp, "timeout:", sizeof("timeout:") - 1)) {
593159063Sharti			i = atoi(cp + sizeof("timeout:") - 1);
594159063Sharti			if (i <= RES_MAXRETRANS)
595159063Sharti				statp->retrans = i;
596159063Sharti			else
597159063Sharti				statp->retrans = RES_MAXRETRANS;
598122394Sharti#ifdef DEBUG
599122394Sharti			if (statp->options & RES_DEBUG)
600122394Sharti				printf(";;\ttimeout=%d\n", statp->retrans);
601159063Sharti#endif
602122394Sharti#ifdef	SOLARIS2
603159063Sharti		} else if (!strncmp(cp, "retrans:", sizeof("retrans:") - 1)) {
604159063Sharti			/*
605122394Sharti		 	 * For backward compatibility, 'retrans' is
606159063Sharti		 	 * supported as an alias for 'timeout', though
607159063Sharti		 	 * without an imposed maximum.
608159063Sharti		 	 */
609159063Sharti			statp->retrans = atoi(cp + sizeof("retrans:") - 1);
610122394Sharti		} else if (!strncmp(cp, "retry:", sizeof("retry:") - 1)){
611159063Sharti			/*
612159063Sharti			 * For backward compatibility, 'retry' is
613159063Sharti			 * supported as an alias for 'attempts', though
614159063Sharti			 * without an imposed maximum.
615159063Sharti			 */
616159063Sharti			statp->retry = atoi(cp + sizeof("retry:") - 1);
617159063Sharti#endif	/* SOLARIS2 */
618159063Sharti		} else if (!strncmp(cp, "attempts:", sizeof("attempts:") - 1)){
619159063Sharti			i = atoi(cp + sizeof("attempts:") - 1);
620159063Sharti			if (i <= RES_MAXRETRY)
621159063Sharti				statp->retry = i;
622159063Sharti			else
623159063Sharti				statp->retry = RES_MAXRETRY;
624159063Sharti#ifdef DEBUG
625159063Sharti			if (statp->options & RES_DEBUG)
626159063Sharti				printf(";;\tattempts=%d\n", statp->retry);
627159063Sharti#endif
628159063Sharti		} else if (!strncmp(cp, "debug", sizeof("debug") - 1)) {
629159063Sharti#ifdef DEBUG
630159063Sharti			if (!(statp->options & RES_DEBUG)) {
631159063Sharti				printf(";; res_setoptions(\"%s\", \"%s\")..\n",
632159063Sharti				       options, source);
633159063Sharti				statp->options |= RES_DEBUG;
634159063Sharti			}
635159063Sharti			printf(";;\tdebug\n");
636159063Sharti#endif
637159063Sharti		} else if (!strncmp(cp, "no_tld_query",
638159063Sharti				    sizeof("no_tld_query") - 1) ||
639159063Sharti			   !strncmp(cp, "no-tld-query",
640159063Sharti				    sizeof("no-tld-query") - 1)) {
641159063Sharti			statp->options |= RES_NOTLDQUERY;
642159063Sharti		} else if (!strncmp(cp, "inet6", sizeof("inet6") - 1)) {
643159063Sharti			statp->options |= RES_USE_INET6;
644159063Sharti		} else if (!strncmp(cp, "insecure1", sizeof("insecure1") - 1)) {
645159063Sharti		       statp->options |= RES_INSECURE1;
646159063Sharti		} else if (!strncmp(cp, "insecure2", sizeof("insecure2") - 1)) {
647159063Sharti		       statp->options |= RES_INSECURE2;
648159063Sharti		} else if (!strncmp(cp, "rotate", sizeof("rotate") - 1)) {
649159063Sharti			statp->options |= RES_ROTATE;
650159063Sharti		} else if (!strncmp(cp, "no-check-names",
651159063Sharti				    sizeof("no-check-names") - 1)) {
652159063Sharti			statp->options |= RES_NOCHECKNAME;
653159063Sharti		}
654159063Sharti#ifdef RES_USE_EDNS0
655159063Sharti		else if (!strncmp(cp, "edns0", sizeof("edns0") - 1)) {
656159063Sharti			statp->options |= RES_USE_EDNS0;
657159063Sharti		}
658159063Sharti#endif
659159063Sharti#ifndef _LIBC
660159063Sharti		else if (!strncmp(cp, "dname", sizeof("dname") - 1)) {
661159063Sharti			statp->options |= RES_USE_DNAME;
662159063Sharti		}
663159063Sharti		else if (!strncmp(cp, "nibble:", sizeof("nibble:") - 1)) {
664159063Sharti			if (ext == NULL)
665159063Sharti				goto skip;
666159063Sharti			cp += sizeof("nibble:") - 1;
667159063Sharti			i = MIN(strcspn(cp, " \t"), sizeof(ext->nsuffix) - 1);
668159063Sharti			strncpy(ext->nsuffix, cp, i);
669159063Sharti			ext->nsuffix[i] = '\0';
670159063Sharti		}
671159063Sharti		else if (!strncmp(cp, "nibble2:", sizeof("nibble2:") - 1)) {
672159063Sharti			if (ext == NULL)
673159063Sharti				goto skip;
674159063Sharti			cp += sizeof("nibble2:") - 1;
675159063Sharti			i = MIN(strcspn(cp, " \t"), sizeof(ext->nsuffix2) - 1);
676159063Sharti			strncpy(ext->nsuffix2, cp, i);
677159063Sharti			ext->nsuffix2[i] = '\0';
678159063Sharti		}
679159063Sharti		else if (!strncmp(cp, "v6revmode:", sizeof("v6revmode:") - 1)) {
680159063Sharti			cp += sizeof("v6revmode:") - 1;
681159063Sharti			/* "nibble" and "bitstring" used to be valid */
682159063Sharti			if (!strncmp(cp, "single", sizeof("single") - 1)) {
683159063Sharti				statp->options |= RES_NO_NIBBLE2;
684159063Sharti			} else if (!strncmp(cp, "both", sizeof("both") - 1)) {
685159063Sharti				statp->options &=
686122394Sharti					 ~RES_NO_NIBBLE2;
687159063Sharti			}
688159063Sharti		}
689159063Sharti#endif
690159063Sharti		else {
691159063Sharti			/* XXX - print a warning here? */
692159063Sharti		}
693159063Sharti#ifndef _LIBC
694159063Sharti   skip:
695159063Sharti#endif
696159063Sharti		/* skip to next run of spaces */
697159063Sharti		while (*cp && *cp != ' ' && *cp != '\t')
698159063Sharti			cp++;
699159063Sharti	}
700159063Sharti}
701159063Sharti
702159063Sharti#ifdef RESOLVSORT
703159063Sharti/* XXX - should really support CIDR which means explicit masks always. */
704159063Shartistatic u_int32_t
705159063Shartinet_mask(in)		/*!< XXX - should really use system's version of this  */
706159063Sharti	struct in_addr in;
707159063Sharti{
708159063Sharti	u_int32_t i = ntohl(in.s_addr);
709159063Sharti
710159063Sharti	if (IN_CLASSA(i))
711159063Sharti		return (htonl(IN_CLASSA_NET));
712159063Sharti	else if (IN_CLASSB(i))
713159063Sharti		return (htonl(IN_CLASSB_NET));
714159063Sharti	return (htonl(IN_CLASSC_NET));
715159063Sharti}
716159063Sharti#endif
717159063Sharti
718159063Shartiu_int
719159063Shartires_randomid(void) {
720159063Sharti	struct timeval now;
721159063Sharti
722159063Sharti	gettimeofday(&now, NULL);
723159063Sharti	return (0xffff & (now.tv_sec ^ now.tv_usec ^ getpid()));
724159063Sharti}
725159063Sharti
726159063Sharti/*%
727159063Sharti * This routine is for closing the socket if a virtual circuit is used and
728159063Sharti * the program wants to close it.  This provides support for endhostent()
729159063Sharti * which expects to close the socket.
730159063Sharti *
731159063Sharti * This routine is not expected to be user visible.
732159063Sharti */
733159063Shartivoid
734159063Shartires_nclose(res_state statp) {
735159063Sharti	int ns;
736159063Sharti
737159063Sharti	if (statp->_vcsock >= 0) {
738159063Sharti		(void) _close(statp->_vcsock);
739159063Sharti		statp->_vcsock = -1;
740159063Sharti		statp->_flags &= ~(RES_F_VC | RES_F_CONN);
741159063Sharti	}
742159063Sharti	for (ns = 0; ns < statp->_u._ext.nscount; ns++) {
743159063Sharti		if (statp->_u._ext.nssocks[ns] != -1) {
744159063Sharti			(void) _close(statp->_u._ext.nssocks[ns]);
745159063Sharti			statp->_u._ext.nssocks[ns] = -1;
746298450Sngie		}
747298450Sngie	}
748159063Sharti}
749159063Sharti
750159063Shartivoid
751159063Shartires_ndestroy(res_state statp) {
752159063Sharti	res_nclose(statp);
753159063Sharti	if (statp->_u._ext.ext != NULL)
754159063Sharti		free(statp->_u._ext.ext);
755159063Sharti	statp->options &= ~RES_INIT;
756159063Sharti	statp->_u._ext.ext = NULL;
757159063Sharti}
758159063Sharti
759159063Sharti#ifndef _LIBC
760159063Sharticonst char *
761159063Shartires_get_nibblesuffix(res_state statp) {
762159063Sharti	if (statp->_u._ext.ext)
763159063Sharti		return (statp->_u._ext.ext->nsuffix);
764159063Sharti	return ("ip6.arpa");
765159063Sharti}
766159063Sharti
767159063Sharticonst char *
768122394Shartires_get_nibblesuffix2(res_state statp) {
769122394Sharti	if (statp->_u._ext.ext)
770122394Sharti		return (statp->_u._ext.ext->nsuffix2);
771122394Sharti	return ("ip6.int");
772122394Sharti}
773122394Sharti#endif
774122394Sharti
775122394Shartivoid
776122394Shartires_setservers(res_state statp, const union res_sockaddr_union *set, int cnt) {
777122394Sharti	int i, nserv;
778159063Sharti	size_t size;
779154182Sharti
780122394Sharti	/* close open servers */
781122394Sharti	res_nclose(statp);
782122394Sharti
783122394Sharti	/* cause rtt times to be forgotten */
784122394Sharti	statp->_u._ext.nscount = 0;
785122394Sharti
786122394Sharti	nserv = 0;
787122394Sharti	for (i = 0; i < cnt && nserv < MAXNS; i++) {
788122394Sharti		switch (set->sin.sin_family) {
789122394Sharti		case AF_INET:
790122394Sharti			size = sizeof(set->sin);
791122394Sharti			if (statp->_u._ext.ext)
792159063Sharti				memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
793159063Sharti					&set->sin, size);
794122394Sharti			if (size <= sizeof(statp->nsaddr_list[nserv]))
795159063Sharti				memcpy(&statp->nsaddr_list[nserv],
796122394Sharti					&set->sin, size);
797159063Sharti			else
798122394Sharti				statp->nsaddr_list[nserv].sin_family = 0;
799122394Sharti			nserv++;
800122394Sharti			break;
801122394Sharti
802122394Sharti#ifdef HAS_INET6_STRUCTS
803122394Sharti		case AF_INET6:
804122394Sharti			size = sizeof(set->sin6);
805122394Sharti			if (statp->_u._ext.ext)
806122394Sharti				memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
807122394Sharti					&set->sin6, size);
808122394Sharti			if (size <= sizeof(statp->nsaddr_list[nserv]))
809122394Sharti				memcpy(&statp->nsaddr_list[nserv],
810122394Sharti					&set->sin6, size);
811122394Sharti			else
812122394Sharti				statp->nsaddr_list[nserv].sin_family = 0;
813122394Sharti			nserv++;
814122394Sharti			break;
815122394Sharti#endif
816122394Sharti
817122394Sharti		default:
818122394Sharti			break;
819122394Sharti		}
820122394Sharti		set++;
821122394Sharti	}
822122394Sharti	statp->nscount = nserv;
823159063Sharti
824159063Sharti}
825159063Sharti
826159063Shartiint
827122394Shartires_getservers(res_state statp, union res_sockaddr_union *set, int cnt) {
828122394Sharti	int i;
829122394Sharti	size_t size;
830159063Sharti	u_int16_t family;
831122394Sharti
832122394Sharti	for (i = 0; i < statp->nscount && i < cnt; i++) {
833122394Sharti		if (statp->_u._ext.ext)
834122394Sharti			family = statp->_u._ext.ext->nsaddrs[i].sin.sin_family;
835122394Sharti		else
836122394Sharti			family = statp->nsaddr_list[i].sin_family;
837122394Sharti
838122394Sharti		switch (family) {
839122394Sharti		case AF_INET:
840122394Sharti			size = sizeof(set->sin);
841122394Sharti			if (statp->_u._ext.ext)
842122394Sharti				memcpy(&set->sin,
843122394Sharti				       &statp->_u._ext.ext->nsaddrs[i],
844122394Sharti				       size);
845122394Sharti			else
846122394Sharti				memcpy(&set->sin, &statp->nsaddr_list[i],
847122394Sharti				       size);
848122394Sharti			break;
849122394Sharti
850122394Sharti#ifdef HAS_INET6_STRUCTS
851122394Sharti		case AF_INET6:
852122394Sharti			size = sizeof(set->sin6);
853122394Sharti			if (statp->_u._ext.ext)
854122394Sharti				memcpy(&set->sin6,
855122394Sharti				       &statp->_u._ext.ext->nsaddrs[i],
856122394Sharti				       size);
857122394Sharti			else
858122394Sharti				memcpy(&set->sin6, &statp->nsaddr_list[i],
859122394Sharti				       size);
860122394Sharti			break;
861122394Sharti#endif
862122394Sharti
863159063Sharti		default:
864159063Sharti			set->sin.sin_family = 0;
865159063Sharti			break;
866159063Sharti		}
867159063Sharti		set++;
868159063Sharti	}
869159063Sharti	return (statp->nscount);
870159063Sharti}
871159063Sharti
872159063Sharti/*! \file */
873159063Sharti