|
@@ -339,6 +339,9 @@ Domain name in a message can be represented as either:
|
|
|
#define BUFSZ (80) /* one line */
|
|
|
#define SBUFSIZE (BUFSZ + 1 + (sizeof(char *) * MAXALIASES))
|
|
|
|
|
|
+#define NS_TYPE_ELT 0x40 /*%< EDNS0 extended label type */
|
|
|
+#define DNS_LABELTYPE_BITSTRING 0x41
|
|
|
+
|
|
|
#undef DEBUG
|
|
|
/* #define DEBUG */
|
|
|
|
|
@@ -2792,6 +2795,259 @@ int ns_name_ntop(const u_char *src, char *dst, size_t dstsiz)
|
|
|
}
|
|
|
libc_hidden_def(ns_name_ntop)
|
|
|
|
|
|
+static const char digits[] = "0123456789";
|
|
|
+
|
|
|
+static const char digitvalue[256] = {
|
|
|
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*16*/
|
|
|
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*32*/
|
|
|
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*48*/
|
|
|
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /*64*/
|
|
|
+ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*80*/
|
|
|
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*96*/
|
|
|
+ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*112*/
|
|
|
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*128*/
|
|
|
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
|
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
|
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
|
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
|
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
|
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
|
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
|
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*256*/
|
|
|
+};
|
|
|
+
|
|
|
+static int encode_bitstring(const char **bp, const char *end,
|
|
|
+ unsigned char **labelp,
|
|
|
+ unsigned char ** dst,
|
|
|
+ unsigned const char *eom)
|
|
|
+{
|
|
|
+ int afterslash = 0;
|
|
|
+ const char *cp = *bp;
|
|
|
+ unsigned char *tp;
|
|
|
+ char c;
|
|
|
+ const char *beg_blen;
|
|
|
+ char *end_blen = NULL;
|
|
|
+ int value = 0, count = 0, tbcount = 0, blen = 0;
|
|
|
+
|
|
|
+ beg_blen = end_blen = NULL;
|
|
|
+
|
|
|
+ /* a bitstring must contain at least 2 characters */
|
|
|
+ if (end - cp < 2)
|
|
|
+ return (EINVAL);
|
|
|
+
|
|
|
+ /* XXX: currently, only hex strings are supported */
|
|
|
+ if (*cp++ != 'x')
|
|
|
+ return (EINVAL);
|
|
|
+ if (!isxdigit((*cp) & 0xff)) /*%< reject '\[x/BLEN]' */
|
|
|
+ return (EINVAL);
|
|
|
+
|
|
|
+ for (tp = *dst + 1; cp < end && tp < eom; cp++) {
|
|
|
+ switch((c = *cp)) {
|
|
|
+ case ']': /*%< end of the bitstring */
|
|
|
+ if (afterslash) {
|
|
|
+ if (beg_blen == NULL)
|
|
|
+ return (EINVAL);
|
|
|
+ blen = (int)strtol(beg_blen, &end_blen, 10);
|
|
|
+ if (*end_blen != ']')
|
|
|
+ return (EINVAL);
|
|
|
+ }
|
|
|
+ if (count)
|
|
|
+ *tp++ = ((value << 4) & 0xff);
|
|
|
+ cp++; /*%< skip ']' */
|
|
|
+ goto done;
|
|
|
+ case '/':
|
|
|
+ afterslash = 1;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ if (afterslash) {
|
|
|
+ if (!isdigit(c&0xff))
|
|
|
+ return (EINVAL);
|
|
|
+ if (beg_blen == NULL) {
|
|
|
+
|
|
|
+ if (c == '0') {
|
|
|
+ /* blen never begings with 0 */
|
|
|
+ return (EINVAL);
|
|
|
+ }
|
|
|
+ beg_blen = cp;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (!isxdigit(c&0xff))
|
|
|
+ return (EINVAL);
|
|
|
+ value <<= 4;
|
|
|
+ value += digitvalue[(int)c];
|
|
|
+ count += 4;
|
|
|
+ tbcount += 4;
|
|
|
+ if (tbcount > 256)
|
|
|
+ return (EINVAL);
|
|
|
+ if (count == 8) {
|
|
|
+ *tp++ = value;
|
|
|
+ count = 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ done:
|
|
|
+ if (cp >= end || tp >= eom)
|
|
|
+ return (EMSGSIZE);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * bit length validation:
|
|
|
+ * If a <length> is present, the number of digits in the <bit-data>
|
|
|
+ * MUST be just sufficient to contain the number of bits specified
|
|
|
+ * by the <length>. If there are insignificant bits in a final
|
|
|
+ * hexadecimal or octal digit, they MUST be zero.
|
|
|
+ * RFC2673, Section 3.2.
|
|
|
+ */
|
|
|
+ if (blen > 0) {
|
|
|
+ int traillen;
|
|
|
+
|
|
|
+ if (((blen + 3) & ~3) != tbcount)
|
|
|
+ return (EINVAL);
|
|
|
+ traillen = tbcount - blen; /*%< between 0 and 3 */
|
|
|
+ if (((value << (8 - traillen)) & 0xff) != 0)
|
|
|
+ return (EINVAL);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ blen = tbcount;
|
|
|
+ if (blen == 256)
|
|
|
+ blen = 0;
|
|
|
+
|
|
|
+ /* encode the type and the significant bit fields */
|
|
|
+ **labelp = DNS_LABELTYPE_BITSTRING;
|
|
|
+ **dst = blen;
|
|
|
+
|
|
|
+ *bp = cp;
|
|
|
+ *dst = tp;
|
|
|
+
|
|
|
+ return (0);
|
|
|
+}
|
|
|
+
|
|
|
+int ns_name_pton(const char *src, u_char *dst, size_t dstsiz)
|
|
|
+{
|
|
|
+ u_char *label, *bp, *eom;
|
|
|
+ int c, n, escaped, e = 0;
|
|
|
+ char *cp;
|
|
|
+
|
|
|
+ escaped = 0;
|
|
|
+ bp = dst;
|
|
|
+ eom = dst + dstsiz;
|
|
|
+ label = bp++;
|
|
|
+
|
|
|
+ while ((c = *src++) != 0) {
|
|
|
+ if (escaped) {
|
|
|
+ if (c == '[') { /*%< start a bit string label */
|
|
|
+ if ((cp = strchr(src, ']')) == NULL) {
|
|
|
+ errno = EINVAL; /*%< ??? */
|
|
|
+ return (-1);
|
|
|
+ }
|
|
|
+ if ((e = encode_bitstring(&src, cp + 2,
|
|
|
+ &label, &bp, eom))
|
|
|
+ != 0) {
|
|
|
+ errno = e;
|
|
|
+ return (-1);
|
|
|
+ }
|
|
|
+ escaped = 0;
|
|
|
+ label = bp++;
|
|
|
+ if ((c = *src++) == 0)
|
|
|
+ goto done;
|
|
|
+ else if (c != '.') {
|
|
|
+ errno = EINVAL;
|
|
|
+ return (-1);
|
|
|
+ }
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ else if ((cp = strchr(digits, c)) != NULL) {
|
|
|
+ n = (cp - digits) * 100;
|
|
|
+ if ((c = *src++) == 0 ||
|
|
|
+ (cp = strchr(digits, c)) == NULL) {
|
|
|
+ errno = EMSGSIZE;
|
|
|
+ return (-1);
|
|
|
+ }
|
|
|
+ n += (cp - digits) * 10;
|
|
|
+ if ((c = *src++) == 0 ||
|
|
|
+ (cp = strchr(digits, c)) == NULL) {
|
|
|
+ errno = EMSGSIZE;
|
|
|
+ return (-1);
|
|
|
+ }
|
|
|
+ n += (cp - digits);
|
|
|
+ if (n > 255) {
|
|
|
+ errno = EMSGSIZE;
|
|
|
+ return (-1);
|
|
|
+ }
|
|
|
+ c = n;
|
|
|
+ }
|
|
|
+ escaped = 0;
|
|
|
+ } else if (c == '\\') {
|
|
|
+ escaped = 1;
|
|
|
+ continue;
|
|
|
+ } else if (c == '.') {
|
|
|
+ c = (bp - label - 1);
|
|
|
+ if ((c & NS_CMPRSFLGS) != 0) { /*%< Label too big. */
|
|
|
+ errno = EMSGSIZE;
|
|
|
+ return (-1);
|
|
|
+ }
|
|
|
+ if (label >= eom) {
|
|
|
+ errno = EMSGSIZE;
|
|
|
+ return (-1);
|
|
|
+ }
|
|
|
+ *label = c;
|
|
|
+ /* Fully qualified ? */
|
|
|
+ if (*src == '\0') {
|
|
|
+ if (c != 0) {
|
|
|
+ if (bp >= eom) {
|
|
|
+ errno = EMSGSIZE;
|
|
|
+ return (-1);
|
|
|
+ }
|
|
|
+ *bp++ = '\0';
|
|
|
+ }
|
|
|
+ if ((bp - dst) > MAXCDNAME) {
|
|
|
+ errno = EMSGSIZE;
|
|
|
+ return (-1);
|
|
|
+ }
|
|
|
+
|
|
|
+ return (1);
|
|
|
+ }
|
|
|
+ if (c == 0 || *src == '.') {
|
|
|
+ errno = EMSGSIZE;
|
|
|
+ return (-1);
|
|
|
+ }
|
|
|
+ label = bp++;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (bp >= eom) {
|
|
|
+ errno = EMSGSIZE;
|
|
|
+ return (-1);
|
|
|
+ }
|
|
|
+ *bp++ = (u_char)c;
|
|
|
+ }
|
|
|
+ c = (bp - label - 1);
|
|
|
+ if ((c & NS_CMPRSFLGS) != 0) { /*%< Label too big. */
|
|
|
+ errno = EMSGSIZE;
|
|
|
+ return (-1);
|
|
|
+ }
|
|
|
+ done:
|
|
|
+ if (label >= eom) {
|
|
|
+ errno = EMSGSIZE;
|
|
|
+ return (-1);
|
|
|
+ }
|
|
|
+ *label = c;
|
|
|
+ if (c != 0) {
|
|
|
+ if (bp >= eom) {
|
|
|
+ errno = EMSGSIZE;
|
|
|
+ return (-1);
|
|
|
+ }
|
|
|
+ *bp++ = 0;
|
|
|
+ }
|
|
|
+ if ((bp - dst) > MAXCDNAME) { /*%< src too big */
|
|
|
+ errno = EMSGSIZE;
|
|
|
+ return (-1);
|
|
|
+ }
|
|
|
+
|
|
|
+ return (0);
|
|
|
+}
|
|
|
+libc_hidden_def(ns_name_pton)
|
|
|
+
|
|
|
/*
|
|
|
* ns_name_unpack(msg, eom, src, dst, dstsiz)
|
|
|
* Unpack a domain name from a message, source may be compressed.
|
|
@@ -2866,6 +3122,218 @@ int ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src,
|
|
|
return len;
|
|
|
}
|
|
|
libc_hidden_def(ns_name_unpack)
|
|
|
+
|
|
|
+static int labellen(const unsigned char *lp)
|
|
|
+{
|
|
|
+ int bitlen;
|
|
|
+ unsigned char l = *lp;
|
|
|
+
|
|
|
+ if ((l & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
|
|
|
+ /* should be avoided by the caller */
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if ((l & NS_CMPRSFLGS) == NS_TYPE_ELT) {
|
|
|
+ if (l == DNS_LABELTYPE_BITSTRING) {
|
|
|
+ if ((bitlen = *(lp + 1)) == 0)
|
|
|
+ bitlen = 256;
|
|
|
+ return ((bitlen + 7 ) / 8 + 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ return -1; /*%< unknwon ELT */
|
|
|
+ }
|
|
|
+
|
|
|
+ return l;
|
|
|
+}
|
|
|
+
|
|
|
+static int mklower(int ch)
|
|
|
+{
|
|
|
+ if (ch >= 0x41 && ch <= 0x5A)
|
|
|
+ return (ch + 0x20);
|
|
|
+
|
|
|
+ return (ch);
|
|
|
+}
|
|
|
+
|
|
|
+static int dn_find(const unsigned char *domain,
|
|
|
+ const unsigned char *msg,
|
|
|
+ const unsigned char * const *dnptrs,
|
|
|
+ const unsigned char * const *lastdnptr)
|
|
|
+{
|
|
|
+ const unsigned char *dn, *cp, *sp;
|
|
|
+ const unsigned char * const *cpp;
|
|
|
+ u_int n;
|
|
|
+
|
|
|
+ for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
|
|
|
+ sp = *cpp;
|
|
|
+ /*
|
|
|
+ * terminate search on:
|
|
|
+ * root label
|
|
|
+ * compression pointer
|
|
|
+ * unusable offset
|
|
|
+ */
|
|
|
+ while (*sp != 0 && (*sp & NS_CMPRSFLGS) == 0 &&
|
|
|
+ (sp - msg) < 0x4000) {
|
|
|
+ dn = domain;
|
|
|
+ cp = sp;
|
|
|
+
|
|
|
+ while ((n = *cp++) != 0) {
|
|
|
+ /*
|
|
|
+ * check for indirection
|
|
|
+ */
|
|
|
+ switch (n & NS_CMPRSFLGS) {
|
|
|
+ case 0: /*%< normal case, n == len */
|
|
|
+ n = labellen(cp - 1); /*%< XXX */
|
|
|
+ if (n != *dn++)
|
|
|
+ goto next;
|
|
|
+
|
|
|
+ for (; n > 0; n--)
|
|
|
+ if (mklower(*dn++) !=
|
|
|
+ mklower(*cp++))
|
|
|
+ goto next;
|
|
|
+ /* Is next root for both ? */
|
|
|
+ if (*dn == '\0' && *cp == '\0')
|
|
|
+ return (sp - msg);
|
|
|
+ if (*dn)
|
|
|
+ continue;
|
|
|
+ goto next;
|
|
|
+ case NS_CMPRSFLGS: /*%< indirection */
|
|
|
+ cp = msg + (((n & 0x3f) << 8) | *cp);
|
|
|
+ break;
|
|
|
+
|
|
|
+ default: /*%< illegal type */
|
|
|
+ errno = EMSGSIZE;
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+next:
|
|
|
+ sp += *sp + 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ errno = ENOENT;
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
+int ns_name_pack(const unsigned char *src,
|
|
|
+ unsigned char *dst, int dstsiz,
|
|
|
+ const unsigned char **dnptrs,
|
|
|
+ const unsigned char **lastdnptr)
|
|
|
+{
|
|
|
+ unsigned char *dstp;
|
|
|
+ const unsigned char **cpp, **lpp, *eob, *msg;
|
|
|
+ const unsigned char *srcp;
|
|
|
+ int n, l, first = 1;
|
|
|
+
|
|
|
+ srcp = src;
|
|
|
+ dstp = dst;
|
|
|
+ eob = dstp + dstsiz;
|
|
|
+ lpp = cpp = NULL;
|
|
|
+
|
|
|
+ if (dnptrs != NULL) {
|
|
|
+ if ((msg = *dnptrs++) != NULL) {
|
|
|
+ for (cpp = dnptrs; *cpp != NULL; cpp++)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ lpp = cpp; /*%< end of list to search */
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ msg = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* make sure the domain we are about to add is legal */
|
|
|
+ l = 0;
|
|
|
+ do {
|
|
|
+ int l0;
|
|
|
+
|
|
|
+ n = *srcp;
|
|
|
+ if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
|
|
|
+ errno = EMSGSIZE;
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if ((l0 = labellen(srcp)) < 0) {
|
|
|
+ errno = EINVAL;
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ l += l0 + 1;
|
|
|
+ if (l > MAXCDNAME) {
|
|
|
+ errno = EMSGSIZE;
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ srcp += l0 + 1;
|
|
|
+ } while (n != 0);
|
|
|
+
|
|
|
+ /* from here on we need to reset compression pointer array on error */
|
|
|
+ srcp = src;
|
|
|
+
|
|
|
+ do {
|
|
|
+ /* Look to see if we can use pointers. */
|
|
|
+ n = *srcp;
|
|
|
+
|
|
|
+ if (n != 0 && msg != NULL) {
|
|
|
+ l = dn_find(srcp, msg, (const unsigned char * const *) dnptrs,
|
|
|
+ (const unsigned char * const *) lpp);
|
|
|
+ if (l >= 0) {
|
|
|
+ if (dstp + 1 >= eob) {
|
|
|
+ goto cleanup;
|
|
|
+ }
|
|
|
+
|
|
|
+ *dstp++ = ((u_int32_t)l >> 8) | NS_CMPRSFLGS;
|
|
|
+ *dstp++ = l % 256;
|
|
|
+ return (dstp - dst);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Not found, save it. */
|
|
|
+ if (lastdnptr != NULL && cpp < lastdnptr - 1 &&
|
|
|
+ (dstp - msg) < 0x4000 && first) {
|
|
|
+ *cpp++ = dstp;
|
|
|
+ *cpp = NULL;
|
|
|
+ first = 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* copy label to buffer */
|
|
|
+ if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
|
|
|
+ /* Should not happen. */
|
|
|
+ goto cleanup;
|
|
|
+ }
|
|
|
+
|
|
|
+ n = labellen(srcp);
|
|
|
+ if (dstp + 1 + n >= eob) {
|
|
|
+ goto cleanup;
|
|
|
+ }
|
|
|
+
|
|
|
+ memcpy(dstp, srcp, (size_t)(n + 1));
|
|
|
+ srcp += n + 1;
|
|
|
+ dstp += n + 1;
|
|
|
+ } while (n != 0);
|
|
|
+
|
|
|
+ if (dstp > eob) {
|
|
|
+cleanup:
|
|
|
+ if (msg != NULL)
|
|
|
+ *lpp = NULL;
|
|
|
+
|
|
|
+ errno = EMSGSIZE;
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ return dstp - dst;
|
|
|
+}
|
|
|
+
|
|
|
+int ns_name_compress(const char *src,
|
|
|
+ unsigned char *dst, size_t dstsiz,
|
|
|
+ const unsigned char **dnptrs,
|
|
|
+ const unsigned char **lastdnptr)
|
|
|
+{
|
|
|
+ unsigned char tmp[NS_MAXCDNAME];
|
|
|
+
|
|
|
+ if (ns_name_pton(src, tmp, sizeof(tmp)) == -1)
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ return ns_name_pack(tmp, dst, dstsiz, dnptrs, lastdnptr);
|
|
|
+}
|
|
|
#endif /* L_ns_name */
|
|
|
|
|
|
|