correct possible security issue(s) in name resolution, due to use of

pre-4.9.7 BIND resolver code.
ftp://ftp.kame.net/pub/mail-list/snap-users/2348 for details.

Reviewed by:	ume
This commit is contained in:
Jun-ichiro itojun Hagino 2000-05-10 00:47:20 +00:00
parent 68b16578ca
commit 73b30f0cdf
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=60296

View File

@ -1,3 +1,6 @@
/* $FreeBSD$ */
/* $KAME: name6.c,v 1.22 2000/05/01 08:19:08 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
* All rights reserved.
@ -25,10 +28,62 @@
* 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.
*
* $FreeBSD$
*/
/* $Id: name6.c,v 1.9 1999/10/29 03:04:26 itojun Exp $ */
/*
* ++Copyright++ 1985, 1988, 1993
* -
* Copyright (c) 1985, 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 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--
*/
/*
* Atsushi Onoe <onoe@sm.sony.co.jp>
*/
@ -118,8 +173,10 @@ static struct hostent *_files_ghbyname(const char *name, int af, int *errp);
static struct hostent *_files_ghbyaddr(const void *addr, int addrlen, int af, int *errp);
static void _files_shent(int stayopen);
static void _files_ehent(void);
#ifdef YP
static struct hostent *_nis_ghbyname(const char *name, int af, int *errp);
static struct hostent *_nis_ghbyaddr(const void *addr, int addrlen, int af, int *errp);
#endif
static struct hostent *_dns_ghbyname(const char *name, int af, int *errp);
static struct hostent *_dns_ghbyaddr(const void *addr, int addrlen, int af, int *errp);
static void _dns_shent(int stayopen);
@ -190,11 +247,13 @@ _hostconf_init(void)
_hostconf[n].byaddr = _dns_ghbyaddr;
n++;
}
#ifdef YP
else if (strcmp(p, "nis") == 0) {
_hostconf[n].byname = _nis_ghbyname;
_hostconf[n].byaddr = _nis_ghbyaddr;
n++;
}
#endif
#ifdef ICMPNL
else if (strcmp(p, "icmp") == 0) {
_hostconf[n].byname = NULL;
@ -245,7 +304,7 @@ _mapped_addr_enabled(void)
/*
* Functions defined in RFC2553
* getipnodebyname, getipnodebyadr, freehostent
* getipnodebyname, getipnodebyaddr, freehostent
*/
static struct hostent *
@ -285,8 +344,7 @@ _ghbyname(const char *name, int af, int flags, int *errp)
for (i = 0; i < MAXHOSTCONF; i++) {
if (_hostconf[i].byname
&& (hp = (*_hostconf[i].byname)(name, af, errp))
!= NULL)
&& (hp = (*_hostconf[i].byname)(name, af, errp)) != NULL)
return hp;
}
@ -895,6 +953,7 @@ _files_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
return hp;
}
#ifdef YP
/*
* NIS
*
@ -928,11 +987,6 @@ _nis_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
}
return (hp);
}
#ifdef DEBUG
#define DNS_ASSERT(X) if (!(X)) { fprintf(stderr, "ASSFAIL: %s %d: %s\n", __FILE__, __LINE__, #X); goto badanswer; }
#else
#define DNS_ASSERT(X) if (!(X)) { goto badanswer; }
#endif
struct __res_type_list {
@ -940,117 +994,297 @@ struct __res_type_list {
int rtl_type;
};
#if PACKETSZ > 1024
#define MAXPACKET PACKETSZ
#else
#define MAXPACKET 1024
#endif
typedef union {
HEADER hdr;
u_char buf[MAXPACKET];
} querybuf;
static struct hostent *getanswer __P((const querybuf *, int, const char *,
int, struct hostent *, int *));
/*
* we don't need to take care about sorting, nor IPv4 mapped address here.
*/
static struct hostent *
_gethpbyanswer(answer, anslen, qtype, errp)
const u_char *answer;
getanswer(answer, anslen, qname, qtype, template, errp)
const querybuf *answer;
int anslen;
const char *qname;
int qtype;
struct hostent *template;
int *errp;
{
int n;
char tbuf[MAXDNAME+1];
HEADER *hp;
const u_char *cp, *eom;
int type, class, ancount, qdcount;
u_long ttl;
char hostbuf[BUFSIZ];
char *bp;
char *alist[MAXALIASES];
char *hlist[MAXADDRS];
struct hostent hbuf;
int buflen;
int na, nh;
register const HEADER *hp;
register const u_char *cp;
register int n;
const u_char *eom, *erdata;
char *bp, **ap, **hap;
int type, class, buflen, ancount, qdcount;
int haveanswer, had_error;
char tbuf[MAXDNAME];
const char *tname;
int (*name_ok) __P((const char *));
static char *h_addr_ptrs[MAXADDRS + 1];
static char *host_aliases[MAXALIASES];
static char hostbuf[8*1024];
hbuf.h_aliases = alist;
hbuf.h_addrtype =
#ifdef INET6
(qtype == T_AAAA) ? AF_INET6 :
#endif
AF_INET;
hbuf.h_length = ADDRLEN(hbuf.h_addrtype);
hbuf.h_addr_list = hlist;
na = nh = 0;
hp = (HEADER *)answer;
eom = answer + anslen;
#define BOUNDED_INCR(x) \
do { \
cp += x; \
if (cp > eom) { \
*errp = NO_RECOVERY; \
return (NULL); \
} \
} while (0)
#define BOUNDS_CHECK(ptr, count) \
do { \
if ((ptr) + (count) > eom) { \
*errp = NO_RECOVERY; \
return (NULL); \
} \
} while (0)
#define DNS_ASSERT(x) \
do { \
if (!(x)) { \
cp += n; \
continue; \
} \
} while (0)
#define DNS_FATAL(x) \
do { \
if (!(x)) { \
had_error++; \
continue; \
} \
} while (0)
tname = qname;
template->h_name = NULL;
eom = answer->buf + anslen;
switch (qtype) {
case T_A:
case T_AAAA:
name_ok = res_hnok;
break;
case T_PTR:
name_ok = res_dnok;
break;
default:
return (NULL); /* XXX should be abort(); */
}
/*
* find first satisfactory answer
*/
hp = &answer->hdr;
ancount = ntohs(hp->ancount);
qdcount = ntohs(hp->qdcount);
DNS_ASSERT(qdcount == 1);
cp = answer + sizeof(HEADER);
bp = hostbuf;
buflen = sizeof(hostbuf);
n = dn_expand(answer, eom, cp, bp, buflen);
DNS_ASSERT(n >= 0);
cp += n + QFIXEDSZ;
hbuf.h_name = bp;
n = strlen(bp) + 1;
bp += n;
buflen -= n;
while (ancount-- > 0 && cp < eom) {
n = dn_expand(answer, eom, cp, bp, buflen);
DNS_ASSERT(n >= 0);
cp += n; /* name */
buflen = sizeof hostbuf;
cp = answer->buf;
BOUNDED_INCR(HFIXEDSZ);
if (qdcount != 1) {
*errp = NO_RECOVERY;
return (NULL);
}
n = dn_expand(answer->buf, eom, cp, bp, buflen);
if ((n < 0) || !(*name_ok)(bp)) {
*errp = NO_RECOVERY;
return (NULL);
}
BOUNDED_INCR(n + QFIXEDSZ);
if (qtype == T_A || qtype == T_AAAA) {
/* res_send() has already verified that the query name is the
* same as the one we sent; this just gets the expanded name
* (i.e., with the succeeding search-domain tacked on).
*/
n = strlen(bp) + 1; /* for the \0 */
if (n >= MAXHOSTNAMELEN) {
*errp = NO_RECOVERY;
return (NULL);
}
template->h_name = bp;
bp += n;
buflen -= n;
/* The qname can be abbreviated, but h_name is now absolute. */
qname = template->h_name;
}
ap = host_aliases;
*ap = NULL;
template->h_aliases = host_aliases;
hap = h_addr_ptrs;
*hap = NULL;
template->h_addr_list = h_addr_ptrs;
haveanswer = 0;
had_error = 0;
while (ancount-- > 0 && cp < eom && !had_error) {
n = dn_expand(answer->buf, eom, cp, bp, buflen);
DNS_FATAL(n >= 0);
DNS_FATAL((*name_ok)(bp));
cp += n; /* name */
BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ);
type = _getshort(cp);
cp += 2; /* type */
cp += INT16SZ; /* type */
class = _getshort(cp);
cp += 2; /* class */
ttl = _getlong(cp);
cp += 4; /* ttl */
cp += INT16SZ + INT32SZ; /* class, TTL */
n = _getshort(cp);
cp += 2; /* len */
cp += INT16SZ; /* len */
BOUNDS_CHECK(cp, n);
erdata = cp + n;
DNS_ASSERT(class == C_IN);
switch (type) {
case T_CNAME:
if (na >= MAXALIASES-1) {
cp += n;
break;
}
n = dn_expand(answer, eom, cp, tbuf, sizeof(tbuf));
DNS_ASSERT(n >= 0);
if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) {
if (ap >= &host_aliases[MAXALIASES-1])
continue;
n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
DNS_FATAL(n >= 0);
DNS_FATAL((*name_ok)(tbuf));
cp += n;
/* alias */
alist[na++] = bp;
n = strlen(bp) + 1;
if (cp != erdata) {
*errp = NO_RECOVERY;
return (NULL);
}
/* Store alias. */
*ap++ = bp;
n = strlen(bp) + 1; /* for the \0 */
DNS_FATAL(n < MAXHOSTNAMELEN);
bp += n;
buflen -= n;
/* canon */
n = strlen(tbuf) + 1;
DNS_ASSERT(n < buflen);
/* Get canonical name. */
n = strlen(tbuf) + 1; /* for the \0 */
DNS_FATAL(n <= buflen);
DNS_FATAL(n < MAXHOSTNAMELEN);
strcpy(bp, tbuf);
hbuf.h_name = bp;
template->h_name = bp;
bp += n;
buflen -= n;
break;
case T_A:
#ifdef INET6
case T_AAAA:
#endif
DNS_ASSERT(type == qtype);
bp = (char *)ALIGN(bp);
DNS_ASSERT(n == hbuf.h_length);
DNS_ASSERT(n < buflen);
if (nh < MAXADDRS-1) {
hlist[nh++] = bp;
memcpy(bp, cp, n);
continue;
}
if (qtype == T_PTR && type == T_CNAME) {
n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
if (n < 0 || !res_dnok(tbuf)) {
had_error++;
continue;
}
cp += n;
if (cp != erdata) {
*errp = NO_RECOVERY;
return (NULL);
}
/* Get canonical name. */
n = strlen(tbuf) + 1; /* for the \0 */
if (n > buflen || n >= MAXHOSTNAMELEN) {
had_error++;
continue;
}
strcpy(bp, tbuf);
tname = bp;
bp += n;
buflen -= n;
continue;
}
DNS_ASSERT(type == qtype);
switch (type) {
case T_PTR:
DNS_ASSERT(strcasecmp(tname, bp) == 0);
n = dn_expand(answer->buf, eom, cp, bp, buflen);
DNS_FATAL(n >= 0);
DNS_FATAL(res_hnok(bp));
#if MULTI_PTRS_ARE_ALIASES
cp += n;
if (cp != erdata) {
*errp = NO_RECOVERY;
return (NULL);
}
if (!haveanswer)
template->h_name = bp;
else if (ap < &host_aliases[MAXALIASES-1])
*ap++ = bp;
else
n = -1;
if (n != -1) {
n = strlen(bp) + 1; /* for the \0 */
if (n >= MAXHOSTNAMELEN) {
had_error++;
break;
}
bp += n;
buflen -= n;
}
break;
#else
template->h_name = bp;
*errp = NETDB_SUCCESS;
return (template);
#endif
case T_A:
case T_AAAA:
DNS_ASSERT(strcasecmp(template->h_name, bp) == 0);
DNS_ASSERT(n == template->h_length);
if (!haveanswer) {
register int nn;
template->h_name = bp;
nn = strlen(bp) + 1; /* for the \0 */
bp += nn;
buflen -= nn;
}
bp = (char *)ALIGN(bp);
DNS_FATAL(bp + n < &hostbuf[sizeof hostbuf]);
DNS_ASSERT(hap < &h_addr_ptrs[MAXADDRS-1]);
#ifdef FILTER_V4MAPPED
if (type == T_AAAA) {
struct in6_addr in6;
memcpy(&in6, cp, sizeof(in6));
DNS_ASSERT(IN6_IS_ADDR_V4MAPPED(&in6) == 0);
}
#endif
bcopy(cp, *hap++ = bp, n);
bp += n;
buflen -= n;
cp += n;
if (cp != erdata) {
*errp = NO_RECOVERY;
return (NULL);
}
break;
default:
DNS_ASSERT(0);
cp += n;
break;
abort();
}
if (!had_error)
haveanswer++;
}
if (nh == 0) {
badanswer:
*errp = NO_RECOVERY;
return NULL;
if (haveanswer) {
*ap = NULL;
*hap = NULL;
if (!template->h_name) {
n = strlen(qname) + 1; /* for the \0 */
if (n > buflen || n >= MAXHOSTNAMELEN)
goto no_recovery;
strcpy(bp, qname);
template->h_name = bp;
bp += n;
buflen -= n;
}
*errp = NETDB_SUCCESS;
return (template);
}
alist[na] = NULL;
hlist[nh] = NULL;
return _hpcopy(&hbuf, errp);
no_recovery:
*errp = NO_RECOVERY;
return (NULL);
#undef BOUNDED_INCR
#undef BOUNDS_CHECK
#undef DNS_ASSERT
#undef DNS_FATAL
}
/* res_search() variant with multiple query support. */
@ -1060,13 +1294,14 @@ _res_search_multi(name, rtl, errp)
struct __res_type_list *rtl; /* list of query types */
int *errp;
{
u_char answer[BUFSIZ]; /* buffer to put answer */
const char *cp, * const *domain;
struct hostent *hp0 = NULL, *hp;
struct hostent hpbuf;
u_int dots;
int trailing_dot, ret, saved_herrno;
int got_nodata = 0, got_servfail = 0, tried_as_is = 0;
struct __res_type_list *rtl0 = rtl;
querybuf buf;
if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
*errp = NETDB_INTERNAL;
@ -1083,11 +1318,15 @@ _res_search_multi(name, rtl, errp)
if (!dots && (cp = hostalias(name)) != NULL) {
for(rtl = rtl0; rtl != NULL;
rtl = SLIST_NEXT(rtl, rtl_entry)) {
ret = res_query(cp, C_IN, rtl->rtl_type, answer,
sizeof(answer));
ret = res_query(cp, C_IN, rtl->rtl_type, buf.buf,
sizeof(buf.buf));
if (ret > 0) {
hp = _gethpbyanswer(answer, ret, rtl->rtl_type,
errp);
hpbuf.h_addrtype = (rtl->rtl_type == T_AAAA)
? AF_INET6 : AF_INET;
hpbuf.h_length = ADDRLEN(hpbuf.h_addrtype);
hp = getanswer(&buf, ret, name, rtl->rtl_type,
&hpbuf, errp);
hp = _hpcopy(&hpbuf, errp);
hp0 = _hpmerge(hp0, hp, errp);
}
}
@ -1103,10 +1342,14 @@ _res_search_multi(name, rtl, errp)
for(rtl = rtl0; rtl != NULL;
rtl = SLIST_NEXT(rtl, rtl_entry)) {
ret = res_querydomain(name, NULL, C_IN, rtl->rtl_type,
answer, sizeof(answer));
buf.buf, sizeof(buf.buf));
if (ret > 0) {
hp = _gethpbyanswer(answer, ret, rtl->rtl_type,
errp);
hpbuf.h_addrtype = (rtl->rtl_type == T_AAAA)
? AF_INET6 : AF_INET;
hpbuf.h_length = ADDRLEN(hpbuf.h_addrtype);
hp = getanswer(&buf, ret, name, rtl->rtl_type,
&hpbuf, errp);
hp = _hpcopy(&hpbuf, errp);
hp0 = _hpmerge(hp0, hp, errp);
}
}
@ -1134,11 +1377,14 @@ _res_search_multi(name, rtl, errp)
rtl = SLIST_NEXT(rtl, rtl_entry)) {
ret = res_querydomain(name, *domain, C_IN,
rtl->rtl_type,
answer, sizeof(answer));
buf.buf, sizeof(buf.buf));
if (ret > 0) {
hp = _gethpbyanswer(answer, ret,
rtl->rtl_type,
errp);
hpbuf.h_addrtype = (rtl->rtl_type == T_AAAA)
? AF_INET6 : AF_INET;
hpbuf.h_length = ADDRLEN(hpbuf.h_addrtype);
hp = getanswer(&buf, ret, name,
rtl->rtl_type, &hpbuf, errp);
hp = _hpcopy(&hpbuf, errp);
hp0 = _hpmerge(hp0, hp, errp);
}
}
@ -1171,7 +1417,7 @@ _res_search_multi(name, rtl, errp)
/* keep trying */
break;
case TRY_AGAIN:
if (((HEADER *)answer)->rcode == SERVFAIL) {
if (buf.hdr.rcode == SERVFAIL) {
/* try next search element, if any */
got_servfail++;
break;
@ -1199,10 +1445,14 @@ _res_search_multi(name, rtl, errp)
for(rtl = rtl0; rtl != NULL;
rtl = SLIST_NEXT(rtl, rtl_entry)) {
ret = res_querydomain(name, NULL, C_IN, rtl->rtl_type,
answer, sizeof(answer));
buf.buf, sizeof(buf.buf));
if (ret > 0) {
hp = _gethpbyanswer(answer, ret, rtl->rtl_type,
errp);
hpbuf.h_addrtype = (rtl->rtl_type == T_AAAA)
? AF_INET6 : AF_INET;
hpbuf.h_length = ADDRLEN(hpbuf.h_addrtype);
hp = getanswer(&buf, ret, name, rtl->rtl_type,
&hpbuf, errp);
hp = _hpcopy(&hpbuf, errp);
hp0 = _hpmerge(hp0, hp, errp);
}
}
@ -1261,21 +1511,17 @@ static struct hostent *
_dns_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
{
int n;
u_char answer[BUFSIZ];
HEADER *hp;
u_char c, *cp, *eom;
int type, class, ancount, qdcount;
u_long ttl;
char hostbuf[BUFSIZ];
struct hostent *hp;
u_char c, *cp;
char *bp;
char *alist[MAXALIASES];
char *hlist[2];
struct hostent hbuf;
int buflen;
int na;
#ifdef INET6
static const char hex[] = "0123456789abcdef";
#endif
querybuf buf;
char qbuf[MAXDNAME+1];
char *hlist[2];
#ifdef INET6
/* XXX */
@ -1289,17 +1535,15 @@ _dns_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
return NULL;
}
}
memset(&hbuf, 0, sizeof(hbuf));
hbuf.h_name = NULL;
hbuf.h_aliases = alist;
hbuf.h_addrtype = af;
hbuf.h_length = addrlen;
hbuf.h_addr_list = hlist;
hlist[0] = (char *)addr;
hlist[1] = NULL;
na = 0;
/* XXX assumes that MAXDNAME is big enough */
n = 0;
bp = hostbuf;
bp = qbuf;
cp = (u_char *)addr+addrlen-1;
switch (af) {
#ifdef INET6
@ -1328,68 +1572,38 @@ _dns_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
break;
}
n = res_query(hostbuf, C_IN, T_PTR, answer, sizeof(answer));
n = res_query(qbuf, C_IN, T_PTR, buf.buf, sizeof buf.buf);
if (n < 0) {
*errp = h_errno;
return NULL;
}
hp = (HEADER *)answer;
eom = answer + n;
ancount = ntohs(hp->ancount);
qdcount = ntohs(hp->qdcount);
DNS_ASSERT(qdcount == 1);
cp = answer + sizeof(HEADER);
bp = hostbuf;
buflen = sizeof(hostbuf);
n = dn_expand(answer, eom, cp, bp, buflen);
DNS_ASSERT(n >= 0);
cp += n + QFIXEDSZ;
while (ancount-- > 0 && cp < eom) {
n = dn_expand(answer, eom, cp, bp, buflen);
DNS_ASSERT(n >= 0);
cp += n; /* name */
type = _getshort(cp);
cp += 2; /* type */
class = _getshort(cp);
cp += 2; /* class */
ttl = _getlong(cp);
cp += 4; /* ttl */
n = _getshort(cp);
cp += 2; /* len */
DNS_ASSERT(class == C_IN);
switch (type) {
case T_PTR:
n = dn_expand(answer, eom, cp, bp, buflen);
DNS_ASSERT(n >= 0);
cp += n;
if (na >= MAXALIASES-1)
break;
if (hbuf.h_name == NULL)
hbuf.h_name = bp;
else
alist[na++] = bp;
n = strlen(bp) + 1;
bp += n;
buflen -= n;
break;
case T_CNAME:
cp += n;
break;
default:
badanswer:
*errp = NO_RECOVERY;
return NULL;
}
}
if (hbuf.h_name == NULL) {
*errp = h_errno;
return NULL;
}
alist[na] = NULL;
hp = getanswer(&buf, n, qbuf, T_PTR, &hbuf, errp);
hbuf.h_addrtype = af;
hbuf.h_length = addrlen;
hbuf.h_addr_list = hlist;
hlist[0] = (char *)addr;
hlist[1] = NULL;
return _hpcopy(&hbuf, errp);
}
static void
_dns_shent(int stayopen)
{
if ((_res.options & RES_INIT) == 0) {
if (res_init() < 0)
return;
}
if (stayopen)
_res.options |= RES_STAYOPEN | RES_USEVC;
}
static void
_dns_ehent(void)
{
_res.options &= ~(RES_STAYOPEN | RES_USEVC);
res_close();
}
#ifdef ICMPNL
/*