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