1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 3*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 4*7c478bd9Sstevel@tonic-gate */ 5*7c478bd9Sstevel@tonic-gate 6*7c478bd9Sstevel@tonic-gate /* 7*7c478bd9Sstevel@tonic-gate * Copyright (c) 1996,1999 by Internet Software Consortium. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * Permission to use, copy, modify, and distribute this software for any 10*7c478bd9Sstevel@tonic-gate * purpose with or without fee is hereby granted, provided that the above 11*7c478bd9Sstevel@tonic-gate * copyright notice and this permission notice appear in all copies. 12*7c478bd9Sstevel@tonic-gate * 13*7c478bd9Sstevel@tonic-gate * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS 14*7c478bd9Sstevel@tonic-gate * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES 15*7c478bd9Sstevel@tonic-gate * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE 16*7c478bd9Sstevel@tonic-gate * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 17*7c478bd9Sstevel@tonic-gate * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 18*7c478bd9Sstevel@tonic-gate * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 19*7c478bd9Sstevel@tonic-gate * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 20*7c478bd9Sstevel@tonic-gate * SOFTWARE. 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate 23*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 24*7c478bd9Sstevel@tonic-gate 25*7c478bd9Sstevel@tonic-gate #ifndef lint 26*7c478bd9Sstevel@tonic-gate static const char rcsid[] = "$Id: ns_name.c,v 8.20 2003/04/03 06:00:07 marka Exp $"; 27*7c478bd9Sstevel@tonic-gate #endif 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #include "port_before.h" 30*7c478bd9Sstevel@tonic-gate 31*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 32*7c478bd9Sstevel@tonic-gate 33*7c478bd9Sstevel@tonic-gate #include <netinet/in.h> 34*7c478bd9Sstevel@tonic-gate #include <arpa/nameser.h> 35*7c478bd9Sstevel@tonic-gate 36*7c478bd9Sstevel@tonic-gate #include <errno.h> 37*7c478bd9Sstevel@tonic-gate #include <resolv.h> 38*7c478bd9Sstevel@tonic-gate #include <string.h> 39*7c478bd9Sstevel@tonic-gate #include <ctype.h> 40*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 41*7c478bd9Sstevel@tonic-gate #include <limits.h> 42*7c478bd9Sstevel@tonic-gate 43*7c478bd9Sstevel@tonic-gate #include "port_after.h" 44*7c478bd9Sstevel@tonic-gate 45*7c478bd9Sstevel@tonic-gate #ifdef SPRINTF_CHAR 46*7c478bd9Sstevel@tonic-gate # define SPRINTF(x) strlen(sprintf/**/x) 47*7c478bd9Sstevel@tonic-gate #else 48*7c478bd9Sstevel@tonic-gate # define SPRINTF(x) ((size_t)sprintf x) 49*7c478bd9Sstevel@tonic-gate #endif 50*7c478bd9Sstevel@tonic-gate 51*7c478bd9Sstevel@tonic-gate #define NS_TYPE_ELT 0x40 /* EDNS0 extended label type */ 52*7c478bd9Sstevel@tonic-gate #define DNS_LABELTYPE_BITSTRING 0x41 53*7c478bd9Sstevel@tonic-gate 54*7c478bd9Sstevel@tonic-gate /* Data. */ 55*7c478bd9Sstevel@tonic-gate 56*7c478bd9Sstevel@tonic-gate static const char digits[] = "0123456789"; 57*7c478bd9Sstevel@tonic-gate 58*7c478bd9Sstevel@tonic-gate static const char digitvalue[256] = { 59*7c478bd9Sstevel@tonic-gate -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*16*/ 60*7c478bd9Sstevel@tonic-gate -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*32*/ 61*7c478bd9Sstevel@tonic-gate -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*48*/ 62*7c478bd9Sstevel@tonic-gate 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /*64*/ 63*7c478bd9Sstevel@tonic-gate -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*80*/ 64*7c478bd9Sstevel@tonic-gate -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*96*/ 65*7c478bd9Sstevel@tonic-gate -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*112*/ 66*7c478bd9Sstevel@tonic-gate -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*128*/ 67*7c478bd9Sstevel@tonic-gate -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 68*7c478bd9Sstevel@tonic-gate -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 69*7c478bd9Sstevel@tonic-gate -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 70*7c478bd9Sstevel@tonic-gate -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 71*7c478bd9Sstevel@tonic-gate -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 72*7c478bd9Sstevel@tonic-gate -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 73*7c478bd9Sstevel@tonic-gate -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 74*7c478bd9Sstevel@tonic-gate -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*256*/ 75*7c478bd9Sstevel@tonic-gate }; 76*7c478bd9Sstevel@tonic-gate 77*7c478bd9Sstevel@tonic-gate /* Forward. */ 78*7c478bd9Sstevel@tonic-gate 79*7c478bd9Sstevel@tonic-gate static int special(int); 80*7c478bd9Sstevel@tonic-gate static int printable(int); 81*7c478bd9Sstevel@tonic-gate static int dn_find(const u_char *, const u_char *, 82*7c478bd9Sstevel@tonic-gate const u_char * const *, 83*7c478bd9Sstevel@tonic-gate const u_char * const *); 84*7c478bd9Sstevel@tonic-gate static int encode_bitsring(const char **, const char *, 85*7c478bd9Sstevel@tonic-gate char **, char **, const char *); 86*7c478bd9Sstevel@tonic-gate static int labellen(const u_char *); 87*7c478bd9Sstevel@tonic-gate static int decode_bitstring(const char **, char *, const char *); 88*7c478bd9Sstevel@tonic-gate 89*7c478bd9Sstevel@tonic-gate /* Public. */ 90*7c478bd9Sstevel@tonic-gate 91*7c478bd9Sstevel@tonic-gate /* 92*7c478bd9Sstevel@tonic-gate * ns_name_ntop(src, dst, dstsiz) 93*7c478bd9Sstevel@tonic-gate * Convert an encoded domain name to printable ascii as per RFC1035. 94*7c478bd9Sstevel@tonic-gate * return: 95*7c478bd9Sstevel@tonic-gate * Number of bytes written to buffer, or -1 (with errno set) 96*7c478bd9Sstevel@tonic-gate * notes: 97*7c478bd9Sstevel@tonic-gate * The root is returned as "." 98*7c478bd9Sstevel@tonic-gate * All other domains are returned in non absolute form 99*7c478bd9Sstevel@tonic-gate */ 100*7c478bd9Sstevel@tonic-gate int 101*7c478bd9Sstevel@tonic-gate ns_name_ntop(const u_char *src, char *dst, size_t dstsiz) 102*7c478bd9Sstevel@tonic-gate { 103*7c478bd9Sstevel@tonic-gate const u_char *cp; 104*7c478bd9Sstevel@tonic-gate char *dn, *eom; 105*7c478bd9Sstevel@tonic-gate u_char c; 106*7c478bd9Sstevel@tonic-gate u_int n; 107*7c478bd9Sstevel@tonic-gate int l; 108*7c478bd9Sstevel@tonic-gate 109*7c478bd9Sstevel@tonic-gate cp = src; 110*7c478bd9Sstevel@tonic-gate dn = dst; 111*7c478bd9Sstevel@tonic-gate eom = dst + dstsiz; 112*7c478bd9Sstevel@tonic-gate 113*7c478bd9Sstevel@tonic-gate while ((n = *cp++) != 0) { 114*7c478bd9Sstevel@tonic-gate if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { 115*7c478bd9Sstevel@tonic-gate /* Some kind of compression pointer. */ 116*7c478bd9Sstevel@tonic-gate errno = EMSGSIZE; 117*7c478bd9Sstevel@tonic-gate return (-1); 118*7c478bd9Sstevel@tonic-gate } 119*7c478bd9Sstevel@tonic-gate if (dn != dst) { 120*7c478bd9Sstevel@tonic-gate if (dn >= eom) { 121*7c478bd9Sstevel@tonic-gate errno = EMSGSIZE; 122*7c478bd9Sstevel@tonic-gate return (-1); 123*7c478bd9Sstevel@tonic-gate } 124*7c478bd9Sstevel@tonic-gate *dn++ = '.'; 125*7c478bd9Sstevel@tonic-gate } 126*7c478bd9Sstevel@tonic-gate if ((l = labellen(cp - 1)) < 0) { 127*7c478bd9Sstevel@tonic-gate errno = EMSGSIZE; /* XXX */ 128*7c478bd9Sstevel@tonic-gate return(-1); 129*7c478bd9Sstevel@tonic-gate } 130*7c478bd9Sstevel@tonic-gate if (dn + l >= eom) { 131*7c478bd9Sstevel@tonic-gate errno = EMSGSIZE; 132*7c478bd9Sstevel@tonic-gate return (-1); 133*7c478bd9Sstevel@tonic-gate } 134*7c478bd9Sstevel@tonic-gate if ((n & NS_CMPRSFLGS) == NS_TYPE_ELT) { 135*7c478bd9Sstevel@tonic-gate int m; 136*7c478bd9Sstevel@tonic-gate 137*7c478bd9Sstevel@tonic-gate if (n != DNS_LABELTYPE_BITSTRING) { 138*7c478bd9Sstevel@tonic-gate /* XXX: labellen should reject this case */ 139*7c478bd9Sstevel@tonic-gate errno = EINVAL; 140*7c478bd9Sstevel@tonic-gate return(-1); 141*7c478bd9Sstevel@tonic-gate } 142*7c478bd9Sstevel@tonic-gate if ((m = decode_bitstring((const char **)&cp, dn, eom)) < 0) 143*7c478bd9Sstevel@tonic-gate { 144*7c478bd9Sstevel@tonic-gate errno = EMSGSIZE; 145*7c478bd9Sstevel@tonic-gate return(-1); 146*7c478bd9Sstevel@tonic-gate } 147*7c478bd9Sstevel@tonic-gate dn += m; 148*7c478bd9Sstevel@tonic-gate continue; 149*7c478bd9Sstevel@tonic-gate } 150*7c478bd9Sstevel@tonic-gate for ((void)NULL; l > 0; l--) { 151*7c478bd9Sstevel@tonic-gate c = *cp++; 152*7c478bd9Sstevel@tonic-gate if (special(c)) { 153*7c478bd9Sstevel@tonic-gate if (dn + 1 >= eom) { 154*7c478bd9Sstevel@tonic-gate errno = EMSGSIZE; 155*7c478bd9Sstevel@tonic-gate return (-1); 156*7c478bd9Sstevel@tonic-gate } 157*7c478bd9Sstevel@tonic-gate *dn++ = '\\'; 158*7c478bd9Sstevel@tonic-gate *dn++ = (char)c; 159*7c478bd9Sstevel@tonic-gate } else if (!printable(c)) { 160*7c478bd9Sstevel@tonic-gate if (dn + 3 >= eom) { 161*7c478bd9Sstevel@tonic-gate errno = EMSGSIZE; 162*7c478bd9Sstevel@tonic-gate return (-1); 163*7c478bd9Sstevel@tonic-gate } 164*7c478bd9Sstevel@tonic-gate *dn++ = '\\'; 165*7c478bd9Sstevel@tonic-gate *dn++ = digits[c / 100]; 166*7c478bd9Sstevel@tonic-gate *dn++ = digits[(c % 100) / 10]; 167*7c478bd9Sstevel@tonic-gate *dn++ = digits[c % 10]; 168*7c478bd9Sstevel@tonic-gate } else { 169*7c478bd9Sstevel@tonic-gate if (dn >= eom) { 170*7c478bd9Sstevel@tonic-gate errno = EMSGSIZE; 171*7c478bd9Sstevel@tonic-gate return (-1); 172*7c478bd9Sstevel@tonic-gate } 173*7c478bd9Sstevel@tonic-gate *dn++ = (char)c; 174*7c478bd9Sstevel@tonic-gate } 175*7c478bd9Sstevel@tonic-gate } 176*7c478bd9Sstevel@tonic-gate } 177*7c478bd9Sstevel@tonic-gate if (dn == dst) { 178*7c478bd9Sstevel@tonic-gate if (dn >= eom) { 179*7c478bd9Sstevel@tonic-gate errno = EMSGSIZE; 180*7c478bd9Sstevel@tonic-gate return (-1); 181*7c478bd9Sstevel@tonic-gate } 182*7c478bd9Sstevel@tonic-gate *dn++ = '.'; 183*7c478bd9Sstevel@tonic-gate } 184*7c478bd9Sstevel@tonic-gate if (dn >= eom) { 185*7c478bd9Sstevel@tonic-gate errno = EMSGSIZE; 186*7c478bd9Sstevel@tonic-gate return (-1); 187*7c478bd9Sstevel@tonic-gate } 188*7c478bd9Sstevel@tonic-gate *dn++ = '\0'; 189*7c478bd9Sstevel@tonic-gate return (dn - dst); 190*7c478bd9Sstevel@tonic-gate } 191*7c478bd9Sstevel@tonic-gate 192*7c478bd9Sstevel@tonic-gate /* 193*7c478bd9Sstevel@tonic-gate * ns_name_pton(src, dst, dstsiz) 194*7c478bd9Sstevel@tonic-gate * Convert a ascii string into an encoded domain name as per RFC1035. 195*7c478bd9Sstevel@tonic-gate * return: 196*7c478bd9Sstevel@tonic-gate * -1 if it fails 197*7c478bd9Sstevel@tonic-gate * 1 if string was fully qualified 198*7c478bd9Sstevel@tonic-gate * 0 is string was not fully qualified 199*7c478bd9Sstevel@tonic-gate * notes: 200*7c478bd9Sstevel@tonic-gate * Enforces label and domain length limits. 201*7c478bd9Sstevel@tonic-gate */ 202*7c478bd9Sstevel@tonic-gate 203*7c478bd9Sstevel@tonic-gate int 204*7c478bd9Sstevel@tonic-gate ns_name_pton(const char *src, u_char *dst, size_t dstsiz) 205*7c478bd9Sstevel@tonic-gate { 206*7c478bd9Sstevel@tonic-gate u_char *label, *bp, *eom; 207*7c478bd9Sstevel@tonic-gate int c, n, escaped, e = 0; 208*7c478bd9Sstevel@tonic-gate char *cp; 209*7c478bd9Sstevel@tonic-gate 210*7c478bd9Sstevel@tonic-gate escaped = 0; 211*7c478bd9Sstevel@tonic-gate bp = dst; 212*7c478bd9Sstevel@tonic-gate eom = dst + dstsiz; 213*7c478bd9Sstevel@tonic-gate label = bp++; 214*7c478bd9Sstevel@tonic-gate 215*7c478bd9Sstevel@tonic-gate while ((c = *src++) != 0) { 216*7c478bd9Sstevel@tonic-gate if (escaped) { 217*7c478bd9Sstevel@tonic-gate if (c == '[') { /* start a bit string label */ 218*7c478bd9Sstevel@tonic-gate if ((cp = strchr(src, ']')) == NULL) { 219*7c478bd9Sstevel@tonic-gate errno = EINVAL; /* ??? */ 220*7c478bd9Sstevel@tonic-gate return(-1); 221*7c478bd9Sstevel@tonic-gate } 222*7c478bd9Sstevel@tonic-gate if ((e = encode_bitsring(&src, 223*7c478bd9Sstevel@tonic-gate cp + 2, 224*7c478bd9Sstevel@tonic-gate (char **)&label, 225*7c478bd9Sstevel@tonic-gate (char **)&bp, 226*7c478bd9Sstevel@tonic-gate (const char *)eom)) 227*7c478bd9Sstevel@tonic-gate != 0) { 228*7c478bd9Sstevel@tonic-gate errno = e; 229*7c478bd9Sstevel@tonic-gate return(-1); 230*7c478bd9Sstevel@tonic-gate } 231*7c478bd9Sstevel@tonic-gate escaped = 0; 232*7c478bd9Sstevel@tonic-gate label = bp++; 233*7c478bd9Sstevel@tonic-gate if ((c = *src++) == 0) 234*7c478bd9Sstevel@tonic-gate goto done; 235*7c478bd9Sstevel@tonic-gate else if (c != '.') { 236*7c478bd9Sstevel@tonic-gate errno = EINVAL; 237*7c478bd9Sstevel@tonic-gate return(-1); 238*7c478bd9Sstevel@tonic-gate } 239*7c478bd9Sstevel@tonic-gate continue; 240*7c478bd9Sstevel@tonic-gate } 241*7c478bd9Sstevel@tonic-gate else if ((cp = strchr(digits, c)) != NULL) { 242*7c478bd9Sstevel@tonic-gate n = (cp - digits) * 100; 243*7c478bd9Sstevel@tonic-gate if ((c = *src++) == 0 || 244*7c478bd9Sstevel@tonic-gate (cp = strchr(digits, c)) == NULL) { 245*7c478bd9Sstevel@tonic-gate errno = EMSGSIZE; 246*7c478bd9Sstevel@tonic-gate return (-1); 247*7c478bd9Sstevel@tonic-gate } 248*7c478bd9Sstevel@tonic-gate n += (cp - digits) * 10; 249*7c478bd9Sstevel@tonic-gate if ((c = *src++) == 0 || 250*7c478bd9Sstevel@tonic-gate (cp = strchr(digits, c)) == NULL) { 251*7c478bd9Sstevel@tonic-gate errno = EMSGSIZE; 252*7c478bd9Sstevel@tonic-gate return (-1); 253*7c478bd9Sstevel@tonic-gate } 254*7c478bd9Sstevel@tonic-gate n += (cp - digits); 255*7c478bd9Sstevel@tonic-gate if (n > 255) { 256*7c478bd9Sstevel@tonic-gate errno = EMSGSIZE; 257*7c478bd9Sstevel@tonic-gate return (-1); 258*7c478bd9Sstevel@tonic-gate } 259*7c478bd9Sstevel@tonic-gate c = n; 260*7c478bd9Sstevel@tonic-gate } 261*7c478bd9Sstevel@tonic-gate escaped = 0; 262*7c478bd9Sstevel@tonic-gate } else if (c == '\\') { 263*7c478bd9Sstevel@tonic-gate escaped = 1; 264*7c478bd9Sstevel@tonic-gate continue; 265*7c478bd9Sstevel@tonic-gate } else if (c == '.') { 266*7c478bd9Sstevel@tonic-gate c = (bp - label - 1); 267*7c478bd9Sstevel@tonic-gate if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */ 268*7c478bd9Sstevel@tonic-gate errno = EMSGSIZE; 269*7c478bd9Sstevel@tonic-gate return (-1); 270*7c478bd9Sstevel@tonic-gate } 271*7c478bd9Sstevel@tonic-gate if (label >= eom) { 272*7c478bd9Sstevel@tonic-gate errno = EMSGSIZE; 273*7c478bd9Sstevel@tonic-gate return (-1); 274*7c478bd9Sstevel@tonic-gate } 275*7c478bd9Sstevel@tonic-gate *label = c; 276*7c478bd9Sstevel@tonic-gate /* Fully qualified ? */ 277*7c478bd9Sstevel@tonic-gate if (*src == '\0') { 278*7c478bd9Sstevel@tonic-gate if (c != 0) { 279*7c478bd9Sstevel@tonic-gate if (bp >= eom) { 280*7c478bd9Sstevel@tonic-gate errno = EMSGSIZE; 281*7c478bd9Sstevel@tonic-gate return (-1); 282*7c478bd9Sstevel@tonic-gate } 283*7c478bd9Sstevel@tonic-gate *bp++ = '\0'; 284*7c478bd9Sstevel@tonic-gate } 285*7c478bd9Sstevel@tonic-gate if ((bp - dst) > MAXCDNAME) { 286*7c478bd9Sstevel@tonic-gate errno = EMSGSIZE; 287*7c478bd9Sstevel@tonic-gate return (-1); 288*7c478bd9Sstevel@tonic-gate } 289*7c478bd9Sstevel@tonic-gate return (1); 290*7c478bd9Sstevel@tonic-gate } 291*7c478bd9Sstevel@tonic-gate if (c == 0 || *src == '.') { 292*7c478bd9Sstevel@tonic-gate errno = EMSGSIZE; 293*7c478bd9Sstevel@tonic-gate return (-1); 294*7c478bd9Sstevel@tonic-gate } 295*7c478bd9Sstevel@tonic-gate label = bp++; 296*7c478bd9Sstevel@tonic-gate continue; 297*7c478bd9Sstevel@tonic-gate } 298*7c478bd9Sstevel@tonic-gate if (bp >= eom) { 299*7c478bd9Sstevel@tonic-gate errno = EMSGSIZE; 300*7c478bd9Sstevel@tonic-gate return (-1); 301*7c478bd9Sstevel@tonic-gate } 302*7c478bd9Sstevel@tonic-gate *bp++ = (u_char)c; 303*7c478bd9Sstevel@tonic-gate } 304*7c478bd9Sstevel@tonic-gate c = (bp - label - 1); 305*7c478bd9Sstevel@tonic-gate if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */ 306*7c478bd9Sstevel@tonic-gate errno = EMSGSIZE; 307*7c478bd9Sstevel@tonic-gate return (-1); 308*7c478bd9Sstevel@tonic-gate } 309*7c478bd9Sstevel@tonic-gate done: 310*7c478bd9Sstevel@tonic-gate if (label >= eom) { 311*7c478bd9Sstevel@tonic-gate errno = EMSGSIZE; 312*7c478bd9Sstevel@tonic-gate return (-1); 313*7c478bd9Sstevel@tonic-gate } 314*7c478bd9Sstevel@tonic-gate *label = c; 315*7c478bd9Sstevel@tonic-gate if (c != 0) { 316*7c478bd9Sstevel@tonic-gate if (bp >= eom) { 317*7c478bd9Sstevel@tonic-gate errno = EMSGSIZE; 318*7c478bd9Sstevel@tonic-gate return (-1); 319*7c478bd9Sstevel@tonic-gate } 320*7c478bd9Sstevel@tonic-gate *bp++ = 0; 321*7c478bd9Sstevel@tonic-gate } 322*7c478bd9Sstevel@tonic-gate if ((bp - dst) > MAXCDNAME) { /* src too big */ 323*7c478bd9Sstevel@tonic-gate errno = EMSGSIZE; 324*7c478bd9Sstevel@tonic-gate return (-1); 325*7c478bd9Sstevel@tonic-gate } 326*7c478bd9Sstevel@tonic-gate return (0); 327*7c478bd9Sstevel@tonic-gate } 328*7c478bd9Sstevel@tonic-gate 329*7c478bd9Sstevel@tonic-gate /* 330*7c478bd9Sstevel@tonic-gate * ns_name_ntol(src, dst, dstsiz) 331*7c478bd9Sstevel@tonic-gate * Convert a network strings labels into all lowercase. 332*7c478bd9Sstevel@tonic-gate * return: 333*7c478bd9Sstevel@tonic-gate * Number of bytes written to buffer, or -1 (with errno set) 334*7c478bd9Sstevel@tonic-gate * notes: 335*7c478bd9Sstevel@tonic-gate * Enforces label and domain length limits. 336*7c478bd9Sstevel@tonic-gate */ 337*7c478bd9Sstevel@tonic-gate 338*7c478bd9Sstevel@tonic-gate int 339*7c478bd9Sstevel@tonic-gate ns_name_ntol(const u_char *src, u_char *dst, size_t dstsiz) 340*7c478bd9Sstevel@tonic-gate { 341*7c478bd9Sstevel@tonic-gate const u_char *cp; 342*7c478bd9Sstevel@tonic-gate u_char *dn, *eom; 343*7c478bd9Sstevel@tonic-gate u_char c; 344*7c478bd9Sstevel@tonic-gate u_int n; 345*7c478bd9Sstevel@tonic-gate int l; 346*7c478bd9Sstevel@tonic-gate 347*7c478bd9Sstevel@tonic-gate cp = src; 348*7c478bd9Sstevel@tonic-gate dn = dst; 349*7c478bd9Sstevel@tonic-gate eom = dst + dstsiz; 350*7c478bd9Sstevel@tonic-gate 351*7c478bd9Sstevel@tonic-gate if (dn >= eom) { 352*7c478bd9Sstevel@tonic-gate errno = EMSGSIZE; 353*7c478bd9Sstevel@tonic-gate return (-1); 354*7c478bd9Sstevel@tonic-gate } 355*7c478bd9Sstevel@tonic-gate while ((n = *cp++) != 0) { 356*7c478bd9Sstevel@tonic-gate if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { 357*7c478bd9Sstevel@tonic-gate /* Some kind of compression pointer. */ 358*7c478bd9Sstevel@tonic-gate errno = EMSGSIZE; 359*7c478bd9Sstevel@tonic-gate return (-1); 360*7c478bd9Sstevel@tonic-gate } 361*7c478bd9Sstevel@tonic-gate *dn++ = n; 362*7c478bd9Sstevel@tonic-gate if ((l = labellen(cp - 1)) < 0) { 363*7c478bd9Sstevel@tonic-gate errno = EMSGSIZE; 364*7c478bd9Sstevel@tonic-gate return (-1); 365*7c478bd9Sstevel@tonic-gate } 366*7c478bd9Sstevel@tonic-gate if (dn + l >= eom) { 367*7c478bd9Sstevel@tonic-gate errno = EMSGSIZE; 368*7c478bd9Sstevel@tonic-gate return (-1); 369*7c478bd9Sstevel@tonic-gate } 370*7c478bd9Sstevel@tonic-gate for ((void)NULL; l > 0; l--) { 371*7c478bd9Sstevel@tonic-gate c = *cp++; 372*7c478bd9Sstevel@tonic-gate if (isupper(c)) 373*7c478bd9Sstevel@tonic-gate *dn++ = tolower(c); 374*7c478bd9Sstevel@tonic-gate else 375*7c478bd9Sstevel@tonic-gate *dn++ = c; 376*7c478bd9Sstevel@tonic-gate } 377*7c478bd9Sstevel@tonic-gate } 378*7c478bd9Sstevel@tonic-gate *dn++ = '\0'; 379*7c478bd9Sstevel@tonic-gate return (dn - dst); 380*7c478bd9Sstevel@tonic-gate } 381*7c478bd9Sstevel@tonic-gate 382*7c478bd9Sstevel@tonic-gate /* 383*7c478bd9Sstevel@tonic-gate * ns_name_unpack(msg, eom, src, dst, dstsiz) 384*7c478bd9Sstevel@tonic-gate * Unpack a domain name from a message, source may be compressed. 385*7c478bd9Sstevel@tonic-gate * return: 386*7c478bd9Sstevel@tonic-gate * -1 if it fails, or consumed octets if it succeeds. 387*7c478bd9Sstevel@tonic-gate */ 388*7c478bd9Sstevel@tonic-gate int 389*7c478bd9Sstevel@tonic-gate ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src, 390*7c478bd9Sstevel@tonic-gate u_char *dst, size_t dstsiz) 391*7c478bd9Sstevel@tonic-gate { 392*7c478bd9Sstevel@tonic-gate const u_char *srcp, *dstlim; 393*7c478bd9Sstevel@tonic-gate u_char *dstp; 394*7c478bd9Sstevel@tonic-gate int n, len, checked, l; 395*7c478bd9Sstevel@tonic-gate 396*7c478bd9Sstevel@tonic-gate len = -1; 397*7c478bd9Sstevel@tonic-gate checked = 0; 398*7c478bd9Sstevel@tonic-gate dstp = dst; 399*7c478bd9Sstevel@tonic-gate srcp = src; 400*7c478bd9Sstevel@tonic-gate dstlim = dst + dstsiz; 401*7c478bd9Sstevel@tonic-gate if (srcp < msg || srcp >= eom) { 402*7c478bd9Sstevel@tonic-gate errno = EMSGSIZE; 403*7c478bd9Sstevel@tonic-gate return (-1); 404*7c478bd9Sstevel@tonic-gate } 405*7c478bd9Sstevel@tonic-gate /* Fetch next label in domain name. */ 406*7c478bd9Sstevel@tonic-gate while ((n = *srcp++) != 0) { 407*7c478bd9Sstevel@tonic-gate /* Check for indirection. */ 408*7c478bd9Sstevel@tonic-gate switch (n & NS_CMPRSFLGS) { 409*7c478bd9Sstevel@tonic-gate case 0: 410*7c478bd9Sstevel@tonic-gate case NS_TYPE_ELT: 411*7c478bd9Sstevel@tonic-gate /* Limit checks. */ 412*7c478bd9Sstevel@tonic-gate if ((l = labellen(srcp - 1)) < 0) { 413*7c478bd9Sstevel@tonic-gate errno = EMSGSIZE; 414*7c478bd9Sstevel@tonic-gate return(-1); 415*7c478bd9Sstevel@tonic-gate } 416*7c478bd9Sstevel@tonic-gate if (dstp + l + 1 >= dstlim || srcp + l >= eom) { 417*7c478bd9Sstevel@tonic-gate errno = EMSGSIZE; 418*7c478bd9Sstevel@tonic-gate return (-1); 419*7c478bd9Sstevel@tonic-gate } 420*7c478bd9Sstevel@tonic-gate checked += l + 1; 421*7c478bd9Sstevel@tonic-gate *dstp++ = n; 422*7c478bd9Sstevel@tonic-gate memcpy(dstp, srcp, l); 423*7c478bd9Sstevel@tonic-gate dstp += l; 424*7c478bd9Sstevel@tonic-gate srcp += l; 425*7c478bd9Sstevel@tonic-gate break; 426*7c478bd9Sstevel@tonic-gate 427*7c478bd9Sstevel@tonic-gate case NS_CMPRSFLGS: 428*7c478bd9Sstevel@tonic-gate if (srcp >= eom) { 429*7c478bd9Sstevel@tonic-gate errno = EMSGSIZE; 430*7c478bd9Sstevel@tonic-gate return (-1); 431*7c478bd9Sstevel@tonic-gate } 432*7c478bd9Sstevel@tonic-gate if (len < 0) 433*7c478bd9Sstevel@tonic-gate len = srcp - src + 1; 434*7c478bd9Sstevel@tonic-gate srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff)); 435*7c478bd9Sstevel@tonic-gate if (srcp < msg || srcp >= eom) { /* Out of range. */ 436*7c478bd9Sstevel@tonic-gate errno = EMSGSIZE; 437*7c478bd9Sstevel@tonic-gate return (-1); 438*7c478bd9Sstevel@tonic-gate } 439*7c478bd9Sstevel@tonic-gate checked += 2; 440*7c478bd9Sstevel@tonic-gate /* 441*7c478bd9Sstevel@tonic-gate * Check for loops in the compressed name; 442*7c478bd9Sstevel@tonic-gate * if we've looked at the whole message, 443*7c478bd9Sstevel@tonic-gate * there must be a loop. 444*7c478bd9Sstevel@tonic-gate */ 445*7c478bd9Sstevel@tonic-gate if (checked >= eom - msg) { 446*7c478bd9Sstevel@tonic-gate errno = EMSGSIZE; 447*7c478bd9Sstevel@tonic-gate return (-1); 448*7c478bd9Sstevel@tonic-gate } 449*7c478bd9Sstevel@tonic-gate break; 450*7c478bd9Sstevel@tonic-gate 451*7c478bd9Sstevel@tonic-gate default: 452*7c478bd9Sstevel@tonic-gate errno = EMSGSIZE; 453*7c478bd9Sstevel@tonic-gate return (-1); /* flag error */ 454*7c478bd9Sstevel@tonic-gate } 455*7c478bd9Sstevel@tonic-gate } 456*7c478bd9Sstevel@tonic-gate *dstp = '\0'; 457*7c478bd9Sstevel@tonic-gate if (len < 0) 458*7c478bd9Sstevel@tonic-gate len = srcp - src; 459*7c478bd9Sstevel@tonic-gate return (len); 460*7c478bd9Sstevel@tonic-gate } 461*7c478bd9Sstevel@tonic-gate 462*7c478bd9Sstevel@tonic-gate /* 463*7c478bd9Sstevel@tonic-gate * ns_name_pack(src, dst, dstsiz, dnptrs, lastdnptr) 464*7c478bd9Sstevel@tonic-gate * Pack domain name 'domain' into 'comp_dn'. 465*7c478bd9Sstevel@tonic-gate * return: 466*7c478bd9Sstevel@tonic-gate * Size of the compressed name, or -1. 467*7c478bd9Sstevel@tonic-gate * notes: 468*7c478bd9Sstevel@tonic-gate * 'dnptrs' is an array of pointers to previous compressed names. 469*7c478bd9Sstevel@tonic-gate * dnptrs[0] is a pointer to the beginning of the message. The array 470*7c478bd9Sstevel@tonic-gate * ends with NULL. 471*7c478bd9Sstevel@tonic-gate * 'lastdnptr' is a pointer to the end of the array pointed to 472*7c478bd9Sstevel@tonic-gate * by 'dnptrs'. 473*7c478bd9Sstevel@tonic-gate * Side effects: 474*7c478bd9Sstevel@tonic-gate * The list of pointers in dnptrs is updated for labels inserted into 475*7c478bd9Sstevel@tonic-gate * the message as we compress the name. If 'dnptr' is NULL, we don't 476*7c478bd9Sstevel@tonic-gate * try to compress names. If 'lastdnptr' is NULL, we don't update the 477*7c478bd9Sstevel@tonic-gate * list. 478*7c478bd9Sstevel@tonic-gate */ 479*7c478bd9Sstevel@tonic-gate int 480*7c478bd9Sstevel@tonic-gate ns_name_pack(const u_char *src, u_char *dst, int dstsiz, 481*7c478bd9Sstevel@tonic-gate const u_char **dnptrs, const u_char **lastdnptr) 482*7c478bd9Sstevel@tonic-gate { 483*7c478bd9Sstevel@tonic-gate u_char *dstp; 484*7c478bd9Sstevel@tonic-gate const u_char **cpp, **lpp, *eob, *msg; 485*7c478bd9Sstevel@tonic-gate const u_char *srcp; 486*7c478bd9Sstevel@tonic-gate int n, l, first = 1; 487*7c478bd9Sstevel@tonic-gate 488*7c478bd9Sstevel@tonic-gate srcp = src; 489*7c478bd9Sstevel@tonic-gate dstp = dst; 490*7c478bd9Sstevel@tonic-gate eob = dstp + dstsiz; 491*7c478bd9Sstevel@tonic-gate lpp = cpp = NULL; 492*7c478bd9Sstevel@tonic-gate if (dnptrs != NULL) { 493*7c478bd9Sstevel@tonic-gate if ((msg = *dnptrs++) != NULL) { 494*7c478bd9Sstevel@tonic-gate for (cpp = dnptrs; *cpp != NULL; cpp++) 495*7c478bd9Sstevel@tonic-gate (void)NULL; 496*7c478bd9Sstevel@tonic-gate lpp = cpp; /* end of list to search */ 497*7c478bd9Sstevel@tonic-gate } 498*7c478bd9Sstevel@tonic-gate } else 499*7c478bd9Sstevel@tonic-gate msg = NULL; 500*7c478bd9Sstevel@tonic-gate 501*7c478bd9Sstevel@tonic-gate /* make sure the domain we are about to add is legal */ 502*7c478bd9Sstevel@tonic-gate l = 0; 503*7c478bd9Sstevel@tonic-gate do { 504*7c478bd9Sstevel@tonic-gate int l0; 505*7c478bd9Sstevel@tonic-gate 506*7c478bd9Sstevel@tonic-gate n = *srcp; 507*7c478bd9Sstevel@tonic-gate if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { 508*7c478bd9Sstevel@tonic-gate errno = EMSGSIZE; 509*7c478bd9Sstevel@tonic-gate return (-1); 510*7c478bd9Sstevel@tonic-gate } 511*7c478bd9Sstevel@tonic-gate if ((l0 = labellen(srcp)) < 0) { 512*7c478bd9Sstevel@tonic-gate errno = EINVAL; 513*7c478bd9Sstevel@tonic-gate return(-1); 514*7c478bd9Sstevel@tonic-gate } 515*7c478bd9Sstevel@tonic-gate l += l0 + 1; 516*7c478bd9Sstevel@tonic-gate if (l > MAXCDNAME) { 517*7c478bd9Sstevel@tonic-gate errno = EMSGSIZE; 518*7c478bd9Sstevel@tonic-gate return (-1); 519*7c478bd9Sstevel@tonic-gate } 520*7c478bd9Sstevel@tonic-gate srcp += l0 + 1; 521*7c478bd9Sstevel@tonic-gate } while (n != 0); 522*7c478bd9Sstevel@tonic-gate 523*7c478bd9Sstevel@tonic-gate /* from here on we need to reset compression pointer array on error */ 524*7c478bd9Sstevel@tonic-gate srcp = src; 525*7c478bd9Sstevel@tonic-gate do { 526*7c478bd9Sstevel@tonic-gate /* Look to see if we can use pointers. */ 527*7c478bd9Sstevel@tonic-gate n = *srcp; 528*7c478bd9Sstevel@tonic-gate if (n != 0 && msg != NULL) { 529*7c478bd9Sstevel@tonic-gate l = dn_find(srcp, msg, (const u_char * const *)dnptrs, 530*7c478bd9Sstevel@tonic-gate (const u_char * const *)lpp); 531*7c478bd9Sstevel@tonic-gate if (l >= 0) { 532*7c478bd9Sstevel@tonic-gate if (dstp + 1 >= eob) { 533*7c478bd9Sstevel@tonic-gate goto cleanup; 534*7c478bd9Sstevel@tonic-gate } 535*7c478bd9Sstevel@tonic-gate *dstp++ = (l >> 8) | NS_CMPRSFLGS; 536*7c478bd9Sstevel@tonic-gate *dstp++ = l % 256; 537*7c478bd9Sstevel@tonic-gate return (dstp - dst); 538*7c478bd9Sstevel@tonic-gate } 539*7c478bd9Sstevel@tonic-gate /* Not found, save it. */ 540*7c478bd9Sstevel@tonic-gate if (lastdnptr != NULL && cpp < lastdnptr - 1 && 541*7c478bd9Sstevel@tonic-gate (dstp - msg) < 0x4000 && first) { 542*7c478bd9Sstevel@tonic-gate *cpp++ = dstp; 543*7c478bd9Sstevel@tonic-gate *cpp = NULL; 544*7c478bd9Sstevel@tonic-gate first = 0; 545*7c478bd9Sstevel@tonic-gate } 546*7c478bd9Sstevel@tonic-gate } 547*7c478bd9Sstevel@tonic-gate /* copy label to buffer */ 548*7c478bd9Sstevel@tonic-gate if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { 549*7c478bd9Sstevel@tonic-gate /* Should not happen. */ 550*7c478bd9Sstevel@tonic-gate goto cleanup; 551*7c478bd9Sstevel@tonic-gate } 552*7c478bd9Sstevel@tonic-gate n = labellen(srcp); 553*7c478bd9Sstevel@tonic-gate if (dstp + 1 + n >= eob) { 554*7c478bd9Sstevel@tonic-gate goto cleanup; 555*7c478bd9Sstevel@tonic-gate } 556*7c478bd9Sstevel@tonic-gate memcpy(dstp, srcp, n + 1); 557*7c478bd9Sstevel@tonic-gate srcp += n + 1; 558*7c478bd9Sstevel@tonic-gate dstp += n + 1; 559*7c478bd9Sstevel@tonic-gate } while (n != 0); 560*7c478bd9Sstevel@tonic-gate 561*7c478bd9Sstevel@tonic-gate if (dstp > eob) { 562*7c478bd9Sstevel@tonic-gate cleanup: 563*7c478bd9Sstevel@tonic-gate if (msg != NULL) 564*7c478bd9Sstevel@tonic-gate *lpp = NULL; 565*7c478bd9Sstevel@tonic-gate errno = EMSGSIZE; 566*7c478bd9Sstevel@tonic-gate return (-1); 567*7c478bd9Sstevel@tonic-gate } 568*7c478bd9Sstevel@tonic-gate return (dstp - dst); 569*7c478bd9Sstevel@tonic-gate } 570*7c478bd9Sstevel@tonic-gate 571*7c478bd9Sstevel@tonic-gate /* 572*7c478bd9Sstevel@tonic-gate * ns_name_uncompress(msg, eom, src, dst, dstsiz) 573*7c478bd9Sstevel@tonic-gate * Expand compressed domain name to presentation format. 574*7c478bd9Sstevel@tonic-gate * return: 575*7c478bd9Sstevel@tonic-gate * Number of bytes read out of `src', or -1 (with errno set). 576*7c478bd9Sstevel@tonic-gate * note: 577*7c478bd9Sstevel@tonic-gate * Root domain returns as "." not "". 578*7c478bd9Sstevel@tonic-gate */ 579*7c478bd9Sstevel@tonic-gate int 580*7c478bd9Sstevel@tonic-gate ns_name_uncompress(const u_char *msg, const u_char *eom, const u_char *src, 581*7c478bd9Sstevel@tonic-gate char *dst, size_t dstsiz) 582*7c478bd9Sstevel@tonic-gate { 583*7c478bd9Sstevel@tonic-gate u_char tmp[NS_MAXCDNAME]; 584*7c478bd9Sstevel@tonic-gate int n; 585*7c478bd9Sstevel@tonic-gate 586*7c478bd9Sstevel@tonic-gate if ((n = ns_name_unpack(msg, eom, src, tmp, sizeof tmp)) == -1) 587*7c478bd9Sstevel@tonic-gate return (-1); 588*7c478bd9Sstevel@tonic-gate if (ns_name_ntop(tmp, dst, dstsiz) == -1) 589*7c478bd9Sstevel@tonic-gate return (-1); 590*7c478bd9Sstevel@tonic-gate return (n); 591*7c478bd9Sstevel@tonic-gate } 592*7c478bd9Sstevel@tonic-gate 593*7c478bd9Sstevel@tonic-gate /* 594*7c478bd9Sstevel@tonic-gate * ns_name_compress(src, dst, dstsiz, dnptrs, lastdnptr) 595*7c478bd9Sstevel@tonic-gate * Compress a domain name into wire format, using compression pointers. 596*7c478bd9Sstevel@tonic-gate * return: 597*7c478bd9Sstevel@tonic-gate * Number of bytes consumed in `dst' or -1 (with errno set). 598*7c478bd9Sstevel@tonic-gate * notes: 599*7c478bd9Sstevel@tonic-gate * 'dnptrs' is an array of pointers to previous compressed names. 600*7c478bd9Sstevel@tonic-gate * dnptrs[0] is a pointer to the beginning of the message. 601*7c478bd9Sstevel@tonic-gate * The list ends with NULL. 'lastdnptr' is a pointer to the end of the 602*7c478bd9Sstevel@tonic-gate * array pointed to by 'dnptrs'. Side effect is to update the list of 603*7c478bd9Sstevel@tonic-gate * pointers for labels inserted into the message as we compress the name. 604*7c478bd9Sstevel@tonic-gate * If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr' 605*7c478bd9Sstevel@tonic-gate * is NULL, we don't update the list. 606*7c478bd9Sstevel@tonic-gate */ 607*7c478bd9Sstevel@tonic-gate int 608*7c478bd9Sstevel@tonic-gate ns_name_compress(const char *src, u_char *dst, size_t dstsiz, 609*7c478bd9Sstevel@tonic-gate const u_char **dnptrs, const u_char **lastdnptr) 610*7c478bd9Sstevel@tonic-gate { 611*7c478bd9Sstevel@tonic-gate u_char tmp[NS_MAXCDNAME]; 612*7c478bd9Sstevel@tonic-gate 613*7c478bd9Sstevel@tonic-gate if (ns_name_pton(src, tmp, sizeof tmp) == -1) 614*7c478bd9Sstevel@tonic-gate return (-1); 615*7c478bd9Sstevel@tonic-gate return (ns_name_pack(tmp, dst, dstsiz, dnptrs, lastdnptr)); 616*7c478bd9Sstevel@tonic-gate } 617*7c478bd9Sstevel@tonic-gate 618*7c478bd9Sstevel@tonic-gate /* 619*7c478bd9Sstevel@tonic-gate * Reset dnptrs so that there are no active references to pointers at or 620*7c478bd9Sstevel@tonic-gate * after src. 621*7c478bd9Sstevel@tonic-gate */ 622*7c478bd9Sstevel@tonic-gate void 623*7c478bd9Sstevel@tonic-gate ns_name_rollback(const u_char *src, const u_char **dnptrs, 624*7c478bd9Sstevel@tonic-gate const u_char **lastdnptr) 625*7c478bd9Sstevel@tonic-gate { 626*7c478bd9Sstevel@tonic-gate while (dnptrs < lastdnptr && *dnptrs != NULL) { 627*7c478bd9Sstevel@tonic-gate if (*dnptrs >= src) { 628*7c478bd9Sstevel@tonic-gate *dnptrs = NULL; 629*7c478bd9Sstevel@tonic-gate break; 630*7c478bd9Sstevel@tonic-gate } 631*7c478bd9Sstevel@tonic-gate dnptrs++; 632*7c478bd9Sstevel@tonic-gate } 633*7c478bd9Sstevel@tonic-gate } 634*7c478bd9Sstevel@tonic-gate 635*7c478bd9Sstevel@tonic-gate /* 636*7c478bd9Sstevel@tonic-gate * ns_name_skip(ptrptr, eom) 637*7c478bd9Sstevel@tonic-gate * Advance *ptrptr to skip over the compressed name it points at. 638*7c478bd9Sstevel@tonic-gate * return: 639*7c478bd9Sstevel@tonic-gate * 0 on success, -1 (with errno set) on failure. 640*7c478bd9Sstevel@tonic-gate */ 641*7c478bd9Sstevel@tonic-gate int 642*7c478bd9Sstevel@tonic-gate ns_name_skip(const u_char **ptrptr, const u_char *eom) 643*7c478bd9Sstevel@tonic-gate { 644*7c478bd9Sstevel@tonic-gate const u_char *cp; 645*7c478bd9Sstevel@tonic-gate u_int n; 646*7c478bd9Sstevel@tonic-gate int l; 647*7c478bd9Sstevel@tonic-gate 648*7c478bd9Sstevel@tonic-gate cp = *ptrptr; 649*7c478bd9Sstevel@tonic-gate while (cp < eom && (n = *cp++) != 0) { 650*7c478bd9Sstevel@tonic-gate /* Check for indirection. */ 651*7c478bd9Sstevel@tonic-gate switch (n & NS_CMPRSFLGS) { 652*7c478bd9Sstevel@tonic-gate case 0: /* normal case, n == len */ 653*7c478bd9Sstevel@tonic-gate cp += n; 654*7c478bd9Sstevel@tonic-gate continue; 655*7c478bd9Sstevel@tonic-gate case NS_TYPE_ELT: /* EDNS0 extended label */ 656*7c478bd9Sstevel@tonic-gate if ((l = labellen(cp - 1)) < 0) { 657*7c478bd9Sstevel@tonic-gate errno = EMSGSIZE; /* XXX */ 658*7c478bd9Sstevel@tonic-gate return(-1); 659*7c478bd9Sstevel@tonic-gate } 660*7c478bd9Sstevel@tonic-gate cp += l; 661*7c478bd9Sstevel@tonic-gate continue; 662*7c478bd9Sstevel@tonic-gate case NS_CMPRSFLGS: /* indirection */ 663*7c478bd9Sstevel@tonic-gate cp++; 664*7c478bd9Sstevel@tonic-gate break; 665*7c478bd9Sstevel@tonic-gate default: /* illegal type */ 666*7c478bd9Sstevel@tonic-gate errno = EMSGSIZE; 667*7c478bd9Sstevel@tonic-gate return (-1); 668*7c478bd9Sstevel@tonic-gate } 669*7c478bd9Sstevel@tonic-gate break; 670*7c478bd9Sstevel@tonic-gate } 671*7c478bd9Sstevel@tonic-gate if (cp > eom) { 672*7c478bd9Sstevel@tonic-gate errno = EMSGSIZE; 673*7c478bd9Sstevel@tonic-gate return (-1); 674*7c478bd9Sstevel@tonic-gate } 675*7c478bd9Sstevel@tonic-gate *ptrptr = cp; 676*7c478bd9Sstevel@tonic-gate return (0); 677*7c478bd9Sstevel@tonic-gate } 678*7c478bd9Sstevel@tonic-gate 679*7c478bd9Sstevel@tonic-gate /* Private. */ 680*7c478bd9Sstevel@tonic-gate 681*7c478bd9Sstevel@tonic-gate /* 682*7c478bd9Sstevel@tonic-gate * special(ch) 683*7c478bd9Sstevel@tonic-gate * Thinking in noninternationalized USASCII (per the DNS spec), 684*7c478bd9Sstevel@tonic-gate * is this characted special ("in need of quoting") ? 685*7c478bd9Sstevel@tonic-gate * return: 686*7c478bd9Sstevel@tonic-gate * boolean. 687*7c478bd9Sstevel@tonic-gate */ 688*7c478bd9Sstevel@tonic-gate static int 689*7c478bd9Sstevel@tonic-gate special(int ch) { 690*7c478bd9Sstevel@tonic-gate switch (ch) { 691*7c478bd9Sstevel@tonic-gate case 0x22: /* '"' */ 692*7c478bd9Sstevel@tonic-gate case 0x2E: /* '.' */ 693*7c478bd9Sstevel@tonic-gate case 0x3B: /* ';' */ 694*7c478bd9Sstevel@tonic-gate case 0x5C: /* '\\' */ 695*7c478bd9Sstevel@tonic-gate case 0x28: /* '(' */ 696*7c478bd9Sstevel@tonic-gate case 0x29: /* ')' */ 697*7c478bd9Sstevel@tonic-gate /* Special modifiers in zone files. */ 698*7c478bd9Sstevel@tonic-gate case 0x40: /* '@' */ 699*7c478bd9Sstevel@tonic-gate case 0x24: /* '$' */ 700*7c478bd9Sstevel@tonic-gate return (1); 701*7c478bd9Sstevel@tonic-gate default: 702*7c478bd9Sstevel@tonic-gate return (0); 703*7c478bd9Sstevel@tonic-gate } 704*7c478bd9Sstevel@tonic-gate } 705*7c478bd9Sstevel@tonic-gate 706*7c478bd9Sstevel@tonic-gate /* 707*7c478bd9Sstevel@tonic-gate * printable(ch) 708*7c478bd9Sstevel@tonic-gate * Thinking in noninternationalized USASCII (per the DNS spec), 709*7c478bd9Sstevel@tonic-gate * is this character visible and not a space when printed ? 710*7c478bd9Sstevel@tonic-gate * return: 711*7c478bd9Sstevel@tonic-gate * boolean. 712*7c478bd9Sstevel@tonic-gate */ 713*7c478bd9Sstevel@tonic-gate static int 714*7c478bd9Sstevel@tonic-gate printable(int ch) { 715*7c478bd9Sstevel@tonic-gate return (ch > 0x20 && ch < 0x7f); 716*7c478bd9Sstevel@tonic-gate } 717*7c478bd9Sstevel@tonic-gate 718*7c478bd9Sstevel@tonic-gate /* 719*7c478bd9Sstevel@tonic-gate * Thinking in noninternationalized USASCII (per the DNS spec), 720*7c478bd9Sstevel@tonic-gate * convert this character to lower case if it's upper case. 721*7c478bd9Sstevel@tonic-gate */ 722*7c478bd9Sstevel@tonic-gate static int 723*7c478bd9Sstevel@tonic-gate mklower(int ch) { 724*7c478bd9Sstevel@tonic-gate if (ch >= 0x41 && ch <= 0x5A) 725*7c478bd9Sstevel@tonic-gate return (ch + 0x20); 726*7c478bd9Sstevel@tonic-gate return (ch); 727*7c478bd9Sstevel@tonic-gate } 728*7c478bd9Sstevel@tonic-gate 729*7c478bd9Sstevel@tonic-gate /* 730*7c478bd9Sstevel@tonic-gate * dn_find(domain, msg, dnptrs, lastdnptr) 731*7c478bd9Sstevel@tonic-gate * Search for the counted-label name in an array of compressed names. 732*7c478bd9Sstevel@tonic-gate * return: 733*7c478bd9Sstevel@tonic-gate * offset from msg if found, or -1. 734*7c478bd9Sstevel@tonic-gate * notes: 735*7c478bd9Sstevel@tonic-gate * dnptrs is the pointer to the first name on the list, 736*7c478bd9Sstevel@tonic-gate * not the pointer to the start of the message. 737*7c478bd9Sstevel@tonic-gate */ 738*7c478bd9Sstevel@tonic-gate static int 739*7c478bd9Sstevel@tonic-gate dn_find(const u_char *domain, const u_char *msg, 740*7c478bd9Sstevel@tonic-gate const u_char * const *dnptrs, 741*7c478bd9Sstevel@tonic-gate const u_char * const *lastdnptr) 742*7c478bd9Sstevel@tonic-gate { 743*7c478bd9Sstevel@tonic-gate const u_char *dn, *cp, *sp; 744*7c478bd9Sstevel@tonic-gate const u_char * const *cpp; 745*7c478bd9Sstevel@tonic-gate u_int n; 746*7c478bd9Sstevel@tonic-gate 747*7c478bd9Sstevel@tonic-gate for (cpp = dnptrs; cpp < lastdnptr; cpp++) { 748*7c478bd9Sstevel@tonic-gate sp = *cpp; 749*7c478bd9Sstevel@tonic-gate /* 750*7c478bd9Sstevel@tonic-gate * terminate search on: 751*7c478bd9Sstevel@tonic-gate * root label 752*7c478bd9Sstevel@tonic-gate * compression pointer 753*7c478bd9Sstevel@tonic-gate * unusable offset 754*7c478bd9Sstevel@tonic-gate */ 755*7c478bd9Sstevel@tonic-gate while (*sp != 0 && (*sp & NS_CMPRSFLGS) == 0 && 756*7c478bd9Sstevel@tonic-gate (sp - msg) < 0x4000) { 757*7c478bd9Sstevel@tonic-gate dn = domain; 758*7c478bd9Sstevel@tonic-gate cp = sp; 759*7c478bd9Sstevel@tonic-gate while ((n = *cp++) != 0) { 760*7c478bd9Sstevel@tonic-gate /* 761*7c478bd9Sstevel@tonic-gate * check for indirection 762*7c478bd9Sstevel@tonic-gate */ 763*7c478bd9Sstevel@tonic-gate switch (n & NS_CMPRSFLGS) { 764*7c478bd9Sstevel@tonic-gate case 0: /* normal case, n == len */ 765*7c478bd9Sstevel@tonic-gate n = labellen(cp - 1); /* XXX */ 766*7c478bd9Sstevel@tonic-gate 767*7c478bd9Sstevel@tonic-gate if (n != *dn++) 768*7c478bd9Sstevel@tonic-gate goto next; 769*7c478bd9Sstevel@tonic-gate 770*7c478bd9Sstevel@tonic-gate for ((void)NULL; n > 0; n--) 771*7c478bd9Sstevel@tonic-gate if (mklower(*dn++) != 772*7c478bd9Sstevel@tonic-gate mklower(*cp++)) 773*7c478bd9Sstevel@tonic-gate goto next; 774*7c478bd9Sstevel@tonic-gate /* Is next root for both ? */ 775*7c478bd9Sstevel@tonic-gate if (*dn == '\0' && *cp == '\0') 776*7c478bd9Sstevel@tonic-gate return (sp - msg); 777*7c478bd9Sstevel@tonic-gate if (*dn) 778*7c478bd9Sstevel@tonic-gate continue; 779*7c478bd9Sstevel@tonic-gate goto next; 780*7c478bd9Sstevel@tonic-gate case NS_CMPRSFLGS: /* indirection */ 781*7c478bd9Sstevel@tonic-gate cp = msg + (((n & 0x3f) << 8) | *cp); 782*7c478bd9Sstevel@tonic-gate break; 783*7c478bd9Sstevel@tonic-gate 784*7c478bd9Sstevel@tonic-gate default: /* illegal type */ 785*7c478bd9Sstevel@tonic-gate errno = EMSGSIZE; 786*7c478bd9Sstevel@tonic-gate return (-1); 787*7c478bd9Sstevel@tonic-gate } 788*7c478bd9Sstevel@tonic-gate } 789*7c478bd9Sstevel@tonic-gate next: ; 790*7c478bd9Sstevel@tonic-gate sp += *sp + 1; 791*7c478bd9Sstevel@tonic-gate } 792*7c478bd9Sstevel@tonic-gate } 793*7c478bd9Sstevel@tonic-gate errno = ENOENT; 794*7c478bd9Sstevel@tonic-gate return (-1); 795*7c478bd9Sstevel@tonic-gate } 796*7c478bd9Sstevel@tonic-gate 797*7c478bd9Sstevel@tonic-gate static int 798*7c478bd9Sstevel@tonic-gate decode_bitstring(const char **cpp, char *dn, const char *eom) 799*7c478bd9Sstevel@tonic-gate { 800*7c478bd9Sstevel@tonic-gate const char *cp = *cpp; 801*7c478bd9Sstevel@tonic-gate char *beg = dn, tc; 802*7c478bd9Sstevel@tonic-gate int b, blen, plen, i; 803*7c478bd9Sstevel@tonic-gate 804*7c478bd9Sstevel@tonic-gate if ((blen = (*cp & 0xff)) == 0) 805*7c478bd9Sstevel@tonic-gate blen = 256; 806*7c478bd9Sstevel@tonic-gate plen = (blen + 3) / 4; 807*7c478bd9Sstevel@tonic-gate plen += sizeof("\\[x/]") + (blen > 99 ? 3 : (blen > 9) ? 2 : 1); 808*7c478bd9Sstevel@tonic-gate if (dn + plen >= eom) 809*7c478bd9Sstevel@tonic-gate return(-1); 810*7c478bd9Sstevel@tonic-gate 811*7c478bd9Sstevel@tonic-gate cp++; 812*7c478bd9Sstevel@tonic-gate i = SPRINTF((dn, "\\[x")); 813*7c478bd9Sstevel@tonic-gate if (i < 0) 814*7c478bd9Sstevel@tonic-gate return (-1); 815*7c478bd9Sstevel@tonic-gate dn += i; 816*7c478bd9Sstevel@tonic-gate for (b = blen; b > 7; b -= 8, cp++) { 817*7c478bd9Sstevel@tonic-gate i = SPRINTF((dn, "%02x", *cp & 0xff)); 818*7c478bd9Sstevel@tonic-gate if (i < 0) 819*7c478bd9Sstevel@tonic-gate return (-1); 820*7c478bd9Sstevel@tonic-gate dn += i; 821*7c478bd9Sstevel@tonic-gate } 822*7c478bd9Sstevel@tonic-gate if (b > 4) { 823*7c478bd9Sstevel@tonic-gate tc = *cp++; 824*7c478bd9Sstevel@tonic-gate i = SPRINTF((dn, "%02x", tc & (0xff << (8 - b)))); 825*7c478bd9Sstevel@tonic-gate if (i < 0) 826*7c478bd9Sstevel@tonic-gate return (-1); 827*7c478bd9Sstevel@tonic-gate dn += i; 828*7c478bd9Sstevel@tonic-gate } else if (b > 0) { 829*7c478bd9Sstevel@tonic-gate tc = *cp++; 830*7c478bd9Sstevel@tonic-gate i = SPRINTF((dn, "%1x", 831*7c478bd9Sstevel@tonic-gate ((tc >> 4) & 0x0f) & (0x0f << (4 - b)))); 832*7c478bd9Sstevel@tonic-gate if (i < 0) 833*7c478bd9Sstevel@tonic-gate return (-1); 834*7c478bd9Sstevel@tonic-gate dn += i; 835*7c478bd9Sstevel@tonic-gate } 836*7c478bd9Sstevel@tonic-gate i = SPRINTF((dn, "/%d]", blen)); 837*7c478bd9Sstevel@tonic-gate if (i < 0) 838*7c478bd9Sstevel@tonic-gate return (-1); 839*7c478bd9Sstevel@tonic-gate dn += i; 840*7c478bd9Sstevel@tonic-gate 841*7c478bd9Sstevel@tonic-gate *cpp = cp; 842*7c478bd9Sstevel@tonic-gate return(dn - beg); 843*7c478bd9Sstevel@tonic-gate } 844*7c478bd9Sstevel@tonic-gate 845*7c478bd9Sstevel@tonic-gate static int 846*7c478bd9Sstevel@tonic-gate encode_bitsring(const char **bp, const char *end, char **labelp, 847*7c478bd9Sstevel@tonic-gate char ** dst, const char *eom) 848*7c478bd9Sstevel@tonic-gate { 849*7c478bd9Sstevel@tonic-gate int afterslash = 0; 850*7c478bd9Sstevel@tonic-gate const char *cp = *bp; 851*7c478bd9Sstevel@tonic-gate char *tp, c; 852*7c478bd9Sstevel@tonic-gate const char *beg_blen; 853*7c478bd9Sstevel@tonic-gate char *end_blen = NULL; 854*7c478bd9Sstevel@tonic-gate int value = 0, count = 0, tbcount = 0, blen = 0; 855*7c478bd9Sstevel@tonic-gate 856*7c478bd9Sstevel@tonic-gate beg_blen = end_blen = NULL; 857*7c478bd9Sstevel@tonic-gate 858*7c478bd9Sstevel@tonic-gate /* a bitstring must contain at least 2 characters */ 859*7c478bd9Sstevel@tonic-gate if (end - cp < 2) 860*7c478bd9Sstevel@tonic-gate return(EINVAL); 861*7c478bd9Sstevel@tonic-gate 862*7c478bd9Sstevel@tonic-gate /* XXX: currently, only hex strings are supported */ 863*7c478bd9Sstevel@tonic-gate if (*cp++ != 'x') 864*7c478bd9Sstevel@tonic-gate return(EINVAL); 865*7c478bd9Sstevel@tonic-gate if (!isxdigit((*cp) & 0xff)) /* reject '\[x/BLEN]' */ 866*7c478bd9Sstevel@tonic-gate return(EINVAL); 867*7c478bd9Sstevel@tonic-gate 868*7c478bd9Sstevel@tonic-gate for (tp = *dst + 1; cp < end && tp < eom; cp++) { 869*7c478bd9Sstevel@tonic-gate switch((c = *cp)) { 870*7c478bd9Sstevel@tonic-gate case ']': /* end of the bitstring */ 871*7c478bd9Sstevel@tonic-gate if (afterslash) { 872*7c478bd9Sstevel@tonic-gate if (beg_blen == NULL) 873*7c478bd9Sstevel@tonic-gate return(EINVAL); 874*7c478bd9Sstevel@tonic-gate blen = (int)strtol(beg_blen, &end_blen, 10); 875*7c478bd9Sstevel@tonic-gate if (*end_blen != ']') 876*7c478bd9Sstevel@tonic-gate return(EINVAL); 877*7c478bd9Sstevel@tonic-gate } 878*7c478bd9Sstevel@tonic-gate if (count) 879*7c478bd9Sstevel@tonic-gate *tp++ = ((value << 4) & 0xff); 880*7c478bd9Sstevel@tonic-gate cp++; /* skip ']' */ 881*7c478bd9Sstevel@tonic-gate goto done; 882*7c478bd9Sstevel@tonic-gate case '/': 883*7c478bd9Sstevel@tonic-gate afterslash = 1; 884*7c478bd9Sstevel@tonic-gate break; 885*7c478bd9Sstevel@tonic-gate default: 886*7c478bd9Sstevel@tonic-gate if (afterslash) { 887*7c478bd9Sstevel@tonic-gate if (!isdigit(c&0xff)) 888*7c478bd9Sstevel@tonic-gate return(EINVAL); 889*7c478bd9Sstevel@tonic-gate if (beg_blen == NULL) { 890*7c478bd9Sstevel@tonic-gate 891*7c478bd9Sstevel@tonic-gate if (c == '0') { 892*7c478bd9Sstevel@tonic-gate /* blen never begings with 0 */ 893*7c478bd9Sstevel@tonic-gate return(EINVAL); 894*7c478bd9Sstevel@tonic-gate } 895*7c478bd9Sstevel@tonic-gate beg_blen = cp; 896*7c478bd9Sstevel@tonic-gate } 897*7c478bd9Sstevel@tonic-gate } else { 898*7c478bd9Sstevel@tonic-gate if (!isxdigit(c&0xff)) 899*7c478bd9Sstevel@tonic-gate return(EINVAL); 900*7c478bd9Sstevel@tonic-gate value <<= 4; 901*7c478bd9Sstevel@tonic-gate value += digitvalue[(int)c]; 902*7c478bd9Sstevel@tonic-gate count += 4; 903*7c478bd9Sstevel@tonic-gate tbcount += 4; 904*7c478bd9Sstevel@tonic-gate if (tbcount > 256) 905*7c478bd9Sstevel@tonic-gate return(EINVAL); 906*7c478bd9Sstevel@tonic-gate if (count == 8) { 907*7c478bd9Sstevel@tonic-gate *tp++ = value; 908*7c478bd9Sstevel@tonic-gate count = 0; 909*7c478bd9Sstevel@tonic-gate } 910*7c478bd9Sstevel@tonic-gate } 911*7c478bd9Sstevel@tonic-gate break; 912*7c478bd9Sstevel@tonic-gate } 913*7c478bd9Sstevel@tonic-gate } 914*7c478bd9Sstevel@tonic-gate done: 915*7c478bd9Sstevel@tonic-gate if (cp >= end || tp >= eom) 916*7c478bd9Sstevel@tonic-gate return(EMSGSIZE); 917*7c478bd9Sstevel@tonic-gate 918*7c478bd9Sstevel@tonic-gate /* 919*7c478bd9Sstevel@tonic-gate * bit length validation: 920*7c478bd9Sstevel@tonic-gate * If a <length> is present, the number of digits in the <bit-data> 921*7c478bd9Sstevel@tonic-gate * MUST be just sufficient to contain the number of bits specified 922*7c478bd9Sstevel@tonic-gate * by the <length>. If there are insignificant bits in a final 923*7c478bd9Sstevel@tonic-gate * hexadecimal or octal digit, they MUST be zero. 924*7c478bd9Sstevel@tonic-gate * RFC 2673, Section 3.2. 925*7c478bd9Sstevel@tonic-gate */ 926*7c478bd9Sstevel@tonic-gate if (blen > 0) { 927*7c478bd9Sstevel@tonic-gate int traillen; 928*7c478bd9Sstevel@tonic-gate 929*7c478bd9Sstevel@tonic-gate if (((blen + 3) & ~3) != tbcount) 930*7c478bd9Sstevel@tonic-gate return(EINVAL); 931*7c478bd9Sstevel@tonic-gate traillen = tbcount - blen; /* between 0 and 3 */ 932*7c478bd9Sstevel@tonic-gate if (((value << (8 - traillen)) & 0xff) != 0) 933*7c478bd9Sstevel@tonic-gate return(EINVAL); 934*7c478bd9Sstevel@tonic-gate } 935*7c478bd9Sstevel@tonic-gate else 936*7c478bd9Sstevel@tonic-gate blen = tbcount; 937*7c478bd9Sstevel@tonic-gate if (blen == 256) 938*7c478bd9Sstevel@tonic-gate blen = 0; 939*7c478bd9Sstevel@tonic-gate 940*7c478bd9Sstevel@tonic-gate /* encode the type and the significant bit fields */ 941*7c478bd9Sstevel@tonic-gate **labelp = DNS_LABELTYPE_BITSTRING; 942*7c478bd9Sstevel@tonic-gate **dst = blen; 943*7c478bd9Sstevel@tonic-gate 944*7c478bd9Sstevel@tonic-gate *bp = cp; 945*7c478bd9Sstevel@tonic-gate *dst = tp; 946*7c478bd9Sstevel@tonic-gate 947*7c478bd9Sstevel@tonic-gate return(0); 948*7c478bd9Sstevel@tonic-gate } 949*7c478bd9Sstevel@tonic-gate 950*7c478bd9Sstevel@tonic-gate static int 951*7c478bd9Sstevel@tonic-gate labellen(const u_char *lp) 952*7c478bd9Sstevel@tonic-gate { 953*7c478bd9Sstevel@tonic-gate int bitlen; 954*7c478bd9Sstevel@tonic-gate u_char l = *lp; 955*7c478bd9Sstevel@tonic-gate 956*7c478bd9Sstevel@tonic-gate if ((l & NS_CMPRSFLGS) == NS_CMPRSFLGS) { 957*7c478bd9Sstevel@tonic-gate /* should be avoided by the caller */ 958*7c478bd9Sstevel@tonic-gate return(-1); 959*7c478bd9Sstevel@tonic-gate } 960*7c478bd9Sstevel@tonic-gate 961*7c478bd9Sstevel@tonic-gate if ((l & NS_CMPRSFLGS) == NS_TYPE_ELT) { 962*7c478bd9Sstevel@tonic-gate if (l == DNS_LABELTYPE_BITSTRING) { 963*7c478bd9Sstevel@tonic-gate if ((bitlen = *(lp + 1)) == 0) 964*7c478bd9Sstevel@tonic-gate bitlen = 256; 965*7c478bd9Sstevel@tonic-gate return((bitlen + 7 ) / 8 + 1); 966*7c478bd9Sstevel@tonic-gate } 967*7c478bd9Sstevel@tonic-gate return(-1); /* unknwon ELT */ 968*7c478bd9Sstevel@tonic-gate } 969*7c478bd9Sstevel@tonic-gate return(l); 970*7c478bd9Sstevel@tonic-gate } 971