res_init.c revision 174226
118334Speter/*
272564Sobrien * Copyright (c) 1985, 1989, 1993
390091Sobrien *    The Regents of the University of California.  All rights reserved.
418334Speter *
590091Sobrien * Redistribution and use in source and binary forms, with or without
618334Speter * modification, are permitted provided that the following conditions
790091Sobrien * are met:
890091Sobrien * 1. Redistributions of source code must retain the above copyright
990091Sobrien *    notice, this list of conditions and the following disclaimer.
1090091Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1118334Speter *    notice, this list of conditions and the following disclaimer in the
1290091Sobrien *    documentation and/or other materials provided with the distribution.
1390091Sobrien * 4. Neither the name of the University nor the names of its contributors
1490091Sobrien *    may be used to endorse or promote products derived from this software
1590091Sobrien *    without specific prior written permission.
1618334Speter *
1718334Speter * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1890091Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1990091Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2090091Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2118334Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2290091Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2352518Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2418334Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2552518Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2618334Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2718334Speter * SUCH DAMAGE.
2818334Speter */
2918334Speter
3018334Speter/*
3118334Speter * Portions Copyright (c) 1993 by Digital Equipment Corporation.
3218334Speter *
3318334Speter * Permission to use, copy, modify, and distribute this software for any
3418334Speter * purpose with or without fee is hereby granted, provided that the above
3518334Speter * copyright notice and this permission notice appear in all copies, and that
3618334Speter * the name of Digital Equipment Corporation not be used in advertising or
3718334Speter * publicity pertaining to distribution of the document or software without
3818334Speter * specific, written prior permission.
3918334Speter *
4018334Speter * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
4118334Speter * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
4218334Speter * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
4318334Speter * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
4418334Speter * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
4518334Speter * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
4652268Sobrien * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
4718334Speter * SOFTWARE.
4818334Speter */
4918334Speter
5052268Sobrien/*
5118334Speter * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
5218334Speter * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
5390091Sobrien *
5418334Speter * Permission to use, copy, modify, and distribute this software for any
5518334Speter * purpose with or without fee is hereby granted, provided that the above
5618334Speter * copyright notice and this permission notice appear in all copies.
5718334Speter *
5818334Speter * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
5918334Speter * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
6018334Speter * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
6152268Sobrien * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
6252518Sobrien * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
6390091Sobrien * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
6490091Sobrien * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
6590091Sobrien */
6618334Speter
6752268Sobrien#if defined(LIBC_SCCS) && !defined(lint)
6852268Sobrienstatic const char sccsid[] = "@(#)res_init.c	8.1 (Berkeley) 6/7/93";
6952268Sobrienstatic const char rcsid[] = "$Id: res_init.c,v 1.16.18.7 2007/07/09 01:52:58 marka Exp $";
7052268Sobrien#endif /* LIBC_SCCS and not lint */
7152518Sobrien#include <sys/cdefs.h>
7252518Sobrien__FBSDID("$FreeBSD: head/lib/libc/resolv/res_init.c 174226 2007-12-03 15:13:44Z ume $");
7352518Sobrien
7452518Sobrien#include "port_before.h"
7518334Speter
7618334Speter#include "namespace.h"
7718334Speter
7852268Sobrien#include <sys/types.h>
7918334Speter#include <sys/param.h>
8018334Speter#include <sys/socket.h>
8118334Speter#include <sys/time.h>
8218334Speter
8318334Speter#include <netinet/in.h>
8418334Speter#include <arpa/inet.h>
8518334Speter#include <arpa/nameser.h>
8618334Speter
8718334Speter#include <ctype.h>
8818334Speter#include <stdio.h>
8918334Speter#include <stdlib.h>
9018334Speter#include <string.h>
9118334Speter#include <unistd.h>
9218334Speter#include <netdb.h>
9318334Speter
9418334Speter#include "un-namespace.h"
9518334Speter
9618334Speter#include "port_after.h"
9718334Speter
9818334Speter/* ensure that sockaddr_in6 and IN6ADDR_ANY_INIT are declared / defined */
9918334Speter#include <resolv.h>
10018334Speter
10118334Speter#include "res_private.h"
10218334Speter
10352518Sobrien/*% Options.  Should all be left alone. */
10452518Sobrien#define RESOLVSORT
10552518Sobrien#define DEBUG
10690091Sobrien
10752518Sobrien#ifdef SOLARIS2
10818334Speter#include <sys/systeminfo.h>
10990091Sobrien#endif
11090091Sobrien
11190091Sobrienstatic void res_setoptions(res_state, const char *, const char *);
11290091Sobrien
11390091Sobrien#ifdef RESOLVSORT
11452518Sobrienstatic const char sort_mask[] = "/&";
11552518Sobrien#define ISSORTMASK(ch) (strchr(sort_mask, ch) != NULL)
11690091Sobrienstatic u_int32_t net_mask(struct in_addr);
11752518Sobrien#endif
11852518Sobrien
11952518Sobrien#if !defined(isascii)	/*%< XXX - could be a function */
12052518Sobrien# define isascii(c) (!(c & 0200))
12152518Sobrien#endif
12252518Sobrien
12352518Sobrien/*
12490091Sobrien * Resolver state default settings.
12590091Sobrien */
12690091Sobrien
12790091Sobrien/*%
12890091Sobrien * Set up default settings.  If the configuration file exist, the values
12952518Sobrien * there will have precedence.  Otherwise, the server address is set to
13096283Sobrien * INADDR_ANY and the default domain name comes from the gethostname().
13196283Sobrien *
13296283Sobrien * An interrim version of this code (BIND 4.9, pre-4.4BSD) used 127.0.0.1
13390091Sobrien * rather than INADDR_ANY ("0.0.0.0") as the default name server address
13490091Sobrien * since it was noted that INADDR_ANY actually meant ``the first interface
13590091Sobrien * you "ifconfig"'d at boot time'' and if this was a SLIP or PPP interface,
13690091Sobrien * it had to be "up" in order for you to reach your own name server.  It
13790091Sobrien * was later decided that since the recommended practice is to always
13890091Sobrien * install local static routes through 127.0.0.1 for all your network
13990091Sobrien * interfaces, that we could solve this problem without a code change.
14090091Sobrien *
14152518Sobrien * The configuration file should always be used, since it is the only way
14290091Sobrien * to specify a default domain.  If you are running a server on your local
14390091Sobrien * machine, you should say "nameserver 0.0.0.0" or "nameserver 127.0.0.1"
14490091Sobrien * in the configuration file.
14590091Sobrien *
14690091Sobrien * Return 0 if completes successfully, -1 on error
14790091Sobrien */
14852268Sobrienint
14918334Speterres_ninit(res_state statp) {
15018334Speter	extern int __res_vinit(res_state, int);
15118334Speter
15290091Sobrien	return (__res_vinit(statp, 0));
15390091Sobrien}
15418334Speter
15590091Sobrien/*% This function has to be reachable by res_data.c but not publically. */
15690091Sobrienint
15790091Sobrien__res_vinit(res_state statp, int preinit) {
15818334Speter	FILE *fp;
15990091Sobrien	char *cp, **pp;
16018334Speter	int n;
16190091Sobrien	char buf[BUFSIZ];
16218334Speter	int nserv = 0;    /*%< number of nameserver records read from file */
16318334Speter	int haveenv = 0;
16418334Speter	int havesearch = 0;
16518334Speter#ifdef RESOLVSORT
16618334Speter	int nsort = 0;
16718334Speter	char *net;
16818334Speter#endif
16918334Speter	int dots;
17018334Speter	union res_sockaddr_union u[2];
17118334Speter	int maxns = MAXNS;
17218334Speter
17318334Speter	RES_SET_H_ERRNO(statp, 0);
17418334Speter	if (statp->_u._ext.ext != NULL)
17518334Speter		res_ndestroy(statp);
17618334Speter
17718334Speter	if (!preinit) {
17818334Speter		statp->retrans = RES_TIMEOUT;
17918334Speter		statp->retry = RES_DFLRETRY;
18018334Speter		statp->options = RES_DEFAULT;
18118334Speter		statp->id = res_randomid();
18218334Speter	}
18318334Speter
18418334Speter	memset(u, 0, sizeof(u));
18552268Sobrien#ifdef USELOOPBACK
18618334Speter	u[nserv].sin.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1);
18718334Speter#else
18818334Speter	u[nserv].sin.sin_addr.s_addr = INADDR_ANY;
18918334Speter#endif
19090091Sobrien	u[nserv].sin.sin_family = AF_INET;
19190091Sobrien	u[nserv].sin.sin_port = htons(NAMESERVER_PORT);
19218334Speter#ifdef HAVE_SA_LEN
19352268Sobrien	u[nserv].sin.sin_len = sizeof(struct sockaddr_in);
19490091Sobrien#endif
19590091Sobrien	nserv++;
19690091Sobrien#ifdef HAS_INET6_STRUCTS
19790091Sobrien#ifdef USELOOPBACK
19890091Sobrien	u[nserv].sin6.sin6_addr = in6addr_loopback;
19918334Speter#else
20018334Speter	u[nserv].sin6.sin6_addr = in6addr_any;
20118334Speter#endif
20218334Speter	u[nserv].sin6.sin6_family = AF_INET6;
20318334Speter	u[nserv].sin6.sin6_port = htons(NAMESERVER_PORT);
20418334Speter#ifdef HAVE_SA_LEN
20518334Speter	u[nserv].sin6.sin6_len = sizeof(struct sockaddr_in6);
20618334Speter#endif
20718334Speter	nserv++;
20818334Speter#endif
20918334Speter	statp->nscount = 0;
21018334Speter	statp->ndots = 1;
21152268Sobrien	statp->pfcode = 0;
21218334Speter	statp->_vcsock = -1;
21318334Speter	statp->_flags = 0;
21452268Sobrien	statp->qhook = NULL;
21518334Speter	statp->rhook = NULL;
21652268Sobrien	statp->_u._ext.nscount = 0;
21718334Speter	statp->_u._ext.ext = malloc(sizeof(*statp->_u._ext.ext));
21818334Speter	if (statp->_u._ext.ext != NULL) {
21918334Speter	        memset(statp->_u._ext.ext, 0, sizeof(*statp->_u._ext.ext));
22018334Speter		statp->_u._ext.ext->nsaddrs[0].sin = statp->nsaddr;
22118334Speter		strcpy(statp->_u._ext.ext->nsuffix, "ip6.arpa");
22218334Speter		strcpy(statp->_u._ext.ext->nsuffix2, "ip6.int");
22318334Speter	} else {
22418334Speter		/*
22518334Speter		 * Historically res_init() rarely, if at all, failed.
22618334Speter		 * Examples and applications exist which do not check
22718334Speter		 * our return code.  Furthermore several applications
22890091Sobrien		 * simply call us to get the systems domainname.  So
22990091Sobrien		 * rather then immediately fail here we store the
23090091Sobrien		 * failure, which is returned later, in h_errno.  And
23152518Sobrien		 * prevent the collection of 'nameserver' information
23252518Sobrien		 * by setting maxns to 0.  Thus applications that fail
23352518Sobrien		 * to check our return code wont be able to make
23452518Sobrien		 * queries anyhow.
23552518Sobrien		 */
23652518Sobrien		RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
23718334Speter		maxns = 0;
23818334Speter	}
23990091Sobrien#ifdef RESOLVSORT
24090091Sobrien	statp->nsort = 0;
24190091Sobrien#endif
24290091Sobrien	res_setservers(statp, u, nserv);
24390091Sobrien
24490091Sobrien#ifdef	SOLARIS2
24590091Sobrien	/*
24690091Sobrien	 * The old libresolv derived the defaultdomain from NIS/NIS+.
24790091Sobrien	 * We want to keep this behaviour
24890091Sobrien	 */
24996283Sobrien	{
25090091Sobrien		char buf[sizeof(statp->defdname)], *cp;
25118334Speter		int ret;
25290091Sobrien
25390091Sobrien		if ((ret = sysinfo(SI_SRPC_DOMAIN, buf, sizeof(buf))) > 0 &&
25496283Sobrien			(unsigned int)ret <= sizeof(buf)) {
25590091Sobrien			if (buf[0] == '+')
25690091Sobrien				buf[0] = '.';
25796283Sobrien			cp = strchr(buf, '.');
25890091Sobrien			cp = (cp == NULL) ? buf : (cp + 1);
25996283Sobrien			strncpy(statp->defdname, cp,
26090091Sobrien				sizeof(statp->defdname) - 1);
26196283Sobrien			statp->defdname[sizeof(statp->defdname) - 1] = '\0';
26296283Sobrien		}
26396283Sobrien	}
26496283Sobrien#endif	/* SOLARIS2 */
26590091Sobrien
26690091Sobrien	/* Allow user to override the local domain definition */
26790091Sobrien	if (issetugid() == 0 && (cp = getenv("LOCALDOMAIN")) != NULL) {
26890091Sobrien		(void)strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
26990091Sobrien		statp->defdname[sizeof(statp->defdname) - 1] = '\0';
27090091Sobrien		haveenv++;
27190091Sobrien
27290091Sobrien		/*
27390091Sobrien		 * Set search list to be blank-separated strings
27490091Sobrien		 * from rest of env value.  Permits users of LOCALDOMAIN
27552268Sobrien		 * to still have a search list, and anyone to set the
27690091Sobrien		 * one that they want to use as an individual (even more
27790091Sobrien		 * important now that the rfc1535 stuff restricts searches)
27852268Sobrien		 */
27990091Sobrien		cp = statp->defdname;
28090091Sobrien		pp = statp->dnsrch;
28190091Sobrien		*pp++ = cp;
28290091Sobrien		for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) {
28390091Sobrien			if (*cp == '\n')	/*%< silly backwards compat */
28490091Sobrien				break;
28590091Sobrien			else if (*cp == ' ' || *cp == '\t') {
28690091Sobrien				*cp = 0;
28790091Sobrien				n = 1;
28890091Sobrien			} else if (n) {
28990091Sobrien				*pp++ = cp;
29090091Sobrien				n = 0;
29190091Sobrien				havesearch = 1;
29290091Sobrien			}
29390091Sobrien		}
29490091Sobrien		/* null terminate last domain if there are excess */
29552268Sobrien		while (*cp != '\0' && *cp != ' ' && *cp != '\t' && *cp != '\n')
29690091Sobrien			cp++;
29790091Sobrien		*cp = '\0';
29890091Sobrien		*pp++ = 0;
29990091Sobrien	}
30090091Sobrien
30190091Sobrien#define	MATCH(line, name) \
30290091Sobrien	(!strncmp(line, name, sizeof(name) - 1) && \
30390091Sobrien	(line[sizeof(name) - 1] == ' ' || \
30490091Sobrien	 line[sizeof(name) - 1] == '\t'))
30590091Sobrien
30690091Sobrien	nserv = 0;
30790091Sobrien	if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) {
30890091Sobrien	    /* read the config file */
30990091Sobrien	    while (fgets(buf, sizeof(buf), fp) != NULL) {
31090091Sobrien		/* skip comments */
31190091Sobrien		if (*buf == ';' || *buf == '#')
31290091Sobrien			continue;
31390091Sobrien		/* read default domain name */
31490091Sobrien		if (MATCH(buf, "domain")) {
31590091Sobrien		    if (haveenv)	/*%< skip if have from environ */
31618334Speter			    continue;
31718334Speter		    cp = buf + sizeof("domain") - 1;
31890091Sobrien		    while (*cp == ' ' || *cp == '\t')
31918334Speter			    cp++;
32018334Speter		    if ((*cp == '\0') || (*cp == '\n'))
32118334Speter			    continue;
32218334Speter		    strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
32318334Speter		    statp->defdname[sizeof(statp->defdname) - 1] = '\0';
32418334Speter		    if ((cp = strpbrk(statp->defdname, " \t\n")) != NULL)
32518334Speter			    *cp = '\0';
32618334Speter		    havesearch = 0;
32718334Speter		    continue;
32852268Sobrien		}
32990091Sobrien		/* set search list */
33018334Speter		if (MATCH(buf, "search")) {
33118334Speter		    if (haveenv)	/*%< skip if have from environ */
33252268Sobrien			    continue;
33318334Speter		    cp = buf + sizeof("search") - 1;
33418334Speter		    while (*cp == ' ' || *cp == '\t')
33518334Speter			    cp++;
33618334Speter		    if ((*cp == '\0') || (*cp == '\n'))
33790091Sobrien			    continue;
33890091Sobrien		    strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
33990091Sobrien		    statp->defdname[sizeof(statp->defdname) - 1] = '\0';
34090091Sobrien		    if ((cp = strchr(statp->defdname, '\n')) != NULL)
34118334Speter			    *cp = '\0';
34218334Speter		    /*
34318334Speter		     * Set search list to be blank-separated strings
34418334Speter		     * on rest of line.
34518334Speter		     */
34690091Sobrien		    cp = statp->defdname;
34718334Speter		    pp = statp->dnsrch;
34890091Sobrien		    *pp++ = cp;
34990091Sobrien		    for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) {
35090091Sobrien			    if (*cp == ' ' || *cp == '\t') {
35190091Sobrien				    *cp = 0;
35290091Sobrien				    n = 1;
35390091Sobrien			    } else if (n) {
35490091Sobrien				    *pp++ = cp;
35590091Sobrien				    n = 0;
35690091Sobrien			    }
35790091Sobrien		    }
35890091Sobrien		    /* null terminate last domain if there are excess */
35990091Sobrien		    while (*cp != '\0' && *cp != ' ' && *cp != '\t')
36090091Sobrien			    cp++;
36190091Sobrien		    *cp = '\0';
36290091Sobrien		    *pp++ = 0;
36390091Sobrien		    havesearch = 1;
36418334Speter		    continue;
36518334Speter		}
36618334Speter		/* read nameservers to query */
36790091Sobrien		if (MATCH(buf, "nameserver") && nserv < maxns) {
36890091Sobrien		    struct addrinfo hints, *ai;
36990091Sobrien		    char sbuf[NI_MAXSERV];
37090091Sobrien		    const size_t minsiz =
37118334Speter		        sizeof(statp->_u._ext.ext->nsaddrs[0]);
37218334Speter
37318334Speter		    cp = buf + sizeof("nameserver") - 1;
37418334Speter		    while (*cp == ' ' || *cp == '\t')
37518334Speter			cp++;
37618334Speter		    cp[strcspn(cp, ";# \t\n")] = '\0';
37718334Speter		    if ((*cp != '\0') && (*cp != '\n')) {
37818334Speter			memset(&hints, 0, sizeof(hints));
37918334Speter			hints.ai_family = PF_UNSPEC;
38018334Speter			hints.ai_socktype = SOCK_DGRAM;	/*dummy*/
38118334Speter			hints.ai_flags = AI_NUMERICHOST;
38218334Speter			sprintf(sbuf, "%u", NAMESERVER_PORT);
38318334Speter			if (getaddrinfo(cp, sbuf, &hints, &ai) == 0 &&
38490091Sobrien			    ai->ai_addrlen <= minsiz) {
38518334Speter			    if (statp->_u._ext.ext != NULL) {
38618334Speter				memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
38752268Sobrien				    ai->ai_addr, ai->ai_addrlen);
38818334Speter			    }
38990091Sobrien			    if (ai->ai_addrlen <=
39090091Sobrien			        sizeof(statp->nsaddr_list[nserv])) {
39118334Speter				memcpy(&statp->nsaddr_list[nserv],
39218334Speter				    ai->ai_addr, ai->ai_addrlen);
39318334Speter			    } else
39418334Speter				statp->nsaddr_list[nserv].sin_family = 0;
39518334Speter			    freeaddrinfo(ai);
39618334Speter			    nserv++;
39790091Sobrien			}
39890091Sobrien		    }
39918334Speter		    continue;
40096283Sobrien		}
40196283Sobrien#ifdef RESOLVSORT
40296283Sobrien		if (MATCH(buf, "sortlist")) {
40396283Sobrien		    struct in_addr a;
40496283Sobrien		    struct in6_addr a6;
40596283Sobrien		    int m, i;
40696283Sobrien		    u_char *u;
40796283Sobrien		    struct __res_state_ext *ext = statp->_u._ext.ext;
40896283Sobrien
40996283Sobrien		    cp = buf + sizeof("sortlist") - 1;
41096283Sobrien		    while (nsort < MAXRESOLVSORT) {
41196283Sobrien			while (*cp == ' ' || *cp == '\t')
41296283Sobrien			    cp++;
41396283Sobrien			if (*cp == '\0' || *cp == '\n' || *cp == ';')
41418334Speter			    break;
41596283Sobrien			net = cp;
41696283Sobrien			while (*cp && !ISSORTMASK(*cp) && *cp != ';' &&
41796283Sobrien			       isascii(*cp) && !isspace((unsigned char)*cp))
41896283Sobrien				cp++;
41996283Sobrien			n = *cp;
42096283Sobrien			*cp = 0;
42196283Sobrien			if (inet_aton(net, &a)) {
42296283Sobrien			    statp->sort_list[nsort].addr = a;
42396283Sobrien			    if (ISSORTMASK(n)) {
42490091Sobrien				*cp++ = n;
42518334Speter				net = cp;
42618334Speter				while (*cp && *cp != ';' &&
42718334Speter					isascii(*cp) &&
42818334Speter					!isspace((unsigned char)*cp))
42990091Sobrien				    cp++;
43018334Speter				n = *cp;
43118334Speter				*cp = 0;
43290091Sobrien				if (inet_aton(net, &a)) {
43390091Sobrien				    statp->sort_list[nsort].mask = a.s_addr;
43418334Speter				} else {
43518334Speter				    statp->sort_list[nsort].mask =
43618334Speter					net_mask(statp->sort_list[nsort].addr);
43790091Sobrien				}
43890091Sobrien			    } else {
43990091Sobrien				statp->sort_list[nsort].mask =
44090091Sobrien				    net_mask(statp->sort_list[nsort].addr);
44190091Sobrien			    }
44290091Sobrien			    ext->sort_list[nsort].af = AF_INET;
44390091Sobrien			    ext->sort_list[nsort].addr.ina =
44490091Sobrien				statp->sort_list[nsort].addr;
44590091Sobrien			    ext->sort_list[nsort].mask.ina.s_addr =
44690091Sobrien				statp->sort_list[nsort].mask;
44790091Sobrien			    nsort++;
44890091Sobrien			}
44990091Sobrien			else if (inet_pton(AF_INET6, net, &a6) == 1) {
45090091Sobrien
45190091Sobrien			    ext->sort_list[nsort].af = AF_INET6;
45290091Sobrien			    ext->sort_list[nsort].addr.in6a = a6;
45390091Sobrien			    u = (u_char *)&ext->sort_list[nsort].mask.in6a;
45490091Sobrien			    *cp++ = n;
45590091Sobrien			    net = cp;
45690091Sobrien			    while (*cp && *cp != ';' &&
45790091Sobrien				    isascii(*cp) && !isspace(*cp))
45890091Sobrien				cp++;
45990091Sobrien			    m = n;
46090091Sobrien			    n = *cp;
46190091Sobrien			    *cp = 0;
46290091Sobrien			    switch (m) {
46390091Sobrien			    case '/':
46490091Sobrien				m = atoi(net);
46590091Sobrien				break;
46690091Sobrien			    case '&':
46790091Sobrien				if (inet_pton(AF_INET6, net, u) == 1) {
46890091Sobrien				    m = -1;
46990091Sobrien				    break;
47090091Sobrien				}
47190091Sobrien				/*FALLTHROUGH*/
47290091Sobrien			    default:
47390091Sobrien				m = sizeof(struct in6_addr) * CHAR_BIT;
47490091Sobrien				break;
47590091Sobrien			    }
47690091Sobrien			    if (m >= 0) {
47790091Sobrien				for (i = 0; i < sizeof(struct in6_addr); i++) {
47890091Sobrien				    if (m <= 0) {
47990091Sobrien					*u = 0;
48090091Sobrien				    } else {
48190091Sobrien					m -= CHAR_BIT;
48290091Sobrien					*u = (u_char)~0;
48390091Sobrien					if (m < 0)
48490091Sobrien					    *u <<= -m;
48590091Sobrien				    }
48690091Sobrien				    u++;
48790091Sobrien				}
48890091Sobrien			    }
48990091Sobrien			    statp->sort_list[nsort].addr.s_addr =
49090091Sobrien				(u_int32_t)0xffffffff;
49190091Sobrien			    statp->sort_list[nsort].mask =
49290091Sobrien				(u_int32_t)0xffffffff;
49390091Sobrien			    nsort++;
49490091Sobrien			}
49590091Sobrien			*cp = n;
49690091Sobrien		    }
49790091Sobrien		    continue;
49890091Sobrien		}
49990091Sobrien#endif
50090091Sobrien		if (MATCH(buf, "options")) {
50190091Sobrien		    res_setoptions(statp, buf + sizeof("options") - 1, "conf");
50290091Sobrien		    continue;
50318334Speter		}
50418334Speter	    }
50518334Speter	    if (nserv > 0)
50690091Sobrien		statp->nscount = nserv;
50790091Sobrien#ifdef RESOLVSORT
50852518Sobrien	    statp->nsort = nsort;
50918334Speter#endif
51018334Speter	    (void) fclose(fp);
51152268Sobrien	}
51290091Sobrien/*
51390091Sobrien * Last chance to get a nameserver.  This should not normally
51418334Speter * be necessary
51518334Speter */
51690091Sobrien#ifdef NO_RESOLV_CONF
51718334Speter	if(nserv == 0)
51890091Sobrien		nserv = get_nameservers(statp);
51918334Speter#endif
52018334Speter
52118334Speter	if (statp->defdname[0] == 0 &&
52290091Sobrien	    gethostname(buf, sizeof(statp->defdname) - 1) == 0 &&
52390091Sobrien	    (cp = strchr(buf, '.')) != NULL)
52490091Sobrien		strcpy(statp->defdname, cp + 1);
52590091Sobrien
52690091Sobrien	/* find components of local domain that might be searched */
52790091Sobrien	if (havesearch == 0) {
52890091Sobrien		pp = statp->dnsrch;
52990091Sobrien		*pp++ = statp->defdname;
53090091Sobrien		*pp = NULL;
53118334Speter
53218334Speter		dots = 0;
53390091Sobrien		for (cp = statp->defdname; *cp; cp++)
53418334Speter			dots += (*cp == '.');
53518334Speter
53618334Speter		cp = statp->defdname;
53718334Speter		while (pp < statp->dnsrch + MAXDFLSRCH) {
53818334Speter			if (dots < LOCALDOMAINPARTS)
53990091Sobrien				break;
54018334Speter			cp = strchr(cp, '.') + 1;    /*%< we know there is one */
54190091Sobrien			*pp++ = cp;
54290091Sobrien			dots--;
54390091Sobrien		}
54490091Sobrien		*pp = NULL;
54518334Speter#ifdef DEBUG
54652268Sobrien		if (statp->options & RES_DEBUG) {
54718334Speter			printf(";; res_init()... default dnsrch list:\n");
54890091Sobrien			for (pp = statp->dnsrch; *pp; pp++)
54918334Speter				printf(";;\t%s\n", *pp);
55090091Sobrien			printf(";;\t..END..\n");
55118334Speter		}
55218334Speter#endif
55390091Sobrien	}
55418334Speter
55518334Speter	if (issetugid())
55618334Speter		statp->options |= RES_NOALIASES;
55752518Sobrien	else if ((cp = getenv("RES_OPTIONS")) != NULL)
55852518Sobrien		res_setoptions(statp, cp, "env");
55918334Speter	statp->options |= RES_INIT;
56052518Sobrien	return (statp->res_h_errno);
56190091Sobrien}
56290091Sobrien
56352518Sobrienstatic void
56452518Sobrienres_setoptions(res_state statp, const char *options, const char *source)
56552518Sobrien{
56652518Sobrien	const char *cp = options;
56752518Sobrien	int i;
56852518Sobrien#ifndef _LIBC
56952518Sobrien	struct __res_state_ext *ext = statp->_u._ext.ext;
57052518Sobrien#endif
57118334Speter
57218334Speter#ifdef DEBUG
57318334Speter	if (statp->options & RES_DEBUG)
57418334Speter		printf(";; res_setoptions(\"%s\", \"%s\")...\n",
57518334Speter		       options, source);
57618334Speter#endif
57718334Speter	while (*cp) {
57818334Speter		/* skip leading and inner runs of spaces */
57918334Speter		while (*cp == ' ' || *cp == '\t')
58052518Sobrien			cp++;
58190091Sobrien		/* search for and process individual options */
58252518Sobrien		if (!strncmp(cp, "ndots:", sizeof("ndots:") - 1)) {
58352518Sobrien			i = atoi(cp + sizeof("ndots:") - 1);
58490091Sobrien			if (i <= RES_MAXNDOTS)
58590091Sobrien				statp->ndots = i;
58690091Sobrien			else
58790091Sobrien				statp->ndots = RES_MAXNDOTS;
58890091Sobrien#ifdef DEBUG
58990091Sobrien			if (statp->options & RES_DEBUG)
59090091Sobrien				printf(";;\tndots=%d\n", statp->ndots);
59190091Sobrien#endif
59290091Sobrien		} else if (!strncmp(cp, "timeout:", sizeof("timeout:") - 1)) {
59390091Sobrien			i = atoi(cp + sizeof("timeout:") - 1);
59490091Sobrien			if (i <= RES_MAXRETRANS)
59590091Sobrien				statp->retrans = i;
59690091Sobrien			else
59718334Speter				statp->retrans = RES_MAXRETRANS;
59818334Speter#ifdef DEBUG
59918334Speter			if (statp->options & RES_DEBUG)
60018334Speter				printf(";;\ttimeout=%d\n", statp->retrans);
60118334Speter#endif
60218334Speter#ifdef	SOLARIS2
60390091Sobrien		} else if (!strncmp(cp, "retrans:", sizeof("retrans:") - 1)) {
60418334Speter			/*
60590091Sobrien		 	 * For backward compatibility, 'retrans' is
60618334Speter		 	 * supported as an alias for 'timeout', though
60718334Speter		 	 * without an imposed maximum.
60818334Speter		 	 */
60918334Speter			statp->retrans = atoi(cp + sizeof("retrans:") - 1);
61018334Speter		} else if (!strncmp(cp, "retry:", sizeof("retry:") - 1)){
61118334Speter			/*
61218334Speter			 * For backward compatibility, 'retry' is
61318334Speter			 * supported as an alias for 'attempts', though
61418334Speter			 * without an imposed maximum.
61590091Sobrien			 */
61618334Speter			statp->retry = atoi(cp + sizeof("retry:") - 1);
61718334Speter#endif	/* SOLARIS2 */
61818334Speter		} else if (!strncmp(cp, "attempts:", sizeof("attempts:") - 1)){
61918334Speter			i = atoi(cp + sizeof("attempts:") - 1);
62018334Speter			if (i <= RES_MAXRETRY)
62190091Sobrien				statp->retry = i;
62218334Speter			else
62318334Speter				statp->retry = RES_MAXRETRY;
62490091Sobrien#ifdef DEBUG
62518334Speter			if (statp->options & RES_DEBUG)
62618334Speter				printf(";;\tattempts=%d\n", statp->retry);
62752268Sobrien#endif
62818334Speter		} else if (!strncmp(cp, "debug", sizeof("debug") - 1)) {
62990091Sobrien#ifdef DEBUG
63090091Sobrien			if (!(statp->options & RES_DEBUG)) {
63118334Speter				printf(";; res_setoptions(\"%s\", \"%s\")..\n",
63218334Speter				       options, source);
63318334Speter				statp->options |= RES_DEBUG;
63418334Speter			}
63590091Sobrien			printf(";;\tdebug\n");
63690091Sobrien#endif
63718334Speter		} else if (!strncmp(cp, "no_tld_query",
63890091Sobrien				    sizeof("no_tld_query") - 1) ||
63990091Sobrien			   !strncmp(cp, "no-tld-query",
64018334Speter				    sizeof("no-tld-query") - 1)) {
64152268Sobrien			statp->options |= RES_NOTLDQUERY;
64218334Speter		} else if (!strncmp(cp, "inet6", sizeof("inet6") - 1)) {
64318334Speter			statp->options |= RES_USE_INET6;
64490091Sobrien		} else if (!strncmp(cp, "insecure1", sizeof("insecure1") - 1)) {
64518334Speter		       statp->options |= RES_INSECURE1;
64618334Speter		} else if (!strncmp(cp, "insecure2", sizeof("insecure2") - 1)) {
64718334Speter		       statp->options |= RES_INSECURE2;
64818334Speter		} else if (!strncmp(cp, "rotate", sizeof("rotate") - 1)) {
64918334Speter			statp->options |= RES_ROTATE;
65018334Speter		} else if (!strncmp(cp, "no-check-names",
65118334Speter				    sizeof("no-check-names") - 1)) {
65218334Speter			statp->options |= RES_NOCHECKNAME;
65318334Speter		}
65418334Speter#ifdef RES_USE_EDNS0
65518334Speter		else if (!strncmp(cp, "edns0", sizeof("edns0") - 1)) {
65618334Speter			statp->options |= RES_USE_EDNS0;
65752268Sobrien		}
65852268Sobrien#endif
65952268Sobrien#ifndef _LIBC
66090091Sobrien		else if (!strncmp(cp, "dname", sizeof("dname") - 1)) {
66118334Speter			statp->options |= RES_USE_DNAME;
66252518Sobrien		}
66352518Sobrien		else if (!strncmp(cp, "nibble:", sizeof("nibble:") - 1)) {
66490091Sobrien			if (ext == NULL)
66552518Sobrien				goto skip;
66618334Speter			cp += sizeof("nibble:") - 1;
66752268Sobrien			i = MIN(strcspn(cp, " \t"), sizeof(ext->nsuffix) - 1);
66818334Speter			strncpy(ext->nsuffix, cp, i);
66952518Sobrien			ext->nsuffix[i] = '\0';
67018334Speter		}
67190091Sobrien		else if (!strncmp(cp, "nibble2:", sizeof("nibble2:") - 1)) {
67218334Speter			if (ext == NULL)
67318334Speter				goto skip;
67418334Speter			cp += sizeof("nibble2:") - 1;
67518334Speter			i = MIN(strcspn(cp, " \t"), sizeof(ext->nsuffix2) - 1);
67618334Speter			strncpy(ext->nsuffix2, cp, i);
67718334Speter			ext->nsuffix2[i] = '\0';
67818334Speter		}
67952518Sobrien		else if (!strncmp(cp, "v6revmode:", sizeof("v6revmode:") - 1)) {
68052518Sobrien			cp += sizeof("v6revmode:") - 1;
68190091Sobrien			/* "nibble" and "bitstring" used to be valid */
68290091Sobrien			if (!strncmp(cp, "single", sizeof("single") - 1)) {
68352518Sobrien				statp->options |= RES_NO_NIBBLE2;
68452518Sobrien			} else if (!strncmp(cp, "both", sizeof("both") - 1)) {
68552518Sobrien				statp->options &=
68690091Sobrien					 ~RES_NO_NIBBLE2;
68752518Sobrien			}
68852518Sobrien		}
68952518Sobrien#endif
69052518Sobrien		else {
69152518Sobrien			/* XXX - print a warning here? */
69252518Sobrien		}
69318334Speter#ifndef _LIBC
69452518Sobrien   skip:
69552518Sobrien#endif
69690091Sobrien		/* skip to next run of spaces */
69752518Sobrien		while (*cp && *cp != ' ' && *cp != '\t')
69852518Sobrien			cp++;
69952518Sobrien	}
70052518Sobrien}
70152518Sobrien
70252518Sobrien#ifdef RESOLVSORT
70352518Sobrien/* XXX - should really support CIDR which means explicit masks always. */
70452518Sobrienstatic u_int32_t
70518334Speternet_mask(in)		/*!< XXX - should really use system's version of this  */
70652518Sobrien	struct in_addr in;
70718334Speter{
70818334Speter	u_int32_t i = ntohl(in.s_addr);
70918334Speter
71018334Speter	if (IN_CLASSA(i))
71118334Speter		return (htonl(IN_CLASSA_NET));
71218334Speter	else if (IN_CLASSB(i))
71318334Speter		return (htonl(IN_CLASSB_NET));
71490091Sobrien	return (htonl(IN_CLASSC_NET));
71518334Speter}
71652518Sobrien#endif
71752268Sobrien
71818334Speteru_int
71918334Speterres_randomid(void) {
72018334Speter	struct timeval now;
72190091Sobrien
72218334Speter	gettimeofday(&now, NULL);
72318334Speter	return (0xffff & (now.tv_sec ^ now.tv_usec ^ getpid()));
72418334Speter}
72518334Speter
72652268Sobrien/*%
72752268Sobrien * This routine is for closing the socket if a virtual circuit is used and
72852268Sobrien * the program wants to close it.  This provides support for endhostent()
72952518Sobrien * which expects to close the socket.
73018334Speter *
73118334Speter * This routine is not expected to be user visible.
73290091Sobrien */
73318334Spetervoid
73418334Speterres_nclose(res_state statp) {
73518334Speter	int ns;
73652268Sobrien
73752268Sobrien	if (statp->_vcsock >= 0) {
73818334Speter		(void) _close(statp->_vcsock);
73918334Speter		statp->_vcsock = -1;
74018334Speter		statp->_flags &= ~(RES_F_VC | RES_F_CONN);
74118334Speter	}
74218334Speter	for (ns = 0; ns < statp->_u._ext.nscount; ns++) {
74318334Speter		if (statp->_u._ext.nssocks[ns] != -1) {
74418334Speter			(void) _close(statp->_u._ext.nssocks[ns]);
74518334Speter			statp->_u._ext.nssocks[ns] = -1;
74690091Sobrien		}
74718334Speter	}
74818334Speter}
74918334Speter
75052268Sobrienvoid
75152268Sobrienres_ndestroy(res_state statp) {
75290091Sobrien	res_nclose(statp);
75352268Sobrien	if (statp->_u._ext.ext != NULL)
75452518Sobrien		free(statp->_u._ext.ext);
75552518Sobrien	statp->options &= ~RES_INIT;
75652518Sobrien	statp->_u._ext.ext = NULL;
75752268Sobrien}
75852518Sobrien
75952518Sobrien#ifndef _LIBC
76052518Sobrienconst char *
76152763Sobrienres_get_nibblesuffix(res_state statp) {
76290091Sobrien	if (statp->_u._ext.ext)
76352518Sobrien		return (statp->_u._ext.ext->nsuffix);
76452763Sobrien	return ("ip6.arpa");
76552763Sobrien}
76652763Sobrien
76752518Sobrienconst char *
76852518Sobrienres_get_nibblesuffix2(res_state statp) {
76952518Sobrien	if (statp->_u._ext.ext)
77052518Sobrien		return (statp->_u._ext.ext->nsuffix2);
77118334Speter	return ("ip6.int");
77218334Speter}
77318334Speter#endif
77418334Speter
77518334Spetervoid
77618334Speterres_setservers(res_state statp, const union res_sockaddr_union *set, int cnt) {
77718334Speter	int i, nserv;
77818334Speter	size_t size;
77918334Speter
78018334Speter	/* close open servers */
78118334Speter	res_nclose(statp);
78218334Speter
78352268Sobrien	/* cause rtt times to be forgotten */
78418334Speter	statp->_u._ext.nscount = 0;
78518334Speter
78618334Speter	nserv = 0;
78718334Speter	for (i = 0; i < cnt && nserv < MAXNS; i++) {
78818334Speter		switch (set->sin.sin_family) {
78918334Speter		case AF_INET:
79018334Speter			size = sizeof(set->sin);
79118334Speter			if (statp->_u._ext.ext)
79218334Speter				memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
79318334Speter					&set->sin, size);
79418334Speter			if (size <= sizeof(statp->nsaddr_list[nserv]))
79518334Speter				memcpy(&statp->nsaddr_list[nserv],
79618334Speter					&set->sin, size);
79718334Speter			else
79818334Speter				statp->nsaddr_list[nserv].sin_family = 0;
79990091Sobrien			nserv++;
80090091Sobrien			break;
80118334Speter
80218334Speter#ifdef HAS_INET6_STRUCTS
80318334Speter		case AF_INET6:
80418334Speter			size = sizeof(set->sin6);
80518334Speter			if (statp->_u._ext.ext)
80618334Speter				memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
80752268Sobrien					&set->sin6, size);
80852268Sobrien			if (size <= sizeof(statp->nsaddr_list[nserv]))
80952268Sobrien				memcpy(&statp->nsaddr_list[nserv],
81052268Sobrien					&set->sin6, size);
81152268Sobrien			else
81218334Speter				statp->nsaddr_list[nserv].sin_family = 0;
81318334Speter			nserv++;
81418334Speter			break;
81518334Speter#endif
81618334Speter
81752268Sobrien		default:
81852268Sobrien			break;
81952268Sobrien		}
82052268Sobrien		set++;
82152268Sobrien	}
82252518Sobrien	statp->nscount = nserv;
82390091Sobrien
82490091Sobrien}
82590091Sobrien
82690091Sobrienint
82790091Sobrienres_getservers(res_state statp, union res_sockaddr_union *set, int cnt) {
82890091Sobrien	int i;
82990091Sobrien	size_t size;
83090091Sobrien	u_int16_t family;
83190091Sobrien
83290091Sobrien	for (i = 0; i < statp->nscount && i < cnt; i++) {
83390091Sobrien		if (statp->_u._ext.ext)
83490091Sobrien			family = statp->_u._ext.ext->nsaddrs[i].sin.sin_family;
83590091Sobrien		else
83690091Sobrien			family = statp->nsaddr_list[i].sin_family;
83790091Sobrien
83890091Sobrien		switch (family) {
83990091Sobrien		case AF_INET:
84018334Speter			size = sizeof(set->sin);
84118334Speter			if (statp->_u._ext.ext)
84252518Sobrien				memcpy(&set->sin,
84352518Sobrien				       &statp->_u._ext.ext->nsaddrs[i],
84452518Sobrien				       size);
84552518Sobrien			else
84652518Sobrien				memcpy(&set->sin, &statp->nsaddr_list[i],
84752518Sobrien				       size);
84852518Sobrien			break;
84952518Sobrien
85052518Sobrien#ifdef HAS_INET6_STRUCTS
85152518Sobrien		case AF_INET6:
85252518Sobrien			size = sizeof(set->sin6);
85352518Sobrien			if (statp->_u._ext.ext)
85452268Sobrien				memcpy(&set->sin6,
85596283Sobrien				       &statp->_u._ext.ext->nsaddrs[i],
85696283Sobrien				       size);
85796283Sobrien			else
85896283Sobrien				memcpy(&set->sin6, &statp->nsaddr_list[i],
85952268Sobrien				       size);
86052268Sobrien			break;
86152268Sobrien#endif
86252268Sobrien
86352268Sobrien		default:
86418334Speter			set->sin.sin_family = 0;
86552268Sobrien			break;
86696283Sobrien		}
86796283Sobrien		set++;
86852268Sobrien	}
86952268Sobrien	return (statp->nscount);
87090091Sobrien}
87152268Sobrien
87296283Sobrien/*! \file */
87396283Sobrien