Index: stable/9/lib/libc/resolv/res_init.c =================================================================== --- stable/9/lib/libc/resolv/res_init.c (revision 292430) +++ stable/9/lib/libc/resolv/res_init.c (revision 292431) @@ -1,929 +1,931 @@ /* * Copyright (c) 1985, 1989, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Portions Copyright (c) 1993 by Digital Equipment Corporation. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies, and that * the name of Digital Equipment Corporation not be used in advertising or * publicity pertaining to distribution of the document or software without * specific, written prior permission. * * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ /* * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") * Portions Copyright (c) 1996-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #if defined(LIBC_SCCS) && !defined(lint) static const char sccsid[] = "@(#)res_init.c 8.1 (Berkeley) 6/7/93"; static const char rcsid[] = "$Id: res_init.c,v 1.26 2008/12/11 09:59:00 marka Exp $"; #endif /* LIBC_SCCS and not lint */ #include __FBSDID("$FreeBSD$"); #include "port_before.h" #include "namespace.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef HAVE_MD5 # include "../dst/md5.h" #else # ifdef SOLARIS2 # include # elif _LIBC # include # endif #endif #ifndef _MD5_H_ # define _MD5_H_ 1 /*%< make sure we do not include rsaref md5.h file */ #endif #include "un-namespace.h" #include "port_after.h" /* ensure that sockaddr_in6 and IN6ADDR_ANY_INIT are declared / defined */ #include #include "res_private.h" /*% Options. Should all be left alone. */ #define RESOLVSORT -#define DEBUG +#ifndef DEBUG +#define DEBUG +#endif #ifdef SOLARIS2 #include #endif static void res_setoptions(res_state, const char *, const char *); #ifdef RESOLVSORT static const char sort_mask[] = "/&"; #define ISSORTMASK(ch) (strchr(sort_mask, ch) != NULL) static u_int32_t net_mask(struct in_addr); #endif #if !defined(isascii) /*%< XXX - could be a function */ # define isascii(c) (!(c & 0200)) #endif /* * Resolver state default settings. */ /*% * Set up default settings. If the configuration file exist, the values * there will have precedence. Otherwise, the server address is set to * INADDR_ANY and the default domain name comes from the gethostname(). * * An interrim version of this code (BIND 4.9, pre-4.4BSD) used 127.0.0.1 * rather than INADDR_ANY ("0.0.0.0") as the default name server address * since it was noted that INADDR_ANY actually meant ``the first interface * you "ifconfig"'d at boot time'' and if this was a SLIP or PPP interface, * it had to be "up" in order for you to reach your own name server. It * was later decided that since the recommended practice is to always * install local static routes through 127.0.0.1 for all your network * interfaces, that we could solve this problem without a code change. * * The configuration file should always be used, since it is the only way * to specify a default domain. If you are running a server on your local * machine, you should say "nameserver 0.0.0.0" or "nameserver 127.0.0.1" * in the configuration file. * * Return 0 if completes successfully, -1 on error */ int res_ninit(res_state statp) { extern int __res_vinit(res_state, int); return (__res_vinit(statp, 0)); } /*% This function has to be reachable by res_data.c but not publically. */ int __res_vinit(res_state statp, int preinit) { FILE *fp; char *cp, **pp; int n; char buf[BUFSIZ]; int nserv = 0; /*%< number of nameserver records read from file */ int haveenv = 0; int havesearch = 0; #ifdef RESOLVSORT int nsort = 0; char *net; #endif int dots; union res_sockaddr_union u[2]; int maxns = MAXNS; RES_SET_H_ERRNO(statp, 0); if (statp->_u._ext.ext != NULL) res_ndestroy(statp); if (!preinit) { statp->retrans = RES_TIMEOUT; statp->retry = RES_DFLRETRY; statp->options = RES_DEFAULT; } statp->_rnd = malloc(16); res_rndinit(statp); statp->id = res_nrandomid(statp); memset(u, 0, sizeof(u)); #ifdef USELOOPBACK u[nserv].sin.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1); #else u[nserv].sin.sin_addr.s_addr = INADDR_ANY; #endif u[nserv].sin.sin_family = AF_INET; u[nserv].sin.sin_port = htons(NAMESERVER_PORT); #ifdef HAVE_SA_LEN u[nserv].sin.sin_len = sizeof(struct sockaddr_in); #endif nserv++; #ifdef HAS_INET6_STRUCTS #ifdef USELOOPBACK u[nserv].sin6.sin6_addr = in6addr_loopback; #else u[nserv].sin6.sin6_addr = in6addr_any; #endif u[nserv].sin6.sin6_family = AF_INET6; u[nserv].sin6.sin6_port = htons(NAMESERVER_PORT); #ifdef HAVE_SA_LEN u[nserv].sin6.sin6_len = sizeof(struct sockaddr_in6); #endif nserv++; #endif statp->nscount = 0; statp->ndots = 1; statp->pfcode = 0; statp->_vcsock = -1; statp->_flags = 0; statp->qhook = NULL; statp->rhook = NULL; statp->_u._ext.nscount = 0; statp->_u._ext.ext = malloc(sizeof(*statp->_u._ext.ext)); if (statp->_u._ext.ext != NULL) { memset(statp->_u._ext.ext, 0, sizeof(*statp->_u._ext.ext)); statp->_u._ext.ext->nsaddrs[0].sin = statp->nsaddr; strcpy(statp->_u._ext.ext->nsuffix, "ip6.arpa"); strcpy(statp->_u._ext.ext->nsuffix2, "ip6.int"); } else { /* * Historically res_init() rarely, if at all, failed. * Examples and applications exist which do not check * our return code. Furthermore several applications * simply call us to get the systems domainname. So * rather then immediately fail here we store the * failure, which is returned later, in h_errno. And * prevent the collection of 'nameserver' information * by setting maxns to 0. Thus applications that fail * to check our return code wont be able to make * queries anyhow. */ RES_SET_H_ERRNO(statp, NETDB_INTERNAL); maxns = 0; } #ifdef RESOLVSORT statp->nsort = 0; #endif res_setservers(statp, u, nserv); #ifdef SOLARIS2 /* * The old libresolv derived the defaultdomain from NIS/NIS+. * We want to keep this behaviour */ { char buf[sizeof(statp->defdname)], *cp; int ret; if ((ret = sysinfo(SI_SRPC_DOMAIN, buf, sizeof(buf))) > 0 && (unsigned int)ret <= sizeof(buf)) { if (buf[0] == '+') buf[0] = '.'; cp = strchr(buf, '.'); cp = (cp == NULL) ? buf : (cp + 1); strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); statp->defdname[sizeof(statp->defdname) - 1] = '\0'; } } #endif /* SOLARIS2 */ /* Allow user to override the local domain definition */ if (issetugid() == 0 && (cp = getenv("LOCALDOMAIN")) != NULL) { (void)strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); statp->defdname[sizeof(statp->defdname) - 1] = '\0'; haveenv++; /* * Set search list to be blank-separated strings * from rest of env value. Permits users of LOCALDOMAIN * to still have a search list, and anyone to set the * one that they want to use as an individual (even more * important now that the rfc1535 stuff restricts searches) */ cp = statp->defdname; pp = statp->dnsrch; *pp++ = cp; for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) { if (*cp == '\n') /*%< silly backwards compat */ break; else if (*cp == ' ' || *cp == '\t') { *cp = 0; n = 1; } else if (n) { *pp++ = cp; n = 0; havesearch = 1; } } /* null terminate last domain if there are excess */ while (*cp != '\0' && *cp != ' ' && *cp != '\t' && *cp != '\n') cp++; *cp = '\0'; *pp++ = 0; } #define MATCH(line, name) \ (!strncmp(line, name, sizeof(name) - 1) && \ (line[sizeof(name) - 1] == ' ' || \ line[sizeof(name) - 1] == '\t')) nserv = 0; if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) { /* read the config file */ while (fgets(buf, sizeof(buf), fp) != NULL) { /* skip comments */ if (*buf == ';' || *buf == '#') continue; /* read default domain name */ if (MATCH(buf, "domain")) { if (haveenv) /*%< skip if have from environ */ continue; cp = buf + sizeof("domain") - 1; while (*cp == ' ' || *cp == '\t') cp++; if ((*cp == '\0') || (*cp == '\n')) continue; strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); statp->defdname[sizeof(statp->defdname) - 1] = '\0'; if ((cp = strpbrk(statp->defdname, " \t\n")) != NULL) *cp = '\0'; havesearch = 0; continue; } /* set search list */ if (MATCH(buf, "search")) { if (haveenv) /*%< skip if have from environ */ continue; cp = buf + sizeof("search") - 1; while (*cp == ' ' || *cp == '\t') cp++; if ((*cp == '\0') || (*cp == '\n')) continue; strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); statp->defdname[sizeof(statp->defdname) - 1] = '\0'; if ((cp = strchr(statp->defdname, '\n')) != NULL) *cp = '\0'; /* * Set search list to be blank-separated strings * on rest of line. */ cp = statp->defdname; pp = statp->dnsrch; *pp++ = cp; for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) { if (*cp == ' ' || *cp == '\t') { *cp = 0; n = 1; } else if (n) { *pp++ = cp; n = 0; } } /* null terminate last domain if there are excess */ while (*cp != '\0' && *cp != ' ' && *cp != '\t') cp++; *cp = '\0'; *pp++ = 0; havesearch = 1; continue; } /* read nameservers to query */ if (MATCH(buf, "nameserver") && nserv < maxns) { struct addrinfo hints, *ai; char sbuf[NI_MAXSERV]; const size_t minsiz = sizeof(statp->_u._ext.ext->nsaddrs[0]); cp = buf + sizeof("nameserver") - 1; while (*cp == ' ' || *cp == '\t') cp++; cp[strcspn(cp, ";# \t\n")] = '\0'; if ((*cp != '\0') && (*cp != '\n')) { memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_DGRAM; /*dummy*/ hints.ai_flags = AI_NUMERICHOST; sprintf(sbuf, "%u", NAMESERVER_PORT); if (getaddrinfo(cp, sbuf, &hints, &ai) == 0 && ai->ai_addrlen <= minsiz) { if (statp->_u._ext.ext != NULL) { memcpy(&statp->_u._ext.ext->nsaddrs[nserv], ai->ai_addr, ai->ai_addrlen); } if (ai->ai_addrlen <= sizeof(statp->nsaddr_list[nserv])) { memcpy(&statp->nsaddr_list[nserv], ai->ai_addr, ai->ai_addrlen); } else statp->nsaddr_list[nserv].sin_family = 0; freeaddrinfo(ai); nserv++; } } continue; } #ifdef RESOLVSORT if (MATCH(buf, "sortlist")) { struct in_addr a; struct in6_addr a6; int m, i; u_char *u; struct __res_state_ext *ext = statp->_u._ext.ext; cp = buf + sizeof("sortlist") - 1; while (nsort < MAXRESOLVSORT) { while (*cp == ' ' || *cp == '\t') cp++; if (*cp == '\0' || *cp == '\n' || *cp == ';') break; net = cp; while (*cp && !ISSORTMASK(*cp) && *cp != ';' && isascii(*cp) && !isspace((unsigned char)*cp)) cp++; n = *cp; *cp = 0; if (inet_aton(net, &a)) { statp->sort_list[nsort].addr = a; if (ISSORTMASK(n)) { *cp++ = n; net = cp; while (*cp && *cp != ';' && isascii(*cp) && !isspace((unsigned char)*cp)) cp++; n = *cp; *cp = 0; if (inet_aton(net, &a)) { statp->sort_list[nsort].mask = a.s_addr; } else { statp->sort_list[nsort].mask = net_mask(statp->sort_list[nsort].addr); } } else { statp->sort_list[nsort].mask = net_mask(statp->sort_list[nsort].addr); } ext->sort_list[nsort].af = AF_INET; ext->sort_list[nsort].addr.ina = statp->sort_list[nsort].addr; ext->sort_list[nsort].mask.ina.s_addr = statp->sort_list[nsort].mask; nsort++; } else if (inet_pton(AF_INET6, net, &a6) == 1) { ext->sort_list[nsort].af = AF_INET6; ext->sort_list[nsort].addr.in6a = a6; u = (u_char *)&ext->sort_list[nsort].mask.in6a; *cp++ = n; net = cp; while (*cp && *cp != ';' && isascii(*cp) && !isspace(*cp)) cp++; m = n; n = *cp; *cp = 0; switch (m) { case '/': m = atoi(net); break; case '&': if (inet_pton(AF_INET6, net, u) == 1) { m = -1; break; } /*FALLTHROUGH*/ default: m = sizeof(struct in6_addr) * CHAR_BIT; break; } if (m >= 0) { for (i = 0; i < sizeof(struct in6_addr); i++) { if (m <= 0) { *u = 0; } else { m -= CHAR_BIT; *u = (u_char)~0; if (m < 0) *u <<= -m; } u++; } } statp->sort_list[nsort].addr.s_addr = (u_int32_t)0xffffffff; statp->sort_list[nsort].mask = (u_int32_t)0xffffffff; nsort++; } *cp = n; } continue; } #endif if (MATCH(buf, "options")) { res_setoptions(statp, buf + sizeof("options") - 1, "conf"); continue; } } if (nserv > 0) statp->nscount = nserv; #ifdef RESOLVSORT statp->nsort = nsort; #endif (void) fclose(fp); } /* * Last chance to get a nameserver. This should not normally * be necessary */ #ifdef NO_RESOLV_CONF if(nserv == 0) nserv = get_nameservers(statp); #endif if (statp->defdname[0] == 0 && gethostname(buf, sizeof(statp->defdname) - 1) == 0 && (cp = strchr(buf, '.')) != NULL) strcpy(statp->defdname, cp + 1); /* find components of local domain that might be searched */ if (havesearch == 0) { pp = statp->dnsrch; *pp++ = statp->defdname; *pp = NULL; dots = 0; for (cp = statp->defdname; *cp; cp++) dots += (*cp == '.'); cp = statp->defdname; while (pp < statp->dnsrch + MAXDFLSRCH) { if (dots < LOCALDOMAINPARTS) break; cp = strchr(cp, '.') + 1; /*%< we know there is one */ *pp++ = cp; dots--; } *pp = NULL; #ifdef DEBUG if (statp->options & RES_DEBUG) { printf(";; res_init()... default dnsrch list:\n"); for (pp = statp->dnsrch; *pp; pp++) printf(";;\t%s\n", *pp); printf(";;\t..END..\n"); } #endif } if (issetugid()) statp->options |= RES_NOALIASES; else if ((cp = getenv("RES_OPTIONS")) != NULL) res_setoptions(statp, cp, "env"); statp->options |= RES_INIT; return (statp->res_h_errno); } static void res_setoptions(res_state statp, const char *options, const char *source) { const char *cp = options; int i; #ifndef _LIBC struct __res_state_ext *ext = statp->_u._ext.ext; #endif #ifdef DEBUG if (statp->options & RES_DEBUG) printf(";; res_setoptions(\"%s\", \"%s\")...\n", options, source); #endif while (*cp) { /* skip leading and inner runs of spaces */ while (*cp == ' ' || *cp == '\t') cp++; /* search for and process individual options */ if (!strncmp(cp, "ndots:", sizeof("ndots:") - 1)) { i = atoi(cp + sizeof("ndots:") - 1); if (i <= RES_MAXNDOTS) statp->ndots = i; else statp->ndots = RES_MAXNDOTS; #ifdef DEBUG if (statp->options & RES_DEBUG) printf(";;\tndots=%d\n", statp->ndots); #endif } else if (!strncmp(cp, "timeout:", sizeof("timeout:") - 1)) { i = atoi(cp + sizeof("timeout:") - 1); if (i <= RES_MAXRETRANS) statp->retrans = i; else statp->retrans = RES_MAXRETRANS; #ifdef DEBUG if (statp->options & RES_DEBUG) printf(";;\ttimeout=%d\n", statp->retrans); #endif #ifdef SOLARIS2 } else if (!strncmp(cp, "retrans:", sizeof("retrans:") - 1)) { /* * For backward compatibility, 'retrans' is * supported as an alias for 'timeout', though * without an imposed maximum. */ statp->retrans = atoi(cp + sizeof("retrans:") - 1); } else if (!strncmp(cp, "retry:", sizeof("retry:") - 1)){ /* * For backward compatibility, 'retry' is * supported as an alias for 'attempts', though * without an imposed maximum. */ statp->retry = atoi(cp + sizeof("retry:") - 1); #endif /* SOLARIS2 */ } else if (!strncmp(cp, "attempts:", sizeof("attempts:") - 1)){ i = atoi(cp + sizeof("attempts:") - 1); if (i <= RES_MAXRETRY) statp->retry = i; else statp->retry = RES_MAXRETRY; #ifdef DEBUG if (statp->options & RES_DEBUG) printf(";;\tattempts=%d\n", statp->retry); #endif } else if (!strncmp(cp, "debug", sizeof("debug") - 1)) { #ifdef DEBUG if (!(statp->options & RES_DEBUG)) { printf(";; res_setoptions(\"%s\", \"%s\")..\n", options, source); statp->options |= RES_DEBUG; } printf(";;\tdebug\n"); #endif } else if (!strncmp(cp, "no_tld_query", sizeof("no_tld_query") - 1) || !strncmp(cp, "no-tld-query", sizeof("no-tld-query") - 1)) { statp->options |= RES_NOTLDQUERY; } else if (!strncmp(cp, "inet6", sizeof("inet6") - 1)) { statp->options |= RES_USE_INET6; } else if (!strncmp(cp, "insecure1", sizeof("insecure1") - 1)) { statp->options |= RES_INSECURE1; } else if (!strncmp(cp, "insecure2", sizeof("insecure2") - 1)) { statp->options |= RES_INSECURE2; } else if (!strncmp(cp, "rotate", sizeof("rotate") - 1)) { statp->options |= RES_ROTATE; } else if (!strncmp(cp, "no-check-names", sizeof("no-check-names") - 1)) { statp->options |= RES_NOCHECKNAME; } #ifdef RES_USE_EDNS0 else if (!strncmp(cp, "edns0", sizeof("edns0") - 1)) { statp->options |= RES_USE_EDNS0; } #endif #ifndef _LIBC else if (!strncmp(cp, "dname", sizeof("dname") - 1)) { statp->options |= RES_USE_DNAME; } else if (!strncmp(cp, "nibble:", sizeof("nibble:") - 1)) { if (ext == NULL) goto skip; cp += sizeof("nibble:") - 1; i = MIN(strcspn(cp, " \t"), sizeof(ext->nsuffix) - 1); strncpy(ext->nsuffix, cp, i); ext->nsuffix[i] = '\0'; } else if (!strncmp(cp, "nibble2:", sizeof("nibble2:") - 1)) { if (ext == NULL) goto skip; cp += sizeof("nibble2:") - 1; i = MIN(strcspn(cp, " \t"), sizeof(ext->nsuffix2) - 1); strncpy(ext->nsuffix2, cp, i); ext->nsuffix2[i] = '\0'; } else if (!strncmp(cp, "v6revmode:", sizeof("v6revmode:") - 1)) { cp += sizeof("v6revmode:") - 1; /* "nibble" and "bitstring" used to be valid */ if (!strncmp(cp, "single", sizeof("single") - 1)) { statp->options |= RES_NO_NIBBLE2; } else if (!strncmp(cp, "both", sizeof("both") - 1)) { statp->options &= ~RES_NO_NIBBLE2; } } #endif else { /* XXX - print a warning here? */ } #ifndef _LIBC skip: #endif /* skip to next run of spaces */ while (*cp && *cp != ' ' && *cp != '\t') cp++; } } #ifdef RESOLVSORT /* XXX - should really support CIDR which means explicit masks always. */ static u_int32_t net_mask(in) /*!< XXX - should really use system's version of this */ struct in_addr in; { u_int32_t i = ntohl(in.s_addr); if (IN_CLASSA(i)) return (htonl(IN_CLASSA_NET)); else if (IN_CLASSB(i)) return (htonl(IN_CLASSB_NET)); return (htonl(IN_CLASSC_NET)); } #endif static u_char srnd[16]; void res_rndinit(res_state statp) { struct timeval now; u_int32_t u32; u_int16_t u16; u_char *rnd = statp->_rnd == NULL ? srnd : statp->_rnd; gettimeofday(&now, NULL); u32 = now.tv_sec; memcpy(rnd, &u32, 4); u32 = now.tv_usec; memcpy(rnd + 4, &u32, 4); u32 += now.tv_sec; memcpy(rnd + 8, &u32, 4); u16 = getpid(); memcpy(rnd + 12, &u16, 2); } u_int res_nrandomid(res_state statp) { struct timeval now; u_int16_t u16; MD5_CTX ctx; u_char *rnd = statp->_rnd == NULL ? srnd : statp->_rnd; gettimeofday(&now, NULL); u16 = (u_int16_t) (now.tv_sec ^ now.tv_usec); memcpy(rnd + 14, &u16, 2); #ifndef HAVE_MD5 MD5_Init(&ctx); MD5_Update(&ctx, rnd, 16); MD5_Final(rnd, &ctx); #else MD5Init(&ctx); MD5Update(&ctx, rnd, 16); MD5Final(rnd, &ctx); #endif memcpy(&u16, rnd + 14, 2); return ((u_int) u16); } /*% * This routine is for closing the socket if a virtual circuit is used and * the program wants to close it. This provides support for endhostent() * which expects to close the socket. * * This routine is not expected to be user visible. */ void res_nclose(res_state statp) { int ns; if (statp->_vcsock >= 0) { (void) _close(statp->_vcsock); statp->_vcsock = -1; statp->_flags &= ~(RES_F_VC | RES_F_CONN); } for (ns = 0; ns < statp->_u._ext.nscount; ns++) { if (statp->_u._ext.nssocks[ns] != -1) { (void) _close(statp->_u._ext.nssocks[ns]); statp->_u._ext.nssocks[ns] = -1; } } } void res_ndestroy(res_state statp) { res_nclose(statp); if (statp->_u._ext.ext != NULL) { free(statp->_u._ext.ext); statp->_u._ext.ext = NULL; } if (statp->_rnd != NULL) { free(statp->_rnd); statp->_rnd = NULL; } statp->options &= ~RES_INIT; } #ifndef _LIBC const char * res_get_nibblesuffix(res_state statp) { if (statp->_u._ext.ext) return (statp->_u._ext.ext->nsuffix); return ("ip6.arpa"); } const char * res_get_nibblesuffix2(res_state statp) { if (statp->_u._ext.ext) return (statp->_u._ext.ext->nsuffix2); return ("ip6.int"); } #endif void res_setservers(res_state statp, const union res_sockaddr_union *set, int cnt) { int i, nserv; size_t size; /* close open servers */ res_nclose(statp); /* cause rtt times to be forgotten */ statp->_u._ext.nscount = 0; nserv = 0; for (i = 0; i < cnt && nserv < MAXNS; i++) { switch (set->sin.sin_family) { case AF_INET: size = sizeof(set->sin); if (statp->_u._ext.ext) memcpy(&statp->_u._ext.ext->nsaddrs[nserv], &set->sin, size); if (size <= sizeof(statp->nsaddr_list[nserv])) memcpy(&statp->nsaddr_list[nserv], &set->sin, size); else statp->nsaddr_list[nserv].sin_family = 0; nserv++; break; #ifdef HAS_INET6_STRUCTS case AF_INET6: size = sizeof(set->sin6); if (statp->_u._ext.ext) memcpy(&statp->_u._ext.ext->nsaddrs[nserv], &set->sin6, size); if (size <= sizeof(statp->nsaddr_list[nserv])) memcpy(&statp->nsaddr_list[nserv], &set->sin6, size); else statp->nsaddr_list[nserv].sin_family = 0; nserv++; break; #endif default: break; } set++; } statp->nscount = nserv; } int res_getservers(res_state statp, union res_sockaddr_union *set, int cnt) { int i; size_t size; u_int16_t family; for (i = 0; i < statp->nscount && i < cnt; i++) { if (statp->_u._ext.ext) family = statp->_u._ext.ext->nsaddrs[i].sin.sin_family; else family = statp->nsaddr_list[i].sin_family; switch (family) { case AF_INET: size = sizeof(set->sin); if (statp->_u._ext.ext) memcpy(&set->sin, &statp->_u._ext.ext->nsaddrs[i], size); else memcpy(&set->sin, &statp->nsaddr_list[i], size); break; #ifdef HAS_INET6_STRUCTS case AF_INET6: size = sizeof(set->sin6); if (statp->_u._ext.ext) memcpy(&set->sin6, &statp->_u._ext.ext->nsaddrs[i], size); else memcpy(&set->sin6, &statp->nsaddr_list[i], size); break; #endif default: set->sin.sin_family = 0; break; } set++; } return (statp->nscount); } /*! \file */ Index: stable/9/lib/libc/resolv/res_mkquery.c =================================================================== --- stable/9/lib/libc/resolv/res_mkquery.c (revision 292430) +++ stable/9/lib/libc/resolv/res_mkquery.c (revision 292431) @@ -1,304 +1,306 @@ /* * Portions Copyright (C) 2004, 2005, 2008 Internet Systems Consortium, Inc. ("ISC") * Portions Copyright (C) 1996, 1997, 1988, 1999, 2001, 2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ /* * Copyright (c) 1985, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Portions Copyright (c) 1993 by Digital Equipment Corporation. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies, and that * the name of Digital Equipment Corporation not be used in advertising or * publicity pertaining to distribution of the document or software without * specific, written prior permission. * * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ #if defined(LIBC_SCCS) && !defined(lint) static const char sccsid[] = "@(#)res_mkquery.c 8.1 (Berkeley) 6/4/93"; static const char rcsid[] = "$Id: res_mkquery.c,v 1.10 2008/12/11 09:59:00 marka Exp $"; #endif /* LIBC_SCCS and not lint */ #include __FBSDID("$FreeBSD$"); #include "port_before.h" #include #include #include #include #include #include #include #include #include "port_after.h" /* Options. Leave them on. */ -#define DEBUG +#ifndef DEBUG +#define DEBUG +#endif extern const char *_res_opcodes[]; /*% * Form all types of queries. * Returns the size of the result or -1. */ int res_nmkquery(res_state statp, int op, /*!< opcode of query */ const char *dname, /*!< domain name */ int class, int type, /*!< class and type of query */ const u_char *data, /*!< resource record data */ int datalen, /*!< length of data */ const u_char *newrr_in, /*!< new rr for modify or append */ u_char *buf, /*!< buffer to put query */ int buflen) /*!< size of buffer */ { HEADER *hp; u_char *cp, *ep; int n; u_char *dnptrs[20], **dpp, **lastdnptr; UNUSED(newrr_in); #ifdef DEBUG if (statp->options & RES_DEBUG) printf(";; res_nmkquery(%s, %s, %s, %s)\n", _res_opcodes[op], dname, p_class(class), p_type(type)); #endif /* * Initialize header fields. */ if ((buf == NULL) || (buflen < HFIXEDSZ)) return (-1); memset(buf, 0, HFIXEDSZ); hp = (HEADER *) buf; statp->id = res_nrandomid(statp); hp->id = htons(statp->id); hp->opcode = op; hp->rd = (statp->options & RES_RECURSE) != 0U; hp->rcode = NOERROR; cp = buf + HFIXEDSZ; ep = buf + buflen; dpp = dnptrs; *dpp++ = buf; *dpp++ = NULL; lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0]; /* * perform opcode specific processing */ switch (op) { case QUERY: /*FALLTHROUGH*/ case NS_NOTIFY_OP: if (ep - cp < QFIXEDSZ) return (-1); if ((n = dn_comp(dname, cp, ep - cp - QFIXEDSZ, dnptrs, lastdnptr)) < 0) return (-1); cp += n; ns_put16(type, cp); cp += INT16SZ; ns_put16(class, cp); cp += INT16SZ; hp->qdcount = htons(1); if (op == QUERY || data == NULL) break; /* * Make an additional record for completion domain. */ if ((ep - cp) < RRFIXEDSZ) return (-1); n = dn_comp((const char *)data, cp, ep - cp - RRFIXEDSZ, dnptrs, lastdnptr); if (n < 0) return (-1); cp += n; ns_put16(T_NULL, cp); cp += INT16SZ; ns_put16(class, cp); cp += INT16SZ; ns_put32(0, cp); cp += INT32SZ; ns_put16(0, cp); cp += INT16SZ; hp->arcount = htons(1); break; case IQUERY: /* * Initialize answer section */ if (ep - cp < 1 + RRFIXEDSZ + datalen) return (-1); *cp++ = '\0'; /*%< no domain name */ ns_put16(type, cp); cp += INT16SZ; ns_put16(class, cp); cp += INT16SZ; ns_put32(0, cp); cp += INT32SZ; ns_put16(datalen, cp); cp += INT16SZ; if (datalen) { memcpy(cp, data, datalen); cp += datalen; } hp->ancount = htons(1); break; default: return (-1); } return (cp - buf); } #ifdef RES_USE_EDNS0 /* attach OPT pseudo-RR, as documented in RFC2671 (EDNS0). */ int res_nopt(res_state statp, int n0, /*%< current offset in buffer */ u_char *buf, /*%< buffer to put query */ int buflen, /*%< size of buffer */ int anslen) /*%< UDP answer buffer size */ { HEADER *hp; u_char *cp, *ep; u_int16_t flags = 0; #ifdef DEBUG if ((statp->options & RES_DEBUG) != 0U) printf(";; res_nopt()\n"); #endif hp = (HEADER *) buf; cp = buf + n0; ep = buf + buflen; if ((ep - cp) < 1 + RRFIXEDSZ) return (-1); *cp++ = 0; /*%< "." */ ns_put16(ns_t_opt, cp); /*%< TYPE */ cp += INT16SZ; if (anslen > 0xffff) anslen = 0xffff; /* limit to 16bit value */ ns_put16(anslen & 0xffff, cp); /*%< CLASS = UDP payload size */ cp += INT16SZ; *cp++ = NOERROR; /*%< extended RCODE */ *cp++ = 0; /*%< EDNS version */ if (statp->options & RES_USE_DNSSEC) { #ifdef DEBUG if (statp->options & RES_DEBUG) printf(";; res_opt()... ENDS0 DNSSEC\n"); #endif flags |= NS_OPT_DNSSEC_OK; } ns_put16(flags, cp); cp += INT16SZ; ns_put16(0U, cp); /*%< RDLEN */ cp += INT16SZ; hp->arcount = htons(ntohs(hp->arcount) + 1); return (cp - buf); } /* * Construct variable data (RDATA) block for OPT psuedo-RR, append it * to the buffer, then update the RDLEN field (previously set to zero by * res_nopt()) with the new RDATA length. */ int res_nopt_rdata(res_state statp, int n0, /*%< current offset in buffer */ u_char *buf, /*%< buffer to put query */ int buflen, /*%< size of buffer */ u_char *rdata, /*%< ptr to start of opt rdata */ u_short code, /*%< OPTION-CODE */ u_short len, /*%< OPTION-LENGTH */ u_char *data) /*%< OPTION_DATA */ { register u_char *cp, *ep; #ifdef DEBUG if ((statp->options & RES_DEBUG) != 0U) printf(";; res_nopt_rdata()\n"); #endif cp = buf + n0; ep = buf + buflen; if ((ep - cp) < (4 + len)) return (-1); if (rdata < (buf + 2) || rdata >= ep) return (-1); ns_put16(code, cp); cp += INT16SZ; ns_put16(len, cp); cp += INT16SZ; memcpy(cp, data, len); cp += len; len = cp - rdata; ns_put16(len, rdata - 2); /* Update RDLEN field */ return (cp - buf); } #endif /*! \file */ Index: stable/9/lib/libc/resolv/res_mkupdate.c =================================================================== --- stable/9/lib/libc/resolv/res_mkupdate.c (revision 292430) +++ stable/9/lib/libc/resolv/res_mkupdate.c (revision 292431) @@ -1,1197 +1,1199 @@ /* * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1996-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /*! \file * \brief * Based on the Dynamic DNS reference implementation by Viraj Bais * <viraj_bais@ccm.fm.intel.com> */ #if !defined(lint) && !defined(SABER) static const char rcsid[] = "$Id: res_mkupdate.c,v 1.10 2008/12/11 09:59:00 marka Exp $"; #endif /* not lint */ #include __FBSDID("$FreeBSD$"); #include "port_before.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef _LIBC #include #endif #include "port_after.h" /* Options. Leave them on. */ -#define DEBUG +#ifndef DEBUG +#define DEBUG +#endif #define MAXPORT 1024 static int getnum_str(u_char **, u_char *); static int gethexnum_str(u_char **, u_char *); static int getword_str(char *, int, u_char **, u_char *); static int getstr_str(char *, int, u_char **, u_char *); #define ShrinkBuffer(x) if ((buflen -= x) < 0) return (-2); /* Forward. */ #ifdef _LIBC static #endif int res_protocolnumber(const char *); #ifdef _LIBC static #endif int res_servicenumber(const char *); /*% * Form update packets. * Returns the size of the resulting packet if no error * * On error, * returns *\li -1 if error in reading a word/number in rdata * portion for update packets *\li -2 if length of buffer passed is insufficient *\li -3 if zone section is not the first section in * the linked list, or section order has a problem *\li -4 on a number overflow *\li -5 unknown operation or no records */ int res_nmkupdate(res_state statp, ns_updrec *rrecp_in, u_char *buf, int buflen) { ns_updrec *rrecp_start = rrecp_in; HEADER *hp; u_char *cp, *sp2, *startp, *endp; int n, i, soanum, multiline; ns_updrec *rrecp; struct in_addr ina; struct in6_addr in6a; char buf2[MAXDNAME]; u_char buf3[MAXDNAME]; int section, numrrs = 0, counts[ns_s_max]; u_int16_t rtype, rclass; u_int32_t n1, rttl; u_char *dnptrs[20], **dpp, **lastdnptr; #ifndef _LIBC int siglen; #endif int keylen, certlen; /* * Initialize header fields. */ if ((buf == NULL) || (buflen < HFIXEDSZ)) return (-1); memset(buf, 0, HFIXEDSZ); hp = (HEADER *) buf; statp->id = res_nrandomid(statp); hp->id = htons(statp->id); hp->opcode = ns_o_update; hp->rcode = NOERROR; cp = buf + HFIXEDSZ; buflen -= HFIXEDSZ; dpp = dnptrs; *dpp++ = buf; *dpp++ = NULL; lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0]; if (rrecp_start == NULL) return (-5); else if (rrecp_start->r_section != S_ZONE) return (-3); memset(counts, 0, sizeof counts); for (rrecp = rrecp_start; rrecp; rrecp = NEXT(rrecp, r_glink)) { numrrs++; section = rrecp->r_section; if (section < 0 || section >= ns_s_max) return (-1); counts[section]++; for (i = section + 1; i < ns_s_max; i++) if (counts[i]) return (-3); rtype = rrecp->r_type; rclass = rrecp->r_class; rttl = rrecp->r_ttl; /* overload class and type */ if (section == S_PREREQ) { rttl = 0; switch (rrecp->r_opcode) { case YXDOMAIN: rclass = C_ANY; rtype = T_ANY; rrecp->r_size = 0; break; case NXDOMAIN: rclass = C_NONE; rtype = T_ANY; rrecp->r_size = 0; break; case NXRRSET: rclass = C_NONE; rrecp->r_size = 0; break; case YXRRSET: if (rrecp->r_size == 0) rclass = C_ANY; break; default: fprintf(stderr, "res_mkupdate: incorrect opcode: %d\n", rrecp->r_opcode); fflush(stderr); return (-1); } } else if (section == S_UPDATE) { switch (rrecp->r_opcode) { case DELETE: rclass = rrecp->r_size == 0 ? C_ANY : C_NONE; break; case ADD: break; default: fprintf(stderr, "res_mkupdate: incorrect opcode: %d\n", rrecp->r_opcode); fflush(stderr); return (-1); } } /* * XXX appending default domain to owner name is omitted, * fqdn must be provided */ if ((n = dn_comp(rrecp->r_dname, cp, buflen, dnptrs, lastdnptr)) < 0) return (-1); cp += n; ShrinkBuffer(n + 2*INT16SZ); PUTSHORT(rtype, cp); PUTSHORT(rclass, cp); if (section == S_ZONE) { if (numrrs != 1 || rrecp->r_type != T_SOA) return (-3); continue; } ShrinkBuffer(INT32SZ + INT16SZ); PUTLONG(rttl, cp); sp2 = cp; /*%< save pointer to length byte */ cp += INT16SZ; if (rrecp->r_size == 0) { if (section == S_UPDATE && rclass != C_ANY) return (-1); else { PUTSHORT(0, sp2); continue; } } startp = rrecp->r_data; endp = startp + rrecp->r_size - 1; /* XXX this should be done centrally. */ switch (rrecp->r_type) { case T_A: if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); if (!inet_aton(buf2, &ina)) return (-1); n1 = ntohl(ina.s_addr); ShrinkBuffer(INT32SZ); PUTLONG(n1, cp); break; case T_CNAME: case T_MB: case T_MG: case T_MR: case T_NS: case T_PTR: case ns_t_dname: if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr); if (n < 0) return (-1); cp += n; ShrinkBuffer(n); break; case T_MINFO: case T_SOA: case T_RP: for (i = 0; i < 2; i++) { if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr); if (n < 0) return (-1); cp += n; ShrinkBuffer(n); } if (rrecp->r_type == T_SOA) { ShrinkBuffer(5 * INT32SZ); while (isspace(*startp) || !*startp) startp++; if (*startp == '(') { multiline = 1; startp++; } else multiline = 0; /* serial, refresh, retry, expire, minimum */ for (i = 0; i < 5; i++) { soanum = getnum_str(&startp, endp); if (soanum < 0) return (-1); PUTLONG(soanum, cp); } if (multiline) { while (isspace(*startp) || !*startp) startp++; if (*startp != ')') return (-1); } } break; case T_MX: case T_AFSDB: case T_RT: n = getnum_str(&startp, endp); if (n < 0) return (-1); ShrinkBuffer(INT16SZ); PUTSHORT(n, cp); if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr); if (n < 0) return (-1); cp += n; ShrinkBuffer(n); break; case T_SRV: n = getnum_str(&startp, endp); if (n < 0) return (-1); ShrinkBuffer(INT16SZ); PUTSHORT(n, cp); n = getnum_str(&startp, endp); if (n < 0) return (-1); ShrinkBuffer(INT16SZ); PUTSHORT(n, cp); n = getnum_str(&startp, endp); if (n < 0) return (-1); ShrinkBuffer(INT16SZ); PUTSHORT(n, cp); if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); n = dn_comp(buf2, cp, buflen, NULL, NULL); if (n < 0) return (-1); cp += n; ShrinkBuffer(n); break; case T_PX: n = getnum_str(&startp, endp); if (n < 0) return (-1); PUTSHORT(n, cp); ShrinkBuffer(INT16SZ); for (i = 0; i < 2; i++) { if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr); if (n < 0) return (-1); cp += n; ShrinkBuffer(n); } break; case T_WKS: { char bm[MAXPORT/8]; unsigned int maxbm = 0; if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); if (!inet_aton(buf2, &ina)) return (-1); n1 = ntohl(ina.s_addr); ShrinkBuffer(INT32SZ); PUTLONG(n1, cp); if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); if ((i = res_protocolnumber(buf2)) < 0) return (-1); ShrinkBuffer(1); *cp++ = i & 0xff; for (i = 0; i < MAXPORT/8 ; i++) bm[i] = 0; while (getword_str(buf2, sizeof buf2, &startp, endp)) { if ((n = res_servicenumber(buf2)) <= 0) return (-1); if (n < MAXPORT) { bm[n/8] |= (0x80>>(n%8)); if ((unsigned)n > maxbm) maxbm = n; } else return (-1); } maxbm = maxbm/8 + 1; ShrinkBuffer(maxbm); memcpy(cp, bm, maxbm); cp += maxbm; break; } case T_HINFO: for (i = 0; i < 2; i++) { if ((n = getstr_str(buf2, sizeof buf2, &startp, endp)) < 0) return (-1); if (n > 255) return (-1); ShrinkBuffer(n+1); *cp++ = n; memcpy(cp, buf2, n); cp += n; } break; case T_TXT: for (;;) { if ((n = getstr_str(buf2, sizeof buf2, &startp, endp)) < 0) { if (cp != (sp2 + INT16SZ)) break; return (-1); } if (n > 255) return (-1); ShrinkBuffer(n+1); *cp++ = n; memcpy(cp, buf2, n); cp += n; } break; case T_X25: /* RFC1183 */ if ((n = getstr_str(buf2, sizeof buf2, &startp, endp)) < 0) return (-1); if (n > 255) return (-1); ShrinkBuffer(n+1); *cp++ = n; memcpy(cp, buf2, n); cp += n; break; case T_ISDN: /* RFC1183 */ if ((n = getstr_str(buf2, sizeof buf2, &startp, endp)) < 0) return (-1); if ((n > 255) || (n == 0)) return (-1); ShrinkBuffer(n+1); *cp++ = n; memcpy(cp, buf2, n); cp += n; if ((n = getstr_str(buf2, sizeof buf2, &startp, endp)) < 0) n = 0; if (n > 255) return (-1); ShrinkBuffer(n+1); *cp++ = n; memcpy(cp, buf2, n); cp += n; break; case T_NSAP: if ((n = inet_nsap_addr((char *)startp, (u_char *)buf2, sizeof(buf2))) != 0) { ShrinkBuffer(n); memcpy(cp, buf2, n); cp += n; } else { return (-1); } break; case T_LOC: if ((n = loc_aton((char *)startp, (u_char *)buf2)) != 0) { ShrinkBuffer(n); memcpy(cp, buf2, n); cp += n; } else return (-1); break; case ns_t_sig: #ifdef _LIBC return (-1); #else { int sig_type, success, dateerror; u_int32_t exptime, timesigned; /* type */ if ((n = getword_str(buf2, sizeof buf2, &startp, endp)) < 0) return (-1); sig_type = sym_ston(__p_type_syms, buf2, &success); if (!success || sig_type == ns_t_any) return (-1); ShrinkBuffer(INT16SZ); PUTSHORT(sig_type, cp); /* alg */ n = getnum_str(&startp, endp); if (n < 0) return (-1); ShrinkBuffer(1); *cp++ = n; /* labels */ n = getnum_str(&startp, endp); if (n <= 0 || n > 255) return (-1); ShrinkBuffer(1); *cp++ = n; /* ottl & expire */ if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); exptime = ns_datetosecs(buf2, &dateerror); if (!dateerror) { ShrinkBuffer(INT32SZ); PUTLONG(rttl, cp); } else { char *ulendp; u_int32_t ottl; errno = 0; ottl = strtoul(buf2, &ulendp, 10); if (errno != 0 || (ulendp != NULL && *ulendp != '\0')) return (-1); ShrinkBuffer(INT32SZ); PUTLONG(ottl, cp); if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); exptime = ns_datetosecs(buf2, &dateerror); if (dateerror) return (-1); } /* expire */ ShrinkBuffer(INT32SZ); PUTLONG(exptime, cp); /* timesigned */ if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); timesigned = ns_datetosecs(buf2, &dateerror); if (!dateerror) { ShrinkBuffer(INT32SZ); PUTLONG(timesigned, cp); } else return (-1); /* footprint */ n = getnum_str(&startp, endp); if (n < 0) return (-1); ShrinkBuffer(INT16SZ); PUTSHORT(n, cp); /* signer name */ if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr); if (n < 0) return (-1); cp += n; ShrinkBuffer(n); /* sig */ if ((n = getword_str(buf2, sizeof buf2, &startp, endp)) < 0) return (-1); siglen = b64_pton(buf2, buf3, sizeof(buf3)); if (siglen < 0) return (-1); ShrinkBuffer(siglen); memcpy(cp, buf3, siglen); cp += siglen; break; } #endif case ns_t_key: /* flags */ n = gethexnum_str(&startp, endp); if (n < 0) return (-1); ShrinkBuffer(INT16SZ); PUTSHORT(n, cp); /* proto */ n = getnum_str(&startp, endp); if (n < 0) return (-1); ShrinkBuffer(1); *cp++ = n; /* alg */ n = getnum_str(&startp, endp); if (n < 0) return (-1); ShrinkBuffer(1); *cp++ = n; /* key */ if ((n = getword_str(buf2, sizeof buf2, &startp, endp)) < 0) return (-1); keylen = b64_pton(buf2, buf3, sizeof(buf3)); if (keylen < 0) return (-1); ShrinkBuffer(keylen); memcpy(cp, buf3, keylen); cp += keylen; break; case ns_t_nxt: { int success, nxt_type; u_char data[32]; int maxtype; /* next name */ if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); n = dn_comp(buf2, cp, buflen, NULL, NULL); if (n < 0) return (-1); cp += n; ShrinkBuffer(n); maxtype = 0; memset(data, 0, sizeof data); for (;;) { if (!getword_str(buf2, sizeof buf2, &startp, endp)) break; nxt_type = sym_ston(__p_type_syms, buf2, &success); if (!success || !ns_t_rr_p(nxt_type)) return (-1); NS_NXT_BIT_SET(nxt_type, data); if (nxt_type > maxtype) maxtype = nxt_type; } n = maxtype/NS_NXT_BITS+1; ShrinkBuffer(n); memcpy(cp, data, n); cp += n; break; } case ns_t_cert: /* type */ n = getnum_str(&startp, endp); if (n < 0) return (-1); ShrinkBuffer(INT16SZ); PUTSHORT(n, cp); /* key tag */ n = getnum_str(&startp, endp); if (n < 0) return (-1); ShrinkBuffer(INT16SZ); PUTSHORT(n, cp); /* alg */ n = getnum_str(&startp, endp); if (n < 0) return (-1); ShrinkBuffer(1); *cp++ = n; /* cert */ if ((n = getword_str(buf2, sizeof buf2, &startp, endp)) < 0) return (-1); certlen = b64_pton(buf2, buf3, sizeof(buf3)); if (certlen < 0) return (-1); ShrinkBuffer(certlen); memcpy(cp, buf3, certlen); cp += certlen; break; case ns_t_aaaa: if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); if (inet_pton(AF_INET6, buf2, &in6a) <= 0) return (-1); ShrinkBuffer(NS_IN6ADDRSZ); memcpy(cp, &in6a, NS_IN6ADDRSZ); cp += NS_IN6ADDRSZ; break; case ns_t_naptr: /* Order Preference Flags Service Replacement Regexp */ /* Order */ n = getnum_str(&startp, endp); if (n < 0 || n > 65535) return (-1); ShrinkBuffer(INT16SZ); PUTSHORT(n, cp); /* Preference */ n = getnum_str(&startp, endp); if (n < 0 || n > 65535) return (-1); ShrinkBuffer(INT16SZ); PUTSHORT(n, cp); /* Flags */ if ((n = getstr_str(buf2, sizeof buf2, &startp, endp)) < 0) { return (-1); } if (n > 255) return (-1); ShrinkBuffer(n+1); *cp++ = n; memcpy(cp, buf2, n); cp += n; /* Service Classes */ if ((n = getstr_str(buf2, sizeof buf2, &startp, endp)) < 0) { return (-1); } if (n > 255) return (-1); ShrinkBuffer(n+1); *cp++ = n; memcpy(cp, buf2, n); cp += n; /* Pattern */ if ((n = getstr_str(buf2, sizeof buf2, &startp, endp)) < 0) { return (-1); } if (n > 255) return (-1); ShrinkBuffer(n+1); *cp++ = n; memcpy(cp, buf2, n); cp += n; /* Replacement */ if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); n = dn_comp(buf2, cp, buflen, NULL, NULL); if (n < 0) return (-1); cp += n; ShrinkBuffer(n); break; default: return (-1); } /*switch*/ n = (u_int16_t)((cp - sp2) - INT16SZ); PUTSHORT(n, sp2); } /*for*/ hp->qdcount = htons(counts[0]); hp->ancount = htons(counts[1]); hp->nscount = htons(counts[2]); hp->arcount = htons(counts[3]); return (cp - buf); } /*% * Get a whitespace delimited word from a string (not file) * into buf. modify the start pointer to point after the * word in the string. */ static int getword_str(char *buf, int size, u_char **startpp, u_char *endp) { char *cp; int c; for (cp = buf; *startpp <= endp; ) { c = **startpp; if (isspace(c) || c == '\0') { if (cp != buf) /*%< trailing whitespace */ break; else { /*%< leading whitespace */ (*startpp)++; continue; } } (*startpp)++; if (cp >= buf+size-1) break; *cp++ = (u_char)c; } *cp = '\0'; return (cp != buf); } /*% * get a white spae delimited string from memory. Process quoted strings * and \\DDD escapes. Return length or -1 on error. Returned string may * contain nulls. */ static char digits[] = "0123456789"; static int getstr_str(char *buf, int size, u_char **startpp, u_char *endp) { char *cp; int c, c1 = 0; int inquote = 0; int seen_quote = 0; int escape = 0; int dig = 0; for (cp = buf; *startpp <= endp; ) { if ((c = **startpp) == '\0') break; /* leading white space */ if ((cp == buf) && !seen_quote && isspace(c)) { (*startpp)++; continue; } switch (c) { case '\\': if (!escape) { escape = 1; dig = 0; c1 = 0; (*startpp)++; continue; } goto do_escape; case '"': if (!escape) { inquote = !inquote; seen_quote = 1; (*startpp)++; continue; } /* fall through */ default: do_escape: if (escape) { switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': c1 = c1 * 10 + (strchr(digits, c) - digits); if (++dig == 3) { c = c1 &0xff; break; } (*startpp)++; continue; } escape = 0; } else if (!inquote && isspace(c)) goto done; if (cp >= buf+size-1) goto done; *cp++ = (u_char)c; (*startpp)++; } } done: *cp = '\0'; return ((cp == buf)? (seen_quote? 0: -1): (cp - buf)); } /*% * Get a whitespace delimited base 16 number from a string (not file) into buf * update the start pointer to point after the number in the string. */ static int gethexnum_str(u_char **startpp, u_char *endp) { int c, n; int seendigit = 0; int m = 0; if (*startpp + 2 >= endp || strncasecmp((char *)*startpp, "0x", 2) != 0) return getnum_str(startpp, endp); (*startpp)+=2; for (n = 0; *startpp <= endp; ) { c = **startpp; if (isspace(c) || c == '\0') { if (seendigit) /*%< trailing whitespace */ break; else { /*%< leading whitespace */ (*startpp)++; continue; } } if (c == ';') { while ((*startpp <= endp) && ((c = **startpp) != '\n')) (*startpp)++; if (seendigit) break; continue; } if (!isxdigit(c)) { if (c == ')' && seendigit) { (*startpp)--; break; } return (-1); } (*startpp)++; if (isdigit(c)) n = n * 16 + (c - '0'); else n = n * 16 + (tolower(c) - 'a' + 10); seendigit = 1; } return (n + m); } /*% * Get a whitespace delimited base 10 number from a string (not file) into buf * update the start pointer to point after the number in the string. */ static int getnum_str(u_char **startpp, u_char *endp) { int c, n; int seendigit = 0; int m = 0; for (n = 0; *startpp <= endp; ) { c = **startpp; if (isspace(c) || c == '\0') { if (seendigit) /*%< trailing whitespace */ break; else { /*%< leading whitespace */ (*startpp)++; continue; } } if (c == ';') { while ((*startpp <= endp) && ((c = **startpp) != '\n')) (*startpp)++; if (seendigit) break; continue; } if (!isdigit(c)) { if (c == ')' && seendigit) { (*startpp)--; break; } return (-1); } (*startpp)++; n = n * 10 + (c - '0'); seendigit = 1; } return (n + m); } /*% * Allocate a resource record buffer & save rr info. */ ns_updrec * res_mkupdrec(int section, const char *dname, u_int class, u_int type, u_long ttl) { ns_updrec *rrecp = (ns_updrec *)calloc(1, sizeof(ns_updrec)); if (!rrecp || !(rrecp->r_dname = strdup(dname))) { if (rrecp) free((char *)rrecp); return (NULL); } INIT_LINK(rrecp, r_link); INIT_LINK(rrecp, r_glink); rrecp->r_class = (ns_class)class; rrecp->r_type = (ns_type)type; rrecp->r_ttl = ttl; rrecp->r_section = (ns_sect)section; return (rrecp); } /*% * Free a resource record buffer created by res_mkupdrec. */ void res_freeupdrec(ns_updrec *rrecp) { /* Note: freeing r_dp is the caller's responsibility. */ if (rrecp->r_dname != NULL) free(rrecp->r_dname); free(rrecp); } struct valuelist { struct valuelist * next; struct valuelist * prev; char * name; char * proto; int port; }; static struct valuelist *servicelist, *protolist; static void res_buildservicelist() { struct servent *sp; struct valuelist *slp; #ifdef MAYBE_HESIOD setservent(0); #else setservent(1); #endif while ((sp = getservent()) != NULL) { slp = (struct valuelist *)malloc(sizeof(struct valuelist)); if (!slp) break; slp->name = strdup(sp->s_name); slp->proto = strdup(sp->s_proto); if ((slp->name == NULL) || (slp->proto == NULL)) { if (slp->name) free(slp->name); if (slp->proto) free(slp->proto); free(slp); break; } slp->port = ntohs((u_int16_t)sp->s_port); /*%< host byt order */ slp->next = servicelist; slp->prev = NULL; if (servicelist) servicelist->prev = slp; servicelist = slp; } endservent(); } #ifndef _LIBC void res_destroyservicelist() { struct valuelist *slp, *slp_next; for (slp = servicelist; slp != NULL; slp = slp_next) { slp_next = slp->next; free(slp->name); free(slp->proto); free(slp); } servicelist = (struct valuelist *)0; } #endif #ifdef _LIBC static #endif void res_buildprotolist(void) { struct protoent *pp; struct valuelist *slp; #ifdef MAYBE_HESIOD setprotoent(0); #else setprotoent(1); #endif while ((pp = getprotoent()) != NULL) { slp = (struct valuelist *)malloc(sizeof(struct valuelist)); if (!slp) break; slp->name = strdup(pp->p_name); if (slp->name == NULL) { free(slp); break; } slp->port = pp->p_proto; /*%< host byte order */ slp->next = protolist; slp->prev = NULL; if (protolist) protolist->prev = slp; protolist = slp; } endprotoent(); } #ifndef _LIBC void res_destroyprotolist(void) { struct valuelist *plp, *plp_next; for (plp = protolist; plp != NULL; plp = plp_next) { plp_next = plp->next; free(plp->name); free(plp); } protolist = (struct valuelist *)0; } #endif static int findservice(const char *s, struct valuelist **list) { struct valuelist *lp = *list; int n; for (; lp != NULL; lp = lp->next) if (strcasecmp(lp->name, s) == 0) { if (lp != *list) { lp->prev->next = lp->next; if (lp->next) lp->next->prev = lp->prev; (*list)->prev = lp; lp->next = *list; *list = lp; } return (lp->port); /*%< host byte order */ } if (sscanf(s, "%d", &n) != 1 || n <= 0) n = -1; return (n); } /*% * Convert service name or (ascii) number to int. */ #ifdef _LIBC static #endif int res_servicenumber(const char *p) { if (servicelist == (struct valuelist *)0) res_buildservicelist(); return (findservice(p, &servicelist)); } /*% * Convert protocol name or (ascii) number to int. */ #ifdef _LIBC static #endif int res_protocolnumber(const char *p) { if (protolist == (struct valuelist *)0) res_buildprotolist(); return (findservice(p, &protolist)); } #ifndef _LIBC static struct servent * cgetservbyport(u_int16_t port, const char *proto) { /*%< Host byte order. */ struct valuelist **list = &servicelist; struct valuelist *lp = *list; static struct servent serv; port = ntohs(port); for (; lp != NULL; lp = lp->next) { if (port != (u_int16_t)lp->port) /*%< Host byte order. */ continue; if (strcasecmp(lp->proto, proto) == 0) { if (lp != *list) { lp->prev->next = lp->next; if (lp->next) lp->next->prev = lp->prev; (*list)->prev = lp; lp->next = *list; *list = lp; } serv.s_name = lp->name; serv.s_port = htons((u_int16_t)lp->port); serv.s_proto = lp->proto; return (&serv); } } return (0); } static struct protoent * cgetprotobynumber(int proto) { /*%< Host byte order. */ struct valuelist **list = &protolist; struct valuelist *lp = *list; static struct protoent prot; for (; lp != NULL; lp = lp->next) if (lp->port == proto) { /*%< Host byte order. */ if (lp != *list) { lp->prev->next = lp->next; if (lp->next) lp->next->prev = lp->prev; (*list)->prev = lp; lp->next = *list; *list = lp; } prot.p_name = lp->name; prot.p_proto = lp->port; /*%< Host byte order. */ return (&prot); } return (0); } const char * res_protocolname(int num) { static char number[8]; struct protoent *pp; if (protolist == (struct valuelist *)0) res_buildprotolist(); pp = cgetprotobynumber(num); if (pp == 0) { (void) sprintf(number, "%d", num); return (number); } return (pp->p_name); } const char * res_servicename(u_int16_t port, const char *proto) { /*%< Host byte order. */ static char number[8]; struct servent *ss; if (servicelist == (struct valuelist *)0) res_buildservicelist(); ss = cgetservbyport(htons(port), proto); if (ss == 0) { (void) sprintf(number, "%d", port); return (number); } return (ss->s_name); } #endif Index: stable/9/lib/libc/resolv/res_query.c =================================================================== --- stable/9/lib/libc/resolv/res_query.c (revision 292430) +++ stable/9/lib/libc/resolv/res_query.c (revision 292431) @@ -1,489 +1,491 @@ /* * Portions Copyright (C) 2004, 2005, 2008 Internet Systems Consortium, Inc. ("ISC") * Portions Copyright (C) 1996-2001, 2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ /* * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Portions Copyright (c) 1993 by Digital Equipment Corporation. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies, and that * the name of Digital Equipment Corporation not be used in advertising or * publicity pertaining to distribution of the document or software without * specific, written prior permission. * * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ #if defined(LIBC_SCCS) && !defined(lint) static const char sccsid[] = "@(#)res_query.c 8.1 (Berkeley) 6/4/93"; static const char rcsid[] = "$Id: res_query.c,v 1.11 2008/11/14 02:36:51 marka Exp $"; #endif /* LIBC_SCCS and not lint */ #include __FBSDID("$FreeBSD$"); #include "port_before.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "port_after.h" /* Options. Leave them on. */ -#define DEBUG +#ifndef DEBUG +#define DEBUG +#endif #if PACKETSZ > 1024 #define MAXPACKET PACKETSZ #else #define MAXPACKET 1024 #endif /*% * Formulate a normal query, send, and await answer. * Returned answer is placed in supplied buffer "answer". * Perform preliminary check of answer, returning success only * if no error is indicated and the answer count is nonzero. * Return the size of the response on success, -1 on error. * Error number is left in H_ERRNO. * * Caller must parse answer and determine whether it answers the question. */ int res_nquery(res_state statp, const char *name, /*%< domain name */ int class, int type, /*%< class and type of query */ u_char *answer, /*%< buffer to put answer */ int anslen) /*%< size of answer buffer */ { u_char buf[MAXPACKET]; HEADER *hp = (HEADER *) answer; u_int oflags; u_char *rdata; int n; oflags = statp->_flags; again: hp->rcode = NOERROR; /*%< default */ #ifdef DEBUG if (statp->options & RES_DEBUG) printf(";; res_query(%s, %d, %d)\n", name, class, type); #endif n = res_nmkquery(statp, QUERY, name, class, type, NULL, 0, NULL, buf, sizeof(buf)); #ifdef RES_USE_EDNS0 if (n > 0 && (statp->_flags & RES_F_EDNS0ERR) == 0 && (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC|RES_NSID))) { n = res_nopt(statp, n, buf, sizeof(buf), anslen); rdata = &buf[n]; if (n > 0 && (statp->options & RES_NSID) != 0U) { n = res_nopt_rdata(statp, n, buf, sizeof(buf), rdata, NS_OPT_NSID, 0, NULL); } } #endif if (n <= 0) { #ifdef DEBUG if (statp->options & RES_DEBUG) printf(";; res_query: mkquery failed\n"); #endif RES_SET_H_ERRNO(statp, NO_RECOVERY); return (n); } n = res_nsend(statp, buf, n, answer, anslen); if (n < 0) { #ifdef RES_USE_EDNS0 /* if the query choked with EDNS0, retry without EDNS0 */ if ((statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0U && ((oflags ^ statp->_flags) & RES_F_EDNS0ERR) != 0) { statp->_flags |= RES_F_EDNS0ERR; if (statp->options & RES_DEBUG) printf(";; res_nquery: retry without EDNS0\n"); goto again; } #endif #ifdef DEBUG if (statp->options & RES_DEBUG) printf(";; res_query: send error\n"); #endif RES_SET_H_ERRNO(statp, TRY_AGAIN); return (n); } if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) { #ifdef DEBUG if (statp->options & RES_DEBUG) printf(";; rcode = (%s), counts = an:%d ns:%d ar:%d\n", p_rcode(hp->rcode), ntohs(hp->ancount), ntohs(hp->nscount), ntohs(hp->arcount)); #endif switch (hp->rcode) { case NXDOMAIN: RES_SET_H_ERRNO(statp, HOST_NOT_FOUND); break; case SERVFAIL: RES_SET_H_ERRNO(statp, TRY_AGAIN); break; case NOERROR: RES_SET_H_ERRNO(statp, NO_DATA); break; case FORMERR: case NOTIMP: case REFUSED: default: RES_SET_H_ERRNO(statp, NO_RECOVERY); break; } return (-1); } return (n); } /*% * Formulate a normal query, send, and retrieve answer in supplied buffer. * Return the size of the response on success, -1 on error. * If enabled, implement search rules until answer or unrecoverable failure * is detected. Error code, if any, is left in H_ERRNO. */ int res_nsearch(res_state statp, const char *name, /*%< domain name */ int class, int type, /*%< class and type of query */ u_char *answer, /*%< buffer to put answer */ int anslen) /*%< size of answer */ { const char *cp, * const *domain; HEADER *hp = (HEADER *) answer; char tmp[NS_MAXDNAME]; u_int dots; int trailing_dot, ret, saved_herrno; int got_nodata = 0, got_servfail = 0, root_on_list = 0; int tried_as_is = 0; int searched = 0; errno = 0; RES_SET_H_ERRNO(statp, HOST_NOT_FOUND); /*%< True if we never query. */ dots = 0; for (cp = name; *cp != '\0'; cp++) dots += (*cp == '.'); trailing_dot = 0; if (cp > name && *--cp == '.') trailing_dot++; /* If there aren't any dots, it could be a user-level alias. */ if (!dots && (cp = res_hostalias(statp, name, tmp, sizeof tmp))!= NULL) return (res_nquery(statp, cp, class, type, answer, anslen)); /* * If there are enough dots in the name, let's just give it a * try 'as is'. The threshold can be set with the "ndots" option. * Also, query 'as is', if there is a trailing dot in the name. */ saved_herrno = -1; if (dots >= statp->ndots || trailing_dot) { ret = res_nquerydomain(statp, name, NULL, class, type, answer, anslen); if (ret > 0 || trailing_dot) return (ret); if (errno == ECONNREFUSED) { RES_SET_H_ERRNO(statp, TRY_AGAIN); return (-1); } switch (statp->res_h_errno) { case NO_DATA: case HOST_NOT_FOUND: break; case TRY_AGAIN: if (hp->rcode == SERVFAIL) break; /* FALLTHROUGH */ default: return (-1); } saved_herrno = statp->res_h_errno; tried_as_is++; } /* * We do at least one level of search if * - there is no dot and RES_DEFNAME is set, or * - there is at least one dot, there is no trailing dot, * and RES_DNSRCH is set. */ if ((!dots && (statp->options & RES_DEFNAMES) != 0U) || (dots && !trailing_dot && (statp->options & RES_DNSRCH) != 0U)) { int done = 0; for (domain = (const char * const *)statp->dnsrch; *domain && !done; domain++) { searched = 1; if (domain[0][0] == '\0' || (domain[0][0] == '.' && domain[0][1] == '\0')) root_on_list++; if (root_on_list && tried_as_is) continue; ret = res_nquerydomain(statp, name, *domain, class, type, answer, anslen); if (ret > 0) return (ret); /* * If no server present, give up. * If name isn't found in this domain, * keep trying higher domains in the search list * (if that's enabled). * On a NO_DATA error, keep trying, otherwise * a wildcard entry of another type could keep us * from finding this entry higher in the domain. * If we get some other error (negative answer or * server failure), then stop searching up, * but try the input name below in case it's * fully-qualified. */ if (errno == ECONNREFUSED) { RES_SET_H_ERRNO(statp, TRY_AGAIN); return (-1); } switch (statp->res_h_errno) { case NO_DATA: got_nodata++; /* FALLTHROUGH */ case HOST_NOT_FOUND: /* keep trying */ break; case TRY_AGAIN: /* * This can occur due to a server failure * (that is, all listed servers have failed), * or all listed servers have timed out. * ((HEADER *)answer)->rcode may not be set * to SERVFAIL in the case of a timeout. * * Either way we must return TRY_AGAIN in * order to avoid non-deterministic * return codes. * For example, loaded name servers or races * against network startup/validation (dhcp, * ppp, etc) can cause the search to timeout * on one search element, e.g. 'fu.bar.com', * and return a definitive failure on the * next search element, e.g. 'fu.'. */ got_servfail++; if (hp->rcode == SERVFAIL) { /* try next search element, if any */ break; } /* FALLTHROUGH */ default: /* anything else implies that we're done */ done++; } /* if we got here for some reason other than DNSRCH, * we only wanted one iteration of the loop, so stop. */ if ((statp->options & RES_DNSRCH) == 0U) done++; } } switch (statp->res_h_errno) { case NO_DATA: case HOST_NOT_FOUND: break; case TRY_AGAIN: if (hp->rcode == SERVFAIL) break; /* FALLTHROUGH */ default: goto giveup; } /* * If the query has not already been tried as is then try it * unless RES_NOTLDQUERY is set and there were no dots. */ if ((dots || !searched || (statp->options & RES_NOTLDQUERY) == 0U) && !(tried_as_is || root_on_list)) { ret = res_nquerydomain(statp, name, NULL, class, type, answer, anslen); if (ret > 0) return (ret); } /* if we got here, we didn't satisfy the search. * if we did an initial full query, return that query's H_ERRNO * (note that we wouldn't be here if that query had succeeded). * else if we ever got a nodata, send that back as the reason. * else send back meaningless H_ERRNO, that being the one from * the last DNSRCH we did. */ giveup: if (saved_herrno != -1) RES_SET_H_ERRNO(statp, saved_herrno); else if (got_nodata) RES_SET_H_ERRNO(statp, NO_DATA); else if (got_servfail) RES_SET_H_ERRNO(statp, TRY_AGAIN); return (-1); } /*% * Perform a call on res_query on the concatenation of name and domain, * removing a trailing dot from name if domain is NULL. */ int res_nquerydomain(res_state statp, const char *name, const char *domain, int class, int type, /*%< class and type of query */ u_char *answer, /*%< buffer to put answer */ int anslen) /*%< size of answer */ { char nbuf[MAXDNAME]; const char *longname = nbuf; int n, d; #ifdef DEBUG if (statp->options & RES_DEBUG) printf(";; res_nquerydomain(%s, %s, %d, %d)\n", name, domain?domain:"", class, type); #endif if (domain == NULL) { /* * Check for trailing '.'; * copy without '.' if present. */ n = strlen(name); if (n >= MAXDNAME) { RES_SET_H_ERRNO(statp, NO_RECOVERY); return (-1); } n--; if (n >= 0 && name[n] == '.') { strncpy(nbuf, name, n); nbuf[n] = '\0'; } else longname = name; } else { n = strlen(name); d = strlen(domain); if (n + d + 1 >= MAXDNAME) { RES_SET_H_ERRNO(statp, NO_RECOVERY); return (-1); } sprintf(nbuf, "%s.%s", name, domain); } return (res_nquery(statp, longname, class, type, answer, anslen)); } const char * res_hostalias(const res_state statp, const char *name, char *dst, size_t siz) { char *file, *cp1, *cp2; char buf[BUFSIZ]; FILE *fp; if (statp->options & RES_NOALIASES) return (NULL); if (issetugid()) return (NULL); file = getenv("HOSTALIASES"); if (file == NULL || (fp = fopen(file, "r")) == NULL) return (NULL); setbuf(fp, NULL); buf[sizeof(buf) - 1] = '\0'; while (fgets(buf, sizeof(buf), fp)) { for (cp1 = buf; *cp1 && !isspace((unsigned char)*cp1); ++cp1) ; if (!*cp1) break; *cp1 = '\0'; if (ns_samename(buf, name) == 1) { while (isspace((unsigned char)*++cp1)) ; if (!*cp1) break; for (cp2 = cp1 + 1; *cp2 && !isspace((unsigned char)*cp2); ++cp2) ; *cp2 = '\0'; strncpy(dst, cp1, siz - 1); dst[siz - 1] = '\0'; fclose(fp); return (dst); } } fclose(fp); return (NULL); } /*! \file */ Index: stable/9/lib/libc/resolv/res_send.c =================================================================== --- stable/9/lib/libc/resolv/res_send.c (revision 292430) +++ stable/9/lib/libc/resolv/res_send.c (revision 292431) @@ -1,1179 +1,1181 @@ /* * Portions Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Portions Copyright (C) 1996-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ /* * Copyright (c) 1985, 1989, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Portions Copyright (c) 1993 by Digital Equipment Corporation. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies, and that * the name of Digital Equipment Corporation not be used in advertising or * publicity pertaining to distribution of the document or software without * specific, written prior permission. * * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ #if defined(LIBC_SCCS) && !defined(lint) static const char sccsid[] = "@(#)res_send.c 8.1 (Berkeley) 6/4/93"; static const char rcsid[] = "$Id: res_send.c,v 1.22 2009/01/22 23:49:23 tbox Exp $"; #endif /* LIBC_SCCS and not lint */ #include __FBSDID("$FreeBSD$"); /*! \file * \brief * Send query to name server and wait for reply. */ #include "port_before.h" #ifndef USE_KQUEUE #include "fd_setsize.h" #endif #include "namespace.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "port_after.h" #ifdef USE_KQUEUE #include #else #ifdef USE_POLL #ifdef HAVE_STROPTS_H #include #endif #include #endif /* USE_POLL */ #endif #include "un-namespace.h" /* Options. Leave them on. */ -#define DEBUG +#ifndef DEBUG +#define DEBUG +#endif #include "res_debug.h" #include "res_private.h" #define EXT(res) ((res)->_u._ext) #if !defined(USE_POLL) && !defined(USE_KQUEUE) static const int highestFD = FD_SETSIZE - 1; #endif /* Forward. */ static int get_salen(const struct sockaddr *); static struct sockaddr * get_nsaddr(res_state, size_t); static int send_vc(res_state, const u_char *, int, u_char *, int, int *, int); static int send_dg(res_state, #ifdef USE_KQUEUE int kq, #endif const u_char *, int, u_char *, int, int *, int, int, int *, int *); static void Aerror(const res_state, FILE *, const char *, int, const struct sockaddr *, int); static void Perror(const res_state, FILE *, const char *, int); static int sock_eq(struct sockaddr *, struct sockaddr *); #if defined(NEED_PSELECT) && !defined(USE_POLL) && !defined(USE_KQUEUE) static int pselect(int, void *, void *, void *, struct timespec *, const sigset_t *); #endif void res_pquery(const res_state, const u_char *, int, FILE *); static const int niflags = NI_NUMERICHOST | NI_NUMERICSERV; /* Public. */ /*% * looks up "ina" in _res.ns_addr_list[] * * returns: *\li 0 : not found *\li >0 : found * * author: *\li paul vixie, 29may94 */ int res_ourserver_p(const res_state statp, const struct sockaddr *sa) { const struct sockaddr_in *inp, *srv; const struct sockaddr_in6 *in6p, *srv6; int ns; switch (sa->sa_family) { case AF_INET: inp = (const struct sockaddr_in *)sa; for (ns = 0; ns < statp->nscount; ns++) { srv = (struct sockaddr_in *)get_nsaddr(statp, ns); if (srv->sin_family == inp->sin_family && srv->sin_port == inp->sin_port && (srv->sin_addr.s_addr == INADDR_ANY || srv->sin_addr.s_addr == inp->sin_addr.s_addr)) return (1); } break; case AF_INET6: if (EXT(statp).ext == NULL) break; in6p = (const struct sockaddr_in6 *)sa; for (ns = 0; ns < statp->nscount; ns++) { srv6 = (struct sockaddr_in6 *)get_nsaddr(statp, ns); if (srv6->sin6_family == in6p->sin6_family && srv6->sin6_port == in6p->sin6_port && #ifdef HAVE_SIN6_SCOPE_ID (srv6->sin6_scope_id == 0 || srv6->sin6_scope_id == in6p->sin6_scope_id) && #endif (IN6_IS_ADDR_UNSPECIFIED(&srv6->sin6_addr) || IN6_ARE_ADDR_EQUAL(&srv6->sin6_addr, &in6p->sin6_addr))) return (1); } break; default: break; } return (0); } /*% * look for (name,type,class) in the query section of packet (buf,eom) * * requires: *\li buf + HFIXEDSZ <= eom * * returns: *\li -1 : format error *\li 0 : not found *\li >0 : found * * author: *\li paul vixie, 29may94 */ int res_nameinquery(const char *name, int type, int class, const u_char *buf, const u_char *eom) { const u_char *cp = buf + HFIXEDSZ; int qdcount = ntohs(((const HEADER*)buf)->qdcount); while (qdcount-- > 0) { char tname[MAXDNAME+1]; int n, ttype, tclass; n = dn_expand(buf, eom, cp, tname, sizeof tname); if (n < 0) return (-1); cp += n; if (cp + 2 * INT16SZ > eom) return (-1); ttype = ns_get16(cp); cp += INT16SZ; tclass = ns_get16(cp); cp += INT16SZ; if (ttype == type && tclass == class && ns_samename(tname, name) == 1) return (1); } return (0); } /*% * is there a 1:1 mapping of (name,type,class) * in (buf1,eom1) and (buf2,eom2)? * * returns: *\li -1 : format error *\li 0 : not a 1:1 mapping *\li >0 : is a 1:1 mapping * * author: *\li paul vixie, 29may94 */ int res_queriesmatch(const u_char *buf1, const u_char *eom1, const u_char *buf2, const u_char *eom2) { const u_char *cp = buf1 + HFIXEDSZ; int qdcount = ntohs(((const HEADER*)buf1)->qdcount); if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2) return (-1); /* * Only header section present in replies to * dynamic update packets. */ if ((((const HEADER *)buf1)->opcode == ns_o_update) && (((const HEADER *)buf2)->opcode == ns_o_update)) return (1); if (qdcount != ntohs(((const HEADER*)buf2)->qdcount)) return (0); while (qdcount-- > 0) { char tname[MAXDNAME+1]; int n, ttype, tclass; n = dn_expand(buf1, eom1, cp, tname, sizeof tname); if (n < 0) return (-1); cp += n; if (cp + 2 * INT16SZ > eom1) return (-1); ttype = ns_get16(cp); cp += INT16SZ; tclass = ns_get16(cp); cp += INT16SZ; if (!res_nameinquery(tname, ttype, tclass, buf2, eom2)) return (0); } return (1); } int res_nsend(res_state statp, const u_char *buf, int buflen, u_char *ans, int anssiz) { int gotsomewhere, terrno, tries, v_circuit, resplen, ns, n; #ifdef USE_KQUEUE int kq; #endif char abuf[NI_MAXHOST]; /* No name servers or res_init() failure */ if (statp->nscount == 0 || EXT(statp).ext == NULL) { errno = ESRCH; return (-1); } if (anssiz < HFIXEDSZ) { errno = EINVAL; return (-1); } DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_QUERY), (stdout, ";; res_send()\n"), buf, buflen); v_circuit = (statp->options & RES_USEVC) || buflen > PACKETSZ; gotsomewhere = 0; terrno = ETIMEDOUT; #ifdef USE_KQUEUE if ((kq = kqueue()) < 0) { Perror(statp, stderr, "kqueue", errno); return (-1); } #endif /* * If the ns_addr_list in the resolver context has changed, then * invalidate our cached copy and the associated timing data. */ if (EXT(statp).nscount != 0) { int needclose = 0; struct sockaddr_storage peer; ISC_SOCKLEN_T peerlen; if (EXT(statp).nscount != statp->nscount) needclose++; else for (ns = 0; ns < statp->nscount; ns++) { if (statp->nsaddr_list[ns].sin_family && !sock_eq((struct sockaddr *)&statp->nsaddr_list[ns], (struct sockaddr *)&EXT(statp).ext->nsaddrs[ns])) { needclose++; break; } if (EXT(statp).nssocks[ns] == -1) continue; peerlen = sizeof(peer); if (_getpeername(EXT(statp).nssocks[ns], (struct sockaddr *)&peer, &peerlen) < 0) { needclose++; break; } if (!sock_eq((struct sockaddr *)&peer, get_nsaddr(statp, ns))) { needclose++; break; } } if (needclose) { res_nclose(statp); EXT(statp).nscount = 0; } } /* * Maybe initialize our private copy of the ns_addr_list. */ if (EXT(statp).nscount == 0) { for (ns = 0; ns < statp->nscount; ns++) { EXT(statp).nstimes[ns] = RES_MAXTIME; EXT(statp).nssocks[ns] = -1; if (!statp->nsaddr_list[ns].sin_family) continue; EXT(statp).ext->nsaddrs[ns].sin = statp->nsaddr_list[ns]; } EXT(statp).nscount = statp->nscount; } /* * Some resolvers want to even out the load on their nameservers. * Note that RES_BLAST overrides RES_ROTATE. */ if ((statp->options & RES_ROTATE) != 0U && (statp->options & RES_BLAST) == 0U) { union res_sockaddr_union inu; struct sockaddr_in ina; int lastns = statp->nscount - 1; int fd; u_int16_t nstime; if (EXT(statp).ext != NULL) inu = EXT(statp).ext->nsaddrs[0]; ina = statp->nsaddr_list[0]; fd = EXT(statp).nssocks[0]; nstime = EXT(statp).nstimes[0]; for (ns = 0; ns < lastns; ns++) { if (EXT(statp).ext != NULL) EXT(statp).ext->nsaddrs[ns] = EXT(statp).ext->nsaddrs[ns + 1]; statp->nsaddr_list[ns] = statp->nsaddr_list[ns + 1]; EXT(statp).nssocks[ns] = EXT(statp).nssocks[ns + 1]; EXT(statp).nstimes[ns] = EXT(statp).nstimes[ns + 1]; } if (EXT(statp).ext != NULL) EXT(statp).ext->nsaddrs[lastns] = inu; statp->nsaddr_list[lastns] = ina; EXT(statp).nssocks[lastns] = fd; EXT(statp).nstimes[lastns] = nstime; } /* * Send request, RETRY times, or until successful. */ for (tries = 0; tries < statp->retry; tries++) { for (ns = 0; ns < statp->nscount; ns++) { struct sockaddr *nsap; int nsaplen; nsap = get_nsaddr(statp, ns); nsaplen = get_salen(nsap); statp->_flags &= ~RES_F_LASTMASK; statp->_flags |= (ns << RES_F_LASTSHIFT); same_ns: if (statp->qhook) { int done = 0, loops = 0; do { res_sendhookact act; act = (*statp->qhook)(&nsap, &buf, &buflen, ans, anssiz, &resplen); switch (act) { case res_goahead: done = 1; break; case res_nextns: res_nclose(statp); goto next_ns; case res_done: #ifdef USE_KQUEUE _close(kq); #endif return (resplen); case res_modified: /* give the hook another try */ if (++loops < 42) /*doug adams*/ break; /*FALLTHROUGH*/ case res_error: /*FALLTHROUGH*/ default: goto fail; } } while (!done); } Dprint(((statp->options & RES_DEBUG) && getnameinfo(nsap, nsaplen, abuf, sizeof(abuf), NULL, 0, niflags) == 0), (stdout, ";; Querying server (# %d) address = %s\n", ns + 1, abuf)); if (v_circuit) { /* Use VC; at most one attempt per server. */ tries = statp->retry; n = send_vc(statp, buf, buflen, ans, anssiz, &terrno, ns); if (n < 0) goto fail; if (n == 0) goto next_ns; resplen = n; } else { /* Use datagrams. */ n = send_dg(statp, #ifdef USE_KQUEUE kq, #endif buf, buflen, ans, anssiz, &terrno, ns, tries, &v_circuit, &gotsomewhere); if (n < 0) goto fail; if (n == 0) goto next_ns; if (v_circuit) goto same_ns; resplen = n; } Dprint((statp->options & RES_DEBUG) || ((statp->pfcode & RES_PRF_REPLY) && (statp->pfcode & RES_PRF_HEAD1)), (stdout, ";; got answer:\n")); DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_REPLY), (stdout, "%s", ""), ans, (resplen > anssiz) ? anssiz : resplen); /* * If we have temporarily opened a virtual circuit, * or if we haven't been asked to keep a socket open, * close the socket. */ if ((v_circuit && (statp->options & RES_USEVC) == 0U) || (statp->options & RES_STAYOPEN) == 0U) { res_nclose(statp); } if (statp->rhook) { int done = 0, loops = 0; do { res_sendhookact act; act = (*statp->rhook)(nsap, buf, buflen, ans, anssiz, &resplen); switch (act) { case res_goahead: case res_done: done = 1; break; case res_nextns: res_nclose(statp); goto next_ns; case res_modified: /* give the hook another try */ if (++loops < 42) /*doug adams*/ break; /*FALLTHROUGH*/ case res_error: /*FALLTHROUGH*/ default: goto fail; } } while (!done); } #ifdef USE_KQUEUE _close(kq); #endif return (resplen); next_ns: ; } /*foreach ns*/ } /*foreach retry*/ res_nclose(statp); #ifdef USE_KQUEUE _close(kq); #endif if (!v_circuit) { if (!gotsomewhere) errno = ECONNREFUSED; /*%< no nameservers found */ else errno = ETIMEDOUT; /*%< no answer obtained */ } else errno = terrno; return (-1); fail: res_nclose(statp); #ifdef USE_KQUEUE _close(kq); #endif return (-1); } /* Private */ static int get_salen(sa) const struct sockaddr *sa; { #ifdef HAVE_SA_LEN /* There are people do not set sa_len. Be forgiving to them. */ if (sa->sa_len) return (sa->sa_len); #endif if (sa->sa_family == AF_INET) return (sizeof(struct sockaddr_in)); else if (sa->sa_family == AF_INET6) return (sizeof(struct sockaddr_in6)); else return (0); /*%< unknown, die on connect */ } /*% * pick appropriate nsaddr_list for use. see res_init() for initialization. */ static struct sockaddr * get_nsaddr(statp, n) res_state statp; size_t n; { if (!statp->nsaddr_list[n].sin_family && EXT(statp).ext) { /* * - EXT(statp).ext->nsaddrs[n] holds an address that is larger * than struct sockaddr, and * - user code did not update statp->nsaddr_list[n]. */ return (struct sockaddr *)(void *)&EXT(statp).ext->nsaddrs[n]; } else { /* * - user code updated statp->nsaddr_list[n], or * - statp->nsaddr_list[n] has the same content as * EXT(statp).ext->nsaddrs[n]. */ return (struct sockaddr *)(void *)&statp->nsaddr_list[n]; } } static int send_vc(res_state statp, const u_char *buf, int buflen, u_char *ans, int anssiz, int *terrno, int ns) { const HEADER *hp = (const HEADER *) buf; HEADER *anhp = (HEADER *) ans; struct sockaddr *nsap; int nsaplen; int truncating, connreset, resplen, n; struct iovec iov[2]; u_short len; u_char *cp; void *tmp; #ifdef SO_NOSIGPIPE int on = 1; #endif nsap = get_nsaddr(statp, ns); nsaplen = get_salen(nsap); connreset = 0; same_ns: truncating = 0; /* Are we still talking to whom we want to talk to? */ if (statp->_vcsock >= 0 && (statp->_flags & RES_F_VC) != 0) { struct sockaddr_storage peer; ISC_SOCKLEN_T size = sizeof peer; if (_getpeername(statp->_vcsock, (struct sockaddr *)&peer, &size) < 0 || !sock_eq((struct sockaddr *)&peer, nsap)) { res_nclose(statp); statp->_flags &= ~RES_F_VC; } } if (statp->_vcsock < 0 || (statp->_flags & RES_F_VC) == 0) { if (statp->_vcsock >= 0) res_nclose(statp); statp->_vcsock = _socket(nsap->sa_family, SOCK_STREAM, 0); #if !defined(USE_POLL) && !defined(USE_KQUEUE) if (statp->_vcsock > highestFD) { res_nclose(statp); errno = ENOTSOCK; } #endif if (statp->_vcsock < 0) { switch (errno) { case EPROTONOSUPPORT: #ifdef EPFNOSUPPORT case EPFNOSUPPORT: #endif case EAFNOSUPPORT: Perror(statp, stderr, "socket(vc)", errno); return (0); default: *terrno = errno; Perror(statp, stderr, "socket(vc)", errno); return (-1); } } #ifdef SO_NOSIGPIPE /* * Disable generation of SIGPIPE when writing to a closed * socket. Write should return -1 and set errno to EPIPE * instead. * * Push on even if setsockopt(SO_NOSIGPIPE) fails. */ (void)_setsockopt(statp->_vcsock, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof(on)); #endif errno = 0; if (_connect(statp->_vcsock, nsap, nsaplen) < 0) { *terrno = errno; Aerror(statp, stderr, "connect/vc", errno, nsap, nsaplen); res_nclose(statp); return (0); } statp->_flags |= RES_F_VC; } /* * Send length & message */ ns_put16((u_short)buflen, (u_char*)&len); iov[0] = evConsIovec(&len, INT16SZ); DE_CONST(buf, tmp); iov[1] = evConsIovec(tmp, buflen); if (_writev(statp->_vcsock, iov, 2) != (INT16SZ + buflen)) { *terrno = errno; Perror(statp, stderr, "write failed", errno); res_nclose(statp); return (0); } /* * Receive length & response */ read_len: cp = ans; len = INT16SZ; while ((n = _read(statp->_vcsock, (char *)cp, (int)len)) > 0) { cp += n; if ((len -= n) == 0) break; } if (n <= 0) { *terrno = errno; Perror(statp, stderr, "read failed", errno); res_nclose(statp); /* * A long running process might get its TCP * connection reset if the remote server was * restarted. Requery the server instead of * trying a new one. When there is only one * server, this means that a query might work * instead of failing. We only allow one reset * per query to prevent looping. */ if (*terrno == ECONNRESET && !connreset) { connreset = 1; res_nclose(statp); goto same_ns; } res_nclose(statp); return (0); } resplen = ns_get16(ans); if (resplen > anssiz) { Dprint(statp->options & RES_DEBUG, (stdout, ";; response truncated\n") ); truncating = 1; len = anssiz; } else len = resplen; if (len < HFIXEDSZ) { /* * Undersized message. */ Dprint(statp->options & RES_DEBUG, (stdout, ";; undersized: %d\n", len)); *terrno = EMSGSIZE; res_nclose(statp); return (0); } cp = ans; while (len != 0 && (n = _read(statp->_vcsock, (char *)cp, (int)len)) > 0) { cp += n; len -= n; } if (n <= 0) { *terrno = errno; Perror(statp, stderr, "read(vc)", errno); res_nclose(statp); return (0); } if (truncating) { /* * Flush rest of answer so connection stays in synch. */ anhp->tc = 1; len = resplen - anssiz; while (len != 0) { char junk[PACKETSZ]; n = _read(statp->_vcsock, junk, (len > sizeof junk) ? sizeof junk : len); if (n > 0) len -= n; else break; } } /* * If the calling applicating has bailed out of * a previous call and failed to arrange to have * the circuit closed or the server has got * itself confused, then drop the packet and * wait for the correct one. */ if (hp->id != anhp->id) { DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_REPLY), (stdout, ";; old answer (unexpected):\n"), ans, (resplen > anssiz) ? anssiz: resplen); goto read_len; } /* * All is well, or the error is fatal. Signal that the * next nameserver ought not be tried. */ return (resplen); } static int send_dg(res_state statp, #ifdef USE_KQUEUE int kq, #endif const u_char *buf, int buflen, u_char *ans, int anssiz, int *terrno, int ns, int tries, int *v_circuit, int *gotsomewhere) { const HEADER *hp = (const HEADER *) buf; HEADER *anhp = (HEADER *) ans; const struct sockaddr *nsap; int nsaplen; struct timespec now, timeout, finish; struct sockaddr_storage from; ISC_SOCKLEN_T fromlen; int resplen, seconds, n, s; #ifdef USE_KQUEUE struct kevent kv; #else #ifdef USE_POLL int polltimeout; struct pollfd pollfd; #else fd_set dsmask; #endif #endif nsap = get_nsaddr(statp, ns); nsaplen = get_salen(nsap); if (EXT(statp).nssocks[ns] == -1) { EXT(statp).nssocks[ns] = _socket(nsap->sa_family, SOCK_DGRAM, 0); #if !defined(USE_POLL) && !defined(USE_KQUEUE) if (EXT(statp).nssocks[ns] > highestFD) { res_nclose(statp); errno = ENOTSOCK; } #endif if (EXT(statp).nssocks[ns] < 0) { switch (errno) { case EPROTONOSUPPORT: #ifdef EPFNOSUPPORT case EPFNOSUPPORT: #endif case EAFNOSUPPORT: Perror(statp, stderr, "socket(dg)", errno); return (0); default: *terrno = errno; Perror(statp, stderr, "socket(dg)", errno); return (-1); } } #ifndef CANNOT_CONNECT_DGRAM /* * On a 4.3BSD+ machine (client and server, * actually), sending to a nameserver datagram * port with no nameserver will cause an * ICMP port unreachable message to be returned. * If our datagram socket is "connected" to the * server, we get an ECONNREFUSED error on the next * socket operation, and select returns if the * error message is received. We can thus detect * the absence of a nameserver without timing out. * * When the option "insecure1" is specified, we'd * rather expect to see responses from an "unknown" * address. In order to let the kernel accept such * responses, do not connect the socket here. * XXX: or do we need an explicit option to disable * connecting? */ if (!(statp->options & RES_INSECURE1) && _connect(EXT(statp).nssocks[ns], nsap, nsaplen) < 0) { Aerror(statp, stderr, "connect(dg)", errno, nsap, nsaplen); res_nclose(statp); return (0); } #endif /* !CANNOT_CONNECT_DGRAM */ Dprint(statp->options & RES_DEBUG, (stdout, ";; new DG socket\n")) } s = EXT(statp).nssocks[ns]; #ifndef CANNOT_CONNECT_DGRAM if (statp->options & RES_INSECURE1) { if (_sendto(s, (const char*)buf, buflen, 0, nsap, nsaplen) != buflen) { Aerror(statp, stderr, "sendto", errno, nsap, nsaplen); res_nclose(statp); return (0); } } else if (send(s, (const char*)buf, buflen, 0) != buflen) { Perror(statp, stderr, "send", errno); res_nclose(statp); return (0); } #else /* !CANNOT_CONNECT_DGRAM */ if (_sendto(s, (const char*)buf, buflen, 0, nsap, nsaplen) != buflen) { Aerror(statp, stderr, "sendto", errno, nsap, nsaplen); res_nclose(statp); return (0); } #endif /* !CANNOT_CONNECT_DGRAM */ /* * Wait for reply. */ seconds = (statp->retrans << tries); if (ns > 0) seconds /= statp->nscount; if (seconds <= 0) seconds = 1; now = evNowTime(); timeout = evConsTime(seconds, 0); finish = evAddTime(now, timeout); goto nonow; wait: now = evNowTime(); nonow: #ifndef USE_POLL if (evCmpTime(finish, now) > 0) timeout = evSubTime(finish, now); else timeout = evConsTime(0, 0); #ifdef USE_KQUEUE EV_SET(&kv, s, EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, 0); n = _kevent(kq, &kv, 1, &kv, 1, &timeout); #else FD_ZERO(&dsmask); FD_SET(s, &dsmask); n = pselect(s + 1, &dsmask, NULL, NULL, &timeout, NULL); #endif #else timeout = evSubTime(finish, now); if (timeout.tv_sec < 0) timeout = evConsTime(0, 0); polltimeout = 1000*timeout.tv_sec + timeout.tv_nsec/1000000; pollfd.fd = s; pollfd.events = POLLRDNORM; n = poll(&pollfd, 1, polltimeout); #endif /* USE_POLL */ if (n == 0) { Dprint(statp->options & RES_DEBUG, (stdout, ";; timeout\n")); *gotsomewhere = 1; return (0); } if (n < 0) { if (errno == EINTR) goto wait; #ifdef USE_KQUEUE Perror(statp, stderr, "kevent", errno); #else #ifndef USE_POLL Perror(statp, stderr, "select", errno); #else Perror(statp, stderr, "poll", errno); #endif /* USE_POLL */ #endif res_nclose(statp); return (0); } #ifdef USE_KQUEUE if (kv.ident != s) goto wait; #endif errno = 0; fromlen = sizeof(from); resplen = _recvfrom(s, (char*)ans, anssiz,0, (struct sockaddr *)&from, &fromlen); if (resplen <= 0) { Perror(statp, stderr, "recvfrom", errno); res_nclose(statp); return (0); } *gotsomewhere = 1; if (resplen < HFIXEDSZ) { /* * Undersized message. */ Dprint(statp->options & RES_DEBUG, (stdout, ";; undersized: %d\n", resplen)); *terrno = EMSGSIZE; res_nclose(statp); return (0); } if (hp->id != anhp->id) { /* * response from old query, ignore it. * XXX - potential security hazard could * be detected here. */ DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_REPLY), (stdout, ";; old answer:\n"), ans, (resplen > anssiz) ? anssiz : resplen); goto wait; } if (!(statp->options & RES_INSECURE1) && !res_ourserver_p(statp, (struct sockaddr *)&from)) { /* * response from wrong server? ignore it. * XXX - potential security hazard could * be detected here. */ DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_REPLY), (stdout, ";; not our server:\n"), ans, (resplen > anssiz) ? anssiz : resplen); goto wait; } #ifdef RES_USE_EDNS0 if (anhp->rcode == FORMERR && (statp->options & RES_USE_EDNS0) != 0U) { /* * Do not retry if the server do not understand EDNS0. * The case has to be captured here, as FORMERR packet do not * carry query section, hence res_queriesmatch() returns 0. */ DprintQ(statp->options & RES_DEBUG, (stdout, "server rejected query with EDNS0:\n"), ans, (resplen > anssiz) ? anssiz : resplen); /* record the error */ statp->_flags |= RES_F_EDNS0ERR; res_nclose(statp); return (0); } #endif if (!(statp->options & RES_INSECURE2) && !res_queriesmatch(buf, buf + buflen, ans, ans + anssiz)) { /* * response contains wrong query? ignore it. * XXX - potential security hazard could * be detected here. */ DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_REPLY), (stdout, ";; wrong query name:\n"), ans, (resplen > anssiz) ? anssiz : resplen); goto wait; } if (anhp->rcode == SERVFAIL || anhp->rcode == NOTIMP || anhp->rcode == REFUSED) { DprintQ(statp->options & RES_DEBUG, (stdout, "server rejected query:\n"), ans, (resplen > anssiz) ? anssiz : resplen); res_nclose(statp); /* don't retry if called from dig */ if (!statp->pfcode) return (0); } if (!(statp->options & RES_IGNTC) && anhp->tc) { /* * To get the rest of answer, * use TCP with same server. */ Dprint(statp->options & RES_DEBUG, (stdout, ";; truncated answer\n")); *v_circuit = 1; res_nclose(statp); return (1); } /* * All is well, or the error is fatal. Signal that the * next nameserver ought not be tried. */ return (resplen); } static void Aerror(const res_state statp, FILE *file, const char *string, int error, const struct sockaddr *address, int alen) { int save = errno; char hbuf[NI_MAXHOST]; char sbuf[NI_MAXSERV]; if ((statp->options & RES_DEBUG) != 0U) { if (getnameinfo(address, alen, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), niflags)) { strncpy(hbuf, "?", sizeof(hbuf) - 1); hbuf[sizeof(hbuf) - 1] = '\0'; strncpy(sbuf, "?", sizeof(sbuf) - 1); sbuf[sizeof(sbuf) - 1] = '\0'; } fprintf(file, "res_send: %s ([%s].%s): %s\n", string, hbuf, sbuf, strerror(error)); } errno = save; } static void Perror(const res_state statp, FILE *file, const char *string, int error) { int save = errno; if ((statp->options & RES_DEBUG) != 0U) fprintf(file, "res_send: %s: %s\n", string, strerror(error)); errno = save; } static int sock_eq(struct sockaddr *a, struct sockaddr *b) { struct sockaddr_in *a4, *b4; struct sockaddr_in6 *a6, *b6; if (a->sa_family != b->sa_family) return 0; switch (a->sa_family) { case AF_INET: a4 = (struct sockaddr_in *)a; b4 = (struct sockaddr_in *)b; return a4->sin_port == b4->sin_port && a4->sin_addr.s_addr == b4->sin_addr.s_addr; case AF_INET6: a6 = (struct sockaddr_in6 *)a; b6 = (struct sockaddr_in6 *)b; return a6->sin6_port == b6->sin6_port && #ifdef HAVE_SIN6_SCOPE_ID a6->sin6_scope_id == b6->sin6_scope_id && #endif IN6_ARE_ADDR_EQUAL(&a6->sin6_addr, &b6->sin6_addr); default: return 0; } } #if defined(NEED_PSELECT) && !defined(USE_POLL) && !defined(USE_KQUEUE) /* XXX needs to move to the porting library. */ static int pselect(int nfds, void *rfds, void *wfds, void *efds, struct timespec *tsp, const sigset_t *sigmask) { struct timeval tv, *tvp; sigset_t sigs; int n; if (tsp) { tvp = &tv; tv = evTimeVal(*tsp); } else tvp = NULL; if (sigmask) sigprocmask(SIG_SETMASK, sigmask, &sigs); n = select(nfds, rfds, wfds, efds, tvp); if (sigmask) sigprocmask(SIG_SETMASK, &sigs, NULL); if (tsp) *tsp = evTimeSpec(tv); return (n); } #endif Index: stable/9/lib/libc =================================================================== --- stable/9/lib/libc (revision 292430) +++ stable/9/lib/libc (revision 292431) Property changes on: stable/9/lib/libc ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /stable/10/lib/libc:r292430 Index: stable/9/lib =================================================================== --- stable/9/lib (revision 292430) +++ stable/9/lib (revision 292431) Property changes on: stable/9/lib ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /stable/10/lib:r292430 Index: stable/9 =================================================================== --- stable/9 (revision 292430) +++ stable/9 (revision 292431) Property changes on: stable/9 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,2 ## Merged /head:r292250 Merged /stable/10:r292430