gethostbydns.c revision 11661
13070Spst/*- 23070Spst * Copyright (c) 1985, 1988, 1993 33070Spst * The Regents of the University of California. All rights reserved. 43070Spst * 53070Spst * Redistribution and use in source and binary forms, with or without 63070Spst * modification, are permitted provided that the following conditions 73070Spst * are met: 83070Spst * 1. Redistributions of source code must retain the above copyright 93070Spst * notice, this list of conditions and the following disclaimer. 103070Spst * 2. Redistributions in binary form must reproduce the above copyright 113070Spst * notice, this list of conditions and the following disclaimer in the 123070Spst * documentation and/or other materials provided with the distribution. 133070Spst * 3. All advertising materials mentioning features or use of this software 143070Spst * must display the following acknowledgement: 153070Spst * This product includes software developed by the University of 163070Spst * California, Berkeley and its contributors. 173070Spst * 4. Neither the name of the University nor the names of its contributors 183070Spst * may be used to endorse or promote products derived from this software 193070Spst * without specific prior written permission. 203070Spst * 213070Spst * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 223070Spst * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 233070Spst * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 243070Spst * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 253070Spst * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 263070Spst * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 273070Spst * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 283070Spst * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 293070Spst * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 303070Spst * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 313070Spst * SUCH DAMAGE. 323070Spst * - 333070Spst * Portions Copyright (c) 1993 by Digital Equipment Corporation. 348870Srgrimes * 353070Spst * Permission to use, copy, modify, and distribute this software for any 363070Spst * purpose with or without fee is hereby granted, provided that the above 373070Spst * copyright notice and this permission notice appear in all copies, and that 383070Spst * the name of Digital Equipment Corporation not be used in advertising or 393070Spst * publicity pertaining to distribution of the document or software without 403070Spst * specific, written prior permission. 418870Srgrimes * 423070Spst * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL 433070Spst * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES 443070Spst * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT 453070Spst * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 463070Spst * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 473070Spst * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 483070Spst * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 493070Spst * SOFTWARE. 503070Spst * - 513070Spst * --Copyright-- 523070Spst */ 533070Spst 543070Spst#if defined(LIBC_SCCS) && !defined(lint) 553070Spststatic char sccsid[] = "@(#)gethostnamadr.c 8.1 (Berkeley) 6/4/93"; 5611661Sphkstatic char rcsid[] = "$Id: gethostbydns.c,v 1.6 1995/08/21 09:15:32 bde Exp $"; 573070Spst#endif /* LIBC_SCCS and not lint */ 583070Spst 593070Spst#include <sys/param.h> 603070Spst#include <sys/socket.h> 613070Spst#include <netinet/in.h> 623070Spst#include <arpa/inet.h> 633070Spst#include <arpa/nameser.h> 6410133Speter 6510133Speter#include <stdio.h> 6611661Sphk#include <unistd.h> 6710133Speter#include <string.h> 683070Spst#include <netdb.h> 693070Spst#include <resolv.h> 703070Spst#include <ctype.h> 713070Spst#include <errno.h> 723070Spst#include <syslog.h> 733070Spst 7410150Sbde#include "res_config.h" 753070Spst 763070Spst#define MAXALIASES 35 773070Spst#define MAXADDRS 35 783070Spst 793070Spst#define MULTI_PTRS_ARE_ALIASES 1 /* XXX - experimental */ 803070Spst 813070Spststatic const char AskedForGot[] = 8210133Speter "gethostby*.gethostanswer: asked for \"%s\", got \"%s\""; 833070Spst 843070Spststatic char *h_addr_ptrs[MAXADDRS + 1]; 853070Spst 863070Spststatic struct hostent host; 873070Spststatic char *host_aliases[MAXALIASES]; 883070Spststatic char hostbuf[8*1024]; 893070Spststatic struct in_addr host_addr; 903070Spststatic FILE *hostf = NULL; 913070Spststatic int stayopen = 0; 923070Spst 933070Spst#if PACKETSZ > 1024 943070Spst#define MAXPACKET PACKETSZ 953070Spst#else 963070Spst#define MAXPACKET 1024 973070Spst#endif 983070Spst 993070Spsttypedef union { 1003070Spst HEADER hdr; 1013070Spst u_char buf[MAXPACKET]; 1023070Spst} querybuf; 1033070Spst 1043070Spsttypedef union { 1053070Spst int32_t al; 1063070Spst char ac; 1073070Spst} align; 1083070Spst 1093070Spstextern int h_errno; 1103070Spst 11110133Speter#ifdef DEBUG 11210133Speterstatic void 11310133Speterdprintf(msg, num) 11410133Speter char *msg; 11510133Speter int num; 11610133Speter{ 11710133Speter if (_res.options & RES_DEBUG) { 11810133Speter int save = errno; 11910133Speter 12010133Speter printf(msg, num); 12110133Speter errno = save; 12210133Speter } 12310133Speter} 12410133Speter#else 12510133Speter# define dprintf(msg, num) /*nada*/ 12610133Speter#endif 12710133Speter 12810133Speter 1293070Spst#ifdef RESOLVSORT 1303070Spststatic void 1313070Spstaddrsort(ap, num) 1323070Spst char **ap; 1333070Spst int num; 1343070Spst{ 1353070Spst int i, j; 1363070Spst char **p; 1373070Spst short aval[MAXADDRS]; 1383070Spst int needsort = 0; 1393070Spst 1403070Spst p = ap; 1413070Spst for (i = 0; i < num; i++, p++) { 14210133Speter for (j = 0 ; (unsigned)j < _res.nsort; j++) 1438870Srgrimes if (_res.sort_list[j].addr.s_addr == 1443070Spst (((struct in_addr *)(*p))->s_addr & _res.sort_list[j].mask)) 1453070Spst break; 1463070Spst aval[i] = j; 1473070Spst if (needsort == 0 && i > 0 && j < aval[i-1]) 1483070Spst needsort = i; 1493070Spst } 1503070Spst if (!needsort) 1513070Spst return; 1523070Spst 1533070Spst while (needsort < num) { 1543070Spst for (j = needsort - 1; j >= 0; j--) { 1553070Spst if (aval[j] > aval[j+1]) { 1563070Spst char *hp; 1573070Spst 1583070Spst i = aval[j]; 1593070Spst aval[j] = aval[j+1]; 1603070Spst aval[j+1] = i; 1613070Spst 1623070Spst hp = ap[j]; 1633070Spst ap[j] = ap[j+1]; 1643070Spst ap[j+1] = hp; 1653070Spst 1663070Spst } else 1673070Spst break; 1683070Spst } 1693070Spst needsort++; 1703070Spst } 1713070Spst} 1723070Spst#endif 1733070Spst 1743070Spststatic struct hostent * 1753070Spstgethostanswer(answer, anslen, qname, qclass, qtype) 1763070Spst const querybuf *answer; 1773070Spst int anslen; 1783070Spst const char *qname; 1793070Spst int qclass, qtype; 1803070Spst{ 1813070Spst register const HEADER *hp; 1823070Spst register const u_char *cp; 1833070Spst register int n; 1843070Spst const u_char *eom; 1853070Spst char *bp, **ap, **hap; 1863070Spst int type, class, buflen, ancount, qdcount; 1873070Spst int haveanswer, had_error; 1883070Spst int toobig = 0; 1893070Spst char tbuf[MAXDNAME+1]; 1903070Spst 1913070Spst host.h_name = NULL; 1923070Spst eom = answer->buf + anslen; 1933070Spst /* 1943070Spst * find first satisfactory answer 1953070Spst */ 1963070Spst hp = &answer->hdr; 1973070Spst ancount = ntohs(hp->ancount); 1983070Spst qdcount = ntohs(hp->qdcount); 1993070Spst bp = hostbuf; 2003070Spst buflen = sizeof hostbuf; 2013070Spst cp = answer->buf + HFIXEDSZ; 2023070Spst if (qdcount != 1) { 2033070Spst h_errno = NO_RECOVERY; 2043070Spst return (NULL); 2053070Spst } 2063070Spst if ((n = dn_expand(answer->buf, eom, cp, bp, buflen)) < 0) { 2073070Spst h_errno = NO_RECOVERY; 2083070Spst return (NULL); 2093070Spst } 2103070Spst cp += n + QFIXEDSZ; 2113070Spst if (qtype == T_A) { 2123070Spst /* res_send() has already verified that the query name is the 2133070Spst * same as the one we sent; this just gets the expanded name 2143070Spst * (i.e., with the succeeding search-domain tacked on). 2153070Spst */ 2163070Spst n = strlen(bp) + 1; /* for the \0 */ 2173070Spst host.h_name = bp; 2183070Spst bp += n; 2193070Spst buflen -= n; 2203070Spst /* The qname can be abbreviated, but h_name is now absolute. */ 2213070Spst qname = host.h_name; 2223070Spst } 2233070Spst ap = host_aliases; 2243070Spst *ap = NULL; 2253070Spst host.h_aliases = host_aliases; 2263070Spst hap = h_addr_ptrs; 2273070Spst *hap = NULL; 2283070Spst host.h_addr_list = h_addr_ptrs; 2293070Spst haveanswer = 0; 2303070Spst had_error = 0; 2313070Spst while (ancount-- > 0 && cp < eom && !had_error) { 2323070Spst n = dn_expand(answer->buf, eom, cp, bp, buflen); 2333070Spst if (n < 0) { 2343070Spst had_error++; 2353070Spst continue; 2363070Spst } 2373070Spst cp += n; /* name */ 2383070Spst type = _getshort(cp); 2393070Spst cp += INT16SZ; /* type */ 2403070Spst class = _getshort(cp); 2413070Spst cp += INT16SZ + INT32SZ; /* class, TTL */ 2423070Spst n = _getshort(cp); 2433070Spst cp += INT16SZ; /* len */ 2443070Spst if (class != qclass) { 2453070Spst /* XXX - debug? syslog? */ 2463070Spst cp += n; 2473070Spst continue; /* XXX - had_error++ ? */ 2483070Spst } 2493070Spst if (qtype == T_A && type == T_CNAME) { 2503070Spst if (ap >= &host_aliases[MAXALIASES-1]) 2513070Spst continue; 2523070Spst n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); 2533070Spst if (n < 0) { 2543070Spst had_error++; 2553070Spst continue; 2563070Spst } 2573070Spst cp += n; 2583070Spst if (host.h_name && strcasecmp(host.h_name, bp) != 0) { 2593070Spst syslog(LOG_NOTICE|LOG_AUTH, 26010133Speter "gethostby*.gethostanswer: asked for \"%s\", got CNAME for \"%s\"", 2613070Spst host.h_name, bp); 2623070Spst continue; /* XXX - had_error++ ? */ 2633070Spst } 2643070Spst /* Store alias. */ 2653070Spst *ap++ = bp; 2663070Spst n = strlen(bp) + 1; /* for the \0 */ 2673070Spst bp += n; 2683070Spst buflen -= n; 2693070Spst /* Get canonical name. */ 2703070Spst n = strlen(tbuf) + 1; /* for the \0 */ 2713070Spst if (n > buflen) { 2723070Spst had_error++; 2733070Spst continue; 2743070Spst } 2753070Spst strcpy(bp, tbuf); 2763070Spst host.h_name = bp; 2773070Spst bp += n; 2783070Spst buflen -= n; 2793070Spst continue; 2803070Spst } 2813070Spst if (type != qtype) { 28210133Speter /* CNAME->PTR should not cause a log message. */ 28310133Speter if (!(qtype == T_PTR && type == T_CNAME)) 2843070Spst syslog(LOG_NOTICE|LOG_AUTH, 28510133Speter "gethostby*.gethostanswer: asked for \"%s %s %s\", got type \"%s\"", 28610133Speter qname, p_class(qclass), p_type(qtype), 28710133Speter p_type(type)); 2883070Spst cp += n; 2893070Spst continue; /* XXX - had_error++ ? */ 2903070Spst } 2913070Spst switch (type) { 2923070Spst case T_PTR: 2933070Spst if (strcasecmp(qname, bp) != 0) { 2943070Spst syslog(LOG_NOTICE|LOG_AUTH, 2953070Spst AskedForGot, qname, bp); 2963070Spst cp += n; 2973070Spst continue; /* XXX - had_error++ ? */ 2983070Spst } 2993070Spst n = dn_expand(answer->buf, eom, cp, bp, buflen); 3003070Spst if (n < 0) { 3013070Spst had_error++; 3023070Spst break; 3033070Spst } 3043070Spst#if MULTI_PTRS_ARE_ALIASES 3053070Spst cp += n; 3063070Spst if (!haveanswer) 3073070Spst host.h_name = bp; 3083070Spst else if (ap < &host_aliases[MAXALIASES-1]) 3093070Spst *ap++ = bp; 3103070Spst else 3113070Spst n = -1; 3123070Spst if (n != -1) { 3133070Spst n = strlen(bp) + 1; /* for the \0 */ 3143070Spst bp += n; 3153070Spst buflen -= n; 3163070Spst } 3173070Spst break; 3183070Spst#else 3193070Spst host.h_name = bp; 32010133Speter h_errno = NETDB_SUCCESS; 3213070Spst return (&host); 3223070Spst#endif 3233070Spst case T_A: 3243070Spst if (strcasecmp(host.h_name, bp) != 0) { 3253070Spst syslog(LOG_NOTICE|LOG_AUTH, 3263070Spst AskedForGot, host.h_name, bp); 3273070Spst cp += n; 3283070Spst continue; /* XXX - had_error++ ? */ 3293070Spst } 3303070Spst if (haveanswer) { 3313070Spst if (n != host.h_length) { 3323070Spst cp += n; 3333070Spst continue; 3343070Spst } 3353070Spst } else { 3363070Spst register int nn; 3373070Spst 3383070Spst host.h_length = n; 3393070Spst host.h_addrtype = (class == C_IN) 3403070Spst ? AF_INET 3413070Spst : AF_UNSPEC; 3423070Spst host.h_name = bp; 3433070Spst nn = strlen(bp) + 1; /* for the \0 */ 3443070Spst bp += nn; 3453070Spst buflen -= nn; 3463070Spst } 3473070Spst 3483070Spst bp += sizeof(align) - ((u_long)bp % sizeof(align)); 3493070Spst 3503070Spst if (bp + n >= &hostbuf[sizeof hostbuf]) { 35110133Speter dprintf("size (%d) too big\n", n); 3523070Spst had_error++; 3533070Spst continue; 3543070Spst } 3553070Spst if (hap >= &h_addr_ptrs[MAXADDRS-1]) { 35610133Speter if (!toobig++) 35710133Speter dprintf("Too many addresses (%d)\n", 3583070Spst MAXADDRS); 3593070Spst cp += n; 3603070Spst continue; 3613070Spst } 3623070Spst bcopy(cp, *hap++ = bp, n); 3633070Spst bp += n; 3643070Spst cp += n; 3653070Spst break; 3663070Spst default: 36710133Speter dprintf("Impossible condition (type=%d)\n", type); 36810133Speter h_errno = NO_RECOVERY; 36910133Speter return (NULL); 3703070Spst } /*switch*/ 3713070Spst if (!had_error) 3723070Spst haveanswer++; 3733070Spst } /*while*/ 3743070Spst if (haveanswer) { 3753070Spst *ap = NULL; 3763070Spst *hap = NULL; 3773070Spst# if defined(RESOLVSORT) 3783070Spst /* 3793070Spst * Note: we sort even if host can take only one address 3803070Spst * in its return structures - should give it the "best" 3813070Spst * address in that case, not some random one 3823070Spst */ 3833070Spst if (_res.nsort && haveanswer > 1 && 3843070Spst qclass == C_IN && qtype == T_A) 3853070Spst addrsort(h_addr_ptrs, haveanswer); 3863070Spst# endif /*RESOLVSORT*/ 3873070Spst if (!host.h_name) { 3883070Spst n = strlen(qname) + 1; /* for the \0 */ 3893070Spst strcpy(bp, qname); 3903070Spst host.h_name = bp; 3913070Spst } 39210133Speter h_errno = NETDB_SUCCESS; 3933070Spst return (&host); 3943070Spst } else { 3953070Spst h_errno = TRY_AGAIN; 3963070Spst return (NULL); 3973070Spst } 3983070Spst} 3993070Spst 4003070Spststruct hostent * 4013070Spst_gethostbydnsname(name) 4023070Spst const char *name; 4033070Spst{ 4043070Spst querybuf buf; 4053070Spst register const char *cp; 4063070Spst int n; 4073070Spst 40810133Speter if ((_res.options & RES_INIT) == 0 && res_init() == -1) { 40910133Speter h_errno = NETDB_INTERNAL; 41010133Speter return (NULL); 41110133Speter } 41210133Speter 4133070Spst /* 41410133Speter * if there aren't any dots, it could be a user-level alias. 41510133Speter * this is also done in res_query() since we are not the only 41610133Speter * function that looks up host names. 41710133Speter */ 41810133Speter if (!strchr(name, '.') && (cp = __hostalias(name))) 41910133Speter name = cp; 42010133Speter 42110133Speter /* 4223070Spst * disallow names consisting only of digits/dots, unless 4233070Spst * they end in a dot. 4243070Spst */ 4253070Spst if (isdigit(name[0])) 4263070Spst for (cp = name;; ++cp) { 4273070Spst if (!*cp) { 4283070Spst if (*--cp == '.') 4293070Spst break; 4303070Spst /* 4313070Spst * All-numeric, no dot at the end. 4323070Spst * Fake up a hostent as if we'd actually 4333070Spst * done a lookup. 4343070Spst */ 4353070Spst if (!inet_aton(name, &host_addr)) { 4363070Spst h_errno = HOST_NOT_FOUND; 4373070Spst return (NULL); 4383070Spst } 43910133Speter strncpy(hostbuf, name, MAXDNAME); 44010133Speter hostbuf[MAXDNAME] = '\0'; 44110133Speter host.h_name = hostbuf; 4423070Spst host.h_aliases = host_aliases; 4433070Spst host_aliases[0] = NULL; 4443070Spst host.h_addrtype = AF_INET; 4453070Spst host.h_length = INT32SZ; 4463070Spst h_addr_ptrs[0] = (char *)&host_addr; 4473070Spst h_addr_ptrs[1] = NULL; 4483070Spst host.h_addr_list = h_addr_ptrs; 4493070Spst return (&host); 4503070Spst } 4518870Srgrimes if (!isdigit(*cp) && *cp != '.') 4523070Spst break; 4533070Spst } 4543070Spst 4553070Spst if ((n = res_search(name, C_IN, T_A, buf.buf, sizeof(buf))) < 0) { 45610133Speter dprintf("res_search failed (%d)\n", n); 4573070Spst return (NULL); 4583070Spst } 4593070Spst return (gethostanswer(&buf, n, name, C_IN, T_A)); 4603070Spst} 4613070Spst 4623070Spststruct hostent * 4633070Spst_gethostbydnsaddr(addr, len, type) 4643070Spst const char *addr; 4653070Spst int len, type; 4663070Spst{ 4673070Spst int n; 4683070Spst querybuf buf; 4693070Spst register struct hostent *hp; 4703070Spst char qbuf[MAXDNAME+1]; 47110133Speter#ifdef SUNSECURITY 47210133Speter register struct hostent *rhp; 47310133Speter char **haddr; 47410133Speter u_long old_options; 47510133Speter char hname2[MAXDNAME+1]; 47610133Speter#endif /*SUNSECURITY*/ 4778870Srgrimes 47810133Speter if ((_res.options & RES_INIT) == 0 && res_init() == -1) { 47910133Speter h_errno = NETDB_INTERNAL; 4803070Spst return (NULL); 48110133Speter } 48210133Speter if (type != AF_INET) { 48310133Speter errno = EAFNOSUPPORT; 48410133Speter h_errno = NETDB_INTERNAL; 48510133Speter return (NULL); 48610133Speter } 4873070Spst (void)sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa", 4883070Spst ((unsigned)addr[3] & 0xff), 4893070Spst ((unsigned)addr[2] & 0xff), 4903070Spst ((unsigned)addr[1] & 0xff), 4913070Spst ((unsigned)addr[0] & 0xff)); 4923070Spst n = res_query(qbuf, C_IN, T_PTR, (u_char *)buf.buf, sizeof buf.buf); 4933070Spst if (n < 0) { 49410133Speter dprintf("res_query failed (%d)\n", n); 4953070Spst return (NULL); 4963070Spst } 4973070Spst if (!(hp = gethostanswer(&buf, n, qbuf, C_IN, T_PTR))) 49810133Speter return (NULL); /* h_errno was set by gethostanswer() */ 49910133Speter#ifdef SUNSECURITY 50010133Speter /* 50110133Speter * turn off search as the name should be absolute, 50210133Speter * 'localhost' should be matched by defnames 50310133Speter */ 50410133Speter strncpy(hname2, hp->h_name, MAXDNAME); 50510133Speter hname2[MAXDNAME] = '\0'; 50610133Speter old_options = _res.options; 50710133Speter _res.options &= ~RES_DNSRCH; 50810133Speter _res.options |= RES_DEFNAMES; 50910133Speter if (!(rhp = gethostbyname(hname2))) { 51010133Speter syslog(LOG_NOTICE|LOG_AUTH, 51110133Speter "gethostbyaddr: No A record for %s (verifying [%s])", 51210133Speter hname2, inet_ntoa(*((struct in_addr *)addr))); 51310133Speter _res.options = old_options; 51410133Speter h_errno = HOST_NOT_FOUND; 5153070Spst return (NULL); 51610133Speter } 51710133Speter _res.options = old_options; 51810133Speter for (haddr = rhp->h_addr_list; *haddr; haddr++) 51910133Speter if (!memcmp(*haddr, addr, INADDRSZ)) 52010133Speter break; 52110133Speter if (!*haddr) { 52210133Speter syslog(LOG_NOTICE|LOG_AUTH, 52310133Speter "gethostbyaddr: A record of %s != PTR record [%s]", 52410133Speter hname2, inet_ntoa(*((struct in_addr *)addr))); 52510133Speter h_errno = HOST_NOT_FOUND; 52610133Speter return (NULL); 52710133Speter } 52810133Speter#endif /*SUNSECURITY*/ 5293070Spst hp->h_addrtype = type; 5303070Spst hp->h_length = len; 5313070Spst h_addr_ptrs[0] = (char *)&host_addr; 5323070Spst h_addr_ptrs[1] = NULL; 5333070Spst host_addr = *(struct in_addr *)addr; 53410133Speter h_errno = NETDB_SUCCESS; 5353070Spst return (hp); 5363070Spst} 5373070Spst 5383070Spstvoid 5393070Spst_sethostdnsent(stayopen) 5403070Spst int stayopen; 5413070Spst{ 5423070Spst if (stayopen) 5433070Spst _res.options |= RES_STAYOPEN | RES_USEVC; 5443070Spst} 5453070Spst 5463070Spstvoid 5473070Spst_endhostdnsent() 5483070Spst{ 5493070Spst _res.options &= ~(RES_STAYOPEN | RES_USEVC); 5503070Spst _res_close(); 5513070Spst} 552