version 1.6, 2008/06/21 20:41:48 |
version 1.6.10.1, 2011/01/10 00:42:18 |
|
|
#include <sys/cdefs.h> |
#include <sys/cdefs.h> |
#ifndef lint |
#ifndef lint |
#ifdef notdef |
#ifdef notdef |
static const char rcsid[] = "Id: ns_name.c,v 1.10 2005/04/27 04:56:40 sra Exp"; |
static const char rcsid[] = "Id: ns_name.c,v 1.11 2009/01/23 19:59:16 each Exp"; |
#else |
#else |
__RCSID("$NetBSD$"); |
__RCSID("$NetBSD$"); |
#endif |
#endif |
Line 128 ns_name_ntop(const u_char *src, char *ds |
|
Line 128 ns_name_ntop(const u_char *src, char *ds |
|
} |
} |
if ((l = labellen(cp - 1)) < 0) { |
if ((l = labellen(cp - 1)) < 0) { |
errno = EMSGSIZE; /*%< XXX */ |
errno = EMSGSIZE; /*%< XXX */ |
return(-1); |
return (-1); |
} |
} |
if (dn + l >= eom) { |
if (dn + l >= eom) { |
errno = EMSGSIZE; |
errno = EMSGSIZE; |
Line 140 ns_name_ntop(const u_char *src, char *ds |
|
Line 140 ns_name_ntop(const u_char *src, char *ds |
|
if (n != DNS_LABELTYPE_BITSTRING) { |
if (n != DNS_LABELTYPE_BITSTRING) { |
/* XXX: labellen should reject this case */ |
/* XXX: labellen should reject this case */ |
errno = EINVAL; |
errno = EINVAL; |
return(-1); |
return (-1); |
} |
} |
if ((m = decode_bitstring(&cp, dn, eom)) < 0) |
if ((m = decode_bitstring(&cp, dn, eom)) < 0) |
{ |
{ |
errno = EMSGSIZE; |
errno = EMSGSIZE; |
return(-1); |
return (-1); |
} |
} |
dn += m; |
dn += m; |
continue; |
continue; |
Line 204 ns_name_ntop(const u_char *src, char *ds |
|
Line 204 ns_name_ntop(const u_char *src, char *ds |
|
* notes: |
* notes: |
*\li Enforces label and domain length limits. |
*\li Enforces label and domain length limits. |
*/ |
*/ |
|
int |
|
ns_name_pton(const char *src, u_char *dst, size_t dstsiz) { |
|
return (ns_name_pton2(src, dst, dstsiz, NULL)); |
|
} |
|
|
|
/* |
|
* ns_name_pton2(src, dst, dstsiz, *dstlen) |
|
* Convert a ascii string into an encoded domain name as per RFC1035. |
|
* return: |
|
* -1 if it fails |
|
* 1 if string was fully qualified |
|
* 0 is string was not fully qualified |
|
* side effects: |
|
* fills in *dstlen (if non-NULL) |
|
* notes: |
|
* Enforces label and domain length limits. |
|
*/ |
int |
int |
ns_name_pton(const char *src, u_char *dst, size_t dstsiz) |
ns_name_pton2(const char *src, u_char *dst, size_t dstsiz, size_t *dstlen) { |
{ |
|
u_char *label, *bp, *eom; |
u_char *label, *bp, *eom; |
int c, n, escaped, e = 0; |
int c, n, escaped, e = 0; |
char *cp; |
char *cp; |
Line 222 ns_name_pton(const char *src, u_char *ds |
|
Line 237 ns_name_pton(const char *src, u_char *ds |
|
if (c == '[') { /*%< start a bit string label */ |
if (c == '[') { /*%< start a bit string label */ |
if ((cp = strchr(src, ']')) == NULL) { |
if ((cp = strchr(src, ']')) == NULL) { |
errno = EINVAL; /*%< ??? */ |
errno = EINVAL; /*%< ??? */ |
return(-1); |
return (-1); |
} |
} |
if ((e = encode_bitsring(&src, cp + 2, |
if ((e = encode_bitsring(&src, cp + 2, |
&label, &bp, eom)) |
&label, &bp, eom)) |
!= 0) { |
!= 0) { |
errno = e; |
errno = e; |
return(-1); |
return (-1); |
} |
} |
escaped = 0; |
escaped = 0; |
label = bp++; |
label = bp++; |
Line 236 ns_name_pton(const char *src, u_char *ds |
|
Line 251 ns_name_pton(const char *src, u_char *ds |
|
goto done; |
goto done; |
else if (c != '.') { |
else if (c != '.') { |
errno = EINVAL; |
errno = EINVAL; |
return(-1); |
return (-1); |
} |
} |
continue; |
continue; |
} |
} |
Line 288 ns_name_pton(const char *src, u_char *ds |
|
Line 303 ns_name_pton(const char *src, u_char *ds |
|
errno = EMSGSIZE; |
errno = EMSGSIZE; |
return (-1); |
return (-1); |
} |
} |
|
if (dstlen != NULL) |
|
*dstlen = (bp - dst); |
return (1); |
return (1); |
} |
} |
if (c == 0 || *src == '.') { |
if (c == 0 || *src == '.') { |
Line 325 ns_name_pton(const char *src, u_char *ds |
|
Line 342 ns_name_pton(const char *src, u_char *ds |
|
errno = EMSGSIZE; |
errno = EMSGSIZE; |
return (-1); |
return (-1); |
} |
} |
|
if (dstlen != NULL) |
|
*dstlen = (bp - dst); |
return (0); |
return (0); |
} |
} |
|
|
Line 372 ns_name_ntol(const u_char *src, u_char * |
|
Line 391 ns_name_ntol(const u_char *src, u_char * |
|
} |
} |
for (; l > 0; l--) { |
for (; l > 0; l--) { |
c = *cp++; |
c = *cp++; |
if (isupper(c)) |
if (isascii(c) && isupper(c)) |
*dn++ = tolower(c); |
*dn++ = tolower(c); |
else |
else |
*dn++ = c; |
*dn++ = c; |
|
|
ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src, |
ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src, |
u_char *dst, size_t dstsiz) |
u_char *dst, size_t dstsiz) |
{ |
{ |
|
return (ns_name_unpack2(msg, eom, src, dst, dstsiz, NULL)); |
|
} |
|
|
|
/* |
|
* ns_name_unpack2(msg, eom, src, dst, dstsiz, *dstlen) |
|
* Unpack a domain name from a message, source may be compressed. |
|
* return: |
|
* -1 if it fails, or consumed octets if it succeeds. |
|
* side effect: |
|
* fills in *dstlen (if non-NULL). |
|
*/ |
|
int |
|
ns_name_unpack2(const u_char *msg, const u_char *eom, const u_char *src, |
|
u_char *dst, size_t dstsiz, size_t *dstlen) |
|
{ |
const u_char *srcp, *dstlim; |
const u_char *srcp, *dstlim; |
u_char *dstp; |
u_char *dstp; |
int n, len, checked, l; |
int n, len, checked, l; |
Line 414 ns_name_unpack(const u_char *msg, const |
|
Line 448 ns_name_unpack(const u_char *msg, const |
|
/* Limit checks. */ |
/* Limit checks. */ |
if ((l = labellen(srcp - 1)) < 0) { |
if ((l = labellen(srcp - 1)) < 0) { |
errno = EMSGSIZE; |
errno = EMSGSIZE; |
return(-1); |
return (-1); |
} |
} |
if (dstp + l + 1 >= dstlim || srcp + l >= eom) { |
if (dstp + l + 1 >= dstlim || srcp + l >= eom) { |
errno = EMSGSIZE; |
errno = EMSGSIZE; |
Line 456 ns_name_unpack(const u_char *msg, const |
|
Line 490 ns_name_unpack(const u_char *msg, const |
|
return (-1); /*%< flag error */ |
return (-1); /*%< flag error */ |
} |
} |
} |
} |
*dstp = '\0'; |
*dstp++ = 0; |
|
if (dstlen != NULL) |
|
*dstlen = dstp - dst; |
if (len < 0) |
if (len < 0) |
len = srcp - src; |
len = srcp - src; |
return (len); |
return (len); |
Line 515 ns_name_pack(const u_char *src, u_char * |
|
Line 551 ns_name_pack(const u_char *src, u_char * |
|
} |
} |
if ((l0 = labellen(srcp)) < 0) { |
if ((l0 = labellen(srcp)) < 0) { |
errno = EINVAL; |
errno = EINVAL; |
return(-1); |
return (-1); |
} |
} |
l += l0 + 1; |
l += l0 + 1; |
if (l > MAXCDNAME) { |
if (l > MAXCDNAME) { |
Line 662 ns_name_skip(const u_char **ptrptr, cons |
|
Line 698 ns_name_skip(const u_char **ptrptr, cons |
|
case NS_TYPE_ELT: /*%< EDNS0 extended label */ |
case NS_TYPE_ELT: /*%< EDNS0 extended label */ |
if ((l = labellen(cp - 1)) < 0) { |
if ((l = labellen(cp - 1)) < 0) { |
errno = EMSGSIZE; /*%< XXX */ |
errno = EMSGSIZE; /*%< XXX */ |
return(-1); |
return (-1); |
} |
} |
cp += l; |
cp += l; |
continue; |
continue; |
Line 683 ns_name_skip(const u_char **ptrptr, cons |
|
Line 719 ns_name_skip(const u_char **ptrptr, cons |
|
return (0); |
return (0); |
} |
} |
|
|
|
/* Find the number of octets an nname takes up, including the root label. |
|
* (This is basically ns_name_skip() without compression-pointer support.) |
|
* ((NOTE: can only return zero if passed-in namesiz argument is zero.)) |
|
*/ |
|
ssize_t |
|
ns_name_length(ns_nname_ct nname, size_t namesiz) { |
|
ns_nname_ct orig = nname; |
|
u_int n; |
|
|
|
while (namesiz-- > 0 && (n = *nname++) != 0) { |
|
if ((n & NS_CMPRSFLGS) != 0) { |
|
errno = EISDIR; |
|
return (-1); |
|
} |
|
if (n > namesiz) { |
|
errno = EMSGSIZE; |
|
return (-1); |
|
} |
|
nname += n; |
|
namesiz -= n; |
|
} |
|
return (nname - orig); |
|
} |
|
|
|
/* Compare two nname's for equality. Return -1 on error (setting errno). |
|
*/ |
|
int |
|
ns_name_eq(ns_nname_ct a, size_t as, ns_nname_ct b, size_t bs) { |
|
ns_nname_ct ae = a + as, be = b + bs; |
|
int ac, bc; |
|
|
|
while (ac = *a, bc = *b, ac != 0 && bc != 0) { |
|
if ((ac & NS_CMPRSFLGS) != 0 || (bc & NS_CMPRSFLGS) != 0) { |
|
errno = EISDIR; |
|
return (-1); |
|
} |
|
if (a + ac >= ae || b + bc >= be) { |
|
errno = EMSGSIZE; |
|
return (-1); |
|
} |
|
if (ac != bc || strncasecmp((const char *) ++a, |
|
(const char *) ++b, |
|
(size_t)ac) != 0) |
|
return (0); |
|
a += ac, b += bc; |
|
} |
|
return (ac == 0 && bc == 0); |
|
} |
|
|
|
/* Is domain "A" owned by (at or below) domain "B"? |
|
*/ |
|
int |
|
ns_name_owned(ns_namemap_ct a, int an, ns_namemap_ct b, int bn) { |
|
/* If A is shorter, it cannot be owned by B. */ |
|
if (an < bn) |
|
return (0); |
|
|
|
/* If they are unequal before the length of the shorter, A cannot... */ |
|
while (bn > 0) { |
|
if (a->len != b->len || |
|
strncasecmp((const char *) a->base, |
|
(const char *) b->base, (size_t)a->len) != 0) |
|
return (0); |
|
a++, an--; |
|
b++, bn--; |
|
} |
|
|
|
/* A might be longer or not, but either way, B owns it. */ |
|
return (1); |
|
} |
|
|
|
/* Build an array of <base,len> tuples from an nname, top-down order. |
|
* Return the number of tuples (labels) thus discovered. |
|
*/ |
|
int |
|
ns_name_map(ns_nname_ct nname, size_t namelen, ns_namemap_t map, int mapsize) { |
|
u_int n; |
|
int l; |
|
|
|
n = *nname++; |
|
namelen--; |
|
|
|
/* Root zone? */ |
|
if (n == 0) { |
|
/* Extra data follows name? */ |
|
if (namelen > 0) { |
|
errno = EMSGSIZE; |
|
return (-1); |
|
} |
|
return (0); |
|
} |
|
|
|
/* Compression pointer? */ |
|
if ((n & NS_CMPRSFLGS) != 0) { |
|
errno = EISDIR; |
|
return (-1); |
|
} |
|
|
|
/* Label too long? */ |
|
if (n > namelen) { |
|
errno = EMSGSIZE; |
|
return (-1); |
|
} |
|
|
|
/* Recurse to get rest of name done first. */ |
|
l = ns_name_map(nname + n, namelen - n, map, mapsize); |
|
if (l < 0) |
|
return (-1); |
|
|
|
/* Too many labels? */ |
|
if (l >= mapsize) { |
|
errno = ENAMETOOLONG; |
|
return (-1); |
|
} |
|
|
|
/* We're on our way back up-stack, store current map data. */ |
|
map[l].base = nname; |
|
map[l].len = n; |
|
return (l + 1); |
|
} |
|
|
|
/* Count the labels in a domain name. Root counts, so COM. has two. This |
|
* is to make the result comparable to the result of ns_name_map(). |
|
*/ |
|
int |
|
ns_name_labels(ns_nname_ct nname, size_t namesiz) { |
|
int ret = 0; |
|
u_int n; |
|
|
|
while (namesiz-- > 0 && (n = *nname++) != 0) { |
|
if ((n & NS_CMPRSFLGS) != 0) { |
|
errno = EISDIR; |
|
return (-1); |
|
} |
|
if (n > namesiz) { |
|
errno = EMSGSIZE; |
|
return (-1); |
|
} |
|
nname += n; |
|
namesiz -= n; |
|
ret++; |
|
} |
|
return (ret + 1); |
|
} |
|
|
/* Private. */ |
/* Private. */ |
|
|
/*% |
/*% |
Line 813 decode_bitstring(const unsigned char **c |
|
Line 994 decode_bitstring(const unsigned char **c |
|
plen = (blen + 3) / 4; |
plen = (blen + 3) / 4; |
plen += sizeof("\\[x/]") + (blen > 99 ? 3 : (blen > 9) ? 2 : 1); |
plen += sizeof("\\[x/]") + (blen > 99 ? 3 : (blen > 9) ? 2 : 1); |
if (dn + plen >= eom) |
if (dn + plen >= eom) |
return(-1); |
return (-1); |
|
|
cp++; |
cp++; |
i = SPRINTF((dn, "\\[x")); |
i = SPRINTF((dn, "\\[x")); |
Line 846 decode_bitstring(const unsigned char **c |
|
Line 1027 decode_bitstring(const unsigned char **c |
|
dn += i; |
dn += i; |
|
|
*cpp = cp; |
*cpp = cp; |
return(dn - beg); |
return (dn - beg); |
} |
} |
|
|
static int |
static int |
encode_bitsring(const char **bp, const char *end, unsigned char **labelp, |
encode_bitsring(const char **bp, const char *end, unsigned char **labelp, |
unsigned char ** dst, unsigned const char *eom) |
unsigned char ** dst, unsigned const char *eom) |
{ |
{ |
int afterslash = 0; |
int afterslash = 0; |
const char *cp = *bp; |
const char *cp = *bp; |
Line 865 encode_bitsring(const char **bp, const c |
|
Line 1046 encode_bitsring(const char **bp, const c |
|
|
|
/* a bitstring must contain at least 2 characters */ |
/* a bitstring must contain at least 2 characters */ |
if (end - cp < 2) |
if (end - cp < 2) |
return(EINVAL); |
return (EINVAL); |
|
|
/* XXX: currently, only hex strings are supported */ |
/* XXX: currently, only hex strings are supported */ |
if (*cp++ != 'x') |
if (*cp++ != 'x') |
return(EINVAL); |
return (EINVAL); |
if (!isxdigit((*cp) & 0xff)) /*%< reject '\[x/BLEN]' */ |
if (!isxdigit((*cp) & 0xff)) /*%< reject '\[x/BLEN]' */ |
return(EINVAL); |
return (EINVAL); |
|
|
for (tp = *dst + 1; cp < end && tp < eom; cp++) { |
for (tp = *dst + 1; cp < end && tp < eom; cp++) { |
switch((c = *cp)) { |
switch((c = *cp)) { |
case ']': /*%< end of the bitstring */ |
case ']': /*%< end of the bitstring */ |
if (afterslash) { |
if (afterslash) { |
if (beg_blen == NULL) |
if (beg_blen == NULL) |
return(EINVAL); |
return (EINVAL); |
blen = (int)strtol(beg_blen, &end_blen, 10); |
blen = (int)strtol(beg_blen, &end_blen, 10); |
if (*end_blen != ']') |
if (*end_blen != ']') |
return(EINVAL); |
return (EINVAL); |
} |
} |
if (count) |
if (count) |
*tp++ = ((value << 4) & 0xff); |
*tp++ = ((value << 4) & 0xff); |
Line 893 encode_bitsring(const char **bp, const c |
|
Line 1074 encode_bitsring(const char **bp, const c |
|
default: |
default: |
if (afterslash) { |
if (afterslash) { |
if (!isdigit(c&0xff)) |
if (!isdigit(c&0xff)) |
return(EINVAL); |
return (EINVAL); |
if (beg_blen == NULL) { |
if (beg_blen == NULL) { |
|
|
if (c == '0') { |
if (c == '0') { |
/* blen never begings with 0 */ |
/* blen never begings with 0 */ |
return(EINVAL); |
return (EINVAL); |
} |
} |
beg_blen = cp; |
beg_blen = cp; |
} |
} |
} else { |
} else { |
if (!isxdigit(c&0xff)) |
if (!isxdigit(c&0xff)) |
return(EINVAL); |
return (EINVAL); |
value <<= 4; |
value <<= 4; |
value += digitvalue[(int)c]; |
value += digitvalue[(int)c]; |
count += 4; |
count += 4; |
tbcount += 4; |
tbcount += 4; |
if (tbcount > 256) |
if (tbcount > 256) |
return(EINVAL); |
return (EINVAL); |
if (count == 8) { |
if (count == 8) { |
*tp++ = value; |
*tp++ = value; |
count = 0; |
count = 0; |
Line 921 encode_bitsring(const char **bp, const c |
|
Line 1102 encode_bitsring(const char **bp, const c |
|
} |
} |
done: |
done: |
if (cp >= end || tp >= eom) |
if (cp >= end || tp >= eom) |
return(EMSGSIZE); |
return (EMSGSIZE); |
|
|
/* |
/* |
* bit length validation: |
* bit length validation: |
Line 935 encode_bitsring(const char **bp, const c |
|
Line 1116 encode_bitsring(const char **bp, const c |
|
int traillen; |
int traillen; |
|
|
if (((blen + 3) & ~3) != tbcount) |
if (((blen + 3) & ~3) != tbcount) |
return(EINVAL); |
return (EINVAL); |
traillen = tbcount - blen; /*%< between 0 and 3 */ |
traillen = tbcount - blen; /*%< between 0 and 3 */ |
if (((value << (8 - traillen)) & 0xff) != 0) |
if (((value << (8 - traillen)) & 0xff) != 0) |
return(EINVAL); |
return (EINVAL); |
} |
} |
else |
else |
blen = tbcount; |
blen = tbcount; |
Line 952 encode_bitsring(const char **bp, const c |
|
Line 1133 encode_bitsring(const char **bp, const c |
|
*bp = cp; |
*bp = cp; |
*dst = tp; |
*dst = tp; |
|
|
return(0); |
return (0); |
} |
} |
|
|
static int |
static int |
Line 963 labellen(const u_char *lp) |
|
Line 1144 labellen(const u_char *lp) |
|
|
|
if ((l & NS_CMPRSFLGS) == NS_CMPRSFLGS) { |
if ((l & NS_CMPRSFLGS) == NS_CMPRSFLGS) { |
/* should be avoided by the caller */ |
/* should be avoided by the caller */ |
return(-1); |
return (-1); |
} |
} |
|
|
if ((l & NS_CMPRSFLGS) == NS_TYPE_ELT) { |
if ((l & NS_CMPRSFLGS) == NS_TYPE_ELT) { |
if (l == DNS_LABELTYPE_BITSTRING) { |
if (l == DNS_LABELTYPE_BITSTRING) { |
if ((bitlen = *(lp + 1)) == 0) |
if ((bitlen = *(lp + 1)) == 0) |
bitlen = 256; |
bitlen = 256; |
return((bitlen + 7 ) / 8 + 1); |
return ((bitlen + 7 ) / 8 + 1); |
} |
} |
return(-1); /*%< unknwon ELT */ |
return (-1); /*%< unknwon ELT */ |
} |
} |
return(l); |
return (l); |
} |
} |
|
|
/*! \file */ |
/*! \file */ |