ns_name.c revision 170242
1156952Sume/* 2156952Sume * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") 3156952Sume * Copyright (c) 1996,1999 by Internet Software Consortium. 4156952Sume * 5156952Sume * Permission to use, copy, modify, and distribute this software for any 6156952Sume * purpose with or without fee is hereby granted, provided that the above 7156952Sume * copyright notice and this permission notice appear in all copies. 8156952Sume * 9156952Sume * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 10156952Sume * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11156952Sume * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 12156952Sume * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13156952Sume * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14156952Sume * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 15156952Sume * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16156952Sume */ 17156952Sume 18156952Sume#ifndef lint 19170242Sumestatic const char rcsid[] = "$Id: ns_name.c,v 1.8.18.2 2005/04/27 05:01:08 sra Exp $"; 20156952Sume#endif 21156952Sume 22156952Sume#include "port_before.h" 23156952Sume 24156952Sume#include <sys/types.h> 25156952Sume 26156952Sume#include <netinet/in.h> 27156952Sume#include <arpa/nameser.h> 28156952Sume 29156952Sume#include <errno.h> 30156952Sume#include <resolv.h> 31156952Sume#include <string.h> 32156952Sume#include <ctype.h> 33156952Sume#include <stdlib.h> 34156952Sume#include <limits.h> 35156952Sume 36156952Sume#include "port_after.h" 37156952Sume 38156952Sume#ifdef SPRINTF_CHAR 39156952Sume# define SPRINTF(x) strlen(sprintf/**/x) 40156952Sume#else 41156952Sume# define SPRINTF(x) ((size_t)sprintf x) 42156952Sume#endif 43156952Sume 44170242Sume#define NS_TYPE_ELT 0x40 /*%< EDNS0 extended label type */ 45156952Sume#define DNS_LABELTYPE_BITSTRING 0x41 46156952Sume 47156952Sume/* Data. */ 48156952Sume 49156952Sumestatic const char digits[] = "0123456789"; 50156952Sume 51156952Sumestatic const char digitvalue[256] = { 52156952Sume -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*16*/ 53156952Sume -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*32*/ 54156952Sume -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*48*/ 55156952Sume 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /*64*/ 56156952Sume -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*80*/ 57156952Sume -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*96*/ 58156952Sume -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*112*/ 59156952Sume -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*128*/ 60156952Sume -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 61156952Sume -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62156952Sume -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 63156952Sume -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 64156952Sume -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 65156952Sume -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 66156952Sume -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 67156952Sume -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*256*/ 68156952Sume}; 69156952Sume 70156952Sume/* Forward. */ 71156952Sume 72156952Sumestatic int special(int); 73156952Sumestatic int printable(int); 74156952Sumestatic int dn_find(const u_char *, const u_char *, 75156952Sume const u_char * const *, 76156952Sume const u_char * const *); 77156952Sumestatic int encode_bitsring(const char **, const char *, 78156952Sume unsigned char **, unsigned char **, 79156952Sume unsigned const char *); 80156952Sumestatic int labellen(const u_char *); 81156952Sumestatic int decode_bitstring(const unsigned char **, 82156952Sume char *, const char *); 83156952Sume 84156952Sume/* Public. */ 85156952Sume 86170242Sume/*% 87156952Sume * Convert an encoded domain name to printable ascii as per RFC1035. 88170242Sume 89156952Sume * return: 90170242Sume *\li Number of bytes written to buffer, or -1 (with errno set) 91170242Sume * 92156952Sume * notes: 93170242Sume *\li The root is returned as "." 94170242Sume *\li All other domains are returned in non absolute form 95156952Sume */ 96156952Sumeint 97156952Sumens_name_ntop(const u_char *src, char *dst, size_t dstsiz) 98156952Sume{ 99156952Sume const u_char *cp; 100156952Sume char *dn, *eom; 101156952Sume u_char c; 102156952Sume u_int n; 103156952Sume int l; 104156952Sume 105156952Sume cp = src; 106156952Sume dn = dst; 107156952Sume eom = dst + dstsiz; 108156952Sume 109156952Sume while ((n = *cp++) != 0) { 110156952Sume if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { 111156952Sume /* Some kind of compression pointer. */ 112156952Sume errno = EMSGSIZE; 113156952Sume return (-1); 114156952Sume } 115156952Sume if (dn != dst) { 116156952Sume if (dn >= eom) { 117156952Sume errno = EMSGSIZE; 118156952Sume return (-1); 119156952Sume } 120156952Sume *dn++ = '.'; 121156952Sume } 122156952Sume if ((l = labellen(cp - 1)) < 0) { 123170242Sume errno = EMSGSIZE; /*%< XXX */ 124156952Sume return(-1); 125156952Sume } 126156952Sume if (dn + l >= eom) { 127156952Sume errno = EMSGSIZE; 128156952Sume return (-1); 129156952Sume } 130156952Sume if ((n & NS_CMPRSFLGS) == NS_TYPE_ELT) { 131156952Sume int m; 132156952Sume 133156952Sume if (n != DNS_LABELTYPE_BITSTRING) { 134156952Sume /* XXX: labellen should reject this case */ 135156952Sume errno = EINVAL; 136156952Sume return(-1); 137156952Sume } 138156952Sume if ((m = decode_bitstring(&cp, dn, eom)) < 0) 139156952Sume { 140156952Sume errno = EMSGSIZE; 141156952Sume return(-1); 142156952Sume } 143156952Sume dn += m; 144156952Sume continue; 145156952Sume } 146156952Sume for ((void)NULL; l > 0; l--) { 147156952Sume c = *cp++; 148156952Sume if (special(c)) { 149156952Sume if (dn + 1 >= eom) { 150156952Sume errno = EMSGSIZE; 151156952Sume return (-1); 152156952Sume } 153156952Sume *dn++ = '\\'; 154156952Sume *dn++ = (char)c; 155156952Sume } else if (!printable(c)) { 156156952Sume if (dn + 3 >= eom) { 157156952Sume errno = EMSGSIZE; 158156952Sume return (-1); 159156952Sume } 160156952Sume *dn++ = '\\'; 161156952Sume *dn++ = digits[c / 100]; 162156952Sume *dn++ = digits[(c % 100) / 10]; 163156952Sume *dn++ = digits[c % 10]; 164156952Sume } else { 165156952Sume if (dn >= eom) { 166156952Sume errno = EMSGSIZE; 167156952Sume return (-1); 168156952Sume } 169156952Sume *dn++ = (char)c; 170156952Sume } 171156952Sume } 172156952Sume } 173156952Sume if (dn == dst) { 174156952Sume if (dn >= eom) { 175156952Sume errno = EMSGSIZE; 176156952Sume return (-1); 177156952Sume } 178156952Sume *dn++ = '.'; 179156952Sume } 180156952Sume if (dn >= eom) { 181156952Sume errno = EMSGSIZE; 182156952Sume return (-1); 183156952Sume } 184156952Sume *dn++ = '\0'; 185156952Sume return (dn - dst); 186156952Sume} 187156952Sume 188170242Sume/*% 189156952Sume * Convert a ascii string into an encoded domain name as per RFC1035. 190170242Sume * 191156952Sume * return: 192170242Sume * 193170242Sume *\li -1 if it fails 194170242Sume *\li 1 if string was fully qualified 195170242Sume *\li 0 is string was not fully qualified 196170242Sume * 197156952Sume * notes: 198170242Sume *\li Enforces label and domain length limits. 199156952Sume */ 200156952Sume 201156952Sumeint 202156952Sumens_name_pton(const char *src, u_char *dst, size_t dstsiz) 203156952Sume{ 204156952Sume u_char *label, *bp, *eom; 205156952Sume int c, n, escaped, e = 0; 206156952Sume char *cp; 207156952Sume 208156952Sume escaped = 0; 209156952Sume bp = dst; 210156952Sume eom = dst + dstsiz; 211156952Sume label = bp++; 212156952Sume 213156952Sume while ((c = *src++) != 0) { 214156952Sume if (escaped) { 215170242Sume if (c == '[') { /*%< start a bit string label */ 216156952Sume if ((cp = strchr(src, ']')) == NULL) { 217170242Sume errno = EINVAL; /*%< ??? */ 218156952Sume return(-1); 219156952Sume } 220156952Sume if ((e = encode_bitsring(&src, cp + 2, 221156952Sume &label, &bp, eom)) 222156952Sume != 0) { 223156952Sume errno = e; 224156952Sume return(-1); 225156952Sume } 226156952Sume escaped = 0; 227156952Sume label = bp++; 228156952Sume if ((c = *src++) == 0) 229156952Sume goto done; 230156952Sume else if (c != '.') { 231156952Sume errno = EINVAL; 232156952Sume return(-1); 233156952Sume } 234156952Sume continue; 235156952Sume } 236156952Sume else if ((cp = strchr(digits, c)) != NULL) { 237156952Sume n = (cp - digits) * 100; 238156952Sume if ((c = *src++) == 0 || 239156952Sume (cp = strchr(digits, c)) == NULL) { 240156952Sume errno = EMSGSIZE; 241156952Sume return (-1); 242156952Sume } 243156952Sume n += (cp - digits) * 10; 244156952Sume if ((c = *src++) == 0 || 245156952Sume (cp = strchr(digits, c)) == NULL) { 246156952Sume errno = EMSGSIZE; 247156952Sume return (-1); 248156952Sume } 249156952Sume n += (cp - digits); 250156952Sume if (n > 255) { 251156952Sume errno = EMSGSIZE; 252156952Sume return (-1); 253156952Sume } 254156952Sume c = n; 255156952Sume } 256156952Sume escaped = 0; 257156952Sume } else if (c == '\\') { 258156952Sume escaped = 1; 259156952Sume continue; 260156952Sume } else if (c == '.') { 261156952Sume c = (bp - label - 1); 262170242Sume if ((c & NS_CMPRSFLGS) != 0) { /*%< Label too big. */ 263156952Sume errno = EMSGSIZE; 264156952Sume return (-1); 265156952Sume } 266156952Sume if (label >= eom) { 267156952Sume errno = EMSGSIZE; 268156952Sume return (-1); 269156952Sume } 270156952Sume *label = c; 271156952Sume /* Fully qualified ? */ 272156952Sume if (*src == '\0') { 273156952Sume if (c != 0) { 274156952Sume if (bp >= eom) { 275156952Sume errno = EMSGSIZE; 276156952Sume return (-1); 277156952Sume } 278156952Sume *bp++ = '\0'; 279156952Sume } 280156952Sume if ((bp - dst) > MAXCDNAME) { 281156952Sume errno = EMSGSIZE; 282156952Sume return (-1); 283156952Sume } 284156952Sume return (1); 285156952Sume } 286156952Sume if (c == 0 || *src == '.') { 287156952Sume errno = EMSGSIZE; 288156952Sume return (-1); 289156952Sume } 290156952Sume label = bp++; 291156952Sume continue; 292156952Sume } 293156952Sume if (bp >= eom) { 294156952Sume errno = EMSGSIZE; 295156952Sume return (-1); 296156952Sume } 297156952Sume *bp++ = (u_char)c; 298156952Sume } 299156952Sume c = (bp - label - 1); 300170242Sume if ((c & NS_CMPRSFLGS) != 0) { /*%< Label too big. */ 301156952Sume errno = EMSGSIZE; 302156952Sume return (-1); 303156952Sume } 304156952Sume done: 305156952Sume if (label >= eom) { 306156952Sume errno = EMSGSIZE; 307156952Sume return (-1); 308156952Sume } 309156952Sume *label = c; 310156952Sume if (c != 0) { 311156952Sume if (bp >= eom) { 312156952Sume errno = EMSGSIZE; 313156952Sume return (-1); 314156952Sume } 315156952Sume *bp++ = 0; 316156952Sume } 317170242Sume if ((bp - dst) > MAXCDNAME) { /*%< src too big */ 318156952Sume errno = EMSGSIZE; 319156952Sume return (-1); 320156952Sume } 321156952Sume return (0); 322156952Sume} 323156952Sume 324170242Sume/*% 325156952Sume * Convert a network strings labels into all lowercase. 326170242Sume * 327156952Sume * return: 328170242Sume *\li Number of bytes written to buffer, or -1 (with errno set) 329170242Sume * 330156952Sume * notes: 331170242Sume *\li Enforces label and domain length limits. 332156952Sume */ 333156952Sume 334156952Sumeint 335156952Sumens_name_ntol(const u_char *src, u_char *dst, size_t dstsiz) 336156952Sume{ 337156952Sume const u_char *cp; 338156952Sume u_char *dn, *eom; 339156952Sume u_char c; 340156952Sume u_int n; 341156952Sume int l; 342156952Sume 343156952Sume cp = src; 344156952Sume dn = dst; 345156952Sume eom = dst + dstsiz; 346156952Sume 347156952Sume if (dn >= eom) { 348156952Sume errno = EMSGSIZE; 349156952Sume return (-1); 350156952Sume } 351156952Sume while ((n = *cp++) != 0) { 352156952Sume if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { 353156952Sume /* Some kind of compression pointer. */ 354156952Sume errno = EMSGSIZE; 355156952Sume return (-1); 356156952Sume } 357156952Sume *dn++ = n; 358156952Sume if ((l = labellen(cp - 1)) < 0) { 359156952Sume errno = EMSGSIZE; 360156952Sume return (-1); 361156952Sume } 362156952Sume if (dn + l >= eom) { 363156952Sume errno = EMSGSIZE; 364156952Sume return (-1); 365156952Sume } 366156952Sume for ((void)NULL; l > 0; l--) { 367156952Sume c = *cp++; 368156952Sume if (isupper(c)) 369156952Sume *dn++ = tolower(c); 370156952Sume else 371156952Sume *dn++ = c; 372156952Sume } 373156952Sume } 374156952Sume *dn++ = '\0'; 375156952Sume return (dn - dst); 376156952Sume} 377156952Sume 378170242Sume/*% 379156952Sume * Unpack a domain name from a message, source may be compressed. 380170242Sume * 381156952Sume * return: 382170242Sume *\li -1 if it fails, or consumed octets if it succeeds. 383156952Sume */ 384156952Sumeint 385156952Sumens_name_unpack(const u_char *msg, const u_char *eom, const u_char *src, 386156952Sume u_char *dst, size_t dstsiz) 387156952Sume{ 388156952Sume const u_char *srcp, *dstlim; 389156952Sume u_char *dstp; 390156952Sume int n, len, checked, l; 391156952Sume 392156952Sume len = -1; 393156952Sume checked = 0; 394156952Sume dstp = dst; 395156952Sume srcp = src; 396156952Sume dstlim = dst + dstsiz; 397156952Sume if (srcp < msg || srcp >= eom) { 398156952Sume errno = EMSGSIZE; 399156952Sume return (-1); 400156952Sume } 401156952Sume /* Fetch next label in domain name. */ 402156952Sume while ((n = *srcp++) != 0) { 403156952Sume /* Check for indirection. */ 404156952Sume switch (n & NS_CMPRSFLGS) { 405156952Sume case 0: 406156952Sume case NS_TYPE_ELT: 407156952Sume /* Limit checks. */ 408156952Sume if ((l = labellen(srcp - 1)) < 0) { 409156952Sume errno = EMSGSIZE; 410156952Sume return(-1); 411156952Sume } 412156952Sume if (dstp + l + 1 >= dstlim || srcp + l >= eom) { 413156952Sume errno = EMSGSIZE; 414156952Sume return (-1); 415156952Sume } 416156952Sume checked += l + 1; 417156952Sume *dstp++ = n; 418156952Sume memcpy(dstp, srcp, l); 419156952Sume dstp += l; 420156952Sume srcp += l; 421156952Sume break; 422156952Sume 423156952Sume case NS_CMPRSFLGS: 424156952Sume if (srcp >= eom) { 425156952Sume errno = EMSGSIZE; 426156952Sume return (-1); 427156952Sume } 428156952Sume if (len < 0) 429156952Sume len = srcp - src + 1; 430156952Sume srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff)); 431170242Sume if (srcp < msg || srcp >= eom) { /*%< Out of range. */ 432156952Sume errno = EMSGSIZE; 433156952Sume return (-1); 434156952Sume } 435156952Sume checked += 2; 436156952Sume /* 437156952Sume * Check for loops in the compressed name; 438156952Sume * if we've looked at the whole message, 439156952Sume * there must be a loop. 440156952Sume */ 441156952Sume if (checked >= eom - msg) { 442156952Sume errno = EMSGSIZE; 443156952Sume return (-1); 444156952Sume } 445156952Sume break; 446156952Sume 447156952Sume default: 448156952Sume errno = EMSGSIZE; 449170242Sume return (-1); /*%< flag error */ 450156952Sume } 451156952Sume } 452156952Sume *dstp = '\0'; 453156952Sume if (len < 0) 454156952Sume len = srcp - src; 455156952Sume return (len); 456156952Sume} 457156952Sume 458170242Sume/*% 459156952Sume * Pack domain name 'domain' into 'comp_dn'. 460170242Sume * 461156952Sume * return: 462170242Sume *\li Size of the compressed name, or -1. 463170242Sume * 464156952Sume * notes: 465170242Sume *\li 'dnptrs' is an array of pointers to previous compressed names. 466170242Sume *\li dnptrs[0] is a pointer to the beginning of the message. The array 467156952Sume * ends with NULL. 468170242Sume *\li 'lastdnptr' is a pointer to the end of the array pointed to 469156952Sume * by 'dnptrs'. 470170242Sume * 471156952Sume * Side effects: 472170242Sume *\li The list of pointers in dnptrs is updated for labels inserted into 473156952Sume * the message as we compress the name. If 'dnptr' is NULL, we don't 474156952Sume * try to compress names. If 'lastdnptr' is NULL, we don't update the 475156952Sume * list. 476156952Sume */ 477156952Sumeint 478156952Sumens_name_pack(const u_char *src, u_char *dst, int dstsiz, 479156952Sume const u_char **dnptrs, const u_char **lastdnptr) 480156952Sume{ 481156952Sume u_char *dstp; 482156952Sume const u_char **cpp, **lpp, *eob, *msg; 483156952Sume const u_char *srcp; 484156952Sume int n, l, first = 1; 485156952Sume 486156952Sume srcp = src; 487156952Sume dstp = dst; 488156952Sume eob = dstp + dstsiz; 489156952Sume lpp = cpp = NULL; 490156952Sume if (dnptrs != NULL) { 491156952Sume if ((msg = *dnptrs++) != NULL) { 492156952Sume for (cpp = dnptrs; *cpp != NULL; cpp++) 493156952Sume (void)NULL; 494170242Sume lpp = cpp; /*%< end of list to search */ 495156952Sume } 496156952Sume } else 497156952Sume msg = NULL; 498156952Sume 499156952Sume /* make sure the domain we are about to add is legal */ 500156952Sume l = 0; 501156952Sume do { 502156952Sume int l0; 503156952Sume 504156952Sume n = *srcp; 505156952Sume if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { 506156952Sume errno = EMSGSIZE; 507156952Sume return (-1); 508156952Sume } 509156952Sume if ((l0 = labellen(srcp)) < 0) { 510156952Sume errno = EINVAL; 511156952Sume return(-1); 512156952Sume } 513156952Sume l += l0 + 1; 514156952Sume if (l > MAXCDNAME) { 515156952Sume errno = EMSGSIZE; 516156952Sume return (-1); 517156952Sume } 518156952Sume srcp += l0 + 1; 519156952Sume } while (n != 0); 520156952Sume 521156952Sume /* from here on we need to reset compression pointer array on error */ 522156952Sume srcp = src; 523156952Sume do { 524156952Sume /* Look to see if we can use pointers. */ 525156952Sume n = *srcp; 526156952Sume if (n != 0 && msg != NULL) { 527156952Sume l = dn_find(srcp, msg, (const u_char * const *)dnptrs, 528156952Sume (const u_char * const *)lpp); 529156952Sume if (l >= 0) { 530156952Sume if (dstp + 1 >= eob) { 531156952Sume goto cleanup; 532156952Sume } 533156952Sume *dstp++ = (l >> 8) | NS_CMPRSFLGS; 534156952Sume *dstp++ = l % 256; 535156952Sume return (dstp - dst); 536156952Sume } 537156952Sume /* Not found, save it. */ 538156952Sume if (lastdnptr != NULL && cpp < lastdnptr - 1 && 539156952Sume (dstp - msg) < 0x4000 && first) { 540156952Sume *cpp++ = dstp; 541156952Sume *cpp = NULL; 542156952Sume first = 0; 543156952Sume } 544156952Sume } 545156952Sume /* copy label to buffer */ 546156952Sume if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { 547156952Sume /* Should not happen. */ 548156952Sume goto cleanup; 549156952Sume } 550156952Sume n = labellen(srcp); 551156952Sume if (dstp + 1 + n >= eob) { 552156952Sume goto cleanup; 553156952Sume } 554156952Sume memcpy(dstp, srcp, n + 1); 555156952Sume srcp += n + 1; 556156952Sume dstp += n + 1; 557156952Sume } while (n != 0); 558156952Sume 559156952Sume if (dstp > eob) { 560156952Sumecleanup: 561156952Sume if (msg != NULL) 562156952Sume *lpp = NULL; 563156952Sume errno = EMSGSIZE; 564156952Sume return (-1); 565156952Sume } 566156952Sume return (dstp - dst); 567156952Sume} 568156952Sume 569170242Sume/*% 570156952Sume * Expand compressed domain name to presentation format. 571170242Sume * 572156952Sume * return: 573170242Sume *\li Number of bytes read out of `src', or -1 (with errno set). 574170242Sume * 575156952Sume * note: 576170242Sume *\li Root domain returns as "." not "". 577156952Sume */ 578156952Sumeint 579156952Sumens_name_uncompress(const u_char *msg, const u_char *eom, const u_char *src, 580156952Sume char *dst, size_t dstsiz) 581156952Sume{ 582156952Sume u_char tmp[NS_MAXCDNAME]; 583156952Sume int n; 584156952Sume 585156952Sume if ((n = ns_name_unpack(msg, eom, src, tmp, sizeof tmp)) == -1) 586156952Sume return (-1); 587156952Sume if (ns_name_ntop(tmp, dst, dstsiz) == -1) 588156952Sume return (-1); 589156952Sume return (n); 590156952Sume} 591156952Sume 592170242Sume/*% 593156952Sume * Compress a domain name into wire format, using compression pointers. 594170242Sume * 595156952Sume * return: 596170242Sume *\li Number of bytes consumed in `dst' or -1 (with errno set). 597170242Sume * 598156952Sume * notes: 599170242Sume *\li 'dnptrs' is an array of pointers to previous compressed names. 600170242Sume *\li dnptrs[0] is a pointer to the beginning of the message. 601170242Sume *\li The list ends with NULL. 'lastdnptr' is a pointer to the end of the 602156952Sume * array pointed to by 'dnptrs'. Side effect is to update the list of 603156952Sume * pointers for labels inserted into the message as we compress the name. 604170242Sume *\li If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr' 605156952Sume * is NULL, we don't update the list. 606156952Sume */ 607156952Sumeint 608156952Sumens_name_compress(const char *src, u_char *dst, size_t dstsiz, 609156952Sume const u_char **dnptrs, const u_char **lastdnptr) 610156952Sume{ 611156952Sume u_char tmp[NS_MAXCDNAME]; 612156952Sume 613156952Sume if (ns_name_pton(src, tmp, sizeof tmp) == -1) 614156952Sume return (-1); 615156952Sume return (ns_name_pack(tmp, dst, dstsiz, dnptrs, lastdnptr)); 616156952Sume} 617156952Sume 618170242Sume/*% 619156952Sume * Reset dnptrs so that there are no active references to pointers at or 620156952Sume * after src. 621156952Sume */ 622156952Sumevoid 623156952Sumens_name_rollback(const u_char *src, const u_char **dnptrs, 624156952Sume const u_char **lastdnptr) 625156952Sume{ 626156952Sume while (dnptrs < lastdnptr && *dnptrs != NULL) { 627156952Sume if (*dnptrs >= src) { 628156952Sume *dnptrs = NULL; 629156952Sume break; 630156952Sume } 631156952Sume dnptrs++; 632156952Sume } 633156952Sume} 634156952Sume 635170242Sume/*% 636156952Sume * Advance *ptrptr to skip over the compressed name it points at. 637170242Sume * 638156952Sume * return: 639170242Sume *\li 0 on success, -1 (with errno set) on failure. 640156952Sume */ 641156952Sumeint 642156952Sumens_name_skip(const u_char **ptrptr, const u_char *eom) 643156952Sume{ 644156952Sume const u_char *cp; 645156952Sume u_int n; 646156952Sume int l; 647156952Sume 648156952Sume cp = *ptrptr; 649156952Sume while (cp < eom && (n = *cp++) != 0) { 650156952Sume /* Check for indirection. */ 651156952Sume switch (n & NS_CMPRSFLGS) { 652170242Sume case 0: /*%< normal case, n == len */ 653156952Sume cp += n; 654156952Sume continue; 655170242Sume case NS_TYPE_ELT: /*%< EDNS0 extended label */ 656156952Sume if ((l = labellen(cp - 1)) < 0) { 657170242Sume errno = EMSGSIZE; /*%< XXX */ 658156952Sume return(-1); 659156952Sume } 660156952Sume cp += l; 661156952Sume continue; 662170242Sume case NS_CMPRSFLGS: /*%< indirection */ 663156952Sume cp++; 664156952Sume break; 665170242Sume default: /*%< illegal type */ 666156952Sume errno = EMSGSIZE; 667156952Sume return (-1); 668156952Sume } 669156952Sume break; 670156952Sume } 671156952Sume if (cp > eom) { 672156952Sume errno = EMSGSIZE; 673156952Sume return (-1); 674156952Sume } 675156952Sume *ptrptr = cp; 676156952Sume return (0); 677156952Sume} 678156952Sume 679156952Sume/* Private. */ 680156952Sume 681170242Sume/*% 682156952Sume * Thinking in noninternationalized USASCII (per the DNS spec), 683156952Sume * is this characted special ("in need of quoting") ? 684170242Sume * 685156952Sume * return: 686170242Sume *\li boolean. 687156952Sume */ 688156952Sumestatic int 689156952Sumespecial(int ch) { 690156952Sume switch (ch) { 691170242Sume case 0x22: /*%< '"' */ 692170242Sume case 0x2E: /*%< '.' */ 693170242Sume case 0x3B: /*%< ';' */ 694170242Sume case 0x5C: /*%< '\\' */ 695170242Sume case 0x28: /*%< '(' */ 696170242Sume case 0x29: /*%< ')' */ 697156952Sume /* Special modifiers in zone files. */ 698170242Sume case 0x40: /*%< '@' */ 699170242Sume case 0x24: /*%< '$' */ 700156952Sume return (1); 701156952Sume default: 702156952Sume return (0); 703156952Sume } 704156952Sume} 705156952Sume 706170242Sume/*% 707156952Sume * Thinking in noninternationalized USASCII (per the DNS spec), 708156952Sume * is this character visible and not a space when printed ? 709170242Sume * 710156952Sume * return: 711170242Sume *\li boolean. 712156952Sume */ 713156952Sumestatic int 714156952Sumeprintable(int ch) { 715156952Sume return (ch > 0x20 && ch < 0x7f); 716156952Sume} 717156952Sume 718170242Sume/*% 719156952Sume * Thinking in noninternationalized USASCII (per the DNS spec), 720156952Sume * convert this character to lower case if it's upper case. 721156952Sume */ 722156952Sumestatic int 723156952Sumemklower(int ch) { 724156952Sume if (ch >= 0x41 && ch <= 0x5A) 725156952Sume return (ch + 0x20); 726156952Sume return (ch); 727156952Sume} 728156952Sume 729170242Sume/*% 730156952Sume * Search for the counted-label name in an array of compressed names. 731170242Sume * 732156952Sume * return: 733170242Sume *\li offset from msg if found, or -1. 734170242Sume * 735156952Sume * notes: 736170242Sume *\li dnptrs is the pointer to the first name on the list, 737170242Sume *\li not the pointer to the start of the message. 738156952Sume */ 739156952Sumestatic int 740156952Sumedn_find(const u_char *domain, const u_char *msg, 741156952Sume const u_char * const *dnptrs, 742156952Sume const u_char * const *lastdnptr) 743156952Sume{ 744156952Sume const u_char *dn, *cp, *sp; 745156952Sume const u_char * const *cpp; 746156952Sume u_int n; 747156952Sume 748156952Sume for (cpp = dnptrs; cpp < lastdnptr; cpp++) { 749156952Sume sp = *cpp; 750156952Sume /* 751156952Sume * terminate search on: 752156952Sume * root label 753156952Sume * compression pointer 754156952Sume * unusable offset 755156952Sume */ 756156952Sume while (*sp != 0 && (*sp & NS_CMPRSFLGS) == 0 && 757156952Sume (sp - msg) < 0x4000) { 758156952Sume dn = domain; 759156952Sume cp = sp; 760156952Sume while ((n = *cp++) != 0) { 761156952Sume /* 762156952Sume * check for indirection 763156952Sume */ 764156952Sume switch (n & NS_CMPRSFLGS) { 765170242Sume case 0: /*%< normal case, n == len */ 766170242Sume n = labellen(cp - 1); /*%< XXX */ 767156952Sume if (n != *dn++) 768156952Sume goto next; 769156952Sume 770156952Sume for ((void)NULL; n > 0; n--) 771156952Sume if (mklower(*dn++) != 772156952Sume mklower(*cp++)) 773156952Sume goto next; 774156952Sume /* Is next root for both ? */ 775156952Sume if (*dn == '\0' && *cp == '\0') 776156952Sume return (sp - msg); 777156952Sume if (*dn) 778156952Sume continue; 779156952Sume goto next; 780170242Sume case NS_CMPRSFLGS: /*%< indirection */ 781156952Sume cp = msg + (((n & 0x3f) << 8) | *cp); 782156952Sume break; 783156952Sume 784170242Sume default: /*%< illegal type */ 785156952Sume errno = EMSGSIZE; 786156952Sume return (-1); 787156952Sume } 788156952Sume } 789156952Sume next: ; 790156952Sume sp += *sp + 1; 791156952Sume } 792156952Sume } 793156952Sume errno = ENOENT; 794156952Sume return (-1); 795156952Sume} 796156952Sume 797156952Sumestatic int 798156952Sumedecode_bitstring(const unsigned char **cpp, char *dn, const char *eom) 799156952Sume{ 800156952Sume const unsigned char *cp = *cpp; 801156952Sume char *beg = dn, tc; 802156952Sume int b, blen, plen, i; 803156952Sume 804156952Sume if ((blen = (*cp & 0xff)) == 0) 805156952Sume blen = 256; 806156952Sume plen = (blen + 3) / 4; 807156952Sume plen += sizeof("\\[x/]") + (blen > 99 ? 3 : (blen > 9) ? 2 : 1); 808156952Sume if (dn + plen >= eom) 809156952Sume return(-1); 810156952Sume 811156952Sume cp++; 812156952Sume i = SPRINTF((dn, "\\[x")); 813156952Sume if (i < 0) 814156952Sume return (-1); 815156952Sume dn += i; 816156952Sume for (b = blen; b > 7; b -= 8, cp++) { 817156952Sume i = SPRINTF((dn, "%02x", *cp & 0xff)); 818156952Sume if (i < 0) 819156952Sume return (-1); 820156952Sume dn += i; 821156952Sume } 822156952Sume if (b > 4) { 823156952Sume tc = *cp++; 824156952Sume i = SPRINTF((dn, "%02x", tc & (0xff << (8 - b)))); 825156952Sume if (i < 0) 826156952Sume return (-1); 827156952Sume dn += i; 828156952Sume } else if (b > 0) { 829156952Sume tc = *cp++; 830156952Sume i = SPRINTF((dn, "%1x", 831156952Sume ((tc >> 4) & 0x0f) & (0x0f << (4 - b)))); 832156952Sume if (i < 0) 833156952Sume return (-1); 834156952Sume dn += i; 835156952Sume } 836156952Sume i = SPRINTF((dn, "/%d]", blen)); 837156952Sume if (i < 0) 838156952Sume return (-1); 839156952Sume dn += i; 840156952Sume 841156952Sume *cpp = cp; 842156952Sume return(dn - beg); 843156952Sume} 844156952Sume 845156952Sumestatic int 846156952Sumeencode_bitsring(const char **bp, const char *end, unsigned char **labelp, 847156952Sume unsigned char ** dst, unsigned const char *eom) 848156952Sume{ 849156952Sume int afterslash = 0; 850156952Sume const char *cp = *bp; 851156952Sume unsigned char *tp; 852156952Sume char c; 853156952Sume const char *beg_blen; 854156952Sume char *end_blen = NULL; 855156952Sume int value = 0, count = 0, tbcount = 0, blen = 0; 856156952Sume 857156952Sume beg_blen = end_blen = NULL; 858156952Sume 859156952Sume /* a bitstring must contain at least 2 characters */ 860156952Sume if (end - cp < 2) 861156952Sume return(EINVAL); 862156952Sume 863156952Sume /* XXX: currently, only hex strings are supported */ 864156952Sume if (*cp++ != 'x') 865156952Sume return(EINVAL); 866170242Sume if (!isxdigit((*cp) & 0xff)) /*%< reject '\[x/BLEN]' */ 867156952Sume return(EINVAL); 868156952Sume 869156952Sume for (tp = *dst + 1; cp < end && tp < eom; cp++) { 870156952Sume switch((c = *cp)) { 871170242Sume case ']': /*%< end of the bitstring */ 872156952Sume if (afterslash) { 873156952Sume if (beg_blen == NULL) 874156952Sume return(EINVAL); 875156952Sume blen = (int)strtol(beg_blen, &end_blen, 10); 876156952Sume if (*end_blen != ']') 877156952Sume return(EINVAL); 878156952Sume } 879156952Sume if (count) 880156952Sume *tp++ = ((value << 4) & 0xff); 881170242Sume cp++; /*%< skip ']' */ 882156952Sume goto done; 883156952Sume case '/': 884156952Sume afterslash = 1; 885156952Sume break; 886156952Sume default: 887156952Sume if (afterslash) { 888156952Sume if (!isdigit(c&0xff)) 889156952Sume return(EINVAL); 890156952Sume if (beg_blen == NULL) { 891156952Sume 892156952Sume if (c == '0') { 893156952Sume /* blen never begings with 0 */ 894156952Sume return(EINVAL); 895156952Sume } 896156952Sume beg_blen = cp; 897156952Sume } 898156952Sume } else { 899156952Sume if (!isxdigit(c&0xff)) 900156952Sume return(EINVAL); 901156952Sume value <<= 4; 902156952Sume value += digitvalue[(int)c]; 903156952Sume count += 4; 904156952Sume tbcount += 4; 905156952Sume if (tbcount > 256) 906156952Sume return(EINVAL); 907156952Sume if (count == 8) { 908156952Sume *tp++ = value; 909156952Sume count = 0; 910156952Sume } 911156952Sume } 912156952Sume break; 913156952Sume } 914156952Sume } 915156952Sume done: 916156952Sume if (cp >= end || tp >= eom) 917156952Sume return(EMSGSIZE); 918156952Sume 919156952Sume /* 920156952Sume * bit length validation: 921156952Sume * If a <length> is present, the number of digits in the <bit-data> 922156952Sume * MUST be just sufficient to contain the number of bits specified 923156952Sume * by the <length>. If there are insignificant bits in a final 924156952Sume * hexadecimal or octal digit, they MUST be zero. 925170242Sume * RFC2673, Section 3.2. 926156952Sume */ 927156952Sume if (blen > 0) { 928156952Sume int traillen; 929156952Sume 930156952Sume if (((blen + 3) & ~3) != tbcount) 931156952Sume return(EINVAL); 932170242Sume traillen = tbcount - blen; /*%< between 0 and 3 */ 933156952Sume if (((value << (8 - traillen)) & 0xff) != 0) 934156952Sume return(EINVAL); 935156952Sume } 936156952Sume else 937156952Sume blen = tbcount; 938156952Sume if (blen == 256) 939156952Sume blen = 0; 940156952Sume 941156952Sume /* encode the type and the significant bit fields */ 942156952Sume **labelp = DNS_LABELTYPE_BITSTRING; 943156952Sume **dst = blen; 944156952Sume 945156952Sume *bp = cp; 946156952Sume *dst = tp; 947156952Sume 948156952Sume return(0); 949156952Sume} 950156952Sume 951156952Sumestatic int 952156952Sumelabellen(const u_char *lp) 953156952Sume{ 954156952Sume int bitlen; 955156952Sume u_char l = *lp; 956156952Sume 957156952Sume if ((l & NS_CMPRSFLGS) == NS_CMPRSFLGS) { 958156952Sume /* should be avoided by the caller */ 959156952Sume return(-1); 960156952Sume } 961156952Sume 962156952Sume if ((l & NS_CMPRSFLGS) == NS_TYPE_ELT) { 963156952Sume if (l == DNS_LABELTYPE_BITSTRING) { 964156952Sume if ((bitlen = *(lp + 1)) == 0) 965156952Sume bitlen = 256; 966156952Sume return((bitlen + 7 ) / 8 + 1); 967156952Sume } 968170242Sume return(-1); /*%< unknwon ELT */ 969156952Sume } 970156952Sume return(l); 971156952Sume} 972170242Sume 973170242Sume/*! \file */ 974