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