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