1331722Seadler/*
2156952Sume * Copyright (c) 1985, 1989, 1993
3156952Sume *    The Regents of the University of California.  All rights reserved.
4156952Sume *
5156952Sume * Redistribution and use in source and binary forms, with or without
6156952Sume * modification, are permitted provided that the following conditions
7156952Sume * are met:
8156952Sume * 1. Redistributions of source code must retain the above copyright
9156952Sume *    notice, this list of conditions and the following disclaimer.
10156952Sume * 2. Redistributions in binary form must reproduce the above copyright
11156952Sume *    notice, this list of conditions and the following disclaimer in the
12156952Sume *    documentation and/or other materials provided with the distribution.
13156952Sume * 4. Neither the name of the University nor the names of its contributors
14156952Sume *    may be used to endorse or promote products derived from this software
15156952Sume *    without specific prior written permission.
16156952Sume *
17156952Sume * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18156952Sume * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19156952Sume * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20156952Sume * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21156952Sume * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22156952Sume * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23156952Sume * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24156952Sume * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25156952Sume * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26156952Sume * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27156952Sume * SUCH DAMAGE.
28156952Sume */
29156952Sume
30156952Sume/*
31156952Sume * Portions Copyright (c) 1993 by Digital Equipment Corporation.
32156952Sume *
33156952Sume * Permission to use, copy, modify, and distribute this software for any
34156952Sume * purpose with or without fee is hereby granted, provided that the above
35156952Sume * copyright notice and this permission notice appear in all copies, and that
36156952Sume * the name of Digital Equipment Corporation not be used in advertising or
37156952Sume * publicity pertaining to distribution of the document or software without
38156952Sume * specific, written prior permission.
39156952Sume *
40156952Sume * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
41156952Sume * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
42156952Sume * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
43156952Sume * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
44156952Sume * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
45156952Sume * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
46156952Sume * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
47156952Sume * SOFTWARE.
48156952Sume */
49156952Sume
50156952Sume/*
51156952Sume * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
52156952Sume * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
53156952Sume *
54156952Sume * Permission to use, copy, modify, and distribute this software for any
55156952Sume * purpose with or without fee is hereby granted, provided that the above
56156952Sume * copyright notice and this permission notice appear in all copies.
57156952Sume *
58156952Sume * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
59156952Sume * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
60156952Sume * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
61156952Sume * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
62156952Sume * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
63156952Sume * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
64156952Sume * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
65156952Sume */
66156952Sume
67156952Sume#if defined(LIBC_SCCS) && !defined(lint)
68156952Sumestatic const char sccsid[] = "@(#)res_init.c	8.1 (Berkeley) 6/7/93";
69269867Sumestatic const char rcsid[] = "$Id: res_init.c,v 1.26 2008/12/11 09:59:00 marka Exp $";
70156952Sume#endif /* LIBC_SCCS and not lint */
71156956Sume#include <sys/cdefs.h>
72156956Sume__FBSDID("$FreeBSD: stable/11/lib/libc/resolv/res_init.c 340058 2018-11-02 15:02:44Z bz $");
73156952Sume
74156952Sume#include "port_before.h"
75156952Sume
76160965Sume#include "namespace.h"
77160965Sume
78156952Sume#include <sys/param.h>
79156952Sume#include <sys/socket.h>
80289315Svangyzen#include <sys/stat.h>
81156952Sume#include <sys/time.h>
82156952Sume
83156952Sume#include <netinet/in.h>
84156952Sume#include <arpa/inet.h>
85156952Sume#include <arpa/nameser.h>
86156952Sume
87156952Sume#include <ctype.h>
88156952Sume#include <stdio.h>
89156952Sume#include <stdlib.h>
90156952Sume#include <string.h>
91156952Sume#include <unistd.h>
92156952Sume#include <netdb.h>
93156952Sume
94269867Sume#ifndef HAVE_MD5
95269867Sume# include "../dst/md5.h"
96269867Sume#else
97269867Sume# ifdef SOLARIS2
98269867Sume#  include <sys/md5.h>
99269867Sume# elif _LIBC
100269867Sume# include <md5.h>
101269867Sume# endif
102269867Sume#endif
103269867Sume#ifndef _MD5_H_
104269867Sume# define _MD5_H_ 1	/*%< make sure we do not include rsaref md5.h file */
105269867Sume#endif
106269867Sume
107160965Sume#include "un-namespace.h"
108160965Sume
109156952Sume#include "port_after.h"
110156952Sume
111156952Sume/* ensure that sockaddr_in6 and IN6ADDR_ANY_INIT are declared / defined */
112156952Sume#include <resolv.h>
113156952Sume
114156952Sume#include "res_private.h"
115156952Sume
116170244Sume/*% Options.  Should all be left alone. */
117156952Sume#define RESOLVSORT
118292250Sngie#ifndef	DEBUG
119292250Sngie#define	DEBUG
120292250Sngie#endif
121156952Sume
122156952Sume#ifdef SOLARIS2
123156952Sume#include <sys/systeminfo.h>
124156952Sume#endif
125156952Sume
126156956Sumestatic void res_setoptions(res_state, const char *, const char *);
127156952Sume
128156952Sume#ifdef RESOLVSORT
129156952Sumestatic const char sort_mask[] = "/&";
130156952Sume#define ISSORTMASK(ch) (strchr(sort_mask, ch) != NULL)
131156956Sumestatic u_int32_t net_mask(struct in_addr);
132156952Sume#endif
133156952Sume
134170244Sume#if !defined(isascii)	/*%< XXX - could be a function */
135156952Sume# define isascii(c) (!(c & 0200))
136156952Sume#endif
137156952Sume
138156952Sume/*
139156952Sume * Resolver state default settings.
140156952Sume */
141156952Sume
142170244Sume/*%
143156952Sume * Set up default settings.  If the configuration file exist, the values
144156952Sume * there will have precedence.  Otherwise, the server address is set to
145156952Sume * INADDR_ANY and the default domain name comes from the gethostname().
146156952Sume *
147298830Spfg * An interim version of this code (BIND 4.9, pre-4.4BSD) used 127.0.0.1
148156952Sume * rather than INADDR_ANY ("0.0.0.0") as the default name server address
149156952Sume * since it was noted that INADDR_ANY actually meant ``the first interface
150156952Sume * you "ifconfig"'d at boot time'' and if this was a SLIP or PPP interface,
151156952Sume * it had to be "up" in order for you to reach your own name server.  It
152156952Sume * was later decided that since the recommended practice is to always
153156952Sume * install local static routes through 127.0.0.1 for all your network
154156952Sume * interfaces, that we could solve this problem without a code change.
155156952Sume *
156156952Sume * The configuration file should always be used, since it is the only way
157156952Sume * to specify a default domain.  If you are running a server on your local
158156952Sume * machine, you should say "nameserver 0.0.0.0" or "nameserver 127.0.0.1"
159156952Sume * in the configuration file.
160156952Sume *
161156952Sume * Return 0 if completes successfully, -1 on error
162156952Sume */
163156952Sumeint
164156952Sumeres_ninit(res_state statp) {
165156952Sume	extern int __res_vinit(res_state, int);
166156952Sume
167156952Sume	return (__res_vinit(statp, 0));
168156952Sume}
169156952Sume
170298830Spfg/*% This function has to be reachable by res_data.c but not publicly. */
171156952Sumeint
172156952Sume__res_vinit(res_state statp, int preinit) {
173156956Sume	FILE *fp;
174156956Sume	char *cp, **pp;
175156956Sume	int n;
176156952Sume	char buf[BUFSIZ];
177170244Sume	int nserv = 0;    /*%< number of nameserver records read from file */
178156952Sume	int haveenv = 0;
179156952Sume	int havesearch = 0;
180156952Sume#ifdef RESOLVSORT
181156952Sume	int nsort = 0;
182156952Sume	char *net;
183156952Sume#endif
184156952Sume	int dots;
185156952Sume	union res_sockaddr_union u[2];
186174226Sume	int maxns = MAXNS;
187156952Sume
188174226Sume	RES_SET_H_ERRNO(statp, 0);
189156952Sume	if (statp->_u._ext.ext != NULL)
190156952Sume		res_ndestroy(statp);
191156952Sume
192156952Sume	if (!preinit) {
193156952Sume		statp->retrans = RES_TIMEOUT;
194156952Sume		statp->retry = RES_DFLRETRY;
195156952Sume		statp->options = RES_DEFAULT;
196156952Sume	}
197156952Sume
198269867Sume	statp->_rnd = malloc(16);
199269867Sume	res_rndinit(statp);
200269867Sume	statp->id = res_nrandomid(statp);
201269867Sume
202156952Sume	memset(u, 0, sizeof(u));
203156952Sume#ifdef USELOOPBACK
204156952Sume	u[nserv].sin.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1);
205156952Sume#else
206156952Sume	u[nserv].sin.sin_addr.s_addr = INADDR_ANY;
207156952Sume#endif
208156952Sume	u[nserv].sin.sin_family = AF_INET;
209156952Sume	u[nserv].sin.sin_port = htons(NAMESERVER_PORT);
210156952Sume#ifdef HAVE_SA_LEN
211156952Sume	u[nserv].sin.sin_len = sizeof(struct sockaddr_in);
212156952Sume#endif
213156952Sume	nserv++;
214156952Sume#ifdef HAS_INET6_STRUCTS
215156952Sume#ifdef USELOOPBACK
216156952Sume	u[nserv].sin6.sin6_addr = in6addr_loopback;
217156952Sume#else
218156952Sume	u[nserv].sin6.sin6_addr = in6addr_any;
219156952Sume#endif
220156952Sume	u[nserv].sin6.sin6_family = AF_INET6;
221156952Sume	u[nserv].sin6.sin6_port = htons(NAMESERVER_PORT);
222156952Sume#ifdef HAVE_SA_LEN
223156952Sume	u[nserv].sin6.sin6_len = sizeof(struct sockaddr_in6);
224156952Sume#endif
225156952Sume	nserv++;
226156952Sume#endif
227156952Sume	statp->nscount = 0;
228156952Sume	statp->ndots = 1;
229156952Sume	statp->pfcode = 0;
230156952Sume	statp->_vcsock = -1;
231156952Sume	statp->_flags = 0;
232156952Sume	statp->qhook = NULL;
233156952Sume	statp->rhook = NULL;
234156952Sume	statp->_u._ext.nscount = 0;
235156952Sume	statp->_u._ext.ext = malloc(sizeof(*statp->_u._ext.ext));
236156952Sume	if (statp->_u._ext.ext != NULL) {
237156952Sume	        memset(statp->_u._ext.ext, 0, sizeof(*statp->_u._ext.ext));
238156952Sume		statp->_u._ext.ext->nsaddrs[0].sin = statp->nsaddr;
239156952Sume		strcpy(statp->_u._ext.ext->nsuffix, "ip6.arpa");
240156952Sume		strcpy(statp->_u._ext.ext->nsuffix2, "ip6.int");
241292216Svangyzen		statp->_u._ext.ext->reload_period = 2;
242174226Sume	} else {
243174226Sume		/*
244174226Sume		 * Historically res_init() rarely, if at all, failed.
245174226Sume		 * Examples and applications exist which do not check
246174226Sume		 * our return code.  Furthermore several applications
247174226Sume		 * simply call us to get the systems domainname.  So
248174226Sume		 * rather then immediately fail here we store the
249174226Sume		 * failure, which is returned later, in h_errno.  And
250174226Sume		 * prevent the collection of 'nameserver' information
251174226Sume		 * by setting maxns to 0.  Thus applications that fail
252174226Sume		 * to check our return code wont be able to make
253174226Sume		 * queries anyhow.
254174226Sume		 */
255174226Sume		RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
256174226Sume		maxns = 0;
257174226Sume	}
258156952Sume#ifdef RESOLVSORT
259156952Sume	statp->nsort = 0;
260156952Sume#endif
261156952Sume	res_setservers(statp, u, nserv);
262156952Sume
263156952Sume#ifdef	SOLARIS2
264156952Sume	/*
265156952Sume	 * The old libresolv derived the defaultdomain from NIS/NIS+.
266156952Sume	 * We want to keep this behaviour
267156952Sume	 */
268156952Sume	{
269156952Sume		char buf[sizeof(statp->defdname)], *cp;
270156952Sume		int ret;
271156952Sume
272156952Sume		if ((ret = sysinfo(SI_SRPC_DOMAIN, buf, sizeof(buf))) > 0 &&
273156952Sume			(unsigned int)ret <= sizeof(buf)) {
274156952Sume			if (buf[0] == '+')
275156952Sume				buf[0] = '.';
276156952Sume			cp = strchr(buf, '.');
277165258Sume			cp = (cp == NULL) ? buf : (cp + 1);
278174226Sume			strncpy(statp->defdname, cp,
279174226Sume				sizeof(statp->defdname) - 1);
280174226Sume			statp->defdname[sizeof(statp->defdname) - 1] = '\0';
281156952Sume		}
282156952Sume	}
283156952Sume#endif	/* SOLARIS2 */
284156952Sume
285156952Sume	/* Allow user to override the local domain definition */
286156956Sume	if (issetugid() == 0 && (cp = getenv("LOCALDOMAIN")) != NULL) {
287156952Sume		(void)strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
288156952Sume		statp->defdname[sizeof(statp->defdname) - 1] = '\0';
289156952Sume		haveenv++;
290156952Sume
291156952Sume		/*
292156952Sume		 * Set search list to be blank-separated strings
293156952Sume		 * from rest of env value.  Permits users of LOCALDOMAIN
294156952Sume		 * to still have a search list, and anyone to set the
295156952Sume		 * one that they want to use as an individual (even more
296156952Sume		 * important now that the rfc1535 stuff restricts searches)
297156952Sume		 */
298156952Sume		cp = statp->defdname;
299156952Sume		pp = statp->dnsrch;
300156952Sume		*pp++ = cp;
301156952Sume		for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) {
302170244Sume			if (*cp == '\n')	/*%< silly backwards compat */
303156952Sume				break;
304156952Sume			else if (*cp == ' ' || *cp == '\t') {
305156952Sume				*cp = 0;
306156952Sume				n = 1;
307156952Sume			} else if (n) {
308156952Sume				*pp++ = cp;
309156952Sume				n = 0;
310156952Sume				havesearch = 1;
311156952Sume			}
312156952Sume		}
313156952Sume		/* null terminate last domain if there are excess */
314156952Sume		while (*cp != '\0' && *cp != ' ' && *cp != '\t' && *cp != '\n')
315156952Sume			cp++;
316156952Sume		*cp = '\0';
317297790Spfg		*pp++ = NULL;
318156952Sume	}
319156952Sume
320156952Sume#define	MATCH(line, name) \
321156952Sume	(!strncmp(line, name, sizeof(name) - 1) && \
322156952Sume	(line[sizeof(name) - 1] == ' ' || \
323156952Sume	 line[sizeof(name) - 1] == '\t'))
324156952Sume
325156952Sume	nserv = 0;
326254700Sjilles	if ((fp = fopen(_PATH_RESCONF, "re")) != NULL) {
327289315Svangyzen	    struct stat sb;
328289315Svangyzen	    struct timespec now;
329289315Svangyzen
330292216Svangyzen	    if (statp->_u._ext.ext != NULL) {
331292216Svangyzen		if (_fstat(fileno(fp), &sb) == 0) {
332292216Svangyzen		    statp->_u._ext.ext->conf_mtim = sb.st_mtim;
333292216Svangyzen		    if (clock_gettime(CLOCK_MONOTONIC_FAST, &now) == 0) {
334292216Svangyzen			statp->_u._ext.ext->conf_stat = now.tv_sec;
335292216Svangyzen		    }
336289315Svangyzen		}
337289315Svangyzen	    }
338289315Svangyzen
339156952Sume	    /* read the config file */
340156952Sume	    while (fgets(buf, sizeof(buf), fp) != NULL) {
341156952Sume		/* skip comments */
342156952Sume		if (*buf == ';' || *buf == '#')
343156952Sume			continue;
344156952Sume		/* read default domain name */
345156952Sume		if (MATCH(buf, "domain")) {
346170244Sume		    if (haveenv)	/*%< skip if have from environ */
347156952Sume			    continue;
348156952Sume		    cp = buf + sizeof("domain") - 1;
349156952Sume		    while (*cp == ' ' || *cp == '\t')
350156952Sume			    cp++;
351156952Sume		    if ((*cp == '\0') || (*cp == '\n'))
352156952Sume			    continue;
353156952Sume		    strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
354156952Sume		    statp->defdname[sizeof(statp->defdname) - 1] = '\0';
355156952Sume		    if ((cp = strpbrk(statp->defdname, " \t\n")) != NULL)
356156952Sume			    *cp = '\0';
357156952Sume		    havesearch = 0;
358156952Sume		    continue;
359156952Sume		}
360156952Sume		/* set search list */
361156952Sume		if (MATCH(buf, "search")) {
362170244Sume		    if (haveenv)	/*%< skip if have from environ */
363156952Sume			    continue;
364156952Sume		    cp = buf + sizeof("search") - 1;
365156952Sume		    while (*cp == ' ' || *cp == '\t')
366156952Sume			    cp++;
367156952Sume		    if ((*cp == '\0') || (*cp == '\n'))
368156952Sume			    continue;
369156952Sume		    strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
370156952Sume		    statp->defdname[sizeof(statp->defdname) - 1] = '\0';
371156952Sume		    if ((cp = strchr(statp->defdname, '\n')) != NULL)
372156952Sume			    *cp = '\0';
373156952Sume		    /*
374156952Sume		     * Set search list to be blank-separated strings
375156952Sume		     * on rest of line.
376156952Sume		     */
377156952Sume		    cp = statp->defdname;
378156952Sume		    pp = statp->dnsrch;
379156952Sume		    *pp++ = cp;
380156952Sume		    for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) {
381156952Sume			    if (*cp == ' ' || *cp == '\t') {
382156952Sume				    *cp = 0;
383156952Sume				    n = 1;
384156952Sume			    } else if (n) {
385156952Sume				    *pp++ = cp;
386156952Sume				    n = 0;
387156952Sume			    }
388156952Sume		    }
389156952Sume		    /* null terminate last domain if there are excess */
390156952Sume		    while (*cp != '\0' && *cp != ' ' && *cp != '\t')
391156952Sume			    cp++;
392156952Sume		    *cp = '\0';
393297790Spfg		    *pp++ = NULL;
394156952Sume		    havesearch = 1;
395156952Sume		    continue;
396156952Sume		}
397156952Sume		/* read nameservers to query */
398174226Sume		if (MATCH(buf, "nameserver") && nserv < maxns) {
399156952Sume		    struct addrinfo hints, *ai;
400156952Sume		    char sbuf[NI_MAXSERV];
401156952Sume		    const size_t minsiz =
402156952Sume		        sizeof(statp->_u._ext.ext->nsaddrs[0]);
403156952Sume
404156952Sume		    cp = buf + sizeof("nameserver") - 1;
405156952Sume		    while (*cp == ' ' || *cp == '\t')
406156952Sume			cp++;
407156952Sume		    cp[strcspn(cp, ";# \t\n")] = '\0';
408156952Sume		    if ((*cp != '\0') && (*cp != '\n')) {
409156952Sume			memset(&hints, 0, sizeof(hints));
410156952Sume			hints.ai_family = PF_UNSPEC;
411156952Sume			hints.ai_socktype = SOCK_DGRAM;	/*dummy*/
412156952Sume			hints.ai_flags = AI_NUMERICHOST;
413156952Sume			sprintf(sbuf, "%u", NAMESERVER_PORT);
414301592Struckman			if (getaddrinfo(cp, sbuf, &hints, &ai) == 0) {
415301592Struckman			    if (ai->ai_addrlen <= minsiz) {
416301592Struckman				if (statp->_u._ext.ext != NULL) {
417301592Struckman				    memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
418301592Struckman					ai->ai_addr, ai->ai_addrlen);
419301592Struckman				}
420301592Struckman				if (ai->ai_addrlen <=
421301592Struckman				    sizeof(statp->nsaddr_list[nserv])) {
422301592Struckman				    memcpy(&statp->nsaddr_list[nserv],
423301592Struckman					ai->ai_addr, ai->ai_addrlen);
424301592Struckman				} else
425301592Struckman				    statp->nsaddr_list[nserv].sin_family = 0;
426301592Struckman				nserv++;
427156952Sume			    }
428156952Sume			    freeaddrinfo(ai);
429156952Sume			}
430156952Sume		    }
431156952Sume		    continue;
432156952Sume		}
433156952Sume#ifdef RESOLVSORT
434156952Sume		if (MATCH(buf, "sortlist")) {
435156952Sume		    struct in_addr a;
436156956Sume		    struct in6_addr a6;
437156956Sume		    int m, i;
438156956Sume		    u_char *u;
439156956Sume		    struct __res_state_ext *ext = statp->_u._ext.ext;
440156952Sume
441156952Sume		    cp = buf + sizeof("sortlist") - 1;
442156952Sume		    while (nsort < MAXRESOLVSORT) {
443156952Sume			while (*cp == ' ' || *cp == '\t')
444156952Sume			    cp++;
445156952Sume			if (*cp == '\0' || *cp == '\n' || *cp == ';')
446156952Sume			    break;
447156952Sume			net = cp;
448156952Sume			while (*cp && !ISSORTMASK(*cp) && *cp != ';' &&
449156952Sume			       isascii(*cp) && !isspace((unsigned char)*cp))
450156952Sume				cp++;
451156952Sume			n = *cp;
452156952Sume			*cp = 0;
453156952Sume			if (inet_aton(net, &a)) {
454156952Sume			    statp->sort_list[nsort].addr = a;
455156952Sume			    if (ISSORTMASK(n)) {
456156952Sume				*cp++ = n;
457156952Sume				net = cp;
458156952Sume				while (*cp && *cp != ';' &&
459156952Sume					isascii(*cp) &&
460156952Sume					!isspace((unsigned char)*cp))
461156952Sume				    cp++;
462156952Sume				n = *cp;
463156952Sume				*cp = 0;
464156952Sume				if (inet_aton(net, &a)) {
465156952Sume				    statp->sort_list[nsort].mask = a.s_addr;
466156952Sume				} else {
467156952Sume				    statp->sort_list[nsort].mask =
468156952Sume					net_mask(statp->sort_list[nsort].addr);
469156952Sume				}
470156952Sume			    } else {
471156952Sume				statp->sort_list[nsort].mask =
472156952Sume				    net_mask(statp->sort_list[nsort].addr);
473156952Sume			    }
474156956Sume			    ext->sort_list[nsort].af = AF_INET;
475156956Sume			    ext->sort_list[nsort].addr.ina =
476156956Sume				statp->sort_list[nsort].addr;
477156956Sume			    ext->sort_list[nsort].mask.ina.s_addr =
478156956Sume				statp->sort_list[nsort].mask;
479156952Sume			    nsort++;
480156952Sume			}
481156956Sume			else if (inet_pton(AF_INET6, net, &a6) == 1) {
482156956Sume
483156956Sume			    ext->sort_list[nsort].af = AF_INET6;
484156956Sume			    ext->sort_list[nsort].addr.in6a = a6;
485156956Sume			    u = (u_char *)&ext->sort_list[nsort].mask.in6a;
486156956Sume			    *cp++ = n;
487156956Sume			    net = cp;
488156956Sume			    while (*cp && *cp != ';' &&
489156956Sume				    isascii(*cp) && !isspace(*cp))
490156956Sume				cp++;
491156956Sume			    m = n;
492156956Sume			    n = *cp;
493156956Sume			    *cp = 0;
494156956Sume			    switch (m) {
495156956Sume			    case '/':
496156956Sume				m = atoi(net);
497156956Sume				break;
498156956Sume			    case '&':
499156956Sume				if (inet_pton(AF_INET6, net, u) == 1) {
500156956Sume				    m = -1;
501156956Sume				    break;
502156956Sume				}
503156956Sume				/*FALLTHROUGH*/
504156956Sume			    default:
505156956Sume				m = sizeof(struct in6_addr) * CHAR_BIT;
506156956Sume				break;
507156956Sume			    }
508156956Sume			    if (m >= 0) {
509156956Sume				for (i = 0; i < sizeof(struct in6_addr); i++) {
510156956Sume				    if (m <= 0) {
511156956Sume					*u = 0;
512156956Sume				    } else {
513156956Sume					m -= CHAR_BIT;
514156956Sume					*u = (u_char)~0;
515156956Sume					if (m < 0)
516156956Sume					    *u <<= -m;
517156956Sume				    }
518156956Sume				    u++;
519156956Sume				}
520156956Sume			    }
521156956Sume			    statp->sort_list[nsort].addr.s_addr =
522156956Sume				(u_int32_t)0xffffffff;
523156956Sume			    statp->sort_list[nsort].mask =
524156956Sume				(u_int32_t)0xffffffff;
525156956Sume			    nsort++;
526156956Sume			}
527156952Sume			*cp = n;
528156952Sume		    }
529156952Sume		    continue;
530156952Sume		}
531156952Sume#endif
532156952Sume		if (MATCH(buf, "options")) {
533156952Sume		    res_setoptions(statp, buf + sizeof("options") - 1, "conf");
534156952Sume		    continue;
535156952Sume		}
536156952Sume	    }
537156952Sume	    if (nserv > 0)
538156952Sume		statp->nscount = nserv;
539156952Sume#ifdef RESOLVSORT
540156952Sume	    statp->nsort = nsort;
541156952Sume#endif
542156952Sume	    (void) fclose(fp);
543156952Sume	}
544156952Sume/*
545156952Sume * Last chance to get a nameserver.  This should not normally
546156952Sume * be necessary
547156952Sume */
548156952Sume#ifdef NO_RESOLV_CONF
549156952Sume	if(nserv == 0)
550156952Sume		nserv = get_nameservers(statp);
551156952Sume#endif
552156952Sume
553156952Sume	if (statp->defdname[0] == 0 &&
554156952Sume	    gethostname(buf, sizeof(statp->defdname) - 1) == 0 &&
555156952Sume	    (cp = strchr(buf, '.')) != NULL)
556156952Sume		strcpy(statp->defdname, cp + 1);
557156952Sume
558156952Sume	/* find components of local domain that might be searched */
559156952Sume	if (havesearch == 0) {
560156952Sume		pp = statp->dnsrch;
561156952Sume		*pp++ = statp->defdname;
562156952Sume		*pp = NULL;
563156952Sume
564156952Sume		dots = 0;
565156952Sume		for (cp = statp->defdname; *cp; cp++)
566156952Sume			dots += (*cp == '.');
567156952Sume
568156952Sume		cp = statp->defdname;
569156952Sume		while (pp < statp->dnsrch + MAXDFLSRCH) {
570156952Sume			if (dots < LOCALDOMAINPARTS)
571156952Sume				break;
572170244Sume			cp = strchr(cp, '.') + 1;    /*%< we know there is one */
573156952Sume			*pp++ = cp;
574156952Sume			dots--;
575156952Sume		}
576156952Sume		*pp = NULL;
577156952Sume#ifdef DEBUG
578156952Sume		if (statp->options & RES_DEBUG) {
579156952Sume			printf(";; res_init()... default dnsrch list:\n");
580156952Sume			for (pp = statp->dnsrch; *pp; pp++)
581156952Sume				printf(";;\t%s\n", *pp);
582156952Sume			printf(";;\t..END..\n");
583156952Sume		}
584156952Sume#endif
585156952Sume	}
586156952Sume
587156956Sume	if (issetugid())
588156956Sume		statp->options |= RES_NOALIASES;
589156956Sume	else if ((cp = getenv("RES_OPTIONS")) != NULL)
590156952Sume		res_setoptions(statp, cp, "env");
591156952Sume	statp->options |= RES_INIT;
592174226Sume	return (statp->res_h_errno);
593156952Sume}
594156952Sume
595156952Sumestatic void
596156952Sumeres_setoptions(res_state statp, const char *options, const char *source)
597156952Sume{
598156952Sume	const char *cp = options;
599156952Sume	int i;
600156952Sume	struct __res_state_ext *ext = statp->_u._ext.ext;
601156952Sume
602156952Sume#ifdef DEBUG
603156952Sume	if (statp->options & RES_DEBUG)
604156952Sume		printf(";; res_setoptions(\"%s\", \"%s\")...\n",
605156952Sume		       options, source);
606156952Sume#endif
607156952Sume	while (*cp) {
608156952Sume		/* skip leading and inner runs of spaces */
609156952Sume		while (*cp == ' ' || *cp == '\t')
610156952Sume			cp++;
611156952Sume		/* search for and process individual options */
612156952Sume		if (!strncmp(cp, "ndots:", sizeof("ndots:") - 1)) {
613156952Sume			i = atoi(cp + sizeof("ndots:") - 1);
614156952Sume			if (i <= RES_MAXNDOTS)
615156952Sume				statp->ndots = i;
616156952Sume			else
617156952Sume				statp->ndots = RES_MAXNDOTS;
618156952Sume#ifdef DEBUG
619156952Sume			if (statp->options & RES_DEBUG)
620156952Sume				printf(";;\tndots=%d\n", statp->ndots);
621156952Sume#endif
622156952Sume		} else if (!strncmp(cp, "timeout:", sizeof("timeout:") - 1)) {
623156952Sume			i = atoi(cp + sizeof("timeout:") - 1);
624156952Sume			if (i <= RES_MAXRETRANS)
625156952Sume				statp->retrans = i;
626156952Sume			else
627156952Sume				statp->retrans = RES_MAXRETRANS;
628156952Sume#ifdef DEBUG
629156952Sume			if (statp->options & RES_DEBUG)
630156952Sume				printf(";;\ttimeout=%d\n", statp->retrans);
631156952Sume#endif
632156952Sume#ifdef	SOLARIS2
633156952Sume		} else if (!strncmp(cp, "retrans:", sizeof("retrans:") - 1)) {
634156952Sume			/*
635156952Sume		 	 * For backward compatibility, 'retrans' is
636156952Sume		 	 * supported as an alias for 'timeout', though
637156952Sume		 	 * without an imposed maximum.
638156952Sume		 	 */
639156952Sume			statp->retrans = atoi(cp + sizeof("retrans:") - 1);
640156952Sume		} else if (!strncmp(cp, "retry:", sizeof("retry:") - 1)){
641156952Sume			/*
642156952Sume			 * For backward compatibility, 'retry' is
643156952Sume			 * supported as an alias for 'attempts', though
644156952Sume			 * without an imposed maximum.
645156952Sume			 */
646156952Sume			statp->retry = atoi(cp + sizeof("retry:") - 1);
647156952Sume#endif	/* SOLARIS2 */
648156952Sume		} else if (!strncmp(cp, "attempts:", sizeof("attempts:") - 1)){
649156952Sume			i = atoi(cp + sizeof("attempts:") - 1);
650156952Sume			if (i <= RES_MAXRETRY)
651156952Sume				statp->retry = i;
652156952Sume			else
653156952Sume				statp->retry = RES_MAXRETRY;
654156952Sume#ifdef DEBUG
655156952Sume			if (statp->options & RES_DEBUG)
656156952Sume				printf(";;\tattempts=%d\n", statp->retry);
657156952Sume#endif
658156952Sume		} else if (!strncmp(cp, "debug", sizeof("debug") - 1)) {
659156952Sume#ifdef DEBUG
660156952Sume			if (!(statp->options & RES_DEBUG)) {
661156952Sume				printf(";; res_setoptions(\"%s\", \"%s\")..\n",
662156952Sume				       options, source);
663156952Sume				statp->options |= RES_DEBUG;
664156952Sume			}
665156952Sume			printf(";;\tdebug\n");
666156952Sume#endif
667156952Sume		} else if (!strncmp(cp, "no_tld_query",
668156952Sume				    sizeof("no_tld_query") - 1) ||
669156952Sume			   !strncmp(cp, "no-tld-query",
670156952Sume				    sizeof("no-tld-query") - 1)) {
671156952Sume			statp->options |= RES_NOTLDQUERY;
672156952Sume		} else if (!strncmp(cp, "inet6", sizeof("inet6") - 1)) {
673156952Sume			statp->options |= RES_USE_INET6;
674156956Sume		} else if (!strncmp(cp, "insecure1", sizeof("insecure1") - 1)) {
675156956Sume		       statp->options |= RES_INSECURE1;
676156956Sume		} else if (!strncmp(cp, "insecure2", sizeof("insecure2") - 1)) {
677156956Sume		       statp->options |= RES_INSECURE2;
678156952Sume		} else if (!strncmp(cp, "rotate", sizeof("rotate") - 1)) {
679156952Sume			statp->options |= RES_ROTATE;
680340058Sbz		} else if (!strncmp(cp, "usevc", sizeof("usevc") - 1)) {
681340058Sbz			statp->options |= RES_USEVC;
682156952Sume		} else if (!strncmp(cp, "no-check-names",
683156952Sume				    sizeof("no-check-names") - 1)) {
684156952Sume			statp->options |= RES_NOCHECKNAME;
685289315Svangyzen		} else if (!strncmp(cp, "reload-period:",
686289315Svangyzen				    sizeof("reload-period:") - 1)) {
687292216Svangyzen			if (ext != NULL) {
688292216Svangyzen				ext->reload_period = (u_short)
689292216Svangyzen				    atoi(cp + sizeof("reload-period:") - 1);
690292216Svangyzen			}
691156952Sume		}
692156952Sume#ifdef RES_USE_EDNS0
693156952Sume		else if (!strncmp(cp, "edns0", sizeof("edns0") - 1)) {
694156952Sume			statp->options |= RES_USE_EDNS0;
695156952Sume		}
696156952Sume#endif
697156956Sume#ifndef _LIBC
698156952Sume		else if (!strncmp(cp, "dname", sizeof("dname") - 1)) {
699156952Sume			statp->options |= RES_USE_DNAME;
700156952Sume		}
701156952Sume		else if (!strncmp(cp, "nibble:", sizeof("nibble:") - 1)) {
702156952Sume			if (ext == NULL)
703156952Sume				goto skip;
704156952Sume			cp += sizeof("nibble:") - 1;
705156952Sume			i = MIN(strcspn(cp, " \t"), sizeof(ext->nsuffix) - 1);
706156952Sume			strncpy(ext->nsuffix, cp, i);
707156952Sume			ext->nsuffix[i] = '\0';
708156952Sume		}
709156952Sume		else if (!strncmp(cp, "nibble2:", sizeof("nibble2:") - 1)) {
710156952Sume			if (ext == NULL)
711156952Sume				goto skip;
712156952Sume			cp += sizeof("nibble2:") - 1;
713156952Sume			i = MIN(strcspn(cp, " \t"), sizeof(ext->nsuffix2) - 1);
714156952Sume			strncpy(ext->nsuffix2, cp, i);
715156952Sume			ext->nsuffix2[i] = '\0';
716156952Sume		}
717156952Sume		else if (!strncmp(cp, "v6revmode:", sizeof("v6revmode:") - 1)) {
718156952Sume			cp += sizeof("v6revmode:") - 1;
719156952Sume			/* "nibble" and "bitstring" used to be valid */
720156952Sume			if (!strncmp(cp, "single", sizeof("single") - 1)) {
721156952Sume				statp->options |= RES_NO_NIBBLE2;
722156952Sume			} else if (!strncmp(cp, "both", sizeof("both") - 1)) {
723156952Sume				statp->options &=
724156952Sume					 ~RES_NO_NIBBLE2;
725156952Sume			}
726156952Sume		}
727156956Sume#endif
728156952Sume		else {
729156952Sume			/* XXX - print a warning here? */
730156952Sume		}
731156956Sume#ifndef _LIBC
732156952Sume   skip:
733156956Sume#endif
734156952Sume		/* skip to next run of spaces */
735156952Sume		while (*cp && *cp != ' ' && *cp != '\t')
736156952Sume			cp++;
737156952Sume	}
738156952Sume}
739156952Sume
740156952Sume#ifdef RESOLVSORT
741156952Sume/* XXX - should really support CIDR which means explicit masks always. */
742156952Sumestatic u_int32_t
743288114Srodrigcnet_mask(struct in_addr in)		/*!< XXX - should really use system's version of this  */
744156952Sume{
745156956Sume	u_int32_t i = ntohl(in.s_addr);
746156952Sume
747156952Sume	if (IN_CLASSA(i))
748156952Sume		return (htonl(IN_CLASSA_NET));
749156952Sume	else if (IN_CLASSB(i))
750156952Sume		return (htonl(IN_CLASSB_NET));
751156952Sume	return (htonl(IN_CLASSC_NET));
752156952Sume}
753156952Sume#endif
754156952Sume
755269867Sumestatic u_char srnd[16];
756269867Sume
757269867Sumevoid
758269867Sumeres_rndinit(res_state statp)
759269867Sume{
760269867Sume	struct timeval now;
761269867Sume	u_int32_t u32;
762269867Sume	u_int16_t u16;
763269867Sume	u_char *rnd = statp->_rnd == NULL ? srnd : statp->_rnd;
764269867Sume
765269867Sume	gettimeofday(&now, NULL);
766269867Sume	u32 = now.tv_sec;
767269867Sume	memcpy(rnd, &u32, 4);
768269867Sume	u32 = now.tv_usec;
769269867Sume	memcpy(rnd + 4, &u32, 4);
770269867Sume	u32 += now.tv_sec;
771269867Sume	memcpy(rnd + 8, &u32, 4);
772269867Sume	u16 = getpid();
773269867Sume	memcpy(rnd + 12, &u16, 2);
774269867Sume}
775269867Sume
776156952Sumeu_int
777269867Sumeres_nrandomid(res_state statp) {
778156952Sume	struct timeval now;
779269867Sume	u_int16_t u16;
780269867Sume	MD5_CTX ctx;
781269867Sume	u_char *rnd = statp->_rnd == NULL ? srnd : statp->_rnd;
782156952Sume
783156952Sume	gettimeofday(&now, NULL);
784269867Sume	u16 = (u_int16_t) (now.tv_sec ^ now.tv_usec);
785269867Sume	memcpy(rnd + 14, &u16, 2);
786269867Sume#ifndef HAVE_MD5
787269867Sume	MD5_Init(&ctx);
788269867Sume	MD5_Update(&ctx, rnd, 16);
789269867Sume	MD5_Final(rnd, &ctx);
790269867Sume#else
791269867Sume	MD5Init(&ctx);
792269867Sume	MD5Update(&ctx, rnd, 16);
793269867Sume	MD5Final(rnd, &ctx);
794269867Sume#endif
795269867Sume	memcpy(&u16, rnd + 14, 2);
796269867Sume	return ((u_int) u16);
797156952Sume}
798156952Sume
799170244Sume/*%
800156952Sume * This routine is for closing the socket if a virtual circuit is used and
801156952Sume * the program wants to close it.  This provides support for endhostent()
802156952Sume * which expects to close the socket.
803156952Sume *
804156952Sume * This routine is not expected to be user visible.
805156952Sume */
806156952Sumevoid
807156952Sumeres_nclose(res_state statp) {
808156952Sume	int ns;
809156952Sume
810156952Sume	if (statp->_vcsock >= 0) {
811160965Sume		(void) _close(statp->_vcsock);
812156952Sume		statp->_vcsock = -1;
813156952Sume		statp->_flags &= ~(RES_F_VC | RES_F_CONN);
814156952Sume	}
815156952Sume	for (ns = 0; ns < statp->_u._ext.nscount; ns++) {
816156952Sume		if (statp->_u._ext.nssocks[ns] != -1) {
817160965Sume			(void) _close(statp->_u._ext.nssocks[ns]);
818156952Sume			statp->_u._ext.nssocks[ns] = -1;
819156952Sume		}
820156952Sume	}
821156952Sume}
822156952Sume
823156952Sumevoid
824156952Sumeres_ndestroy(res_state statp) {
825156952Sume	res_nclose(statp);
826269867Sume	if (statp->_u._ext.ext != NULL) {
827156952Sume		free(statp->_u._ext.ext);
828269867Sume		statp->_u._ext.ext = NULL;
829269867Sume	}
830269867Sume	if (statp->_rnd != NULL) {
831269867Sume		free(statp->_rnd);
832269867Sume		statp->_rnd = NULL;
833269867Sume	}
834156952Sume	statp->options &= ~RES_INIT;
835156952Sume}
836156952Sume
837156956Sume#ifndef _LIBC
838156952Sumeconst char *
839156952Sumeres_get_nibblesuffix(res_state statp) {
840156952Sume	if (statp->_u._ext.ext)
841156952Sume		return (statp->_u._ext.ext->nsuffix);
842156952Sume	return ("ip6.arpa");
843156952Sume}
844156952Sume
845156952Sumeconst char *
846156952Sumeres_get_nibblesuffix2(res_state statp) {
847156952Sume	if (statp->_u._ext.ext)
848156952Sume		return (statp->_u._ext.ext->nsuffix2);
849156952Sume	return ("ip6.int");
850156952Sume}
851156956Sume#endif
852156952Sume
853156952Sumevoid
854156952Sumeres_setservers(res_state statp, const union res_sockaddr_union *set, int cnt) {
855156952Sume	int i, nserv;
856156952Sume	size_t size;
857156952Sume
858156952Sume	/* close open servers */
859156952Sume	res_nclose(statp);
860156952Sume
861156952Sume	/* cause rtt times to be forgotten */
862156952Sume	statp->_u._ext.nscount = 0;
863156952Sume
864156952Sume	nserv = 0;
865156952Sume	for (i = 0; i < cnt && nserv < MAXNS; i++) {
866156952Sume		switch (set->sin.sin_family) {
867156952Sume		case AF_INET:
868156952Sume			size = sizeof(set->sin);
869156952Sume			if (statp->_u._ext.ext)
870156952Sume				memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
871156952Sume					&set->sin, size);
872156952Sume			if (size <= sizeof(statp->nsaddr_list[nserv]))
873156952Sume				memcpy(&statp->nsaddr_list[nserv],
874156952Sume					&set->sin, size);
875156952Sume			else
876156952Sume				statp->nsaddr_list[nserv].sin_family = 0;
877156952Sume			nserv++;
878156952Sume			break;
879156952Sume
880156952Sume#ifdef HAS_INET6_STRUCTS
881156952Sume		case AF_INET6:
882156952Sume			size = sizeof(set->sin6);
883156952Sume			if (statp->_u._ext.ext)
884156952Sume				memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
885156952Sume					&set->sin6, size);
886156952Sume			if (size <= sizeof(statp->nsaddr_list[nserv]))
887156952Sume				memcpy(&statp->nsaddr_list[nserv],
888156952Sume					&set->sin6, size);
889156952Sume			else
890156952Sume				statp->nsaddr_list[nserv].sin_family = 0;
891156952Sume			nserv++;
892156952Sume			break;
893156952Sume#endif
894156952Sume
895156952Sume		default:
896156952Sume			break;
897156952Sume		}
898156952Sume		set++;
899156952Sume	}
900156952Sume	statp->nscount = nserv;
901156952Sume
902156952Sume}
903156952Sume
904156952Sumeint
905156952Sumeres_getservers(res_state statp, union res_sockaddr_union *set, int cnt) {
906156952Sume	int i;
907156952Sume	size_t size;
908156952Sume	u_int16_t family;
909156952Sume
910156952Sume	for (i = 0; i < statp->nscount && i < cnt; i++) {
911156952Sume		if (statp->_u._ext.ext)
912156952Sume			family = statp->_u._ext.ext->nsaddrs[i].sin.sin_family;
913156952Sume		else
914156952Sume			family = statp->nsaddr_list[i].sin_family;
915156952Sume
916156952Sume		switch (family) {
917156952Sume		case AF_INET:
918156952Sume			size = sizeof(set->sin);
919156952Sume			if (statp->_u._ext.ext)
920156952Sume				memcpy(&set->sin,
921156952Sume				       &statp->_u._ext.ext->nsaddrs[i],
922156952Sume				       size);
923156952Sume			else
924156952Sume				memcpy(&set->sin, &statp->nsaddr_list[i],
925156952Sume				       size);
926156952Sume			break;
927156952Sume
928156952Sume#ifdef HAS_INET6_STRUCTS
929156952Sume		case AF_INET6:
930156952Sume			size = sizeof(set->sin6);
931156952Sume			if (statp->_u._ext.ext)
932156952Sume				memcpy(&set->sin6,
933156952Sume				       &statp->_u._ext.ext->nsaddrs[i],
934156952Sume				       size);
935156952Sume			else
936156952Sume				memcpy(&set->sin6, &statp->nsaddr_list[i],
937156952Sume				       size);
938156952Sume			break;
939156952Sume#endif
940156952Sume
941156952Sume		default:
942156952Sume			set->sin.sin_family = 0;
943156952Sume			break;
944156952Sume		}
945156952Sume		set++;
946156952Sume	}
947156952Sume	return (statp->nscount);
948156952Sume}
949170244Sume
950170244Sume/*! \file */
951