/*
* 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.
*/
if (!nwent)
return (NULL);
if (make1101inaddr(nwent->n_addr, nwent->n_length, qbuf, sizeof qbuf)
< 0) {
/* "First, do no harm." */
return (nwent);
}
ansbuf = memget(MAXPACKET);
if (ansbuf == NULL) {
errno = ENOMEM;
RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
return (NULL);
}
/* Query for the A RR that would hold this network's mask. */
anslen = res_nquery(pvt->res, qbuf, C_IN, T_A, ansbuf, MAXPACKET);
if (anslen < HFIXEDSZ) {
memput(ansbuf, MAXPACKET);
return (nwent);
}
/* Initialize, and parse header. */
hp = (HEADER *)ansbuf;
cp = ansbuf + HFIXEDSZ;
eom = ansbuf + anslen;
qdcount = ntohs(hp->qdcount);
while (qdcount-- > 0) {
int n = dn_skipname(cp, eom);
cp += n + QFIXEDSZ;
if (n < 0 || cp > eom) {
memput(ansbuf, MAXPACKET);
return (nwent);
}
}
ancount = ntohs(hp->ancount);
/* Parse the answer, collect aliases. */
while (--ancount >= 0 && cp < eom) {
int n = dn_expand(ansbuf, eom, cp, owner, sizeof owner);
if (n < 0 || !maybe_dnok(pvt->res, owner))
break;
cp += n; /*%< Owner */
if (cp + 3 * INT16SZ + INT32SZ > eom)
break;
GETSHORT(type, cp); /*%< Type */
GETSHORT(class, cp); /*%< Class */
cp += INT32SZ; /*%< TTL */
GETSHORT(n, cp); /*%< RDLENGTH */
if (cp + n > eom)
break;
if (n == INADDRSZ && class == C_IN && type == T_A &&
ns_samename(qbuf, owner) == 1) {
/* This A RR indicates the actual netmask. */
int nn, mm;
nwent->n_length = 0;
for (nn = 0; nn < INADDRSZ; nn++)
for (mm = 7; mm >= 0; mm--)
if (cp[nn] & (1 << mm))
nwent->n_length++;
else
break;
}
cp += n; /*%< RDATA */
}
memput(ansbuf, MAXPACKET);
return (nwent);
}
static int
make1101inaddr(const u_char *net, int bits, char *name, int size) {
int n, m;
char *ep;
ep = name + size;
/* Zero fill any whole bytes left out of the prefix. */
for (n = (32 - bits) / 8; n > 0; n--) {
if (ep - name < (int)(sizeof "0."))
goto emsgsize;
m = SPRINTF((name, "0."));
name += m;
}
/* Format the partial byte, if any, within the prefix. */
if ((n = bits % 8) != 0) {
if (ep - name < (int)(sizeof "255."))
goto emsgsize;
m = SPRINTF((name, "%u.",
net[bits / 8] & ~((1 << (8 - n)) - 1)));
name += m;
}
/* Format the whole bytes within the prefix. */
for (n = bits / 8; n > 0; n--) {
if (ep - name < (int)(sizeof "255."))
goto emsgsize;
m = SPRINTF((name, "%u.", net[n - 1]));
name += m;
}
/* Add the static text. */
if (ep - name < (int)(sizeof "in-addr.arpa"))
goto emsgsize;
(void) SPRINTF((name, "in-addr.arpa"));
return (0);
emsgsize:
errno = EMSGSIZE;
return (-1);
}
static void
normalize_name(char *name) {
char *t;
/* Make lower case. */
for (t = name; *t; t++)
if (isascii((unsigned char)*t) && isupper((unsigned char)*t))
*t = tolower((*t)&0xff);
/* Remove trailing dots. */
while (t > name && t[-1] == '.')
*--t = '\0';
}