1*f14fb602SLionel Sambuc /* $NetBSD: ns_name.c,v 1.9 2012/03/13 21:13:39 christos Exp $ */ 22fe8fb19SBen Gras 32fe8fb19SBen Gras /* 42fe8fb19SBen Gras * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") 52fe8fb19SBen Gras * Copyright (c) 1996,1999 by Internet Software Consortium. 62fe8fb19SBen Gras * 72fe8fb19SBen Gras * Permission to use, copy, modify, and distribute this software for any 82fe8fb19SBen Gras * purpose with or without fee is hereby granted, provided that the above 92fe8fb19SBen Gras * copyright notice and this permission notice appear in all copies. 102fe8fb19SBen Gras * 112fe8fb19SBen Gras * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 122fe8fb19SBen Gras * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 132fe8fb19SBen Gras * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 142fe8fb19SBen Gras * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 152fe8fb19SBen Gras * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 162fe8fb19SBen Gras * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 172fe8fb19SBen Gras * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 182fe8fb19SBen Gras */ 192fe8fb19SBen Gras 202fe8fb19SBen Gras #include <sys/cdefs.h> 212fe8fb19SBen Gras #ifndef lint 222fe8fb19SBen Gras #ifdef notdef 232fe8fb19SBen Gras static const char rcsid[] = "Id: ns_name.c,v 1.11 2009/01/23 19:59:16 each Exp"; 242fe8fb19SBen Gras #else 25*f14fb602SLionel Sambuc __RCSID("$NetBSD: ns_name.c,v 1.9 2012/03/13 21:13:39 christos Exp $"); 262fe8fb19SBen Gras #endif 272fe8fb19SBen Gras #endif 282fe8fb19SBen Gras 292fe8fb19SBen Gras #include "port_before.h" 302fe8fb19SBen Gras 312fe8fb19SBen Gras #include <sys/types.h> 322fe8fb19SBen Gras 332fe8fb19SBen Gras #include <netinet/in.h> 342fe8fb19SBen Gras #include <arpa/nameser.h> 352fe8fb19SBen Gras 36*f14fb602SLionel Sambuc #include <assert.h> 372fe8fb19SBen Gras #include <errno.h> 382fe8fb19SBen Gras #include <resolv.h> 392fe8fb19SBen Gras #include <string.h> 402fe8fb19SBen Gras #include <ctype.h> 412fe8fb19SBen Gras #include <stdlib.h> 422fe8fb19SBen Gras #include <limits.h> 432fe8fb19SBen Gras 442fe8fb19SBen Gras #include "port_after.h" 452fe8fb19SBen Gras 462fe8fb19SBen Gras #ifdef SPRINTF_CHAR 47*f14fb602SLionel Sambuc # define SPRINTF(x) ((int)strlen(sprintf/**/x)) 482fe8fb19SBen Gras #else 49*f14fb602SLionel Sambuc # define SPRINTF(x) (sprintf x) 502fe8fb19SBen Gras #endif 512fe8fb19SBen Gras 522fe8fb19SBen Gras #define NS_TYPE_ELT 0x40 /*%< EDNS0 extended label type */ 532fe8fb19SBen Gras #define DNS_LABELTYPE_BITSTRING 0x41 542fe8fb19SBen Gras 552fe8fb19SBen Gras /* Data. */ 562fe8fb19SBen Gras 572fe8fb19SBen Gras static const char digits[] = "0123456789"; 582fe8fb19SBen Gras 592fe8fb19SBen Gras static const char digitvalue[256] = { 602fe8fb19SBen Gras -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*16*/ 612fe8fb19SBen Gras -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*32*/ 622fe8fb19SBen Gras -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*48*/ 632fe8fb19SBen Gras 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /*64*/ 642fe8fb19SBen Gras -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*80*/ 652fe8fb19SBen Gras -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*96*/ 662fe8fb19SBen Gras -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*112*/ 672fe8fb19SBen Gras -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*128*/ 682fe8fb19SBen Gras -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 692fe8fb19SBen Gras -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 702fe8fb19SBen Gras -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 712fe8fb19SBen Gras -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 722fe8fb19SBen Gras -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 732fe8fb19SBen Gras -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 742fe8fb19SBen Gras -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 752fe8fb19SBen Gras -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*256*/ 762fe8fb19SBen Gras }; 772fe8fb19SBen Gras 782fe8fb19SBen Gras /* Forward. */ 792fe8fb19SBen Gras 802fe8fb19SBen Gras static int special(int); 812fe8fb19SBen Gras static int printable(int); 822fe8fb19SBen Gras static int dn_find(const u_char *, const u_char *, 832fe8fb19SBen Gras const u_char * const *, 842fe8fb19SBen Gras const u_char * const *); 852fe8fb19SBen Gras static int encode_bitsring(const char **, const char *, 862fe8fb19SBen Gras unsigned char **, unsigned char **, 872fe8fb19SBen Gras unsigned const char *); 882fe8fb19SBen Gras static int labellen(const u_char *); 892fe8fb19SBen Gras static int decode_bitstring(const unsigned char **, 902fe8fb19SBen Gras char *, const char *); 912fe8fb19SBen Gras 922fe8fb19SBen Gras /* Public. */ 932fe8fb19SBen Gras 942fe8fb19SBen Gras /*% 952fe8fb19SBen Gras * Convert an encoded domain name to printable ascii as per RFC1035. 962fe8fb19SBen Gras 972fe8fb19SBen Gras * return: 982fe8fb19SBen Gras *\li Number of bytes written to buffer, or -1 (with errno set) 992fe8fb19SBen Gras * 1002fe8fb19SBen Gras * notes: 1012fe8fb19SBen Gras *\li The root is returned as "." 1022fe8fb19SBen Gras *\li All other domains are returned in non absolute form 1032fe8fb19SBen Gras */ 1042fe8fb19SBen Gras int 1052fe8fb19SBen Gras ns_name_ntop(const u_char *src, char *dst, size_t dstsiz) 1062fe8fb19SBen Gras { 1072fe8fb19SBen Gras const u_char *cp; 1082fe8fb19SBen Gras char *dn, *eom; 1092fe8fb19SBen Gras u_char c; 1102fe8fb19SBen Gras u_int n; 1112fe8fb19SBen Gras int l; 1122fe8fb19SBen Gras 1132fe8fb19SBen Gras cp = src; 1142fe8fb19SBen Gras dn = dst; 1152fe8fb19SBen Gras eom = dst + dstsiz; 1162fe8fb19SBen Gras 1172fe8fb19SBen Gras while ((n = *cp++) != 0) { 1182fe8fb19SBen Gras if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { 1192fe8fb19SBen Gras /* Some kind of compression pointer. */ 1202fe8fb19SBen Gras errno = EMSGSIZE; 1212fe8fb19SBen Gras return (-1); 1222fe8fb19SBen Gras } 1232fe8fb19SBen Gras if (dn != dst) { 1242fe8fb19SBen Gras if (dn >= eom) { 1252fe8fb19SBen Gras errno = EMSGSIZE; 1262fe8fb19SBen Gras return (-1); 1272fe8fb19SBen Gras } 1282fe8fb19SBen Gras *dn++ = '.'; 1292fe8fb19SBen Gras } 1302fe8fb19SBen Gras if ((l = labellen(cp - 1)) < 0) { 1312fe8fb19SBen Gras errno = EMSGSIZE; /*%< XXX */ 1322fe8fb19SBen Gras return (-1); 1332fe8fb19SBen Gras } 1342fe8fb19SBen Gras if (dn + l >= eom) { 1352fe8fb19SBen Gras errno = EMSGSIZE; 1362fe8fb19SBen Gras return (-1); 1372fe8fb19SBen Gras } 1382fe8fb19SBen Gras if ((n & NS_CMPRSFLGS) == NS_TYPE_ELT) { 1392fe8fb19SBen Gras int m; 1402fe8fb19SBen Gras 1412fe8fb19SBen Gras if (n != DNS_LABELTYPE_BITSTRING) { 1422fe8fb19SBen Gras /* XXX: labellen should reject this case */ 1432fe8fb19SBen Gras errno = EINVAL; 1442fe8fb19SBen Gras return (-1); 1452fe8fb19SBen Gras } 1462fe8fb19SBen Gras if ((m = decode_bitstring(&cp, dn, eom)) < 0) 1472fe8fb19SBen Gras { 1482fe8fb19SBen Gras errno = EMSGSIZE; 1492fe8fb19SBen Gras return (-1); 1502fe8fb19SBen Gras } 1512fe8fb19SBen Gras dn += m; 1522fe8fb19SBen Gras continue; 1532fe8fb19SBen Gras } 1542fe8fb19SBen Gras for (; l > 0; l--) { 1552fe8fb19SBen Gras c = *cp++; 1562fe8fb19SBen Gras if (special(c)) { 1572fe8fb19SBen Gras if (dn + 1 >= eom) { 1582fe8fb19SBen Gras errno = EMSGSIZE; 1592fe8fb19SBen Gras return (-1); 1602fe8fb19SBen Gras } 1612fe8fb19SBen Gras *dn++ = '\\'; 1622fe8fb19SBen Gras *dn++ = (char)c; 1632fe8fb19SBen Gras } else if (!printable(c)) { 1642fe8fb19SBen Gras if (dn + 3 >= eom) { 1652fe8fb19SBen Gras errno = EMSGSIZE; 1662fe8fb19SBen Gras return (-1); 1672fe8fb19SBen Gras } 1682fe8fb19SBen Gras *dn++ = '\\'; 1692fe8fb19SBen Gras *dn++ = digits[c / 100]; 1702fe8fb19SBen Gras *dn++ = digits[(c % 100) / 10]; 1712fe8fb19SBen Gras *dn++ = digits[c % 10]; 1722fe8fb19SBen Gras } else { 1732fe8fb19SBen Gras if (dn >= eom) { 1742fe8fb19SBen Gras errno = EMSGSIZE; 1752fe8fb19SBen Gras return (-1); 1762fe8fb19SBen Gras } 1772fe8fb19SBen Gras *dn++ = (char)c; 1782fe8fb19SBen Gras } 1792fe8fb19SBen Gras } 1802fe8fb19SBen Gras } 1812fe8fb19SBen Gras if (dn == dst) { 1822fe8fb19SBen Gras if (dn >= eom) { 1832fe8fb19SBen Gras errno = EMSGSIZE; 1842fe8fb19SBen Gras return (-1); 1852fe8fb19SBen Gras } 1862fe8fb19SBen Gras *dn++ = '.'; 1872fe8fb19SBen Gras } 1882fe8fb19SBen Gras if (dn >= eom) { 1892fe8fb19SBen Gras errno = EMSGSIZE; 1902fe8fb19SBen Gras return (-1); 1912fe8fb19SBen Gras } 1922fe8fb19SBen Gras *dn++ = '\0'; 193*f14fb602SLionel Sambuc _DIAGASSERT(__type_fit(int, dn - dst)); 194*f14fb602SLionel Sambuc return (int)(dn - dst); 1952fe8fb19SBen Gras } 1962fe8fb19SBen Gras 1972fe8fb19SBen Gras /*% 1982fe8fb19SBen Gras * Convert a ascii string into an encoded domain name as per RFC1035. 1992fe8fb19SBen Gras * 2002fe8fb19SBen Gras * return: 2012fe8fb19SBen Gras * 2022fe8fb19SBen Gras *\li -1 if it fails 2032fe8fb19SBen Gras *\li 1 if string was fully qualified 2042fe8fb19SBen Gras *\li 0 is string was not fully qualified 2052fe8fb19SBen Gras * 2062fe8fb19SBen Gras * notes: 2072fe8fb19SBen Gras *\li Enforces label and domain length limits. 2082fe8fb19SBen Gras */ 2092fe8fb19SBen Gras int 2102fe8fb19SBen Gras ns_name_pton(const char *src, u_char *dst, size_t dstsiz) { 2112fe8fb19SBen Gras return (ns_name_pton2(src, dst, dstsiz, NULL)); 2122fe8fb19SBen Gras } 2132fe8fb19SBen Gras 2142fe8fb19SBen Gras /* 2152fe8fb19SBen Gras * ns_name_pton2(src, dst, dstsiz, *dstlen) 2162fe8fb19SBen Gras * Convert a ascii string into an encoded domain name as per RFC1035. 2172fe8fb19SBen Gras * return: 2182fe8fb19SBen Gras * -1 if it fails 2192fe8fb19SBen Gras * 1 if string was fully qualified 2202fe8fb19SBen Gras * 0 is string was not fully qualified 2212fe8fb19SBen Gras * side effects: 2222fe8fb19SBen Gras * fills in *dstlen (if non-NULL) 2232fe8fb19SBen Gras * notes: 2242fe8fb19SBen Gras * Enforces label and domain length limits. 2252fe8fb19SBen Gras */ 2262fe8fb19SBen Gras int 2272fe8fb19SBen Gras ns_name_pton2(const char *src, u_char *dst, size_t dstsiz, size_t *dstlen) { 2282fe8fb19SBen Gras u_char *label, *bp, *eom; 2292fe8fb19SBen Gras int c, n, escaped, e = 0; 2302fe8fb19SBen Gras char *cp; 2312fe8fb19SBen Gras 2322fe8fb19SBen Gras escaped = 0; 2332fe8fb19SBen Gras bp = dst; 2342fe8fb19SBen Gras eom = dst + dstsiz; 2352fe8fb19SBen Gras label = bp++; 2362fe8fb19SBen Gras 2372fe8fb19SBen Gras while ((c = *src++) != 0) { 2382fe8fb19SBen Gras if (escaped) { 2392fe8fb19SBen Gras if (c == '[') { /*%< start a bit string label */ 2402fe8fb19SBen Gras if ((cp = strchr(src, ']')) == NULL) { 2412fe8fb19SBen Gras errno = EINVAL; /*%< ??? */ 2422fe8fb19SBen Gras return (-1); 2432fe8fb19SBen Gras } 2442fe8fb19SBen Gras if ((e = encode_bitsring(&src, cp + 2, 2452fe8fb19SBen Gras &label, &bp, eom)) 2462fe8fb19SBen Gras != 0) { 2472fe8fb19SBen Gras errno = e; 2482fe8fb19SBen Gras return (-1); 2492fe8fb19SBen Gras } 2502fe8fb19SBen Gras escaped = 0; 2512fe8fb19SBen Gras label = bp++; 2522fe8fb19SBen Gras if ((c = *src++) == 0) 2532fe8fb19SBen Gras goto done; 2542fe8fb19SBen Gras else if (c != '.') { 2552fe8fb19SBen Gras errno = EINVAL; 2562fe8fb19SBen Gras return (-1); 2572fe8fb19SBen Gras } 2582fe8fb19SBen Gras continue; 2592fe8fb19SBen Gras } 2602fe8fb19SBen Gras else if ((cp = strchr(digits, c)) != NULL) { 261*f14fb602SLionel Sambuc n = (int)(cp - digits) * 100; 2622fe8fb19SBen Gras if ((c = *src++) == 0 || 2632fe8fb19SBen Gras (cp = strchr(digits, c)) == NULL) { 2642fe8fb19SBen Gras errno = EMSGSIZE; 2652fe8fb19SBen Gras return (-1); 2662fe8fb19SBen Gras } 267*f14fb602SLionel Sambuc n += (int)(cp - digits) * 10; 2682fe8fb19SBen Gras if ((c = *src++) == 0 || 2692fe8fb19SBen Gras (cp = strchr(digits, c)) == NULL) { 2702fe8fb19SBen Gras errno = EMSGSIZE; 2712fe8fb19SBen Gras return (-1); 2722fe8fb19SBen Gras } 273*f14fb602SLionel Sambuc n += (int)(cp - digits); 2742fe8fb19SBen Gras if (n > 255) { 2752fe8fb19SBen Gras errno = EMSGSIZE; 2762fe8fb19SBen Gras return (-1); 2772fe8fb19SBen Gras } 2782fe8fb19SBen Gras c = n; 2792fe8fb19SBen Gras } 2802fe8fb19SBen Gras escaped = 0; 2812fe8fb19SBen Gras } else if (c == '\\') { 2822fe8fb19SBen Gras escaped = 1; 2832fe8fb19SBen Gras continue; 2842fe8fb19SBen Gras } else if (c == '.') { 285*f14fb602SLionel Sambuc c = (int)(bp - label - 1); 2862fe8fb19SBen Gras if ((c & NS_CMPRSFLGS) != 0) { /*%< Label too big. */ 2872fe8fb19SBen Gras errno = EMSGSIZE; 2882fe8fb19SBen Gras return (-1); 2892fe8fb19SBen Gras } 2902fe8fb19SBen Gras if (label >= eom) { 2912fe8fb19SBen Gras errno = EMSGSIZE; 2922fe8fb19SBen Gras return (-1); 2932fe8fb19SBen Gras } 2942fe8fb19SBen Gras *label = c; 2952fe8fb19SBen Gras /* Fully qualified ? */ 2962fe8fb19SBen Gras if (*src == '\0') { 2972fe8fb19SBen Gras if (c != 0) { 2982fe8fb19SBen Gras if (bp >= eom) { 2992fe8fb19SBen Gras errno = EMSGSIZE; 3002fe8fb19SBen Gras return (-1); 3012fe8fb19SBen Gras } 3022fe8fb19SBen Gras *bp++ = '\0'; 3032fe8fb19SBen Gras } 3042fe8fb19SBen Gras if ((bp - dst) > MAXCDNAME) { 3052fe8fb19SBen Gras errno = EMSGSIZE; 3062fe8fb19SBen Gras return (-1); 3072fe8fb19SBen Gras } 3082fe8fb19SBen Gras if (dstlen != NULL) 3092fe8fb19SBen Gras *dstlen = (bp - dst); 3102fe8fb19SBen Gras return (1); 3112fe8fb19SBen Gras } 3122fe8fb19SBen Gras if (c == 0 || *src == '.') { 3132fe8fb19SBen Gras errno = EMSGSIZE; 3142fe8fb19SBen Gras return (-1); 3152fe8fb19SBen Gras } 3162fe8fb19SBen Gras label = bp++; 3172fe8fb19SBen Gras continue; 3182fe8fb19SBen Gras } 3192fe8fb19SBen Gras if (bp >= eom) { 3202fe8fb19SBen Gras errno = EMSGSIZE; 3212fe8fb19SBen Gras return (-1); 3222fe8fb19SBen Gras } 3232fe8fb19SBen Gras *bp++ = (u_char)c; 3242fe8fb19SBen Gras } 325*f14fb602SLionel Sambuc c = (int)(bp - label - 1); 3262fe8fb19SBen Gras if ((c & NS_CMPRSFLGS) != 0) { /*%< Label too big. */ 3272fe8fb19SBen Gras errno = EMSGSIZE; 3282fe8fb19SBen Gras return (-1); 3292fe8fb19SBen Gras } 3302fe8fb19SBen Gras done: 3312fe8fb19SBen Gras if (label >= eom) { 3322fe8fb19SBen Gras errno = EMSGSIZE; 3332fe8fb19SBen Gras return (-1); 3342fe8fb19SBen Gras } 3352fe8fb19SBen Gras *label = c; 3362fe8fb19SBen Gras if (c != 0) { 3372fe8fb19SBen Gras if (bp >= eom) { 3382fe8fb19SBen Gras errno = EMSGSIZE; 3392fe8fb19SBen Gras return (-1); 3402fe8fb19SBen Gras } 3412fe8fb19SBen Gras *bp++ = 0; 3422fe8fb19SBen Gras } 3432fe8fb19SBen Gras if ((bp - dst) > MAXCDNAME) { /*%< src too big */ 3442fe8fb19SBen Gras errno = EMSGSIZE; 3452fe8fb19SBen Gras return (-1); 3462fe8fb19SBen Gras } 3472fe8fb19SBen Gras if (dstlen != NULL) 3482fe8fb19SBen Gras *dstlen = (bp - dst); 3492fe8fb19SBen Gras return (0); 3502fe8fb19SBen Gras } 3512fe8fb19SBen Gras 3522fe8fb19SBen Gras /*% 3532fe8fb19SBen Gras * Convert a network strings labels into all lowercase. 3542fe8fb19SBen Gras * 3552fe8fb19SBen Gras * return: 3562fe8fb19SBen Gras *\li Number of bytes written to buffer, or -1 (with errno set) 3572fe8fb19SBen Gras * 3582fe8fb19SBen Gras * notes: 3592fe8fb19SBen Gras *\li Enforces label and domain length limits. 3602fe8fb19SBen Gras */ 3612fe8fb19SBen Gras 3622fe8fb19SBen Gras int 3632fe8fb19SBen Gras ns_name_ntol(const u_char *src, u_char *dst, size_t dstsiz) 3642fe8fb19SBen Gras { 3652fe8fb19SBen Gras const u_char *cp; 3662fe8fb19SBen Gras u_char *dn, *eom; 3672fe8fb19SBen Gras u_char c; 3682fe8fb19SBen Gras u_int n; 3692fe8fb19SBen Gras int l; 3702fe8fb19SBen Gras 3712fe8fb19SBen Gras cp = src; 3722fe8fb19SBen Gras dn = dst; 3732fe8fb19SBen Gras eom = dst + dstsiz; 3742fe8fb19SBen Gras 3752fe8fb19SBen Gras if (dn >= eom) { 3762fe8fb19SBen Gras errno = EMSGSIZE; 3772fe8fb19SBen Gras return (-1); 3782fe8fb19SBen Gras } 3792fe8fb19SBen Gras while ((n = *cp++) != 0) { 3802fe8fb19SBen Gras if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { 3812fe8fb19SBen Gras /* Some kind of compression pointer. */ 3822fe8fb19SBen Gras errno = EMSGSIZE; 3832fe8fb19SBen Gras return (-1); 3842fe8fb19SBen Gras } 3852fe8fb19SBen Gras *dn++ = n; 3862fe8fb19SBen Gras if ((l = labellen(cp - 1)) < 0) { 3872fe8fb19SBen Gras errno = EMSGSIZE; 3882fe8fb19SBen Gras return (-1); 3892fe8fb19SBen Gras } 3902fe8fb19SBen Gras if (dn + l >= eom) { 3912fe8fb19SBen Gras errno = EMSGSIZE; 3922fe8fb19SBen Gras return (-1); 3932fe8fb19SBen Gras } 3942fe8fb19SBen Gras for (; l > 0; l--) { 3952fe8fb19SBen Gras c = *cp++; 3962fe8fb19SBen Gras if (isascii(c) && isupper(c)) 3972fe8fb19SBen Gras *dn++ = tolower(c); 3982fe8fb19SBen Gras else 3992fe8fb19SBen Gras *dn++ = c; 4002fe8fb19SBen Gras } 4012fe8fb19SBen Gras } 4022fe8fb19SBen Gras *dn++ = '\0'; 403*f14fb602SLionel Sambuc _DIAGASSERT(__type_fit(int, dn - dst)); 404*f14fb602SLionel Sambuc return (int)(dn - dst); 4052fe8fb19SBen Gras } 4062fe8fb19SBen Gras 4072fe8fb19SBen Gras /*% 4082fe8fb19SBen Gras * Unpack a domain name from a message, source may be compressed. 4092fe8fb19SBen Gras * 4102fe8fb19SBen Gras * return: 4112fe8fb19SBen Gras *\li -1 if it fails, or consumed octets if it succeeds. 4122fe8fb19SBen Gras */ 4132fe8fb19SBen Gras int 4142fe8fb19SBen Gras ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src, 4152fe8fb19SBen Gras u_char *dst, size_t dstsiz) 4162fe8fb19SBen Gras { 4172fe8fb19SBen Gras return (ns_name_unpack2(msg, eom, src, dst, dstsiz, NULL)); 4182fe8fb19SBen Gras } 4192fe8fb19SBen Gras 4202fe8fb19SBen Gras /* 4212fe8fb19SBen Gras * ns_name_unpack2(msg, eom, src, dst, dstsiz, *dstlen) 4222fe8fb19SBen Gras * Unpack a domain name from a message, source may be compressed. 4232fe8fb19SBen Gras * return: 4242fe8fb19SBen Gras * -1 if it fails, or consumed octets if it succeeds. 4252fe8fb19SBen Gras * side effect: 4262fe8fb19SBen Gras * fills in *dstlen (if non-NULL). 4272fe8fb19SBen Gras */ 4282fe8fb19SBen Gras int 4292fe8fb19SBen Gras ns_name_unpack2(const u_char *msg, const u_char *eom, const u_char *src, 4302fe8fb19SBen Gras u_char *dst, size_t dstsiz, size_t *dstlen) 4312fe8fb19SBen Gras { 4322fe8fb19SBen Gras const u_char *srcp, *dstlim; 4332fe8fb19SBen Gras u_char *dstp; 4342fe8fb19SBen Gras int n, len, checked, l; 4352fe8fb19SBen Gras 4362fe8fb19SBen Gras len = -1; 4372fe8fb19SBen Gras checked = 0; 4382fe8fb19SBen Gras dstp = dst; 4392fe8fb19SBen Gras srcp = src; 4402fe8fb19SBen Gras dstlim = dst + dstsiz; 4412fe8fb19SBen Gras if (srcp < msg || srcp >= eom) { 4422fe8fb19SBen Gras errno = EMSGSIZE; 4432fe8fb19SBen Gras return (-1); 4442fe8fb19SBen Gras } 4452fe8fb19SBen Gras /* Fetch next label in domain name. */ 4462fe8fb19SBen Gras while ((n = *srcp++) != 0) { 4472fe8fb19SBen Gras /* Check for indirection. */ 4482fe8fb19SBen Gras switch (n & NS_CMPRSFLGS) { 4492fe8fb19SBen Gras case 0: 4502fe8fb19SBen Gras case NS_TYPE_ELT: 4512fe8fb19SBen Gras /* Limit checks. */ 4522fe8fb19SBen Gras if ((l = labellen(srcp - 1)) < 0) { 4532fe8fb19SBen Gras errno = EMSGSIZE; 4542fe8fb19SBen Gras return (-1); 4552fe8fb19SBen Gras } 4562fe8fb19SBen Gras if (dstp + l + 1 >= dstlim || srcp + l >= eom) { 4572fe8fb19SBen Gras errno = EMSGSIZE; 4582fe8fb19SBen Gras return (-1); 4592fe8fb19SBen Gras } 4602fe8fb19SBen Gras checked += l + 1; 4612fe8fb19SBen Gras *dstp++ = n; 4622fe8fb19SBen Gras memcpy(dstp, srcp, (size_t)l); 4632fe8fb19SBen Gras dstp += l; 4642fe8fb19SBen Gras srcp += l; 4652fe8fb19SBen Gras break; 4662fe8fb19SBen Gras 4672fe8fb19SBen Gras case NS_CMPRSFLGS: 4682fe8fb19SBen Gras if (srcp >= eom) { 4692fe8fb19SBen Gras errno = EMSGSIZE; 4702fe8fb19SBen Gras return (-1); 4712fe8fb19SBen Gras } 472*f14fb602SLionel Sambuc if (len < 0) { 473*f14fb602SLionel Sambuc _DIAGASSERT(__type_fit(int, srcp - src + 1)); 474*f14fb602SLionel Sambuc len = (int)(srcp - src + 1); 475*f14fb602SLionel Sambuc } 4762fe8fb19SBen Gras srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff)); 4772fe8fb19SBen Gras if (srcp < msg || srcp >= eom) { /*%< Out of range. */ 4782fe8fb19SBen Gras errno = EMSGSIZE; 4792fe8fb19SBen Gras return (-1); 4802fe8fb19SBen Gras } 4812fe8fb19SBen Gras checked += 2; 4822fe8fb19SBen Gras /* 4832fe8fb19SBen Gras * Check for loops in the compressed name; 4842fe8fb19SBen Gras * if we've looked at the whole message, 4852fe8fb19SBen Gras * there must be a loop. 4862fe8fb19SBen Gras */ 4872fe8fb19SBen Gras if (checked >= eom - msg) { 4882fe8fb19SBen Gras errno = EMSGSIZE; 4892fe8fb19SBen Gras return (-1); 4902fe8fb19SBen Gras } 4912fe8fb19SBen Gras break; 4922fe8fb19SBen Gras 4932fe8fb19SBen Gras default: 4942fe8fb19SBen Gras errno = EMSGSIZE; 4952fe8fb19SBen Gras return (-1); /*%< flag error */ 4962fe8fb19SBen Gras } 4972fe8fb19SBen Gras } 4982fe8fb19SBen Gras *dstp++ = 0; 4992fe8fb19SBen Gras if (dstlen != NULL) 5002fe8fb19SBen Gras *dstlen = dstp - dst; 501*f14fb602SLionel Sambuc if (len < 0) { 502*f14fb602SLionel Sambuc _DIAGASSERT(__type_fit(int, srcp - src)); 503*f14fb602SLionel Sambuc len = (int)(srcp - src); 504*f14fb602SLionel Sambuc } 505*f14fb602SLionel Sambuc return len; 5062fe8fb19SBen Gras } 5072fe8fb19SBen Gras 5082fe8fb19SBen Gras /*% 5092fe8fb19SBen Gras * Pack domain name 'domain' into 'comp_dn'. 5102fe8fb19SBen Gras * 5112fe8fb19SBen Gras * return: 5122fe8fb19SBen Gras *\li Size of the compressed name, or -1. 5132fe8fb19SBen Gras * 5142fe8fb19SBen Gras * notes: 5152fe8fb19SBen Gras *\li 'dnptrs' is an array of pointers to previous compressed names. 5162fe8fb19SBen Gras *\li dnptrs[0] is a pointer to the beginning of the message. The array 5172fe8fb19SBen Gras * ends with NULL. 5182fe8fb19SBen Gras *\li 'lastdnptr' is a pointer to the end of the array pointed to 5192fe8fb19SBen Gras * by 'dnptrs'. 5202fe8fb19SBen Gras * 5212fe8fb19SBen Gras * Side effects: 5222fe8fb19SBen Gras *\li The list of pointers in dnptrs is updated for labels inserted into 5232fe8fb19SBen Gras * the message as we compress the name. If 'dnptr' is NULL, we don't 5242fe8fb19SBen Gras * try to compress names. If 'lastdnptr' is NULL, we don't update the 5252fe8fb19SBen Gras * list. 5262fe8fb19SBen Gras */ 5272fe8fb19SBen Gras int 5282fe8fb19SBen Gras ns_name_pack(const u_char *src, u_char *dst, int dstsiz, 5292fe8fb19SBen Gras const u_char **dnptrs, const u_char **lastdnptr) 5302fe8fb19SBen Gras { 5312fe8fb19SBen Gras u_char *dstp; 5322fe8fb19SBen Gras const u_char **cpp, **lpp, *eob, *msg; 5332fe8fb19SBen Gras const u_char *srcp; 5342fe8fb19SBen Gras int n, l, first = 1; 5352fe8fb19SBen Gras 5362fe8fb19SBen Gras srcp = src; 5372fe8fb19SBen Gras dstp = dst; 5382fe8fb19SBen Gras eob = dstp + dstsiz; 5392fe8fb19SBen Gras lpp = cpp = NULL; 5402fe8fb19SBen Gras if (dnptrs != NULL) { 5412fe8fb19SBen Gras if ((msg = *dnptrs++) != NULL) { 5422fe8fb19SBen Gras for (cpp = dnptrs; *cpp != NULL; cpp++) 5432fe8fb19SBen Gras continue; 5442fe8fb19SBen Gras lpp = cpp; /*%< end of list to search */ 5452fe8fb19SBen Gras } 5462fe8fb19SBen Gras } else 5472fe8fb19SBen Gras msg = NULL; 5482fe8fb19SBen Gras 5492fe8fb19SBen Gras /* make sure the domain we are about to add is legal */ 5502fe8fb19SBen Gras l = 0; 5512fe8fb19SBen Gras do { 5522fe8fb19SBen Gras int l0; 5532fe8fb19SBen Gras 5542fe8fb19SBen Gras n = *srcp; 5552fe8fb19SBen Gras if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { 5562fe8fb19SBen Gras errno = EMSGSIZE; 5572fe8fb19SBen Gras return (-1); 5582fe8fb19SBen Gras } 5592fe8fb19SBen Gras if ((l0 = labellen(srcp)) < 0) { 5602fe8fb19SBen Gras errno = EINVAL; 5612fe8fb19SBen Gras return (-1); 5622fe8fb19SBen Gras } 5632fe8fb19SBen Gras l += l0 + 1; 5642fe8fb19SBen Gras if (l > MAXCDNAME) { 5652fe8fb19SBen Gras errno = EMSGSIZE; 5662fe8fb19SBen Gras return (-1); 5672fe8fb19SBen Gras } 5682fe8fb19SBen Gras srcp += l0 + 1; 5692fe8fb19SBen Gras } while (n != 0); 5702fe8fb19SBen Gras 5712fe8fb19SBen Gras /* from here on we need to reset compression pointer array on error */ 5722fe8fb19SBen Gras srcp = src; 5732fe8fb19SBen Gras do { 5742fe8fb19SBen Gras /* Look to see if we can use pointers. */ 5752fe8fb19SBen Gras n = *srcp; 5762fe8fb19SBen Gras if (n != 0 && msg != NULL) { 5772fe8fb19SBen Gras l = dn_find(srcp, msg, (const u_char * const *)dnptrs, 5782fe8fb19SBen Gras (const u_char * const *)lpp); 5792fe8fb19SBen Gras if (l >= 0) { 5802fe8fb19SBen Gras if (dstp + 1 >= eob) { 5812fe8fb19SBen Gras goto cleanup; 5822fe8fb19SBen Gras } 5832fe8fb19SBen Gras *dstp++ = ((u_int32_t)l >> 8) | NS_CMPRSFLGS; 5842fe8fb19SBen Gras *dstp++ = l % 256; 585*f14fb602SLionel Sambuc _DIAGASSERT(__type_fit(int, dstp - dst)); 586*f14fb602SLionel Sambuc return (int)(dstp - dst); 5872fe8fb19SBen Gras } 5882fe8fb19SBen Gras /* Not found, save it. */ 5892fe8fb19SBen Gras if (lastdnptr != NULL && cpp < lastdnptr - 1 && 5902fe8fb19SBen Gras (dstp - msg) < 0x4000 && first) { 5912fe8fb19SBen Gras *cpp++ = dstp; 5922fe8fb19SBen Gras *cpp = NULL; 5932fe8fb19SBen Gras first = 0; 5942fe8fb19SBen Gras } 5952fe8fb19SBen Gras } 5962fe8fb19SBen Gras /* copy label to buffer */ 5972fe8fb19SBen Gras if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { 5982fe8fb19SBen Gras /* Should not happen. */ 5992fe8fb19SBen Gras goto cleanup; 6002fe8fb19SBen Gras } 6012fe8fb19SBen Gras n = labellen(srcp); 6022fe8fb19SBen Gras if (dstp + 1 + n >= eob) { 6032fe8fb19SBen Gras goto cleanup; 6042fe8fb19SBen Gras } 6052fe8fb19SBen Gras memcpy(dstp, srcp, (size_t)(n + 1)); 6062fe8fb19SBen Gras srcp += n + 1; 6072fe8fb19SBen Gras dstp += n + 1; 6082fe8fb19SBen Gras } while (n != 0); 6092fe8fb19SBen Gras 6102fe8fb19SBen Gras if (dstp > eob) { 6112fe8fb19SBen Gras cleanup: 6122fe8fb19SBen Gras if (msg != NULL) 6132fe8fb19SBen Gras *lpp = NULL; 6142fe8fb19SBen Gras errno = EMSGSIZE; 6152fe8fb19SBen Gras return (-1); 6162fe8fb19SBen Gras } 617*f14fb602SLionel Sambuc _DIAGASSERT(__type_fit(int, dstp - dst)); 618*f14fb602SLionel Sambuc return (int)(dstp - dst); 6192fe8fb19SBen Gras } 6202fe8fb19SBen Gras 6212fe8fb19SBen Gras /*% 6222fe8fb19SBen Gras * Expand compressed domain name to presentation format. 6232fe8fb19SBen Gras * 6242fe8fb19SBen Gras * return: 6252fe8fb19SBen Gras *\li Number of bytes read out of `src', or -1 (with errno set). 6262fe8fb19SBen Gras * 6272fe8fb19SBen Gras * note: 6282fe8fb19SBen Gras *\li Root domain returns as "." not "". 6292fe8fb19SBen Gras */ 6302fe8fb19SBen Gras int 6312fe8fb19SBen Gras ns_name_uncompress(const u_char *msg, const u_char *eom, const u_char *src, 6322fe8fb19SBen Gras char *dst, size_t dstsiz) 6332fe8fb19SBen Gras { 6342fe8fb19SBen Gras u_char tmp[NS_MAXCDNAME]; 6352fe8fb19SBen Gras int n; 6362fe8fb19SBen Gras 6372fe8fb19SBen Gras if ((n = ns_name_unpack(msg, eom, src, tmp, sizeof tmp)) == -1) 6382fe8fb19SBen Gras return (-1); 6392fe8fb19SBen Gras if (ns_name_ntop(tmp, dst, dstsiz) == -1) 6402fe8fb19SBen Gras return (-1); 6412fe8fb19SBen Gras return (n); 6422fe8fb19SBen Gras } 6432fe8fb19SBen Gras 6442fe8fb19SBen Gras /*% 6452fe8fb19SBen Gras * Compress a domain name into wire format, using compression pointers. 6462fe8fb19SBen Gras * 6472fe8fb19SBen Gras * return: 6482fe8fb19SBen Gras *\li Number of bytes consumed in `dst' or -1 (with errno set). 6492fe8fb19SBen Gras * 6502fe8fb19SBen Gras * notes: 6512fe8fb19SBen Gras *\li 'dnptrs' is an array of pointers to previous compressed names. 6522fe8fb19SBen Gras *\li dnptrs[0] is a pointer to the beginning of the message. 6532fe8fb19SBen Gras *\li The list ends with NULL. 'lastdnptr' is a pointer to the end of the 6542fe8fb19SBen Gras * array pointed to by 'dnptrs'. Side effect is to update the list of 6552fe8fb19SBen Gras * pointers for labels inserted into the message as we compress the name. 6562fe8fb19SBen Gras *\li If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr' 6572fe8fb19SBen Gras * is NULL, we don't update the list. 6582fe8fb19SBen Gras */ 6592fe8fb19SBen Gras int 6602fe8fb19SBen Gras ns_name_compress(const char *src, u_char *dst, size_t dstsiz, 6612fe8fb19SBen Gras const u_char **dnptrs, const u_char **lastdnptr) 6622fe8fb19SBen Gras { 6632fe8fb19SBen Gras u_char tmp[NS_MAXCDNAME]; 6642fe8fb19SBen Gras 6652fe8fb19SBen Gras if (ns_name_pton(src, tmp, sizeof tmp) == -1) 6662fe8fb19SBen Gras return (-1); 6672fe8fb19SBen Gras return (ns_name_pack(tmp, dst, (int)dstsiz, dnptrs, lastdnptr)); 6682fe8fb19SBen Gras } 6692fe8fb19SBen Gras 6702fe8fb19SBen Gras /*% 6712fe8fb19SBen Gras * Reset dnptrs so that there are no active references to pointers at or 6722fe8fb19SBen Gras * after src. 6732fe8fb19SBen Gras */ 6742fe8fb19SBen Gras void 6752fe8fb19SBen Gras ns_name_rollback(const u_char *src, const u_char **dnptrs, 6762fe8fb19SBen Gras const u_char **lastdnptr) 6772fe8fb19SBen Gras { 6782fe8fb19SBen Gras while (dnptrs < lastdnptr && *dnptrs != NULL) { 6792fe8fb19SBen Gras if (*dnptrs >= src) { 6802fe8fb19SBen Gras *dnptrs = NULL; 6812fe8fb19SBen Gras break; 6822fe8fb19SBen Gras } 6832fe8fb19SBen Gras dnptrs++; 6842fe8fb19SBen Gras } 6852fe8fb19SBen Gras } 6862fe8fb19SBen Gras 6872fe8fb19SBen Gras /*% 6882fe8fb19SBen Gras * Advance *ptrptr to skip over the compressed name it points at. 6892fe8fb19SBen Gras * 6902fe8fb19SBen Gras * return: 6912fe8fb19SBen Gras *\li 0 on success, -1 (with errno set) on failure. 6922fe8fb19SBen Gras */ 6932fe8fb19SBen Gras int 6942fe8fb19SBen Gras ns_name_skip(const u_char **ptrptr, const u_char *eom) 6952fe8fb19SBen Gras { 6962fe8fb19SBen Gras const u_char *cp; 6972fe8fb19SBen Gras u_int n; 6982fe8fb19SBen Gras int l; 6992fe8fb19SBen Gras 7002fe8fb19SBen Gras cp = *ptrptr; 7012fe8fb19SBen Gras while (cp < eom && (n = *cp++) != 0) { 7022fe8fb19SBen Gras /* Check for indirection. */ 7032fe8fb19SBen Gras switch (n & NS_CMPRSFLGS) { 7042fe8fb19SBen Gras case 0: /*%< normal case, n == len */ 7052fe8fb19SBen Gras cp += n; 7062fe8fb19SBen Gras continue; 7072fe8fb19SBen Gras case NS_TYPE_ELT: /*%< EDNS0 extended label */ 7082fe8fb19SBen Gras if ((l = labellen(cp - 1)) < 0) { 7092fe8fb19SBen Gras errno = EMSGSIZE; /*%< XXX */ 7102fe8fb19SBen Gras return (-1); 7112fe8fb19SBen Gras } 7122fe8fb19SBen Gras cp += l; 7132fe8fb19SBen Gras continue; 7142fe8fb19SBen Gras case NS_CMPRSFLGS: /*%< indirection */ 7152fe8fb19SBen Gras cp++; 7162fe8fb19SBen Gras break; 7172fe8fb19SBen Gras default: /*%< illegal type */ 7182fe8fb19SBen Gras errno = EMSGSIZE; 7192fe8fb19SBen Gras return (-1); 7202fe8fb19SBen Gras } 7212fe8fb19SBen Gras break; 7222fe8fb19SBen Gras } 7232fe8fb19SBen Gras if (cp > eom) { 7242fe8fb19SBen Gras errno = EMSGSIZE; 7252fe8fb19SBen Gras return (-1); 7262fe8fb19SBen Gras } 7272fe8fb19SBen Gras *ptrptr = cp; 7282fe8fb19SBen Gras return (0); 7292fe8fb19SBen Gras } 7302fe8fb19SBen Gras 7312fe8fb19SBen Gras /* Find the number of octets an nname takes up, including the root label. 7322fe8fb19SBen Gras * (This is basically ns_name_skip() without compression-pointer support.) 7332fe8fb19SBen Gras * ((NOTE: can only return zero if passed-in namesiz argument is zero.)) 7342fe8fb19SBen Gras */ 7352fe8fb19SBen Gras ssize_t 7362fe8fb19SBen Gras ns_name_length(ns_nname_ct nname, size_t namesiz) { 7372fe8fb19SBen Gras ns_nname_ct orig = nname; 7382fe8fb19SBen Gras u_int n; 7392fe8fb19SBen Gras 7402fe8fb19SBen Gras while (namesiz-- > 0 && (n = *nname++) != 0) { 7412fe8fb19SBen Gras if ((n & NS_CMPRSFLGS) != 0) { 7422fe8fb19SBen Gras errno = EISDIR; 7432fe8fb19SBen Gras return (-1); 7442fe8fb19SBen Gras } 7452fe8fb19SBen Gras if (n > namesiz) { 7462fe8fb19SBen Gras errno = EMSGSIZE; 7472fe8fb19SBen Gras return (-1); 7482fe8fb19SBen Gras } 7492fe8fb19SBen Gras nname += n; 7502fe8fb19SBen Gras namesiz -= n; 7512fe8fb19SBen Gras } 7522fe8fb19SBen Gras return (nname - orig); 7532fe8fb19SBen Gras } 7542fe8fb19SBen Gras 7552fe8fb19SBen Gras /* Compare two nname's for equality. Return -1 on error (setting errno). 7562fe8fb19SBen Gras */ 7572fe8fb19SBen Gras int 7582fe8fb19SBen Gras ns_name_eq(ns_nname_ct a, size_t as, ns_nname_ct b, size_t bs) { 7592fe8fb19SBen Gras ns_nname_ct ae = a + as, be = b + bs; 7602fe8fb19SBen Gras int ac, bc; 7612fe8fb19SBen Gras 7622fe8fb19SBen Gras while (ac = *a, bc = *b, ac != 0 && bc != 0) { 7632fe8fb19SBen Gras if ((ac & NS_CMPRSFLGS) != 0 || (bc & NS_CMPRSFLGS) != 0) { 7642fe8fb19SBen Gras errno = EISDIR; 7652fe8fb19SBen Gras return (-1); 7662fe8fb19SBen Gras } 7672fe8fb19SBen Gras if (a + ac >= ae || b + bc >= be) { 7682fe8fb19SBen Gras errno = EMSGSIZE; 7692fe8fb19SBen Gras return (-1); 7702fe8fb19SBen Gras } 7712fe8fb19SBen Gras if (ac != bc || strncasecmp((const char *) ++a, 7722fe8fb19SBen Gras (const char *) ++b, 7732fe8fb19SBen Gras (size_t)ac) != 0) 7742fe8fb19SBen Gras return (0); 7752fe8fb19SBen Gras a += ac, b += bc; 7762fe8fb19SBen Gras } 7772fe8fb19SBen Gras return (ac == 0 && bc == 0); 7782fe8fb19SBen Gras } 7792fe8fb19SBen Gras 7802fe8fb19SBen Gras /* Is domain "A" owned by (at or below) domain "B"? 7812fe8fb19SBen Gras */ 7822fe8fb19SBen Gras int 7832fe8fb19SBen Gras ns_name_owned(ns_namemap_ct a, int an, ns_namemap_ct b, int bn) { 7842fe8fb19SBen Gras /* If A is shorter, it cannot be owned by B. */ 7852fe8fb19SBen Gras if (an < bn) 7862fe8fb19SBen Gras return (0); 7872fe8fb19SBen Gras 7882fe8fb19SBen Gras /* If they are unequal before the length of the shorter, A cannot... */ 7892fe8fb19SBen Gras while (bn > 0) { 7902fe8fb19SBen Gras if (a->len != b->len || 7912fe8fb19SBen Gras strncasecmp((const char *) a->base, 7922fe8fb19SBen Gras (const char *) b->base, (size_t)a->len) != 0) 7932fe8fb19SBen Gras return (0); 7942fe8fb19SBen Gras a++, an--; 7952fe8fb19SBen Gras b++, bn--; 7962fe8fb19SBen Gras } 7972fe8fb19SBen Gras 7982fe8fb19SBen Gras /* A might be longer or not, but either way, B owns it. */ 7992fe8fb19SBen Gras return (1); 8002fe8fb19SBen Gras } 8012fe8fb19SBen Gras 8022fe8fb19SBen Gras /* Build an array of <base,len> tuples from an nname, top-down order. 8032fe8fb19SBen Gras * Return the number of tuples (labels) thus discovered. 8042fe8fb19SBen Gras */ 8052fe8fb19SBen Gras int 8062fe8fb19SBen Gras ns_name_map(ns_nname_ct nname, size_t namelen, ns_namemap_t map, int mapsize) { 8072fe8fb19SBen Gras u_int n; 8082fe8fb19SBen Gras int l; 8092fe8fb19SBen Gras 8102fe8fb19SBen Gras n = *nname++; 8112fe8fb19SBen Gras namelen--; 8122fe8fb19SBen Gras 8132fe8fb19SBen Gras /* Root zone? */ 8142fe8fb19SBen Gras if (n == 0) { 8152fe8fb19SBen Gras /* Extra data follows name? */ 8162fe8fb19SBen Gras if (namelen > 0) { 8172fe8fb19SBen Gras errno = EMSGSIZE; 8182fe8fb19SBen Gras return (-1); 8192fe8fb19SBen Gras } 8202fe8fb19SBen Gras return (0); 8212fe8fb19SBen Gras } 8222fe8fb19SBen Gras 8232fe8fb19SBen Gras /* Compression pointer? */ 8242fe8fb19SBen Gras if ((n & NS_CMPRSFLGS) != 0) { 8252fe8fb19SBen Gras errno = EISDIR; 8262fe8fb19SBen Gras return (-1); 8272fe8fb19SBen Gras } 8282fe8fb19SBen Gras 8292fe8fb19SBen Gras /* Label too long? */ 8302fe8fb19SBen Gras if (n > namelen) { 8312fe8fb19SBen Gras errno = EMSGSIZE; 8322fe8fb19SBen Gras return (-1); 8332fe8fb19SBen Gras } 8342fe8fb19SBen Gras 8352fe8fb19SBen Gras /* Recurse to get rest of name done first. */ 8362fe8fb19SBen Gras l = ns_name_map(nname + n, namelen - n, map, mapsize); 8372fe8fb19SBen Gras if (l < 0) 8382fe8fb19SBen Gras return (-1); 8392fe8fb19SBen Gras 8402fe8fb19SBen Gras /* Too many labels? */ 8412fe8fb19SBen Gras if (l >= mapsize) { 8422fe8fb19SBen Gras errno = ENAMETOOLONG; 8432fe8fb19SBen Gras return (-1); 8442fe8fb19SBen Gras } 8452fe8fb19SBen Gras 8462fe8fb19SBen Gras /* We're on our way back up-stack, store current map data. */ 8472fe8fb19SBen Gras map[l].base = nname; 8482fe8fb19SBen Gras map[l].len = n; 8492fe8fb19SBen Gras return (l + 1); 8502fe8fb19SBen Gras } 8512fe8fb19SBen Gras 8522fe8fb19SBen Gras /* Count the labels in a domain name. Root counts, so COM. has two. This 8532fe8fb19SBen Gras * is to make the result comparable to the result of ns_name_map(). 8542fe8fb19SBen Gras */ 8552fe8fb19SBen Gras int 8562fe8fb19SBen Gras ns_name_labels(ns_nname_ct nname, size_t namesiz) { 8572fe8fb19SBen Gras int ret = 0; 8582fe8fb19SBen Gras u_int n; 8592fe8fb19SBen Gras 8602fe8fb19SBen Gras while (namesiz-- > 0 && (n = *nname++) != 0) { 8612fe8fb19SBen Gras if ((n & NS_CMPRSFLGS) != 0) { 8622fe8fb19SBen Gras errno = EISDIR; 8632fe8fb19SBen Gras return (-1); 8642fe8fb19SBen Gras } 8652fe8fb19SBen Gras if (n > namesiz) { 8662fe8fb19SBen Gras errno = EMSGSIZE; 8672fe8fb19SBen Gras return (-1); 8682fe8fb19SBen Gras } 8692fe8fb19SBen Gras nname += n; 8702fe8fb19SBen Gras namesiz -= n; 8712fe8fb19SBen Gras ret++; 8722fe8fb19SBen Gras } 8732fe8fb19SBen Gras return (ret + 1); 8742fe8fb19SBen Gras } 8752fe8fb19SBen Gras 8762fe8fb19SBen Gras /* Private. */ 8772fe8fb19SBen Gras 8782fe8fb19SBen Gras /*% 8792fe8fb19SBen Gras * Thinking in noninternationalized USASCII (per the DNS spec), 8802fe8fb19SBen Gras * is this characted special ("in need of quoting") ? 8812fe8fb19SBen Gras * 8822fe8fb19SBen Gras * return: 8832fe8fb19SBen Gras *\li boolean. 8842fe8fb19SBen Gras */ 8852fe8fb19SBen Gras static int 8862fe8fb19SBen Gras special(int ch) { 8872fe8fb19SBen Gras switch (ch) { 8882fe8fb19SBen Gras case 0x22: /*%< '"' */ 8892fe8fb19SBen Gras case 0x2E: /*%< '.' */ 8902fe8fb19SBen Gras case 0x3B: /*%< ';' */ 8912fe8fb19SBen Gras case 0x5C: /*%< '\\' */ 8922fe8fb19SBen Gras case 0x28: /*%< '(' */ 8932fe8fb19SBen Gras case 0x29: /*%< ')' */ 8942fe8fb19SBen Gras /* Special modifiers in zone files. */ 8952fe8fb19SBen Gras case 0x40: /*%< '@' */ 8962fe8fb19SBen Gras case 0x24: /*%< '$' */ 8972fe8fb19SBen Gras return (1); 8982fe8fb19SBen Gras default: 8992fe8fb19SBen Gras return (0); 9002fe8fb19SBen Gras } 9012fe8fb19SBen Gras } 9022fe8fb19SBen Gras 9032fe8fb19SBen Gras /*% 9042fe8fb19SBen Gras * Thinking in noninternationalized USASCII (per the DNS spec), 9052fe8fb19SBen Gras * is this character visible and not a space when printed ? 9062fe8fb19SBen Gras * 9072fe8fb19SBen Gras * return: 9082fe8fb19SBen Gras *\li boolean. 9092fe8fb19SBen Gras */ 9102fe8fb19SBen Gras static int 9112fe8fb19SBen Gras printable(int ch) { 9122fe8fb19SBen Gras return (ch > 0x20 && ch < 0x7f); 9132fe8fb19SBen Gras } 9142fe8fb19SBen Gras 9152fe8fb19SBen Gras /*% 9162fe8fb19SBen Gras * Thinking in noninternationalized USASCII (per the DNS spec), 9172fe8fb19SBen Gras * convert this character to lower case if it's upper case. 9182fe8fb19SBen Gras */ 9192fe8fb19SBen Gras static int 9202fe8fb19SBen Gras mklower(int ch) { 9212fe8fb19SBen Gras if (ch >= 0x41 && ch <= 0x5A) 9222fe8fb19SBen Gras return (ch + 0x20); 9232fe8fb19SBen Gras return (ch); 9242fe8fb19SBen Gras } 9252fe8fb19SBen Gras 9262fe8fb19SBen Gras /*% 9272fe8fb19SBen Gras * Search for the counted-label name in an array of compressed names. 9282fe8fb19SBen Gras * 9292fe8fb19SBen Gras * return: 9302fe8fb19SBen Gras *\li offset from msg if found, or -1. 9312fe8fb19SBen Gras * 9322fe8fb19SBen Gras * notes: 9332fe8fb19SBen Gras *\li dnptrs is the pointer to the first name on the list, 9342fe8fb19SBen Gras *\li not the pointer to the start of the message. 9352fe8fb19SBen Gras */ 9362fe8fb19SBen Gras static int 9372fe8fb19SBen Gras dn_find(const u_char *domain, const u_char *msg, 9382fe8fb19SBen Gras const u_char * const *dnptrs, 9392fe8fb19SBen Gras const u_char * const *lastdnptr) 9402fe8fb19SBen Gras { 9412fe8fb19SBen Gras const u_char *dn, *cp, *sp; 9422fe8fb19SBen Gras const u_char * const *cpp; 9432fe8fb19SBen Gras u_int n; 9442fe8fb19SBen Gras 9452fe8fb19SBen Gras for (cpp = dnptrs; cpp < lastdnptr; cpp++) { 9462fe8fb19SBen Gras sp = *cpp; 9472fe8fb19SBen Gras /* 9482fe8fb19SBen Gras * terminate search on: 9492fe8fb19SBen Gras * root label 9502fe8fb19SBen Gras * compression pointer 9512fe8fb19SBen Gras * unusable offset 9522fe8fb19SBen Gras */ 9532fe8fb19SBen Gras while (*sp != 0 && (*sp & NS_CMPRSFLGS) == 0 && 9542fe8fb19SBen Gras (sp - msg) < 0x4000) { 9552fe8fb19SBen Gras dn = domain; 9562fe8fb19SBen Gras cp = sp; 9572fe8fb19SBen Gras while ((n = *cp++) != 0) { 9582fe8fb19SBen Gras /* 9592fe8fb19SBen Gras * check for indirection 9602fe8fb19SBen Gras */ 9612fe8fb19SBen Gras switch (n & NS_CMPRSFLGS) { 9622fe8fb19SBen Gras case 0: /*%< normal case, n == len */ 9632fe8fb19SBen Gras n = labellen(cp - 1); /*%< XXX */ 9642fe8fb19SBen Gras if (n != *dn++) 9652fe8fb19SBen Gras goto next; 9662fe8fb19SBen Gras 9672fe8fb19SBen Gras for (; n > 0; n--) 9682fe8fb19SBen Gras if (mklower(*dn++) != 9692fe8fb19SBen Gras mklower(*cp++)) 9702fe8fb19SBen Gras goto next; 9712fe8fb19SBen Gras /* Is next root for both ? */ 972*f14fb602SLionel Sambuc if (*dn == '\0' && *cp == '\0') { 973*f14fb602SLionel Sambuc _DIAGASSERT(__type_fit(int, 974*f14fb602SLionel Sambuc sp - msg)); 975*f14fb602SLionel Sambuc return (int)(sp - msg); 976*f14fb602SLionel Sambuc } 9772fe8fb19SBen Gras if (*dn) 9782fe8fb19SBen Gras continue; 9792fe8fb19SBen Gras goto next; 9802fe8fb19SBen Gras case NS_CMPRSFLGS: /*%< indirection */ 9812fe8fb19SBen Gras cp = msg + (((n & 0x3f) << 8) | *cp); 9822fe8fb19SBen Gras break; 9832fe8fb19SBen Gras 9842fe8fb19SBen Gras default: /*%< illegal type */ 9852fe8fb19SBen Gras errno = EMSGSIZE; 9862fe8fb19SBen Gras return (-1); 9872fe8fb19SBen Gras } 9882fe8fb19SBen Gras } 9892fe8fb19SBen Gras next: ; 9902fe8fb19SBen Gras sp += *sp + 1; 9912fe8fb19SBen Gras } 9922fe8fb19SBen Gras } 9932fe8fb19SBen Gras errno = ENOENT; 9942fe8fb19SBen Gras return (-1); 9952fe8fb19SBen Gras } 9962fe8fb19SBen Gras 9972fe8fb19SBen Gras static int 9982fe8fb19SBen Gras decode_bitstring(const unsigned char **cpp, char *dn, const char *eom) 9992fe8fb19SBen Gras { 10002fe8fb19SBen Gras const unsigned char *cp = *cpp; 10012fe8fb19SBen Gras char *beg = dn, tc; 10022fe8fb19SBen Gras int b, blen, plen, i; 10032fe8fb19SBen Gras 10042fe8fb19SBen Gras if ((blen = (*cp & 0xff)) == 0) 10052fe8fb19SBen Gras blen = 256; 10062fe8fb19SBen Gras plen = (blen + 3) / 4; 1007*f14fb602SLionel Sambuc plen += (int)sizeof("\\[x/]") + (blen > 99 ? 3 : (blen > 9) ? 2 : 1); 10082fe8fb19SBen Gras if (dn + plen >= eom) 10092fe8fb19SBen Gras return (-1); 10102fe8fb19SBen Gras 10112fe8fb19SBen Gras cp++; 10122fe8fb19SBen Gras i = SPRINTF((dn, "\\[x")); 10132fe8fb19SBen Gras if (i < 0) 10142fe8fb19SBen Gras return (-1); 10152fe8fb19SBen Gras dn += i; 10162fe8fb19SBen Gras for (b = blen; b > 7; b -= 8, cp++) { 10172fe8fb19SBen Gras i = SPRINTF((dn, "%02x", *cp & 0xff)); 10182fe8fb19SBen Gras if (i < 0) 10192fe8fb19SBen Gras return (-1); 10202fe8fb19SBen Gras dn += i; 10212fe8fb19SBen Gras } 10222fe8fb19SBen Gras if (b > 4) { 10232fe8fb19SBen Gras tc = *cp++; 10242fe8fb19SBen Gras i = SPRINTF((dn, "%02x", tc & (0xff << (8 - b)))); 10252fe8fb19SBen Gras if (i < 0) 10262fe8fb19SBen Gras return (-1); 10272fe8fb19SBen Gras dn += i; 10282fe8fb19SBen Gras } else if (b > 0) { 10292fe8fb19SBen Gras tc = *cp++; 10302fe8fb19SBen Gras i = SPRINTF((dn, "%1x", 10312fe8fb19SBen Gras (((u_int32_t)tc >> 4) & 0x0f) & (0x0f << (4 - b)))); 10322fe8fb19SBen Gras if (i < 0) 10332fe8fb19SBen Gras return (-1); 10342fe8fb19SBen Gras dn += i; 10352fe8fb19SBen Gras } 10362fe8fb19SBen Gras i = SPRINTF((dn, "/%d]", blen)); 10372fe8fb19SBen Gras if (i < 0) 10382fe8fb19SBen Gras return (-1); 10392fe8fb19SBen Gras dn += i; 10402fe8fb19SBen Gras 10412fe8fb19SBen Gras *cpp = cp; 1042*f14fb602SLionel Sambuc _DIAGASSERT(__type_fit(int, dn - beg)); 1043*f14fb602SLionel Sambuc return (int)(dn - beg); 10442fe8fb19SBen Gras } 10452fe8fb19SBen Gras 10462fe8fb19SBen Gras static int 10472fe8fb19SBen Gras encode_bitsring(const char **bp, const char *end, unsigned char **labelp, 10482fe8fb19SBen Gras unsigned char ** dst, unsigned const char *eom) 10492fe8fb19SBen Gras { 10502fe8fb19SBen Gras int afterslash = 0; 10512fe8fb19SBen Gras const char *cp = *bp; 10522fe8fb19SBen Gras unsigned char *tp; 10532fe8fb19SBen Gras char c; 10542fe8fb19SBen Gras const char *beg_blen; 10552fe8fb19SBen Gras char *end_blen = NULL; 10562fe8fb19SBen Gras int value = 0, count = 0, tbcount = 0, blen = 0; 10572fe8fb19SBen Gras 10582fe8fb19SBen Gras beg_blen = end_blen = NULL; 10592fe8fb19SBen Gras 10602fe8fb19SBen Gras /* a bitstring must contain at least 2 characters */ 10612fe8fb19SBen Gras if (end - cp < 2) 10622fe8fb19SBen Gras return (EINVAL); 10632fe8fb19SBen Gras 10642fe8fb19SBen Gras /* XXX: currently, only hex strings are supported */ 10652fe8fb19SBen Gras if (*cp++ != 'x') 10662fe8fb19SBen Gras return (EINVAL); 10672fe8fb19SBen Gras if (!isxdigit((*cp) & 0xff)) /*%< reject '\[x/BLEN]' */ 10682fe8fb19SBen Gras return (EINVAL); 10692fe8fb19SBen Gras 10702fe8fb19SBen Gras for (tp = *dst + 1; cp < end && tp < eom; cp++) { 10712fe8fb19SBen Gras switch((c = *cp)) { 10722fe8fb19SBen Gras case ']': /*%< end of the bitstring */ 10732fe8fb19SBen Gras if (afterslash) { 10742fe8fb19SBen Gras if (beg_blen == NULL) 10752fe8fb19SBen Gras return (EINVAL); 10762fe8fb19SBen Gras blen = (int)strtol(beg_blen, &end_blen, 10); 10772fe8fb19SBen Gras if (*end_blen != ']') 10782fe8fb19SBen Gras return (EINVAL); 10792fe8fb19SBen Gras } 10802fe8fb19SBen Gras if (count) 10812fe8fb19SBen Gras *tp++ = ((value << 4) & 0xff); 10822fe8fb19SBen Gras cp++; /*%< skip ']' */ 10832fe8fb19SBen Gras goto done; 10842fe8fb19SBen Gras case '/': 10852fe8fb19SBen Gras afterslash = 1; 10862fe8fb19SBen Gras break; 10872fe8fb19SBen Gras default: 10882fe8fb19SBen Gras if (afterslash) { 10892fe8fb19SBen Gras if (!isdigit(c&0xff)) 10902fe8fb19SBen Gras return (EINVAL); 10912fe8fb19SBen Gras if (beg_blen == NULL) { 10922fe8fb19SBen Gras 10932fe8fb19SBen Gras if (c == '0') { 10942fe8fb19SBen Gras /* blen never begings with 0 */ 10952fe8fb19SBen Gras return (EINVAL); 10962fe8fb19SBen Gras } 10972fe8fb19SBen Gras beg_blen = cp; 10982fe8fb19SBen Gras } 10992fe8fb19SBen Gras } else { 11002fe8fb19SBen Gras if (!isxdigit(c&0xff)) 11012fe8fb19SBen Gras return (EINVAL); 11022fe8fb19SBen Gras value <<= 4; 11032fe8fb19SBen Gras value += digitvalue[(int)c]; 11042fe8fb19SBen Gras count += 4; 11052fe8fb19SBen Gras tbcount += 4; 11062fe8fb19SBen Gras if (tbcount > 256) 11072fe8fb19SBen Gras return (EINVAL); 11082fe8fb19SBen Gras if (count == 8) { 11092fe8fb19SBen Gras *tp++ = value; 11102fe8fb19SBen Gras count = 0; 11112fe8fb19SBen Gras } 11122fe8fb19SBen Gras } 11132fe8fb19SBen Gras break; 11142fe8fb19SBen Gras } 11152fe8fb19SBen Gras } 11162fe8fb19SBen Gras done: 11172fe8fb19SBen Gras if (cp >= end || tp >= eom) 11182fe8fb19SBen Gras return (EMSGSIZE); 11192fe8fb19SBen Gras 11202fe8fb19SBen Gras /* 11212fe8fb19SBen Gras * bit length validation: 11222fe8fb19SBen Gras * If a <length> is present, the number of digits in the <bit-data> 11232fe8fb19SBen Gras * MUST be just sufficient to contain the number of bits specified 11242fe8fb19SBen Gras * by the <length>. If there are insignificant bits in a final 11252fe8fb19SBen Gras * hexadecimal or octal digit, they MUST be zero. 11262fe8fb19SBen Gras * RFC2673, Section 3.2. 11272fe8fb19SBen Gras */ 11282fe8fb19SBen Gras if (blen > 0) { 11292fe8fb19SBen Gras int traillen; 11302fe8fb19SBen Gras 11312fe8fb19SBen Gras if (((blen + 3) & ~3) != tbcount) 11322fe8fb19SBen Gras return (EINVAL); 11332fe8fb19SBen Gras traillen = tbcount - blen; /*%< between 0 and 3 */ 11342fe8fb19SBen Gras if (((value << (8 - traillen)) & 0xff) != 0) 11352fe8fb19SBen Gras return (EINVAL); 11362fe8fb19SBen Gras } 11372fe8fb19SBen Gras else 11382fe8fb19SBen Gras blen = tbcount; 11392fe8fb19SBen Gras if (blen == 256) 11402fe8fb19SBen Gras blen = 0; 11412fe8fb19SBen Gras 11422fe8fb19SBen Gras /* encode the type and the significant bit fields */ 11432fe8fb19SBen Gras **labelp = DNS_LABELTYPE_BITSTRING; 11442fe8fb19SBen Gras **dst = blen; 11452fe8fb19SBen Gras 11462fe8fb19SBen Gras *bp = cp; 11472fe8fb19SBen Gras *dst = tp; 11482fe8fb19SBen Gras 11492fe8fb19SBen Gras return (0); 11502fe8fb19SBen Gras } 11512fe8fb19SBen Gras 11522fe8fb19SBen Gras static int 11532fe8fb19SBen Gras labellen(const u_char *lp) 11542fe8fb19SBen Gras { 11552fe8fb19SBen Gras int bitlen; 11562fe8fb19SBen Gras u_char l = *lp; 11572fe8fb19SBen Gras 11582fe8fb19SBen Gras if ((l & NS_CMPRSFLGS) == NS_CMPRSFLGS) { 11592fe8fb19SBen Gras /* should be avoided by the caller */ 11602fe8fb19SBen Gras return (-1); 11612fe8fb19SBen Gras } 11622fe8fb19SBen Gras 11632fe8fb19SBen Gras if ((l & NS_CMPRSFLGS) == NS_TYPE_ELT) { 11642fe8fb19SBen Gras if (l == DNS_LABELTYPE_BITSTRING) { 11652fe8fb19SBen Gras if ((bitlen = *(lp + 1)) == 0) 11662fe8fb19SBen Gras bitlen = 256; 11672fe8fb19SBen Gras return ((bitlen + 7 ) / 8 + 1); 11682fe8fb19SBen Gras } 11692fe8fb19SBen Gras return (-1); /*%< unknwon ELT */ 11702fe8fb19SBen Gras } 11712fe8fb19SBen Gras return (l); 11722fe8fb19SBen Gras } 11732fe8fb19SBen Gras 11742fe8fb19SBen Gras /*! \file */ 1175