res_init.c revision 156952
1156952Sume/*
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 * 3. All advertising materials mentioning features or use of this software
14156952Sume *    must display the following acknowledgement:
15156952Sume * 	This product includes software developed by the University of
16156952Sume * 	California, Berkeley and its contributors.
17156952Sume * 4. Neither the name of the University nor the names of its contributors
18156952Sume *    may be used to endorse or promote products derived from this software
19156952Sume *    without specific prior written permission.
20156952Sume *
21156952Sume * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22156952Sume * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23156952Sume * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24156952Sume * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25156952Sume * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26156952Sume * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27156952Sume * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28156952Sume * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29156952Sume * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30156952Sume * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31156952Sume * SUCH DAMAGE.
32156952Sume */
33156952Sume
34156952Sume/*
35156952Sume * Portions Copyright (c) 1993 by Digital Equipment Corporation.
36156952Sume *
37156952Sume * Permission to use, copy, modify, and distribute this software for any
38156952Sume * purpose with or without fee is hereby granted, provided that the above
39156952Sume * copyright notice and this permission notice appear in all copies, and that
40156952Sume * the name of Digital Equipment Corporation not be used in advertising or
41156952Sume * publicity pertaining to distribution of the document or software without
42156952Sume * specific, written prior permission.
43156952Sume *
44156952Sume * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
45156952Sume * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
46156952Sume * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
47156952Sume * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
48156952Sume * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
49156952Sume * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
50156952Sume * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
51156952Sume * SOFTWARE.
52156952Sume */
53156952Sume
54156952Sume/*
55156952Sume * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
56156952Sume * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
57156952Sume *
58156952Sume * Permission to use, copy, modify, and distribute this software for any
59156952Sume * purpose with or without fee is hereby granted, provided that the above
60156952Sume * copyright notice and this permission notice appear in all copies.
61156952Sume *
62156952Sume * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
63156952Sume * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
64156952Sume * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
65156952Sume * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
66156952Sume * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
67156952Sume * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
68156952Sume * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
69156952Sume */
70156952Sume
71156952Sume#if defined(LIBC_SCCS) && !defined(lint)
72156952Sumestatic const char sccsid[] = "@(#)res_init.c	8.1 (Berkeley) 6/7/93";
73156952Sumestatic const char rcsid[] = "$Id: res_init.c,v 1.9.2.5.4.5 2005/11/03 00:00:52 marka Exp $";
74156952Sume#endif /* LIBC_SCCS and not lint */
75156952Sume
76156952Sume#include "port_before.h"
77156952Sume
78156952Sume#include <sys/types.h>
79156952Sume#include <sys/param.h>
80156952Sume#include <sys/socket.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
94156952Sume#include "port_after.h"
95156952Sume
96156952Sume/* ensure that sockaddr_in6 and IN6ADDR_ANY_INIT are declared / defined */
97156952Sume#include <resolv.h>
98156952Sume
99156952Sume#include "res_private.h"
100156952Sume
101156952Sume/* Options.  Should all be left alone. */
102156952Sume#define RESOLVSORT
103156952Sume#define DEBUG
104156952Sume
105156952Sume#ifdef SOLARIS2
106156952Sume#include <sys/systeminfo.h>
107156952Sume#endif
108156952Sume
109156952Sumestatic void res_setoptions __P((res_state, const char *, const char *));
110156952Sume
111156952Sume#ifdef RESOLVSORT
112156952Sumestatic const char sort_mask[] = "/&";
113156952Sume#define ISSORTMASK(ch) (strchr(sort_mask, ch) != NULL)
114156952Sumestatic u_int32_t net_mask __P((struct in_addr));
115156952Sume#endif
116156952Sume
117156952Sume#if !defined(isascii)	/* XXX - could be a function */
118156952Sume# define isascii(c) (!(c & 0200))
119156952Sume#endif
120156952Sume
121156952Sume/*
122156952Sume * Resolver state default settings.
123156952Sume */
124156952Sume
125156952Sume/*
126156952Sume * Set up default settings.  If the configuration file exist, the values
127156952Sume * there will have precedence.  Otherwise, the server address is set to
128156952Sume * INADDR_ANY and the default domain name comes from the gethostname().
129156952Sume *
130156952Sume * An interrim version of this code (BIND 4.9, pre-4.4BSD) used 127.0.0.1
131156952Sume * rather than INADDR_ANY ("0.0.0.0") as the default name server address
132156952Sume * since it was noted that INADDR_ANY actually meant ``the first interface
133156952Sume * you "ifconfig"'d at boot time'' and if this was a SLIP or PPP interface,
134156952Sume * it had to be "up" in order for you to reach your own name server.  It
135156952Sume * was later decided that since the recommended practice is to always
136156952Sume * install local static routes through 127.0.0.1 for all your network
137156952Sume * interfaces, that we could solve this problem without a code change.
138156952Sume *
139156952Sume * The configuration file should always be used, since it is the only way
140156952Sume * to specify a default domain.  If you are running a server on your local
141156952Sume * machine, you should say "nameserver 0.0.0.0" or "nameserver 127.0.0.1"
142156952Sume * in the configuration file.
143156952Sume *
144156952Sume * Return 0 if completes successfully, -1 on error
145156952Sume */
146156952Sumeint
147156952Sumeres_ninit(res_state statp) {
148156952Sume	extern int __res_vinit(res_state, int);
149156952Sume
150156952Sume	return (__res_vinit(statp, 0));
151156952Sume}
152156952Sume
153156952Sume/* This function has to be reachable by res_data.c but not publically. */
154156952Sumeint
155156952Sume__res_vinit(res_state statp, int preinit) {
156156952Sume	register FILE *fp;
157156952Sume	register char *cp, **pp;
158156952Sume	register int n;
159156952Sume	char buf[BUFSIZ];
160156952Sume	int nserv = 0;    /* number of nameserver records read from file */
161156952Sume	int haveenv = 0;
162156952Sume	int havesearch = 0;
163156952Sume#ifdef RESOLVSORT
164156952Sume	int nsort = 0;
165156952Sume	char *net;
166156952Sume#endif
167156952Sume	int dots;
168156952Sume	union res_sockaddr_union u[2];
169156952Sume
170156952Sume	if (statp->_u._ext.ext != NULL)
171156952Sume		res_ndestroy(statp);
172156952Sume
173156952Sume	if (!preinit) {
174156952Sume		statp->retrans = RES_TIMEOUT;
175156952Sume		statp->retry = RES_DFLRETRY;
176156952Sume		statp->options = RES_DEFAULT;
177156952Sume		statp->id = res_randomid();
178156952Sume	}
179156952Sume
180156952Sume	memset(u, 0, sizeof(u));
181156952Sume#ifdef USELOOPBACK
182156952Sume	u[nserv].sin.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1);
183156952Sume#else
184156952Sume	u[nserv].sin.sin_addr.s_addr = INADDR_ANY;
185156952Sume#endif
186156952Sume	u[nserv].sin.sin_family = AF_INET;
187156952Sume	u[nserv].sin.sin_port = htons(NAMESERVER_PORT);
188156952Sume#ifdef HAVE_SA_LEN
189156952Sume	u[nserv].sin.sin_len = sizeof(struct sockaddr_in);
190156952Sume#endif
191156952Sume	nserv++;
192156952Sume#ifdef HAS_INET6_STRUCTS
193156952Sume#ifdef USELOOPBACK
194156952Sume	u[nserv].sin6.sin6_addr = in6addr_loopback;
195156952Sume#else
196156952Sume	u[nserv].sin6.sin6_addr = in6addr_any;
197156952Sume#endif
198156952Sume	u[nserv].sin6.sin6_family = AF_INET6;
199156952Sume	u[nserv].sin6.sin6_port = htons(NAMESERVER_PORT);
200156952Sume#ifdef HAVE_SA_LEN
201156952Sume	u[nserv].sin6.sin6_len = sizeof(struct sockaddr_in6);
202156952Sume#endif
203156952Sume	nserv++;
204156952Sume#endif
205156952Sume	statp->nscount = 0;
206156952Sume	statp->ndots = 1;
207156952Sume	statp->pfcode = 0;
208156952Sume	statp->_vcsock = -1;
209156952Sume	statp->_flags = 0;
210156952Sume	statp->qhook = NULL;
211156952Sume	statp->rhook = NULL;
212156952Sume	statp->_u._ext.nscount = 0;
213156952Sume	statp->_u._ext.ext = malloc(sizeof(*statp->_u._ext.ext));
214156952Sume	if (statp->_u._ext.ext != NULL) {
215156952Sume	        memset(statp->_u._ext.ext, 0, sizeof(*statp->_u._ext.ext));
216156952Sume		statp->_u._ext.ext->nsaddrs[0].sin = statp->nsaddr;
217156952Sume		strcpy(statp->_u._ext.ext->nsuffix, "ip6.arpa");
218156952Sume		strcpy(statp->_u._ext.ext->nsuffix2, "ip6.int");
219156952Sume	} else
220156952Sume		return (-1);
221156952Sume#ifdef RESOLVSORT
222156952Sume	statp->nsort = 0;
223156952Sume#endif
224156952Sume	res_setservers(statp, u, nserv);
225156952Sume
226156952Sume#ifdef	SOLARIS2
227156952Sume	/*
228156952Sume	 * The old libresolv derived the defaultdomain from NIS/NIS+.
229156952Sume	 * We want to keep this behaviour
230156952Sume	 */
231156952Sume	{
232156952Sume		char buf[sizeof(statp->defdname)], *cp;
233156952Sume		int ret;
234156952Sume
235156952Sume		if ((ret = sysinfo(SI_SRPC_DOMAIN, buf, sizeof(buf))) > 0 &&
236156952Sume			(unsigned int)ret <= sizeof(buf)) {
237156952Sume			if (buf[0] == '+')
238156952Sume				buf[0] = '.';
239156952Sume			cp = strchr(buf, '.');
240156952Sume			if (cp == NULL) {
241156952Sume				if (strlcpy(statp->defdname, buf,
242156952Sume					sizeof(statp->defdname))
243156952Sume					>= sizeof(statp->defdname))
244156952Sume					goto freedata;
245156952Sume			} else {
246156952Sume				if (strlcpy(statp->defdname, cp+1,
247156952Sume					sizeof(statp->defdname))
248156952Sume					 >= sizeof(statp->defdname))
249156952Sume					goto freedata;
250156952Sume			}
251156952Sume		}
252156952Sume	}
253156952Sume#endif	/* SOLARIS2 */
254156952Sume
255156952Sume	/* Allow user to override the local domain definition */
256156952Sume	if ((cp = getenv("LOCALDOMAIN")) != NULL) {
257156952Sume		(void)strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
258156952Sume		statp->defdname[sizeof(statp->defdname) - 1] = '\0';
259156952Sume		haveenv++;
260156952Sume
261156952Sume		/*
262156952Sume		 * Set search list to be blank-separated strings
263156952Sume		 * from rest of env value.  Permits users of LOCALDOMAIN
264156952Sume		 * to still have a search list, and anyone to set the
265156952Sume		 * one that they want to use as an individual (even more
266156952Sume		 * important now that the rfc1535 stuff restricts searches)
267156952Sume		 */
268156952Sume		cp = statp->defdname;
269156952Sume		pp = statp->dnsrch;
270156952Sume		*pp++ = cp;
271156952Sume		for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) {
272156952Sume			if (*cp == '\n')	/* silly backwards compat */
273156952Sume				break;
274156952Sume			else if (*cp == ' ' || *cp == '\t') {
275156952Sume				*cp = 0;
276156952Sume				n = 1;
277156952Sume			} else if (n) {
278156952Sume				*pp++ = cp;
279156952Sume				n = 0;
280156952Sume				havesearch = 1;
281156952Sume			}
282156952Sume		}
283156952Sume		/* null terminate last domain if there are excess */
284156952Sume		while (*cp != '\0' && *cp != ' ' && *cp != '\t' && *cp != '\n')
285156952Sume			cp++;
286156952Sume		*cp = '\0';
287156952Sume		*pp++ = 0;
288156952Sume	}
289156952Sume
290156952Sume#define	MATCH(line, name) \
291156952Sume	(!strncmp(line, name, sizeof(name) - 1) && \
292156952Sume	(line[sizeof(name) - 1] == ' ' || \
293156952Sume	 line[sizeof(name) - 1] == '\t'))
294156952Sume
295156952Sume	nserv = 0;
296156952Sume	if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) {
297156952Sume	    /* read the config file */
298156952Sume	    while (fgets(buf, sizeof(buf), fp) != NULL) {
299156952Sume		/* skip comments */
300156952Sume		if (*buf == ';' || *buf == '#')
301156952Sume			continue;
302156952Sume		/* read default domain name */
303156952Sume		if (MATCH(buf, "domain")) {
304156952Sume		    if (haveenv)	/* skip if have from environ */
305156952Sume			    continue;
306156952Sume		    cp = buf + sizeof("domain") - 1;
307156952Sume		    while (*cp == ' ' || *cp == '\t')
308156952Sume			    cp++;
309156952Sume		    if ((*cp == '\0') || (*cp == '\n'))
310156952Sume			    continue;
311156952Sume		    strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
312156952Sume		    statp->defdname[sizeof(statp->defdname) - 1] = '\0';
313156952Sume		    if ((cp = strpbrk(statp->defdname, " \t\n")) != NULL)
314156952Sume			    *cp = '\0';
315156952Sume		    havesearch = 0;
316156952Sume		    continue;
317156952Sume		}
318156952Sume		/* set search list */
319156952Sume		if (MATCH(buf, "search")) {
320156952Sume		    if (haveenv)	/* skip if have from environ */
321156952Sume			    continue;
322156952Sume		    cp = buf + sizeof("search") - 1;
323156952Sume		    while (*cp == ' ' || *cp == '\t')
324156952Sume			    cp++;
325156952Sume		    if ((*cp == '\0') || (*cp == '\n'))
326156952Sume			    continue;
327156952Sume		    strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
328156952Sume		    statp->defdname[sizeof(statp->defdname) - 1] = '\0';
329156952Sume		    if ((cp = strchr(statp->defdname, '\n')) != NULL)
330156952Sume			    *cp = '\0';
331156952Sume		    /*
332156952Sume		     * Set search list to be blank-separated strings
333156952Sume		     * on rest of line.
334156952Sume		     */
335156952Sume		    cp = statp->defdname;
336156952Sume		    pp = statp->dnsrch;
337156952Sume		    *pp++ = cp;
338156952Sume		    for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) {
339156952Sume			    if (*cp == ' ' || *cp == '\t') {
340156952Sume				    *cp = 0;
341156952Sume				    n = 1;
342156952Sume			    } else if (n) {
343156952Sume				    *pp++ = cp;
344156952Sume				    n = 0;
345156952Sume			    }
346156952Sume		    }
347156952Sume		    /* null terminate last domain if there are excess */
348156952Sume		    while (*cp != '\0' && *cp != ' ' && *cp != '\t')
349156952Sume			    cp++;
350156952Sume		    *cp = '\0';
351156952Sume		    *pp++ = 0;
352156952Sume		    havesearch = 1;
353156952Sume		    continue;
354156952Sume		}
355156952Sume		/* read nameservers to query */
356156952Sume		if (MATCH(buf, "nameserver") && nserv < MAXNS) {
357156952Sume		    struct addrinfo hints, *ai;
358156952Sume		    char sbuf[NI_MAXSERV];
359156952Sume		    const size_t minsiz =
360156952Sume		        sizeof(statp->_u._ext.ext->nsaddrs[0]);
361156952Sume
362156952Sume		    cp = buf + sizeof("nameserver") - 1;
363156952Sume		    while (*cp == ' ' || *cp == '\t')
364156952Sume			cp++;
365156952Sume		    cp[strcspn(cp, ";# \t\n")] = '\0';
366156952Sume		    if ((*cp != '\0') && (*cp != '\n')) {
367156952Sume			memset(&hints, 0, sizeof(hints));
368156952Sume			hints.ai_family = PF_UNSPEC;
369156952Sume			hints.ai_socktype = SOCK_DGRAM;	/*dummy*/
370156952Sume			hints.ai_flags = AI_NUMERICHOST;
371156952Sume			sprintf(sbuf, "%u", NAMESERVER_PORT);
372156952Sume			if (getaddrinfo(cp, sbuf, &hints, &ai) == 0 &&
373156952Sume			    ai->ai_addrlen <= minsiz) {
374156952Sume			    if (statp->_u._ext.ext != NULL) {
375156952Sume				memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
376156952Sume				    ai->ai_addr, ai->ai_addrlen);
377156952Sume			    }
378156952Sume			    if (ai->ai_addrlen <=
379156952Sume			        sizeof(statp->nsaddr_list[nserv])) {
380156952Sume				memcpy(&statp->nsaddr_list[nserv],
381156952Sume				    ai->ai_addr, ai->ai_addrlen);
382156952Sume			    } else
383156952Sume				statp->nsaddr_list[nserv].sin_family = 0;
384156952Sume			    freeaddrinfo(ai);
385156952Sume			    nserv++;
386156952Sume			}
387156952Sume		    }
388156952Sume		    continue;
389156952Sume		}
390156952Sume#ifdef RESOLVSORT
391156952Sume		if (MATCH(buf, "sortlist")) {
392156952Sume		    struct in_addr a;
393156952Sume
394156952Sume		    cp = buf + sizeof("sortlist") - 1;
395156952Sume		    while (nsort < MAXRESOLVSORT) {
396156952Sume			while (*cp == ' ' || *cp == '\t')
397156952Sume			    cp++;
398156952Sume			if (*cp == '\0' || *cp == '\n' || *cp == ';')
399156952Sume			    break;
400156952Sume			net = cp;
401156952Sume			while (*cp && !ISSORTMASK(*cp) && *cp != ';' &&
402156952Sume			       isascii(*cp) && !isspace((unsigned char)*cp))
403156952Sume				cp++;
404156952Sume			n = *cp;
405156952Sume			*cp = 0;
406156952Sume			if (inet_aton(net, &a)) {
407156952Sume			    statp->sort_list[nsort].addr = a;
408156952Sume			    if (ISSORTMASK(n)) {
409156952Sume				*cp++ = n;
410156952Sume				net = cp;
411156952Sume				while (*cp && *cp != ';' &&
412156952Sume					isascii(*cp) &&
413156952Sume					!isspace((unsigned char)*cp))
414156952Sume				    cp++;
415156952Sume				n = *cp;
416156952Sume				*cp = 0;
417156952Sume				if (inet_aton(net, &a)) {
418156952Sume				    statp->sort_list[nsort].mask = a.s_addr;
419156952Sume				} else {
420156952Sume				    statp->sort_list[nsort].mask =
421156952Sume					net_mask(statp->sort_list[nsort].addr);
422156952Sume				}
423156952Sume			    } else {
424156952Sume				statp->sort_list[nsort].mask =
425156952Sume				    net_mask(statp->sort_list[nsort].addr);
426156952Sume			    }
427156952Sume			    nsort++;
428156952Sume			}
429156952Sume			*cp = n;
430156952Sume		    }
431156952Sume		    continue;
432156952Sume		}
433156952Sume#endif
434156952Sume		if (MATCH(buf, "options")) {
435156952Sume		    res_setoptions(statp, buf + sizeof("options") - 1, "conf");
436156952Sume		    continue;
437156952Sume		}
438156952Sume	    }
439156952Sume	    if (nserv > 0)
440156952Sume		statp->nscount = nserv;
441156952Sume#ifdef RESOLVSORT
442156952Sume	    statp->nsort = nsort;
443156952Sume#endif
444156952Sume	    (void) fclose(fp);
445156952Sume	}
446156952Sume/*
447156952Sume * Last chance to get a nameserver.  This should not normally
448156952Sume * be necessary
449156952Sume */
450156952Sume#ifdef NO_RESOLV_CONF
451156952Sume	if(nserv == 0)
452156952Sume		nserv = get_nameservers(statp);
453156952Sume#endif
454156952Sume
455156952Sume	if (statp->defdname[0] == 0 &&
456156952Sume	    gethostname(buf, sizeof(statp->defdname) - 1) == 0 &&
457156952Sume	    (cp = strchr(buf, '.')) != NULL)
458156952Sume		strcpy(statp->defdname, cp + 1);
459156952Sume
460156952Sume	/* find components of local domain that might be searched */
461156952Sume	if (havesearch == 0) {
462156952Sume		pp = statp->dnsrch;
463156952Sume		*pp++ = statp->defdname;
464156952Sume		*pp = NULL;
465156952Sume
466156952Sume		dots = 0;
467156952Sume		for (cp = statp->defdname; *cp; cp++)
468156952Sume			dots += (*cp == '.');
469156952Sume
470156952Sume		cp = statp->defdname;
471156952Sume		while (pp < statp->dnsrch + MAXDFLSRCH) {
472156952Sume			if (dots < LOCALDOMAINPARTS)
473156952Sume				break;
474156952Sume			cp = strchr(cp, '.') + 1;    /* we know there is one */
475156952Sume			*pp++ = cp;
476156952Sume			dots--;
477156952Sume		}
478156952Sume		*pp = NULL;
479156952Sume#ifdef DEBUG
480156952Sume		if (statp->options & RES_DEBUG) {
481156952Sume			printf(";; res_init()... default dnsrch list:\n");
482156952Sume			for (pp = statp->dnsrch; *pp; pp++)
483156952Sume				printf(";;\t%s\n", *pp);
484156952Sume			printf(";;\t..END..\n");
485156952Sume		}
486156952Sume#endif
487156952Sume	}
488156952Sume
489156952Sume	if ((cp = getenv("RES_OPTIONS")) != NULL)
490156952Sume		res_setoptions(statp, cp, "env");
491156952Sume	statp->options |= RES_INIT;
492156952Sume	return (0);
493156952Sume
494156952Sume#ifdef	SOLARIS2
495156952Sume freedata:
496156952Sume	if (statp->_u._ext.ext != NULL) {
497156952Sume		free(statp->_u._ext.ext);
498156952Sume		statp->_u._ext.ext = NULL;
499156952Sume	}
500156952Sume	return (-1);
501156952Sume#endif
502156952Sume}
503156952Sume
504156952Sumestatic void
505156952Sumeres_setoptions(res_state statp, const char *options, const char *source)
506156952Sume{
507156952Sume	const char *cp = options;
508156952Sume	int i;
509156952Sume	struct __res_state_ext *ext = statp->_u._ext.ext;
510156952Sume
511156952Sume#ifdef DEBUG
512156952Sume	if (statp->options & RES_DEBUG)
513156952Sume		printf(";; res_setoptions(\"%s\", \"%s\")...\n",
514156952Sume		       options, source);
515156952Sume#endif
516156952Sume	while (*cp) {
517156952Sume		/* skip leading and inner runs of spaces */
518156952Sume		while (*cp == ' ' || *cp == '\t')
519156952Sume			cp++;
520156952Sume		/* search for and process individual options */
521156952Sume		if (!strncmp(cp, "ndots:", sizeof("ndots:") - 1)) {
522156952Sume			i = atoi(cp + sizeof("ndots:") - 1);
523156952Sume			if (i <= RES_MAXNDOTS)
524156952Sume				statp->ndots = i;
525156952Sume			else
526156952Sume				statp->ndots = RES_MAXNDOTS;
527156952Sume#ifdef DEBUG
528156952Sume			if (statp->options & RES_DEBUG)
529156952Sume				printf(";;\tndots=%d\n", statp->ndots);
530156952Sume#endif
531156952Sume		} else if (!strncmp(cp, "timeout:", sizeof("timeout:") - 1)) {
532156952Sume			i = atoi(cp + sizeof("timeout:") - 1);
533156952Sume			if (i <= RES_MAXRETRANS)
534156952Sume				statp->retrans = i;
535156952Sume			else
536156952Sume				statp->retrans = RES_MAXRETRANS;
537156952Sume#ifdef DEBUG
538156952Sume			if (statp->options & RES_DEBUG)
539156952Sume				printf(";;\ttimeout=%d\n", statp->retrans);
540156952Sume#endif
541156952Sume#ifdef	SOLARIS2
542156952Sume		} else if (!strncmp(cp, "retrans:", sizeof("retrans:") - 1)) {
543156952Sume			/*
544156952Sume		 	 * For backward compatibility, 'retrans' is
545156952Sume		 	 * supported as an alias for 'timeout', though
546156952Sume		 	 * without an imposed maximum.
547156952Sume		 	 */
548156952Sume			statp->retrans = atoi(cp + sizeof("retrans:") - 1);
549156952Sume		} else if (!strncmp(cp, "retry:", sizeof("retry:") - 1)){
550156952Sume			/*
551156952Sume			 * For backward compatibility, 'retry' is
552156952Sume			 * supported as an alias for 'attempts', though
553156952Sume			 * without an imposed maximum.
554156952Sume			 */
555156952Sume			statp->retry = atoi(cp + sizeof("retry:") - 1);
556156952Sume#endif	/* SOLARIS2 */
557156952Sume		} else if (!strncmp(cp, "attempts:", sizeof("attempts:") - 1)){
558156952Sume			i = atoi(cp + sizeof("attempts:") - 1);
559156952Sume			if (i <= RES_MAXRETRY)
560156952Sume				statp->retry = i;
561156952Sume			else
562156952Sume				statp->retry = RES_MAXRETRY;
563156952Sume#ifdef DEBUG
564156952Sume			if (statp->options & RES_DEBUG)
565156952Sume				printf(";;\tattempts=%d\n", statp->retry);
566156952Sume#endif
567156952Sume		} else if (!strncmp(cp, "debug", sizeof("debug") - 1)) {
568156952Sume#ifdef DEBUG
569156952Sume			if (!(statp->options & RES_DEBUG)) {
570156952Sume				printf(";; res_setoptions(\"%s\", \"%s\")..\n",
571156952Sume				       options, source);
572156952Sume				statp->options |= RES_DEBUG;
573156952Sume			}
574156952Sume			printf(";;\tdebug\n");
575156952Sume#endif
576156952Sume		} else if (!strncmp(cp, "no_tld_query",
577156952Sume				    sizeof("no_tld_query") - 1) ||
578156952Sume			   !strncmp(cp, "no-tld-query",
579156952Sume				    sizeof("no-tld-query") - 1)) {
580156952Sume			statp->options |= RES_NOTLDQUERY;
581156952Sume		} else if (!strncmp(cp, "inet6", sizeof("inet6") - 1)) {
582156952Sume			statp->options |= RES_USE_INET6;
583156952Sume		} else if (!strncmp(cp, "rotate", sizeof("rotate") - 1)) {
584156952Sume			statp->options |= RES_ROTATE;
585156952Sume		} else if (!strncmp(cp, "no-check-names",
586156952Sume				    sizeof("no-check-names") - 1)) {
587156952Sume			statp->options |= RES_NOCHECKNAME;
588156952Sume		}
589156952Sume#ifdef RES_USE_EDNS0
590156952Sume		else if (!strncmp(cp, "edns0", sizeof("edns0") - 1)) {
591156952Sume			statp->options |= RES_USE_EDNS0;
592156952Sume		}
593156952Sume#endif
594156952Sume		else if (!strncmp(cp, "dname", sizeof("dname") - 1)) {
595156952Sume			statp->options |= RES_USE_DNAME;
596156952Sume		}
597156952Sume		else if (!strncmp(cp, "nibble:", sizeof("nibble:") - 1)) {
598156952Sume			if (ext == NULL)
599156952Sume				goto skip;
600156952Sume			cp += sizeof("nibble:") - 1;
601156952Sume			i = MIN(strcspn(cp, " \t"), sizeof(ext->nsuffix) - 1);
602156952Sume			strncpy(ext->nsuffix, cp, i);
603156952Sume			ext->nsuffix[i] = '\0';
604156952Sume		}
605156952Sume		else if (!strncmp(cp, "nibble2:", sizeof("nibble2:") - 1)) {
606156952Sume			if (ext == NULL)
607156952Sume				goto skip;
608156952Sume			cp += sizeof("nibble2:") - 1;
609156952Sume			i = MIN(strcspn(cp, " \t"), sizeof(ext->nsuffix2) - 1);
610156952Sume			strncpy(ext->nsuffix2, cp, i);
611156952Sume			ext->nsuffix2[i] = '\0';
612156952Sume		}
613156952Sume		else if (!strncmp(cp, "v6revmode:", sizeof("v6revmode:") - 1)) {
614156952Sume			cp += sizeof("v6revmode:") - 1;
615156952Sume			/* "nibble" and "bitstring" used to be valid */
616156952Sume			if (!strncmp(cp, "single", sizeof("single") - 1)) {
617156952Sume				statp->options |= RES_NO_NIBBLE2;
618156952Sume			} else if (!strncmp(cp, "both", sizeof("both") - 1)) {
619156952Sume				statp->options &=
620156952Sume					 ~RES_NO_NIBBLE2;
621156952Sume			}
622156952Sume		}
623156952Sume		else {
624156952Sume			/* XXX - print a warning here? */
625156952Sume		}
626156952Sume   skip:
627156952Sume		/* skip to next run of spaces */
628156952Sume		while (*cp && *cp != ' ' && *cp != '\t')
629156952Sume			cp++;
630156952Sume	}
631156952Sume}
632156952Sume
633156952Sume#ifdef RESOLVSORT
634156952Sume/* XXX - should really support CIDR which means explicit masks always. */
635156952Sumestatic u_int32_t
636156952Sumenet_mask(in)		/* XXX - should really use system's version of this */
637156952Sume	struct in_addr in;
638156952Sume{
639156952Sume	register u_int32_t i = ntohl(in.s_addr);
640156952Sume
641156952Sume	if (IN_CLASSA(i))
642156952Sume		return (htonl(IN_CLASSA_NET));
643156952Sume	else if (IN_CLASSB(i))
644156952Sume		return (htonl(IN_CLASSB_NET));
645156952Sume	return (htonl(IN_CLASSC_NET));
646156952Sume}
647156952Sume#endif
648156952Sume
649156952Sumeu_int
650156952Sumeres_randomid(void) {
651156952Sume	struct timeval now;
652156952Sume
653156952Sume	gettimeofday(&now, NULL);
654156952Sume	return (0xffff & (now.tv_sec ^ now.tv_usec ^ getpid()));
655156952Sume}
656156952Sume
657156952Sume/*
658156952Sume * This routine is for closing the socket if a virtual circuit is used and
659156952Sume * the program wants to close it.  This provides support for endhostent()
660156952Sume * which expects to close the socket.
661156952Sume *
662156952Sume * This routine is not expected to be user visible.
663156952Sume */
664156952Sumevoid
665156952Sumeres_nclose(res_state statp) {
666156952Sume	int ns;
667156952Sume
668156952Sume	if (statp->_vcsock >= 0) {
669156952Sume		(void) close(statp->_vcsock);
670156952Sume		statp->_vcsock = -1;
671156952Sume		statp->_flags &= ~(RES_F_VC | RES_F_CONN);
672156952Sume	}
673156952Sume	for (ns = 0; ns < statp->_u._ext.nscount; ns++) {
674156952Sume		if (statp->_u._ext.nssocks[ns] != -1) {
675156952Sume			(void) close(statp->_u._ext.nssocks[ns]);
676156952Sume			statp->_u._ext.nssocks[ns] = -1;
677156952Sume		}
678156952Sume	}
679156952Sume}
680156952Sume
681156952Sumevoid
682156952Sumeres_ndestroy(res_state statp) {
683156952Sume	res_nclose(statp);
684156952Sume	if (statp->_u._ext.ext != NULL)
685156952Sume		free(statp->_u._ext.ext);
686156952Sume	statp->options &= ~RES_INIT;
687156952Sume	statp->_u._ext.ext = NULL;
688156952Sume}
689156952Sume
690156952Sumeconst char *
691156952Sumeres_get_nibblesuffix(res_state statp) {
692156952Sume	if (statp->_u._ext.ext)
693156952Sume		return (statp->_u._ext.ext->nsuffix);
694156952Sume	return ("ip6.arpa");
695156952Sume}
696156952Sume
697156952Sumeconst char *
698156952Sumeres_get_nibblesuffix2(res_state statp) {
699156952Sume	if (statp->_u._ext.ext)
700156952Sume		return (statp->_u._ext.ext->nsuffix2);
701156952Sume	return ("ip6.int");
702156952Sume}
703156952Sume
704156952Sumevoid
705156952Sumeres_setservers(res_state statp, const union res_sockaddr_union *set, int cnt) {
706156952Sume	int i, nserv;
707156952Sume	size_t size;
708156952Sume
709156952Sume	/* close open servers */
710156952Sume	res_nclose(statp);
711156952Sume
712156952Sume	/* cause rtt times to be forgotten */
713156952Sume	statp->_u._ext.nscount = 0;
714156952Sume
715156952Sume	nserv = 0;
716156952Sume	for (i = 0; i < cnt && nserv < MAXNS; i++) {
717156952Sume		switch (set->sin.sin_family) {
718156952Sume		case AF_INET:
719156952Sume			size = sizeof(set->sin);
720156952Sume			if (statp->_u._ext.ext)
721156952Sume				memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
722156952Sume					&set->sin, size);
723156952Sume			if (size <= sizeof(statp->nsaddr_list[nserv]))
724156952Sume				memcpy(&statp->nsaddr_list[nserv],
725156952Sume					&set->sin, size);
726156952Sume			else
727156952Sume				statp->nsaddr_list[nserv].sin_family = 0;
728156952Sume			nserv++;
729156952Sume			break;
730156952Sume
731156952Sume#ifdef HAS_INET6_STRUCTS
732156952Sume		case AF_INET6:
733156952Sume			size = sizeof(set->sin6);
734156952Sume			if (statp->_u._ext.ext)
735156952Sume				memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
736156952Sume					&set->sin6, size);
737156952Sume			if (size <= sizeof(statp->nsaddr_list[nserv]))
738156952Sume				memcpy(&statp->nsaddr_list[nserv],
739156952Sume					&set->sin6, size);
740156952Sume			else
741156952Sume				statp->nsaddr_list[nserv].sin_family = 0;
742156952Sume			nserv++;
743156952Sume			break;
744156952Sume#endif
745156952Sume
746156952Sume		default:
747156952Sume			break;
748156952Sume		}
749156952Sume		set++;
750156952Sume	}
751156952Sume	statp->nscount = nserv;
752156952Sume
753156952Sume}
754156952Sume
755156952Sumeint
756156952Sumeres_getservers(res_state statp, union res_sockaddr_union *set, int cnt) {
757156952Sume	int i;
758156952Sume	size_t size;
759156952Sume	u_int16_t family;
760156952Sume
761156952Sume	for (i = 0; i < statp->nscount && i < cnt; i++) {
762156952Sume		if (statp->_u._ext.ext)
763156952Sume			family = statp->_u._ext.ext->nsaddrs[i].sin.sin_family;
764156952Sume		else
765156952Sume			family = statp->nsaddr_list[i].sin_family;
766156952Sume
767156952Sume		switch (family) {
768156952Sume		case AF_INET:
769156952Sume			size = sizeof(set->sin);
770156952Sume			if (statp->_u._ext.ext)
771156952Sume				memcpy(&set->sin,
772156952Sume				       &statp->_u._ext.ext->nsaddrs[i],
773156952Sume				       size);
774156952Sume			else
775156952Sume				memcpy(&set->sin, &statp->nsaddr_list[i],
776156952Sume				       size);
777156952Sume			break;
778156952Sume
779156952Sume#ifdef HAS_INET6_STRUCTS
780156952Sume		case AF_INET6:
781156952Sume			size = sizeof(set->sin6);
782156952Sume			if (statp->_u._ext.ext)
783156952Sume				memcpy(&set->sin6,
784156952Sume				       &statp->_u._ext.ext->nsaddrs[i],
785156952Sume				       size);
786156952Sume			else
787156952Sume				memcpy(&set->sin6, &statp->nsaddr_list[i],
788156952Sume				       size);
789156952Sume			break;
790156952Sume#endif
791156952Sume
792156952Sume		default:
793156952Sume			set->sin.sin_family = 0;
794156952Sume			break;
795156952Sume		}
796156952Sume		set++;
797156952Sume	}
798156952Sume	return (statp->nscount);
799156952Sume}
800