name.c revision 224092
1135446Strhodes/* 2224092Sdougb * Copyright (C) 2004-2011 Internet Systems Consortium, Inc. ("ISC") 3135446Strhodes * Copyright (C) 1998-2003 Internet Software Consortium. 4135446Strhodes * 5193149Sdougb * Permission to use, copy, modify, and/or distribute this software for any 6135446Strhodes * purpose with or without fee is hereby granted, provided that the above 7135446Strhodes * copyright notice and this permission notice appear in all copies. 8135446Strhodes * 9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11135446Strhodes * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15135446Strhodes * PERFORMANCE OF THIS SOFTWARE. 16135446Strhodes */ 17135446Strhodes 18224092Sdougb/* $Id: name.c,v 1.174 2011-01-13 04:59:25 tbox Exp $ */ 19135446Strhodes 20170222Sdougb/*! \file */ 21170222Sdougb 22135446Strhodes#include <config.h> 23135446Strhodes 24135446Strhodes#include <ctype.h> 25170222Sdougb#include <stdlib.h> 26135446Strhodes 27135446Strhodes#include <isc/buffer.h> 28135446Strhodes#include <isc/hash.h> 29135446Strhodes#include <isc/mem.h> 30170222Sdougb#include <isc/once.h> 31135446Strhodes#include <isc/print.h> 32135446Strhodes#include <isc/string.h> 33170222Sdougb#include <isc/thread.h> 34135446Strhodes#include <isc/util.h> 35135446Strhodes 36135446Strhodes#include <dns/compress.h> 37224092Sdougb#include <dns/fixedname.h> 38135446Strhodes#include <dns/name.h> 39135446Strhodes#include <dns/result.h> 40135446Strhodes 41135446Strhodes#define VALID_NAME(n) ISC_MAGIC_VALID(n, DNS_NAME_MAGIC) 42135446Strhodes 43135446Strhodestypedef enum { 44135446Strhodes ft_init = 0, 45135446Strhodes ft_start, 46135446Strhodes ft_ordinary, 47135446Strhodes ft_initialescape, 48135446Strhodes ft_escape, 49135446Strhodes ft_escdecimal, 50135446Strhodes ft_at 51135446Strhodes} ft_state; 52135446Strhodes 53135446Strhodestypedef enum { 54135446Strhodes fw_start = 0, 55135446Strhodes fw_ordinary, 56135446Strhodes fw_copy, 57135446Strhodes fw_newcurrent 58135446Strhodes} fw_state; 59135446Strhodes 60135446Strhodesstatic char digitvalue[256] = { 61135446Strhodes -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*16*/ 62135446Strhodes -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*32*/ 63135446Strhodes -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*48*/ 64135446Strhodes 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /*64*/ 65135446Strhodes -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*80*/ 66135446Strhodes -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*96*/ 67135446Strhodes -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*112*/ 68135446Strhodes -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*128*/ 69135446Strhodes -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 70135446Strhodes -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 71135446Strhodes -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 72135446Strhodes -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 73135446Strhodes -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 74135446Strhodes -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 75135446Strhodes -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 76135446Strhodes -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*256*/ 77135446Strhodes}; 78135446Strhodes 79135446Strhodesstatic unsigned char maptolower[] = { 80135446Strhodes 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 81135446Strhodes 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 82135446Strhodes 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 83135446Strhodes 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 84135446Strhodes 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 85135446Strhodes 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 86135446Strhodes 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 87135446Strhodes 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 88135446Strhodes 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 89135446Strhodes 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 90135446Strhodes 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 91135446Strhodes 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 92135446Strhodes 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 93135446Strhodes 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 94135446Strhodes 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 95135446Strhodes 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 96135446Strhodes 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 97135446Strhodes 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 98135446Strhodes 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 99135446Strhodes 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 100135446Strhodes 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 101135446Strhodes 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 102135446Strhodes 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 103135446Strhodes 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 104135446Strhodes 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 105135446Strhodes 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 106135446Strhodes 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 107135446Strhodes 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 108135446Strhodes 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 109135446Strhodes 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 110135446Strhodes 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 111135446Strhodes 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff 112135446Strhodes}; 113135446Strhodes 114135446Strhodes#define CONVERTTOASCII(c) 115135446Strhodes#define CONVERTFROMASCII(c) 116135446Strhodes 117135446Strhodes#define INIT_OFFSETS(name, var, default) \ 118135446Strhodes if (name->offsets != NULL) \ 119135446Strhodes var = name->offsets; \ 120135446Strhodes else \ 121135446Strhodes var = default; 122135446Strhodes 123135446Strhodes#define SETUP_OFFSETS(name, var, default) \ 124135446Strhodes if (name->offsets != NULL) \ 125135446Strhodes var = name->offsets; \ 126135446Strhodes else { \ 127135446Strhodes var = default; \ 128135446Strhodes set_offsets(name, var, NULL); \ 129135446Strhodes } 130135446Strhodes 131170222Sdougb/*% 132135446Strhodes * Note: If additional attributes are added that should not be set for 133135446Strhodes * empty names, MAKE_EMPTY() must be changed so it clears them. 134135446Strhodes */ 135135446Strhodes#define MAKE_EMPTY(name) \ 136135446Strhodesdo { \ 137135446Strhodes name->ndata = NULL; \ 138135446Strhodes name->length = 0; \ 139135446Strhodes name->labels = 0; \ 140135446Strhodes name->attributes &= ~DNS_NAMEATTR_ABSOLUTE; \ 141135446Strhodes} while (0); 142135446Strhodes 143170222Sdougb/*% 144135446Strhodes * A name is "bindable" if it can be set to point to a new value, i.e. 145135446Strhodes * name->ndata and name->length may be changed. 146135446Strhodes */ 147135446Strhodes#define BINDABLE(name) \ 148135446Strhodes ((name->attributes & (DNS_NAMEATTR_READONLY|DNS_NAMEATTR_DYNAMIC)) \ 149135446Strhodes == 0) 150135446Strhodes 151170222Sdougb/*% 152135446Strhodes * Note that the name data must be a char array, not a string 153135446Strhodes * literal, to avoid compiler warnings about discarding 154135446Strhodes * the const attribute of a string. 155135446Strhodes */ 156135446Strhodesstatic unsigned char root_ndata[] = { '\0' }; 157135446Strhodesstatic unsigned char root_offsets[] = { 0 }; 158135446Strhodes 159193149Sdougbstatic dns_name_t root = 160135446Strhodes{ 161135446Strhodes DNS_NAME_MAGIC, 162135446Strhodes root_ndata, 1, 1, 163135446Strhodes DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE, 164135446Strhodes root_offsets, NULL, 165135446Strhodes {(void *)-1, (void *)-1}, 166135446Strhodes {NULL, NULL} 167135446Strhodes}; 168135446Strhodes 169135446Strhodes/* XXXDCL make const? */ 170135446StrhodesLIBDNS_EXTERNAL_DATA dns_name_t *dns_rootname = &root; 171135446Strhodes 172135446Strhodesstatic unsigned char wild_ndata[] = { '\001', '*' }; 173135446Strhodesstatic unsigned char wild_offsets[] = { 0 }; 174135446Strhodes 175135446Strhodesstatic dns_name_t wild = 176135446Strhodes{ 177135446Strhodes DNS_NAME_MAGIC, 178135446Strhodes wild_ndata, 2, 1, 179135446Strhodes DNS_NAMEATTR_READONLY, 180135446Strhodes wild_offsets, NULL, 181135446Strhodes {(void *)-1, (void *)-1}, 182135446Strhodes {NULL, NULL} 183135446Strhodes}; 184135446Strhodes 185135446Strhodes/* XXXDCL make const? */ 186135446StrhodesLIBDNS_EXTERNAL_DATA dns_name_t *dns_wildcardname = &wild; 187135446Strhodes 188135446Strhodesunsigned int 189135446Strhodesdns_fullname_hash(dns_name_t *name, isc_boolean_t case_sensitive); 190135446Strhodes 191170222Sdougb/* 192170222Sdougb * dns_name_t to text post-conversion procedure. 193170222Sdougb */ 194170222Sdougb#ifdef ISC_PLATFORM_USETHREADS 195170222Sdougbstatic int thread_key_initialized = 0; 196170222Sdougbstatic isc_mutex_t thread_key_mutex; 197170222Sdougbstatic isc_mem_t *thread_key_mctx = NULL; 198170222Sdougbstatic isc_thread_key_t totext_filter_proc_key; 199170222Sdougbstatic isc_once_t once = ISC_ONCE_INIT; 200170222Sdougb#else 201170222Sdougbstatic dns_name_totextfilter_t totext_filter_proc = NULL; 202170222Sdougb#endif 203170222Sdougb 204135446Strhodesstatic void 205135446Strhodesset_offsets(const dns_name_t *name, unsigned char *offsets, 206135446Strhodes dns_name_t *set_name); 207135446Strhodes 208135446Strhodesvoid 209135446Strhodesdns_name_init(dns_name_t *name, unsigned char *offsets) { 210135446Strhodes /* 211135446Strhodes * Initialize 'name'. 212135446Strhodes */ 213135446Strhodes DNS_NAME_INIT(name, offsets); 214135446Strhodes} 215135446Strhodes 216135446Strhodesvoid 217135446Strhodesdns_name_reset(dns_name_t *name) { 218135446Strhodes REQUIRE(VALID_NAME(name)); 219135446Strhodes REQUIRE(BINDABLE(name)); 220135446Strhodes 221135446Strhodes DNS_NAME_RESET(name); 222135446Strhodes} 223135446Strhodes 224135446Strhodesvoid 225135446Strhodesdns_name_invalidate(dns_name_t *name) { 226135446Strhodes /* 227135446Strhodes * Make 'name' invalid. 228135446Strhodes */ 229135446Strhodes 230135446Strhodes REQUIRE(VALID_NAME(name)); 231135446Strhodes 232135446Strhodes name->magic = 0; 233135446Strhodes name->ndata = NULL; 234135446Strhodes name->length = 0; 235135446Strhodes name->labels = 0; 236135446Strhodes name->attributes = 0; 237135446Strhodes name->offsets = NULL; 238135446Strhodes name->buffer = NULL; 239135446Strhodes ISC_LINK_INIT(name, link); 240135446Strhodes} 241135446Strhodes 242135446Strhodesvoid 243135446Strhodesdns_name_setbuffer(dns_name_t *name, isc_buffer_t *buffer) { 244135446Strhodes /* 245135446Strhodes * Dedicate a buffer for use with 'name'. 246135446Strhodes */ 247135446Strhodes 248135446Strhodes REQUIRE(VALID_NAME(name)); 249135446Strhodes REQUIRE((buffer != NULL && name->buffer == NULL) || 250135446Strhodes (buffer == NULL)); 251135446Strhodes 252135446Strhodes name->buffer = buffer; 253135446Strhodes} 254135446Strhodes 255135446Strhodesisc_boolean_t 256135446Strhodesdns_name_hasbuffer(const dns_name_t *name) { 257135446Strhodes /* 258135446Strhodes * Does 'name' have a dedicated buffer? 259135446Strhodes */ 260135446Strhodes 261135446Strhodes REQUIRE(VALID_NAME(name)); 262135446Strhodes 263135446Strhodes if (name->buffer != NULL) 264135446Strhodes return (ISC_TRUE); 265135446Strhodes 266135446Strhodes return (ISC_FALSE); 267135446Strhodes} 268135446Strhodes 269135446Strhodesisc_boolean_t 270135446Strhodesdns_name_isabsolute(const dns_name_t *name) { 271135446Strhodes 272135446Strhodes /* 273135446Strhodes * Does 'name' end in the root label? 274135446Strhodes */ 275135446Strhodes 276135446Strhodes REQUIRE(VALID_NAME(name)); 277135446Strhodes 278135446Strhodes if ((name->attributes & DNS_NAMEATTR_ABSOLUTE) != 0) 279135446Strhodes return (ISC_TRUE); 280135446Strhodes return (ISC_FALSE); 281135446Strhodes} 282135446Strhodes 283135446Strhodes#define hyphenchar(c) ((c) == 0x2d) 284135446Strhodes#define asterchar(c) ((c) == 0x2a) 285135446Strhodes#define alphachar(c) (((c) >= 0x41 && (c) <= 0x5a) \ 286135446Strhodes || ((c) >= 0x61 && (c) <= 0x7a)) 287135446Strhodes#define digitchar(c) ((c) >= 0x30 && (c) <= 0x39) 288135446Strhodes#define borderchar(c) (alphachar(c) || digitchar(c)) 289135446Strhodes#define middlechar(c) (borderchar(c) || hyphenchar(c)) 290135446Strhodes#define domainchar(c) ((c) > 0x20 && (c) < 0x7f) 291135446Strhodes 292135446Strhodesisc_boolean_t 293135446Strhodesdns_name_ismailbox(const dns_name_t *name) { 294135446Strhodes unsigned char *ndata, ch; 295135446Strhodes unsigned int n; 296135446Strhodes isc_boolean_t first; 297135446Strhodes 298135446Strhodes REQUIRE(VALID_NAME(name)); 299135446Strhodes REQUIRE(name->labels > 0); 300135446Strhodes REQUIRE(name->attributes & DNS_NAMEATTR_ABSOLUTE); 301135446Strhodes 302193149Sdougb /* 303135446Strhodes * Root label. 304135446Strhodes */ 305135446Strhodes if (name->length == 1) 306135446Strhodes return (ISC_TRUE); 307135446Strhodes 308135446Strhodes ndata = name->ndata; 309135446Strhodes n = *ndata++; 310135446Strhodes INSIST(n <= 63); 311135446Strhodes while (n--) { 312135446Strhodes ch = *ndata++; 313135446Strhodes if (!domainchar(ch)) 314135446Strhodes return (ISC_FALSE); 315135446Strhodes } 316193149Sdougb 317135446Strhodes if (ndata == name->ndata + name->length) 318135446Strhodes return (ISC_FALSE); 319135446Strhodes 320135446Strhodes /* 321135446Strhodes * RFC292/RFC1123 hostname. 322135446Strhodes */ 323135446Strhodes while (ndata < (name->ndata + name->length)) { 324135446Strhodes n = *ndata++; 325135446Strhodes INSIST(n <= 63); 326135446Strhodes first = ISC_TRUE; 327135446Strhodes while (n--) { 328135446Strhodes ch = *ndata++; 329135446Strhodes if (first || n == 0) { 330135446Strhodes if (!borderchar(ch)) 331135446Strhodes return (ISC_FALSE); 332135446Strhodes } else { 333135446Strhodes if (!middlechar(ch)) 334135446Strhodes return (ISC_FALSE); 335135446Strhodes } 336135446Strhodes first = ISC_FALSE; 337135446Strhodes } 338135446Strhodes } 339135446Strhodes return (ISC_TRUE); 340135446Strhodes} 341135446Strhodes 342135446Strhodesisc_boolean_t 343135446Strhodesdns_name_ishostname(const dns_name_t *name, isc_boolean_t wildcard) { 344135446Strhodes unsigned char *ndata, ch; 345135446Strhodes unsigned int n; 346135446Strhodes isc_boolean_t first; 347135446Strhodes 348135446Strhodes REQUIRE(VALID_NAME(name)); 349135446Strhodes REQUIRE(name->labels > 0); 350135446Strhodes REQUIRE(name->attributes & DNS_NAMEATTR_ABSOLUTE); 351193149Sdougb 352193149Sdougb /* 353135446Strhodes * Root label. 354135446Strhodes */ 355135446Strhodes if (name->length == 1) 356135446Strhodes return (ISC_TRUE); 357135446Strhodes 358135446Strhodes /* 359135446Strhodes * Skip wildcard if this is a ownername. 360135446Strhodes */ 361135446Strhodes ndata = name->ndata; 362135446Strhodes if (wildcard && ndata[0] == 1 && ndata[1] == '*') 363135446Strhodes ndata += 2; 364135446Strhodes 365135446Strhodes /* 366135446Strhodes * RFC292/RFC1123 hostname. 367135446Strhodes */ 368135446Strhodes while (ndata < (name->ndata + name->length)) { 369135446Strhodes n = *ndata++; 370135446Strhodes INSIST(n <= 63); 371135446Strhodes first = ISC_TRUE; 372135446Strhodes while (n--) { 373135446Strhodes ch = *ndata++; 374135446Strhodes if (first || n == 0) { 375135446Strhodes if (!borderchar(ch)) 376135446Strhodes return (ISC_FALSE); 377135446Strhodes } else { 378135446Strhodes if (!middlechar(ch)) 379135446Strhodes return (ISC_FALSE); 380135446Strhodes } 381135446Strhodes first = ISC_FALSE; 382135446Strhodes } 383135446Strhodes } 384135446Strhodes return (ISC_TRUE); 385135446Strhodes} 386135446Strhodes 387135446Strhodesisc_boolean_t 388135446Strhodesdns_name_iswildcard(const dns_name_t *name) { 389135446Strhodes unsigned char *ndata; 390135446Strhodes 391135446Strhodes /* 392135446Strhodes * Is 'name' a wildcard name? 393135446Strhodes */ 394135446Strhodes 395135446Strhodes REQUIRE(VALID_NAME(name)); 396135446Strhodes REQUIRE(name->labels > 0); 397135446Strhodes 398135446Strhodes if (name->length >= 2) { 399135446Strhodes ndata = name->ndata; 400135446Strhodes if (ndata[0] == 1 && ndata[1] == '*') 401135446Strhodes return (ISC_TRUE); 402135446Strhodes } 403135446Strhodes 404135446Strhodes return (ISC_FALSE); 405135446Strhodes} 406135446Strhodes 407170222Sdougbisc_boolean_t 408170222Sdougbdns_name_internalwildcard(const dns_name_t *name) { 409170222Sdougb unsigned char *ndata; 410170222Sdougb unsigned int count; 411170222Sdougb unsigned int label; 412170222Sdougb 413170222Sdougb /* 414170222Sdougb * Does 'name' contain a internal wildcard? 415170222Sdougb */ 416170222Sdougb 417170222Sdougb REQUIRE(VALID_NAME(name)); 418170222Sdougb REQUIRE(name->labels > 0); 419170222Sdougb 420170222Sdougb /* 421170222Sdougb * Skip first label. 422170222Sdougb */ 423170222Sdougb ndata = name->ndata; 424170222Sdougb count = *ndata++; 425170222Sdougb INSIST(count <= 63); 426170222Sdougb ndata += count; 427170222Sdougb label = 1; 428170222Sdougb /* 429170222Sdougb * Check all but the last of the remaining labels. 430170222Sdougb */ 431170222Sdougb while (label + 1 < name->labels) { 432170222Sdougb count = *ndata++; 433170222Sdougb INSIST(count <= 63); 434170222Sdougb if (count == 1 && *ndata == '*') 435170222Sdougb return (ISC_TRUE); 436170222Sdougb ndata += count; 437170222Sdougb label++; 438170222Sdougb } 439170222Sdougb return (ISC_FALSE); 440170222Sdougb} 441170222Sdougb 442135446Strhodesstatic inline unsigned int 443135446Strhodesname_hash(dns_name_t *name, isc_boolean_t case_sensitive) { 444135446Strhodes unsigned int length; 445135446Strhodes const unsigned char *s; 446135446Strhodes unsigned int h = 0; 447135446Strhodes unsigned char c; 448135446Strhodes 449135446Strhodes length = name->length; 450135446Strhodes if (length > 16) 451135446Strhodes length = 16; 452135446Strhodes 453135446Strhodes /* 454135446Strhodes * This hash function is similar to the one Ousterhout 455135446Strhodes * uses in Tcl. 456135446Strhodes */ 457135446Strhodes s = name->ndata; 458135446Strhodes if (case_sensitive) { 459135446Strhodes while (length > 0) { 460135446Strhodes h += ( h << 3 ) + *s; 461135446Strhodes s++; 462135446Strhodes length--; 463135446Strhodes } 464135446Strhodes } else { 465135446Strhodes while (length > 0) { 466135446Strhodes c = maptolower[*s]; 467135446Strhodes h += ( h << 3 ) + c; 468135446Strhodes s++; 469135446Strhodes length--; 470135446Strhodes } 471135446Strhodes } 472135446Strhodes 473135446Strhodes return (h); 474135446Strhodes} 475135446Strhodes 476135446Strhodesunsigned int 477135446Strhodesdns_name_hash(dns_name_t *name, isc_boolean_t case_sensitive) { 478135446Strhodes /* 479135446Strhodes * Provide a hash value for 'name'. 480135446Strhodes */ 481135446Strhodes REQUIRE(VALID_NAME(name)); 482135446Strhodes 483135446Strhodes if (name->labels == 0) 484135446Strhodes return (0); 485135446Strhodes 486135446Strhodes return (name_hash(name, case_sensitive)); 487135446Strhodes} 488135446Strhodes 489135446Strhodesunsigned int 490135446Strhodesdns_name_fullhash(dns_name_t *name, isc_boolean_t case_sensitive) { 491135446Strhodes /* 492135446Strhodes * Provide a hash value for 'name'. 493135446Strhodes */ 494135446Strhodes REQUIRE(VALID_NAME(name)); 495135446Strhodes 496135446Strhodes if (name->labels == 0) 497135446Strhodes return (0); 498135446Strhodes 499135446Strhodes return (isc_hash_calc((const unsigned char *)name->ndata, 500135446Strhodes name->length, case_sensitive)); 501135446Strhodes} 502135446Strhodes 503135446Strhodesunsigned int 504135446Strhodesdns_fullname_hash(dns_name_t *name, isc_boolean_t case_sensitive) { 505135446Strhodes /* 506135446Strhodes * This function was deprecated due to the breakage of the name space 507135446Strhodes * convention. We only keep this internally to provide binary backward 508135446Strhodes * compatibility. 509135446Strhodes */ 510135446Strhodes REQUIRE(VALID_NAME(name)); 511135446Strhodes 512135446Strhodes return (dns_name_fullhash(name, case_sensitive)); 513135446Strhodes} 514135446Strhodes 515135446Strhodesunsigned int 516135446Strhodesdns_name_hashbylabel(dns_name_t *name, isc_boolean_t case_sensitive) { 517135446Strhodes unsigned char *offsets; 518135446Strhodes dns_offsets_t odata; 519135446Strhodes dns_name_t tname; 520135446Strhodes unsigned int h = 0; 521135446Strhodes unsigned int i; 522135446Strhodes 523135446Strhodes /* 524135446Strhodes * Provide a hash value for 'name'. 525135446Strhodes */ 526135446Strhodes REQUIRE(VALID_NAME(name)); 527135446Strhodes 528135446Strhodes if (name->labels == 0) 529135446Strhodes return (0); 530135446Strhodes else if (name->labels == 1) 531135446Strhodes return (name_hash(name, case_sensitive)); 532135446Strhodes 533135446Strhodes SETUP_OFFSETS(name, offsets, odata); 534135446Strhodes DNS_NAME_INIT(&tname, NULL); 535135446Strhodes tname.labels = 1; 536135446Strhodes h = 0; 537135446Strhodes for (i = 0; i < name->labels; i++) { 538135446Strhodes tname.ndata = name->ndata + offsets[i]; 539135446Strhodes if (i == name->labels - 1) 540135446Strhodes tname.length = name->length - offsets[i]; 541135446Strhodes else 542135446Strhodes tname.length = offsets[i + 1] - offsets[i]; 543135446Strhodes h += name_hash(&tname, case_sensitive); 544135446Strhodes } 545135446Strhodes 546135446Strhodes return (h); 547135446Strhodes} 548135446Strhodes 549135446Strhodesdns_namereln_t 550135446Strhodesdns_name_fullcompare(const dns_name_t *name1, const dns_name_t *name2, 551135446Strhodes int *orderp, unsigned int *nlabelsp) 552135446Strhodes{ 553135446Strhodes unsigned int l1, l2, l, count1, count2, count, nlabels; 554135446Strhodes int cdiff, ldiff, chdiff; 555135446Strhodes unsigned char *label1, *label2; 556135446Strhodes unsigned char *offsets1, *offsets2; 557135446Strhodes dns_offsets_t odata1, odata2; 558135446Strhodes dns_namereln_t namereln = dns_namereln_none; 559135446Strhodes 560135446Strhodes /* 561135446Strhodes * Determine the relative ordering under the DNSSEC order relation of 562135446Strhodes * 'name1' and 'name2', and also determine the hierarchical 563135446Strhodes * relationship of the names. 564135446Strhodes * 565135446Strhodes * Note: It makes no sense for one of the names to be relative and the 566135446Strhodes * other absolute. If both names are relative, then to be meaningfully 567135446Strhodes * compared the caller must ensure that they are both relative to the 568135446Strhodes * same domain. 569135446Strhodes */ 570135446Strhodes 571135446Strhodes REQUIRE(VALID_NAME(name1)); 572135446Strhodes REQUIRE(VALID_NAME(name2)); 573135446Strhodes REQUIRE(orderp != NULL); 574135446Strhodes REQUIRE(nlabelsp != NULL); 575135446Strhodes /* 576135446Strhodes * Either name1 is absolute and name2 is absolute, or neither is. 577135446Strhodes */ 578135446Strhodes REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) == 579135446Strhodes (name2->attributes & DNS_NAMEATTR_ABSOLUTE)); 580135446Strhodes 581135446Strhodes SETUP_OFFSETS(name1, offsets1, odata1); 582135446Strhodes SETUP_OFFSETS(name2, offsets2, odata2); 583135446Strhodes 584135446Strhodes nlabels = 0; 585135446Strhodes l1 = name1->labels; 586135446Strhodes l2 = name2->labels; 587135446Strhodes ldiff = (int)l1 - (int)l2; 588135446Strhodes if (ldiff < 0) 589135446Strhodes l = l1; 590135446Strhodes else 591135446Strhodes l = l2; 592135446Strhodes 593135446Strhodes while (l > 0) { 594135446Strhodes l--; 595135446Strhodes l1--; 596135446Strhodes l2--; 597135446Strhodes label1 = &name1->ndata[offsets1[l1]]; 598135446Strhodes label2 = &name2->ndata[offsets2[l2]]; 599135446Strhodes count1 = *label1++; 600135446Strhodes count2 = *label2++; 601135446Strhodes 602135446Strhodes /* 603135446Strhodes * We dropped bitstring labels, and we don't support any 604135446Strhodes * other extended label types. 605135446Strhodes */ 606135446Strhodes INSIST(count1 <= 63 && count2 <= 63); 607135446Strhodes 608135446Strhodes cdiff = (int)count1 - (int)count2; 609135446Strhodes if (cdiff < 0) 610135446Strhodes count = count1; 611135446Strhodes else 612135446Strhodes count = count2; 613135446Strhodes 614135446Strhodes while (count > 0) { 615135446Strhodes chdiff = (int)maptolower[*label1] - 616135446Strhodes (int)maptolower[*label2]; 617135446Strhodes if (chdiff != 0) { 618135446Strhodes *orderp = chdiff; 619135446Strhodes goto done; 620135446Strhodes } 621135446Strhodes count--; 622135446Strhodes label1++; 623135446Strhodes label2++; 624135446Strhodes } 625135446Strhodes if (cdiff != 0) { 626135446Strhodes *orderp = cdiff; 627135446Strhodes goto done; 628135446Strhodes } 629135446Strhodes nlabels++; 630135446Strhodes } 631135446Strhodes 632135446Strhodes *orderp = ldiff; 633135446Strhodes if (ldiff < 0) 634135446Strhodes namereln = dns_namereln_contains; 635135446Strhodes else if (ldiff > 0) 636135446Strhodes namereln = dns_namereln_subdomain; 637135446Strhodes else 638135446Strhodes namereln = dns_namereln_equal; 639135446Strhodes 640135446Strhodes done: 641135446Strhodes *nlabelsp = nlabels; 642135446Strhodes 643135446Strhodes if (nlabels > 0 && namereln == dns_namereln_none) 644135446Strhodes namereln = dns_namereln_commonancestor; 645135446Strhodes 646135446Strhodes return (namereln); 647135446Strhodes} 648135446Strhodes 649135446Strhodesint 650135446Strhodesdns_name_compare(const dns_name_t *name1, const dns_name_t *name2) { 651135446Strhodes int order; 652135446Strhodes unsigned int nlabels; 653135446Strhodes 654135446Strhodes /* 655135446Strhodes * Determine the relative ordering under the DNSSEC order relation of 656135446Strhodes * 'name1' and 'name2'. 657135446Strhodes * 658135446Strhodes * Note: It makes no sense for one of the names to be relative and the 659135446Strhodes * other absolute. If both names are relative, then to be meaningfully 660135446Strhodes * compared the caller must ensure that they are both relative to the 661135446Strhodes * same domain. 662135446Strhodes */ 663135446Strhodes 664135446Strhodes (void)dns_name_fullcompare(name1, name2, &order, &nlabels); 665135446Strhodes 666135446Strhodes return (order); 667135446Strhodes} 668135446Strhodes 669135446Strhodesisc_boolean_t 670135446Strhodesdns_name_equal(const dns_name_t *name1, const dns_name_t *name2) { 671135446Strhodes unsigned int l, count; 672135446Strhodes unsigned char c; 673135446Strhodes unsigned char *label1, *label2; 674135446Strhodes 675135446Strhodes /* 676135446Strhodes * Are 'name1' and 'name2' equal? 677135446Strhodes * 678135446Strhodes * Note: It makes no sense for one of the names to be relative and the 679135446Strhodes * other absolute. If both names are relative, then to be meaningfully 680135446Strhodes * compared the caller must ensure that they are both relative to the 681135446Strhodes * same domain. 682135446Strhodes */ 683135446Strhodes 684135446Strhodes REQUIRE(VALID_NAME(name1)); 685135446Strhodes REQUIRE(VALID_NAME(name2)); 686135446Strhodes /* 687135446Strhodes * Either name1 is absolute and name2 is absolute, or neither is. 688135446Strhodes */ 689135446Strhodes REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) == 690135446Strhodes (name2->attributes & DNS_NAMEATTR_ABSOLUTE)); 691135446Strhodes 692135446Strhodes if (name1->length != name2->length) 693135446Strhodes return (ISC_FALSE); 694135446Strhodes 695135446Strhodes l = name1->labels; 696135446Strhodes 697135446Strhodes if (l != name2->labels) 698135446Strhodes return (ISC_FALSE); 699135446Strhodes 700135446Strhodes label1 = name1->ndata; 701135446Strhodes label2 = name2->ndata; 702135446Strhodes while (l > 0) { 703135446Strhodes l--; 704135446Strhodes count = *label1++; 705135446Strhodes if (count != *label2++) 706135446Strhodes return (ISC_FALSE); 707135446Strhodes 708135446Strhodes INSIST(count <= 63); /* no bitstring support */ 709135446Strhodes 710135446Strhodes while (count > 0) { 711135446Strhodes count--; 712135446Strhodes c = maptolower[*label1++]; 713135446Strhodes if (c != maptolower[*label2++]) 714135446Strhodes return (ISC_FALSE); 715135446Strhodes } 716135446Strhodes } 717135446Strhodes 718135446Strhodes return (ISC_TRUE); 719135446Strhodes} 720135446Strhodes 721170222Sdougbisc_boolean_t 722170222Sdougbdns_name_caseequal(const dns_name_t *name1, const dns_name_t *name2) { 723170222Sdougb 724170222Sdougb /* 725170222Sdougb * Are 'name1' and 'name2' equal? 726170222Sdougb * 727170222Sdougb * Note: It makes no sense for one of the names to be relative and the 728170222Sdougb * other absolute. If both names are relative, then to be meaningfully 729170222Sdougb * compared the caller must ensure that they are both relative to the 730170222Sdougb * same domain. 731170222Sdougb */ 732170222Sdougb 733170222Sdougb REQUIRE(VALID_NAME(name1)); 734170222Sdougb REQUIRE(VALID_NAME(name2)); 735170222Sdougb /* 736170222Sdougb * Either name1 is absolute and name2 is absolute, or neither is. 737170222Sdougb */ 738170222Sdougb REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) == 739170222Sdougb (name2->attributes & DNS_NAMEATTR_ABSOLUTE)); 740170222Sdougb 741170222Sdougb if (name1->length != name2->length) 742170222Sdougb return (ISC_FALSE); 743170222Sdougb 744170222Sdougb if (memcmp(name1->ndata, name2->ndata, name1->length) != 0) 745170222Sdougb return (ISC_FALSE); 746170222Sdougb 747170222Sdougb return (ISC_TRUE); 748170222Sdougb} 749170222Sdougb 750135446Strhodesint 751135446Strhodesdns_name_rdatacompare(const dns_name_t *name1, const dns_name_t *name2) { 752135446Strhodes unsigned int l1, l2, l, count1, count2, count; 753135446Strhodes unsigned char c1, c2; 754135446Strhodes unsigned char *label1, *label2; 755135446Strhodes 756135446Strhodes /* 757135446Strhodes * Compare two absolute names as rdata. 758135446Strhodes */ 759135446Strhodes 760135446Strhodes REQUIRE(VALID_NAME(name1)); 761135446Strhodes REQUIRE(name1->labels > 0); 762135446Strhodes REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) != 0); 763135446Strhodes REQUIRE(VALID_NAME(name2)); 764135446Strhodes REQUIRE(name2->labels > 0); 765135446Strhodes REQUIRE((name2->attributes & DNS_NAMEATTR_ABSOLUTE) != 0); 766135446Strhodes 767135446Strhodes l1 = name1->labels; 768135446Strhodes l2 = name2->labels; 769135446Strhodes 770135446Strhodes l = (l1 < l2) ? l1 : l2; 771135446Strhodes 772135446Strhodes label1 = name1->ndata; 773135446Strhodes label2 = name2->ndata; 774135446Strhodes while (l > 0) { 775135446Strhodes l--; 776135446Strhodes count1 = *label1++; 777135446Strhodes count2 = *label2++; 778135446Strhodes 779135446Strhodes /* no bitstring support */ 780135446Strhodes INSIST(count1 <= 63 && count2 <= 63); 781135446Strhodes 782135446Strhodes if (count1 != count2) 783135446Strhodes return ((count1 < count2) ? -1 : 1); 784135446Strhodes count = count1; 785135446Strhodes while (count > 0) { 786135446Strhodes count--; 787135446Strhodes c1 = maptolower[*label1++]; 788135446Strhodes c2 = maptolower[*label2++]; 789135446Strhodes if (c1 < c2) 790135446Strhodes return (-1); 791135446Strhodes else if (c1 > c2) 792135446Strhodes return (1); 793135446Strhodes } 794135446Strhodes } 795135446Strhodes 796135446Strhodes /* 797135446Strhodes * If one name had more labels than the other, their common 798135446Strhodes * prefix must have been different because the shorter name 799135446Strhodes * ended with the root label and the longer one can't have 800135446Strhodes * a root label in the middle of it. Therefore, if we get 801135446Strhodes * to this point, the lengths must be equal. 802135446Strhodes */ 803135446Strhodes INSIST(l1 == l2); 804135446Strhodes 805135446Strhodes return (0); 806135446Strhodes} 807135446Strhodes 808135446Strhodesisc_boolean_t 809135446Strhodesdns_name_issubdomain(const dns_name_t *name1, const dns_name_t *name2) { 810135446Strhodes int order; 811135446Strhodes unsigned int nlabels; 812135446Strhodes dns_namereln_t namereln; 813135446Strhodes 814135446Strhodes /* 815135446Strhodes * Is 'name1' a subdomain of 'name2'? 816135446Strhodes * 817135446Strhodes * Note: It makes no sense for one of the names to be relative and the 818135446Strhodes * other absolute. If both names are relative, then to be meaningfully 819135446Strhodes * compared the caller must ensure that they are both relative to the 820135446Strhodes * same domain. 821135446Strhodes */ 822135446Strhodes 823135446Strhodes namereln = dns_name_fullcompare(name1, name2, &order, &nlabels); 824135446Strhodes if (namereln == dns_namereln_subdomain || 825135446Strhodes namereln == dns_namereln_equal) 826135446Strhodes return (ISC_TRUE); 827135446Strhodes 828135446Strhodes return (ISC_FALSE); 829135446Strhodes} 830135446Strhodes 831135446Strhodesisc_boolean_t 832135446Strhodesdns_name_matcheswildcard(const dns_name_t *name, const dns_name_t *wname) { 833135446Strhodes int order; 834135446Strhodes unsigned int nlabels, labels; 835135446Strhodes dns_name_t tname; 836135446Strhodes 837135446Strhodes REQUIRE(VALID_NAME(name)); 838135446Strhodes REQUIRE(name->labels > 0); 839135446Strhodes REQUIRE(VALID_NAME(wname)); 840135446Strhodes labels = wname->labels; 841135446Strhodes REQUIRE(labels > 0); 842135446Strhodes REQUIRE(dns_name_iswildcard(wname)); 843135446Strhodes 844135446Strhodes DNS_NAME_INIT(&tname, NULL); 845135446Strhodes dns_name_getlabelsequence(wname, 1, labels - 1, &tname); 846135446Strhodes if (dns_name_fullcompare(name, &tname, &order, &nlabels) == 847135446Strhodes dns_namereln_subdomain) 848135446Strhodes return (ISC_TRUE); 849135446Strhodes return (ISC_FALSE); 850135446Strhodes} 851135446Strhodes 852135446Strhodesunsigned int 853135446Strhodesdns_name_countlabels(const dns_name_t *name) { 854135446Strhodes /* 855135446Strhodes * How many labels does 'name' have? 856135446Strhodes */ 857135446Strhodes 858135446Strhodes REQUIRE(VALID_NAME(name)); 859135446Strhodes 860135446Strhodes ENSURE(name->labels <= 128); 861135446Strhodes 862135446Strhodes return (name->labels); 863135446Strhodes} 864135446Strhodes 865135446Strhodesvoid 866135446Strhodesdns_name_getlabel(const dns_name_t *name, unsigned int n, dns_label_t *label) { 867135446Strhodes unsigned char *offsets; 868135446Strhodes dns_offsets_t odata; 869135446Strhodes 870135446Strhodes /* 871135446Strhodes * Make 'label' refer to the 'n'th least significant label of 'name'. 872135446Strhodes */ 873135446Strhodes 874135446Strhodes REQUIRE(VALID_NAME(name)); 875135446Strhodes REQUIRE(name->labels > 0); 876135446Strhodes REQUIRE(n < name->labels); 877135446Strhodes REQUIRE(label != NULL); 878135446Strhodes 879135446Strhodes SETUP_OFFSETS(name, offsets, odata); 880135446Strhodes 881135446Strhodes label->base = &name->ndata[offsets[n]]; 882135446Strhodes if (n == name->labels - 1) 883135446Strhodes label->length = name->length - offsets[n]; 884135446Strhodes else 885135446Strhodes label->length = offsets[n + 1] - offsets[n]; 886135446Strhodes} 887135446Strhodes 888135446Strhodesvoid 889135446Strhodesdns_name_getlabelsequence(const dns_name_t *source, 890135446Strhodes unsigned int first, unsigned int n, 891135446Strhodes dns_name_t *target) 892135446Strhodes{ 893135446Strhodes unsigned char *offsets; 894135446Strhodes dns_offsets_t odata; 895135446Strhodes unsigned int firstoffset, endoffset; 896135446Strhodes 897135446Strhodes /* 898135446Strhodes * Make 'target' refer to the 'n' labels including and following 899135446Strhodes * 'first' in 'source'. 900135446Strhodes */ 901135446Strhodes 902135446Strhodes REQUIRE(VALID_NAME(source)); 903135446Strhodes REQUIRE(VALID_NAME(target)); 904135446Strhodes REQUIRE(first <= source->labels); 905218384Sdougb REQUIRE(n <= source->labels - first); /* note first+n could overflow */ 906135446Strhodes REQUIRE(BINDABLE(target)); 907135446Strhodes 908135446Strhodes SETUP_OFFSETS(source, offsets, odata); 909135446Strhodes 910135446Strhodes if (first == source->labels) 911135446Strhodes firstoffset = source->length; 912135446Strhodes else 913135446Strhodes firstoffset = offsets[first]; 914135446Strhodes 915135446Strhodes if (first + n == source->labels) 916135446Strhodes endoffset = source->length; 917135446Strhodes else 918135446Strhodes endoffset = offsets[first + n]; 919135446Strhodes 920135446Strhodes target->ndata = &source->ndata[firstoffset]; 921135446Strhodes target->length = endoffset - firstoffset; 922193149Sdougb 923135446Strhodes if (first + n == source->labels && n > 0 && 924135446Strhodes (source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0) 925135446Strhodes target->attributes |= DNS_NAMEATTR_ABSOLUTE; 926135446Strhodes else 927135446Strhodes target->attributes &= ~DNS_NAMEATTR_ABSOLUTE; 928135446Strhodes 929135446Strhodes target->labels = n; 930135446Strhodes 931135446Strhodes /* 932135446Strhodes * If source and target are the same, and we're making target 933135446Strhodes * a prefix of source, the offsets table is correct already 934135446Strhodes * so we don't need to call set_offsets(). 935135446Strhodes */ 936135446Strhodes if (target->offsets != NULL && 937135446Strhodes (target != source || first != 0)) 938135446Strhodes set_offsets(target, target->offsets, NULL); 939135446Strhodes} 940135446Strhodes 941135446Strhodesvoid 942165071Sdougbdns_name_clone(const dns_name_t *source, dns_name_t *target) { 943135446Strhodes 944135446Strhodes /* 945135446Strhodes * Make 'target' refer to the same name as 'source'. 946135446Strhodes */ 947135446Strhodes 948135446Strhodes REQUIRE(VALID_NAME(source)); 949135446Strhodes REQUIRE(VALID_NAME(target)); 950135446Strhodes REQUIRE(BINDABLE(target)); 951135446Strhodes 952135446Strhodes target->ndata = source->ndata; 953135446Strhodes target->length = source->length; 954135446Strhodes target->labels = source->labels; 955135446Strhodes target->attributes = source->attributes & 956135446Strhodes (unsigned int)~(DNS_NAMEATTR_READONLY | DNS_NAMEATTR_DYNAMIC | 957135446Strhodes DNS_NAMEATTR_DYNOFFSETS); 958135446Strhodes if (target->offsets != NULL && source->labels > 0) { 959135446Strhodes if (source->offsets != NULL) 960135446Strhodes memcpy(target->offsets, source->offsets, 961135446Strhodes source->labels); 962135446Strhodes else 963135446Strhodes set_offsets(target, target->offsets, NULL); 964135446Strhodes } 965135446Strhodes} 966135446Strhodes 967135446Strhodesvoid 968135446Strhodesdns_name_fromregion(dns_name_t *name, const isc_region_t *r) { 969135446Strhodes unsigned char *offsets; 970135446Strhodes dns_offsets_t odata; 971135446Strhodes unsigned int len; 972135446Strhodes isc_region_t r2; 973135446Strhodes 974135446Strhodes /* 975135446Strhodes * Make 'name' refer to region 'r'. 976135446Strhodes */ 977135446Strhodes 978135446Strhodes REQUIRE(VALID_NAME(name)); 979135446Strhodes REQUIRE(r != NULL); 980135446Strhodes REQUIRE(BINDABLE(name)); 981135446Strhodes 982135446Strhodes INIT_OFFSETS(name, offsets, odata); 983135446Strhodes 984135446Strhodes if (name->buffer != NULL) { 985135446Strhodes isc_buffer_clear(name->buffer); 986135446Strhodes isc_buffer_availableregion(name->buffer, &r2); 987135446Strhodes len = (r->length < r2.length) ? r->length : r2.length; 988135446Strhodes if (len > DNS_NAME_MAXWIRE) 989135446Strhodes len = DNS_NAME_MAXWIRE; 990135446Strhodes memcpy(r2.base, r->base, len); 991135446Strhodes name->ndata = r2.base; 992135446Strhodes name->length = len; 993135446Strhodes } else { 994135446Strhodes name->ndata = r->base; 995193149Sdougb name->length = (r->length <= DNS_NAME_MAXWIRE) ? 996135446Strhodes r->length : DNS_NAME_MAXWIRE; 997135446Strhodes } 998135446Strhodes 999135446Strhodes if (r->length > 0) 1000135446Strhodes set_offsets(name, offsets, name); 1001135446Strhodes else { 1002135446Strhodes name->labels = 0; 1003135446Strhodes name->attributes &= ~DNS_NAMEATTR_ABSOLUTE; 1004135446Strhodes } 1005135446Strhodes 1006135446Strhodes if (name->buffer != NULL) 1007135446Strhodes isc_buffer_add(name->buffer, name->length); 1008135446Strhodes} 1009135446Strhodes 1010135446Strhodesvoid 1011135446Strhodesdns_name_toregion(dns_name_t *name, isc_region_t *r) { 1012135446Strhodes /* 1013135446Strhodes * Make 'r' refer to 'name'. 1014135446Strhodes */ 1015135446Strhodes 1016135446Strhodes REQUIRE(VALID_NAME(name)); 1017135446Strhodes REQUIRE(r != NULL); 1018135446Strhodes 1019135446Strhodes DNS_NAME_TOREGION(name, r); 1020135446Strhodes} 1021135446Strhodes 1022135446Strhodesisc_result_t 1023135446Strhodesdns_name_fromtext(dns_name_t *name, isc_buffer_t *source, 1024224092Sdougb const dns_name_t *origin, unsigned int options, 1025135446Strhodes isc_buffer_t *target) 1026135446Strhodes{ 1027135446Strhodes unsigned char *ndata, *label; 1028135446Strhodes char *tdata; 1029135446Strhodes char c; 1030153816Sdougb ft_state state; 1031153816Sdougb unsigned int value, count; 1032153816Sdougb unsigned int n1, n2, tlen, nrem, nused, digits, labels, tused; 1033135446Strhodes isc_boolean_t done; 1034135446Strhodes unsigned char *offsets; 1035135446Strhodes dns_offsets_t odata; 1036135446Strhodes isc_boolean_t downcase; 1037135446Strhodes 1038135446Strhodes /* 1039135446Strhodes * Convert the textual representation of a DNS name at source 1040135446Strhodes * into uncompressed wire form stored in target. 1041135446Strhodes * 1042135446Strhodes * Notes: 1043135446Strhodes * Relative domain names will have 'origin' appended to them 1044135446Strhodes * unless 'origin' is NULL, in which case relative domain names 1045135446Strhodes * will remain relative. 1046135446Strhodes */ 1047135446Strhodes 1048135446Strhodes REQUIRE(VALID_NAME(name)); 1049135446Strhodes REQUIRE(ISC_BUFFER_VALID(source)); 1050135446Strhodes REQUIRE((target != NULL && ISC_BUFFER_VALID(target)) || 1051135446Strhodes (target == NULL && ISC_BUFFER_VALID(name->buffer))); 1052193149Sdougb 1053135446Strhodes downcase = ISC_TF((options & DNS_NAME_DOWNCASE) != 0); 1054135446Strhodes 1055135446Strhodes if (target == NULL && name->buffer != NULL) { 1056135446Strhodes target = name->buffer; 1057135446Strhodes isc_buffer_clear(target); 1058135446Strhodes } 1059135446Strhodes 1060135446Strhodes REQUIRE(BINDABLE(name)); 1061135446Strhodes 1062135446Strhodes INIT_OFFSETS(name, offsets, odata); 1063135446Strhodes offsets[0] = 0; 1064135446Strhodes 1065135446Strhodes /* 1066135446Strhodes * Initialize things to make the compiler happy; they're not required. 1067135446Strhodes */ 1068135446Strhodes n1 = 0; 1069135446Strhodes n2 = 0; 1070135446Strhodes label = NULL; 1071135446Strhodes digits = 0; 1072135446Strhodes value = 0; 1073135446Strhodes count = 0; 1074135446Strhodes 1075135446Strhodes /* 1076135446Strhodes * Make 'name' empty in case of failure. 1077135446Strhodes */ 1078135446Strhodes MAKE_EMPTY(name); 1079135446Strhodes 1080135446Strhodes /* 1081135446Strhodes * Set up the state machine. 1082135446Strhodes */ 1083135446Strhodes tdata = (char *)source->base + source->current; 1084135446Strhodes tlen = isc_buffer_remaininglength(source); 1085135446Strhodes tused = 0; 1086135446Strhodes ndata = isc_buffer_used(target); 1087135446Strhodes nrem = isc_buffer_availablelength(target); 1088135446Strhodes if (nrem > 255) 1089135446Strhodes nrem = 255; 1090135446Strhodes nused = 0; 1091135446Strhodes labels = 0; 1092135446Strhodes done = ISC_FALSE; 1093135446Strhodes state = ft_init; 1094135446Strhodes 1095135446Strhodes while (nrem > 0 && tlen > 0 && !done) { 1096135446Strhodes c = *tdata++; 1097135446Strhodes tlen--; 1098135446Strhodes tused++; 1099135446Strhodes 1100135446Strhodes switch (state) { 1101135446Strhodes case ft_init: 1102135446Strhodes /* 1103135446Strhodes * Is this the root name? 1104135446Strhodes */ 1105135446Strhodes if (c == '.') { 1106135446Strhodes if (tlen != 0) 1107135446Strhodes return (DNS_R_EMPTYLABEL); 1108135446Strhodes labels++; 1109135446Strhodes *ndata++ = 0; 1110135446Strhodes nrem--; 1111135446Strhodes nused++; 1112135446Strhodes done = ISC_TRUE; 1113135446Strhodes break; 1114135446Strhodes } 1115135446Strhodes if (c == '@' && tlen == 0) { 1116135446Strhodes state = ft_at; 1117135446Strhodes break; 1118135446Strhodes } 1119135446Strhodes 1120135446Strhodes /* FALLTHROUGH */ 1121135446Strhodes case ft_start: 1122135446Strhodes label = ndata; 1123135446Strhodes ndata++; 1124135446Strhodes nrem--; 1125135446Strhodes nused++; 1126135446Strhodes count = 0; 1127135446Strhodes if (c == '\\') { 1128135446Strhodes state = ft_initialescape; 1129135446Strhodes break; 1130135446Strhodes } 1131135446Strhodes state = ft_ordinary; 1132135446Strhodes if (nrem == 0) 1133135446Strhodes return (ISC_R_NOSPACE); 1134135446Strhodes /* FALLTHROUGH */ 1135135446Strhodes case ft_ordinary: 1136135446Strhodes if (c == '.') { 1137135446Strhodes if (count == 0) 1138135446Strhodes return (DNS_R_EMPTYLABEL); 1139135446Strhodes *label = count; 1140135446Strhodes labels++; 1141135446Strhodes INSIST(labels <= 127); 1142135446Strhodes offsets[labels] = nused; 1143135446Strhodes if (tlen == 0) { 1144135446Strhodes labels++; 1145135446Strhodes *ndata++ = 0; 1146135446Strhodes nrem--; 1147135446Strhodes nused++; 1148135446Strhodes done = ISC_TRUE; 1149135446Strhodes } 1150135446Strhodes state = ft_start; 1151135446Strhodes } else if (c == '\\') { 1152135446Strhodes state = ft_escape; 1153135446Strhodes } else { 1154135446Strhodes if (count >= 63) 1155135446Strhodes return (DNS_R_LABELTOOLONG); 1156135446Strhodes count++; 1157135446Strhodes CONVERTTOASCII(c); 1158135446Strhodes if (downcase) 1159135446Strhodes c = maptolower[(int)c]; 1160135446Strhodes *ndata++ = c; 1161135446Strhodes nrem--; 1162135446Strhodes nused++; 1163135446Strhodes } 1164135446Strhodes break; 1165135446Strhodes case ft_initialescape: 1166135446Strhodes if (c == '[') { 1167135446Strhodes /* 1168135446Strhodes * This looks like a bitstring label, which 1169135446Strhodes * was deprecated. Intentionally drop it. 1170135446Strhodes */ 1171135446Strhodes return (DNS_R_BADLABELTYPE); 1172135446Strhodes } 1173135446Strhodes state = ft_escape; 1174135446Strhodes /* FALLTHROUGH */ 1175135446Strhodes case ft_escape: 1176135446Strhodes if (!isdigit(c & 0xff)) { 1177135446Strhodes if (count >= 63) 1178135446Strhodes return (DNS_R_LABELTOOLONG); 1179135446Strhodes count++; 1180135446Strhodes CONVERTTOASCII(c); 1181135446Strhodes if (downcase) 1182135446Strhodes c = maptolower[(int)c]; 1183135446Strhodes *ndata++ = c; 1184135446Strhodes nrem--; 1185135446Strhodes nused++; 1186135446Strhodes state = ft_ordinary; 1187135446Strhodes break; 1188135446Strhodes } 1189135446Strhodes digits = 0; 1190135446Strhodes value = 0; 1191135446Strhodes state = ft_escdecimal; 1192135446Strhodes /* FALLTHROUGH */ 1193135446Strhodes case ft_escdecimal: 1194135446Strhodes if (!isdigit(c & 0xff)) 1195135446Strhodes return (DNS_R_BADESCAPE); 1196135446Strhodes value *= 10; 1197135446Strhodes value += digitvalue[(int)c]; 1198135446Strhodes digits++; 1199135446Strhodes if (digits == 3) { 1200135446Strhodes if (value > 255) 1201135446Strhodes return (DNS_R_BADESCAPE); 1202135446Strhodes if (count >= 63) 1203135446Strhodes return (DNS_R_LABELTOOLONG); 1204135446Strhodes count++; 1205135446Strhodes if (downcase) 1206135446Strhodes value = maptolower[value]; 1207135446Strhodes *ndata++ = value; 1208135446Strhodes nrem--; 1209135446Strhodes nused++; 1210135446Strhodes state = ft_ordinary; 1211135446Strhodes } 1212135446Strhodes break; 1213135446Strhodes default: 1214135446Strhodes FATAL_ERROR(__FILE__, __LINE__, 1215135446Strhodes "Unexpected state %d", state); 1216135446Strhodes /* Does not return. */ 1217135446Strhodes } 1218135446Strhodes } 1219135446Strhodes 1220135446Strhodes if (!done) { 1221135446Strhodes if (nrem == 0) 1222135446Strhodes return (ISC_R_NOSPACE); 1223135446Strhodes INSIST(tlen == 0); 1224135446Strhodes if (state != ft_ordinary && state != ft_at) 1225135446Strhodes return (ISC_R_UNEXPECTEDEND); 1226135446Strhodes if (state == ft_ordinary) { 1227135446Strhodes INSIST(count != 0); 1228135446Strhodes *label = count; 1229135446Strhodes labels++; 1230135446Strhodes INSIST(labels <= 127); 1231135446Strhodes offsets[labels] = nused; 1232135446Strhodes } 1233135446Strhodes if (origin != NULL) { 1234135446Strhodes if (nrem < origin->length) 1235135446Strhodes return (ISC_R_NOSPACE); 1236135446Strhodes label = origin->ndata; 1237135446Strhodes n1 = origin->length; 1238135446Strhodes nrem -= n1; 1239135446Strhodes while (n1 > 0) { 1240135446Strhodes n2 = *label++; 1241135446Strhodes INSIST(n2 <= 63); /* no bitstring support */ 1242135446Strhodes *ndata++ = n2; 1243135446Strhodes n1 -= n2 + 1; 1244135446Strhodes nused += n2 + 1; 1245135446Strhodes while (n2 > 0) { 1246135446Strhodes c = *label++; 1247135446Strhodes if (downcase) 1248135446Strhodes c = maptolower[(int)c]; 1249135446Strhodes *ndata++ = c; 1250135446Strhodes n2--; 1251135446Strhodes } 1252135446Strhodes labels++; 1253135446Strhodes if (n1 > 0) { 1254135446Strhodes INSIST(labels <= 127); 1255135446Strhodes offsets[labels] = nused; 1256135446Strhodes } 1257135446Strhodes } 1258135446Strhodes if ((origin->attributes & DNS_NAMEATTR_ABSOLUTE) != 0) 1259135446Strhodes name->attributes |= DNS_NAMEATTR_ABSOLUTE; 1260135446Strhodes } 1261135446Strhodes } else 1262135446Strhodes name->attributes |= DNS_NAMEATTR_ABSOLUTE; 1263135446Strhodes 1264135446Strhodes name->ndata = (unsigned char *)target->base + target->used; 1265135446Strhodes name->labels = labels; 1266135446Strhodes name->length = nused; 1267135446Strhodes 1268135446Strhodes isc_buffer_forward(source, tused); 1269135446Strhodes isc_buffer_add(target, name->length); 1270135446Strhodes 1271135446Strhodes return (ISC_R_SUCCESS); 1272135446Strhodes} 1273135446Strhodes 1274170222Sdougb#ifdef ISC_PLATFORM_USETHREADS 1275170222Sdougbstatic void 1276170222Sdougbfree_specific(void *arg) { 1277170222Sdougb dns_name_totextfilter_t *mem = arg; 1278170222Sdougb isc_mem_put(thread_key_mctx, mem, sizeof(*mem)); 1279170222Sdougb /* Stop use being called again. */ 1280170222Sdougb (void)isc_thread_key_setspecific(totext_filter_proc_key, NULL); 1281170222Sdougb} 1282170222Sdougb 1283170222Sdougbstatic void 1284170222Sdougbthread_key_mutex_init(void) { 1285170222Sdougb RUNTIME_CHECK(isc_mutex_init(&thread_key_mutex) == ISC_R_SUCCESS); 1286170222Sdougb} 1287170222Sdougb 1288170222Sdougbstatic isc_result_t 1289170222Sdougbtotext_filter_proc_key_init(void) { 1290170222Sdougb isc_result_t result; 1291170222Sdougb 1292170222Sdougb /* 1293170222Sdougb * We need the call to isc_once_do() to support profiled mutex 1294170222Sdougb * otherwise thread_key_mutex could be initialized at compile time. 1295170222Sdougb */ 1296170222Sdougb result = isc_once_do(&once, thread_key_mutex_init); 1297170222Sdougb if (result != ISC_R_SUCCESS) 1298170222Sdougb return (result); 1299170222Sdougb 1300193149Sdougb if (!thread_key_initialized) { 1301170222Sdougb LOCK(&thread_key_mutex); 1302170222Sdougb if (thread_key_mctx == NULL) 1303170222Sdougb result = isc_mem_create2(0, 0, &thread_key_mctx, 0); 1304170222Sdougb if (result != ISC_R_SUCCESS) 1305170222Sdougb goto unlock; 1306193149Sdougb isc_mem_setname(thread_key_mctx, "threadkey", NULL); 1307170222Sdougb isc_mem_setdestroycheck(thread_key_mctx, ISC_FALSE); 1308193149Sdougb 1309170222Sdougb if (!thread_key_initialized && 1310170222Sdougb isc_thread_key_create(&totext_filter_proc_key, 1311193149Sdougb free_specific) != 0) { 1312170222Sdougb result = ISC_R_FAILURE; 1313170222Sdougb isc_mem_detach(&thread_key_mctx); 1314170222Sdougb } else 1315170222Sdougb thread_key_initialized = 1; 1316170222Sdougb unlock: 1317170222Sdougb UNLOCK(&thread_key_mutex); 1318193149Sdougb } 1319170222Sdougb return (result); 1320170222Sdougb} 1321170222Sdougb#endif 1322170222Sdougb 1323135446Strhodesisc_result_t 1324135446Strhodesdns_name_totext(dns_name_t *name, isc_boolean_t omit_final_dot, 1325135446Strhodes isc_buffer_t *target) 1326135446Strhodes{ 1327218384Sdougb unsigned int options = DNS_NAME_MASTERFILE; 1328218384Sdougb 1329218384Sdougb if (omit_final_dot) 1330218384Sdougb options |= DNS_NAME_OMITFINALDOT; 1331218384Sdougb return (dns_name_totext2(name, options, target)); 1332218384Sdougb} 1333218384Sdougb 1334218384Sdougbisc_result_t 1335218384Sdougbdns_name_toprincipal(dns_name_t *name, isc_buffer_t *target) { 1336218384Sdougb return (dns_name_totext2(name, DNS_NAME_OMITFINALDOT, target)); 1337218384Sdougb} 1338218384Sdougb 1339218384Sdougbisc_result_t 1340218384Sdougbdns_name_totext2(dns_name_t *name, unsigned int options, isc_buffer_t *target) 1341218384Sdougb{ 1342135446Strhodes unsigned char *ndata; 1343135446Strhodes char *tdata; 1344135446Strhodes unsigned int nlen, tlen; 1345135446Strhodes unsigned char c; 1346135446Strhodes unsigned int trem, count; 1347135446Strhodes unsigned int labels; 1348135446Strhodes isc_boolean_t saw_root = ISC_FALSE; 1349170222Sdougb unsigned int oused = target->used; 1350170222Sdougb#ifdef ISC_PLATFORM_USETHREADS 1351170222Sdougb dns_name_totextfilter_t *mem; 1352170222Sdougb dns_name_totextfilter_t totext_filter_proc = NULL; 1353170222Sdougb isc_result_t result; 1354170222Sdougb#endif 1355218384Sdougb isc_boolean_t omit_final_dot = 1356218384Sdougb ISC_TF(options & DNS_NAME_OMITFINALDOT); 1357135446Strhodes 1358135446Strhodes /* 1359135446Strhodes * This function assumes the name is in proper uncompressed 1360135446Strhodes * wire format. 1361135446Strhodes */ 1362135446Strhodes REQUIRE(VALID_NAME(name)); 1363135446Strhodes REQUIRE(ISC_BUFFER_VALID(target)); 1364135446Strhodes 1365170222Sdougb#ifdef ISC_PLATFORM_USETHREADS 1366170222Sdougb result = totext_filter_proc_key_init(); 1367170222Sdougb if (result != ISC_R_SUCCESS) 1368170222Sdougb return (result); 1369170222Sdougb#endif 1370135446Strhodes ndata = name->ndata; 1371135446Strhodes nlen = name->length; 1372135446Strhodes labels = name->labels; 1373135446Strhodes tdata = isc_buffer_used(target); 1374135446Strhodes tlen = isc_buffer_availablelength(target); 1375135446Strhodes 1376135446Strhodes trem = tlen; 1377135446Strhodes 1378135446Strhodes if (labels == 0 && nlen == 0) { 1379135446Strhodes /* 1380135446Strhodes * Special handling for an empty name. 1381135446Strhodes */ 1382135446Strhodes if (trem == 0) 1383135446Strhodes return (ISC_R_NOSPACE); 1384135446Strhodes 1385135446Strhodes /* 1386135446Strhodes * The names of these booleans are misleading in this case. 1387135446Strhodes * This empty name is not necessarily from the root node of 1388135446Strhodes * the DNS root zone, nor is a final dot going to be included. 1389135446Strhodes * They need to be set this way, though, to keep the "@" 1390135446Strhodes * from being trounced. 1391135446Strhodes */ 1392135446Strhodes saw_root = ISC_TRUE; 1393135446Strhodes omit_final_dot = ISC_FALSE; 1394135446Strhodes *tdata++ = '@'; 1395135446Strhodes trem--; 1396135446Strhodes 1397135446Strhodes /* 1398135446Strhodes * Skip the while() loop. 1399135446Strhodes */ 1400135446Strhodes nlen = 0; 1401135446Strhodes } else if (nlen == 1 && labels == 1 && *ndata == '\0') { 1402135446Strhodes /* 1403135446Strhodes * Special handling for the root label. 1404135446Strhodes */ 1405135446Strhodes if (trem == 0) 1406135446Strhodes return (ISC_R_NOSPACE); 1407135446Strhodes 1408135446Strhodes saw_root = ISC_TRUE; 1409135446Strhodes omit_final_dot = ISC_FALSE; 1410135446Strhodes *tdata++ = '.'; 1411135446Strhodes trem--; 1412135446Strhodes 1413135446Strhodes /* 1414135446Strhodes * Skip the while() loop. 1415135446Strhodes */ 1416135446Strhodes nlen = 0; 1417135446Strhodes } 1418135446Strhodes 1419135446Strhodes while (labels > 0 && nlen > 0 && trem > 0) { 1420135446Strhodes labels--; 1421135446Strhodes count = *ndata++; 1422135446Strhodes nlen--; 1423135446Strhodes if (count == 0) { 1424135446Strhodes saw_root = ISC_TRUE; 1425135446Strhodes break; 1426135446Strhodes } 1427135446Strhodes if (count < 64) { 1428135446Strhodes INSIST(nlen >= count); 1429135446Strhodes while (count > 0) { 1430135446Strhodes c = *ndata; 1431135446Strhodes switch (c) { 1432218384Sdougb /* Special modifiers in zone files. */ 1433218384Sdougb case 0x40: /* '@' */ 1434218384Sdougb case 0x24: /* '$' */ 1435218384Sdougb if ((options & DNS_NAME_MASTERFILE) == 0) 1436218384Sdougb goto no_escape; 1437135446Strhodes case 0x22: /* '"' */ 1438135446Strhodes case 0x28: /* '(' */ 1439135446Strhodes case 0x29: /* ')' */ 1440135446Strhodes case 0x2E: /* '.' */ 1441135446Strhodes case 0x3B: /* ';' */ 1442135446Strhodes case 0x5C: /* '\\' */ 1443135446Strhodes if (trem < 2) 1444135446Strhodes return (ISC_R_NOSPACE); 1445135446Strhodes *tdata++ = '\\'; 1446135446Strhodes CONVERTFROMASCII(c); 1447135446Strhodes *tdata++ = c; 1448135446Strhodes ndata++; 1449135446Strhodes trem -= 2; 1450135446Strhodes nlen--; 1451135446Strhodes break; 1452218384Sdougb no_escape: 1453135446Strhodes default: 1454135446Strhodes if (c > 0x20 && c < 0x7f) { 1455135446Strhodes if (trem == 0) 1456135446Strhodes return (ISC_R_NOSPACE); 1457135446Strhodes CONVERTFROMASCII(c); 1458135446Strhodes *tdata++ = c; 1459135446Strhodes ndata++; 1460135446Strhodes trem--; 1461135446Strhodes nlen--; 1462135446Strhodes } else { 1463135446Strhodes if (trem < 4) 1464135446Strhodes return (ISC_R_NOSPACE); 1465153816Sdougb *tdata++ = 0x5c; 1466153816Sdougb *tdata++ = 0x30 + 1467153816Sdougb ((c / 100) % 10); 1468153816Sdougb *tdata++ = 0x30 + 1469153816Sdougb ((c / 10) % 10); 1470153816Sdougb *tdata++ = 0x30 + (c % 10); 1471135446Strhodes trem -= 4; 1472135446Strhodes ndata++; 1473135446Strhodes nlen--; 1474135446Strhodes } 1475135446Strhodes } 1476135446Strhodes count--; 1477135446Strhodes } 1478135446Strhodes } else { 1479135446Strhodes FATAL_ERROR(__FILE__, __LINE__, 1480135446Strhodes "Unexpected label type %02x", count); 1481135446Strhodes /* NOTREACHED */ 1482135446Strhodes } 1483135446Strhodes 1484135446Strhodes /* 1485135446Strhodes * The following assumes names are absolute. If not, we 1486135446Strhodes * fix things up later. Note that this means that in some 1487135446Strhodes * cases one more byte of text buffer is required than is 1488135446Strhodes * needed in the final output. 1489135446Strhodes */ 1490135446Strhodes if (trem == 0) 1491135446Strhodes return (ISC_R_NOSPACE); 1492135446Strhodes *tdata++ = '.'; 1493135446Strhodes trem--; 1494135446Strhodes } 1495135446Strhodes 1496135446Strhodes if (nlen != 0 && trem == 0) 1497135446Strhodes return (ISC_R_NOSPACE); 1498135446Strhodes 1499135446Strhodes if (!saw_root || omit_final_dot) 1500135446Strhodes trem++; 1501135446Strhodes 1502135446Strhodes isc_buffer_add(target, tlen - trem); 1503135446Strhodes 1504170222Sdougb#ifdef ISC_PLATFORM_USETHREADS 1505170222Sdougb mem = isc_thread_key_getspecific(totext_filter_proc_key); 1506170222Sdougb if (mem != NULL) 1507170222Sdougb totext_filter_proc = *mem; 1508170222Sdougb#endif 1509170222Sdougb if (totext_filter_proc != NULL) 1510170222Sdougb return ((*totext_filter_proc)(target, oused, saw_root)); 1511170222Sdougb 1512135446Strhodes return (ISC_R_SUCCESS); 1513135446Strhodes} 1514135446Strhodes 1515135446Strhodesisc_result_t 1516135446Strhodesdns_name_tofilenametext(dns_name_t *name, isc_boolean_t omit_final_dot, 1517135446Strhodes isc_buffer_t *target) 1518135446Strhodes{ 1519135446Strhodes unsigned char *ndata; 1520135446Strhodes char *tdata; 1521135446Strhodes unsigned int nlen, tlen; 1522135446Strhodes unsigned char c; 1523135446Strhodes unsigned int trem, count; 1524135446Strhodes unsigned int labels; 1525135446Strhodes 1526135446Strhodes /* 1527135446Strhodes * This function assumes the name is in proper uncompressed 1528135446Strhodes * wire format. 1529135446Strhodes */ 1530135446Strhodes REQUIRE(VALID_NAME(name)); 1531135446Strhodes REQUIRE((name->attributes & DNS_NAMEATTR_ABSOLUTE) != 0); 1532135446Strhodes REQUIRE(ISC_BUFFER_VALID(target)); 1533135446Strhodes 1534135446Strhodes ndata = name->ndata; 1535135446Strhodes nlen = name->length; 1536135446Strhodes labels = name->labels; 1537135446Strhodes tdata = isc_buffer_used(target); 1538135446Strhodes tlen = isc_buffer_availablelength(target); 1539135446Strhodes 1540135446Strhodes trem = tlen; 1541135446Strhodes 1542135446Strhodes if (nlen == 1 && labels == 1 && *ndata == '\0') { 1543135446Strhodes /* 1544135446Strhodes * Special handling for the root label. 1545135446Strhodes */ 1546135446Strhodes if (trem == 0) 1547135446Strhodes return (ISC_R_NOSPACE); 1548135446Strhodes 1549135446Strhodes omit_final_dot = ISC_FALSE; 1550135446Strhodes *tdata++ = '.'; 1551135446Strhodes trem--; 1552135446Strhodes 1553135446Strhodes /* 1554135446Strhodes * Skip the while() loop. 1555135446Strhodes */ 1556135446Strhodes nlen = 0; 1557135446Strhodes } 1558135446Strhodes 1559135446Strhodes while (labels > 0 && nlen > 0 && trem > 0) { 1560135446Strhodes labels--; 1561135446Strhodes count = *ndata++; 1562135446Strhodes nlen--; 1563135446Strhodes if (count == 0) 1564135446Strhodes break; 1565135446Strhodes if (count < 64) { 1566135446Strhodes INSIST(nlen >= count); 1567135446Strhodes while (count > 0) { 1568135446Strhodes c = *ndata; 1569135446Strhodes if ((c >= 0x30 && c <= 0x39) || /* digit */ 1570135446Strhodes (c >= 0x41 && c <= 0x5A) || /* uppercase */ 1571135446Strhodes (c >= 0x61 && c <= 0x7A) || /* lowercase */ 1572135446Strhodes c == 0x2D || /* hyphen */ 1573135446Strhodes c == 0x5F) /* underscore */ 1574135446Strhodes { 1575135446Strhodes if (trem == 0) 1576135446Strhodes return (ISC_R_NOSPACE); 1577135446Strhodes /* downcase */ 1578135446Strhodes if (c >= 0x41 && c <= 0x5A) 1579135446Strhodes c += 0x20; 1580135446Strhodes CONVERTFROMASCII(c); 1581135446Strhodes *tdata++ = c; 1582135446Strhodes ndata++; 1583135446Strhodes trem--; 1584135446Strhodes nlen--; 1585135446Strhodes } else { 1586135446Strhodes if (trem < 3) 1587135446Strhodes return (ISC_R_NOSPACE); 1588135446Strhodes sprintf(tdata, "%%%02X", c); 1589135446Strhodes tdata += 3; 1590135446Strhodes trem -= 3; 1591135446Strhodes ndata++; 1592135446Strhodes nlen--; 1593135446Strhodes } 1594135446Strhodes count--; 1595135446Strhodes } 1596135446Strhodes } else { 1597135446Strhodes FATAL_ERROR(__FILE__, __LINE__, 1598135446Strhodes "Unexpected label type %02x", count); 1599135446Strhodes /* NOTREACHED */ 1600135446Strhodes } 1601135446Strhodes 1602135446Strhodes /* 1603135446Strhodes * The following assumes names are absolute. If not, we 1604135446Strhodes * fix things up later. Note that this means that in some 1605135446Strhodes * cases one more byte of text buffer is required than is 1606135446Strhodes * needed in the final output. 1607135446Strhodes */ 1608135446Strhodes if (trem == 0) 1609135446Strhodes return (ISC_R_NOSPACE); 1610135446Strhodes *tdata++ = '.'; 1611135446Strhodes trem--; 1612135446Strhodes } 1613135446Strhodes 1614135446Strhodes if (nlen != 0 && trem == 0) 1615135446Strhodes return (ISC_R_NOSPACE); 1616135446Strhodes 1617135446Strhodes if (omit_final_dot) 1618135446Strhodes trem++; 1619135446Strhodes 1620135446Strhodes isc_buffer_add(target, tlen - trem); 1621135446Strhodes 1622135446Strhodes return (ISC_R_SUCCESS); 1623135446Strhodes} 1624135446Strhodes 1625135446Strhodesisc_result_t 1626135446Strhodesdns_name_downcase(dns_name_t *source, dns_name_t *name, isc_buffer_t *target) { 1627135446Strhodes unsigned char *sndata, *ndata; 1628135446Strhodes unsigned int nlen, count, labels; 1629135446Strhodes isc_buffer_t buffer; 1630135446Strhodes 1631135446Strhodes /* 1632135446Strhodes * Downcase 'source'. 1633135446Strhodes */ 1634135446Strhodes 1635135446Strhodes REQUIRE(VALID_NAME(source)); 1636135446Strhodes REQUIRE(VALID_NAME(name)); 1637135446Strhodes if (source == name) { 1638135446Strhodes REQUIRE((name->attributes & DNS_NAMEATTR_READONLY) == 0); 1639135446Strhodes isc_buffer_init(&buffer, source->ndata, source->length); 1640135446Strhodes target = &buffer; 1641135446Strhodes ndata = source->ndata; 1642135446Strhodes } else { 1643135446Strhodes REQUIRE(BINDABLE(name)); 1644135446Strhodes REQUIRE((target != NULL && ISC_BUFFER_VALID(target)) || 1645135446Strhodes (target == NULL && ISC_BUFFER_VALID(name->buffer))); 1646135446Strhodes if (target == NULL) { 1647135446Strhodes target = name->buffer; 1648135446Strhodes isc_buffer_clear(name->buffer); 1649135446Strhodes } 1650135446Strhodes ndata = (unsigned char *)target->base + target->used; 1651135446Strhodes name->ndata = ndata; 1652135446Strhodes } 1653135446Strhodes 1654135446Strhodes sndata = source->ndata; 1655135446Strhodes nlen = source->length; 1656135446Strhodes labels = source->labels; 1657135446Strhodes 1658135446Strhodes if (nlen > (target->length - target->used)) { 1659135446Strhodes MAKE_EMPTY(name); 1660135446Strhodes return (ISC_R_NOSPACE); 1661135446Strhodes } 1662135446Strhodes 1663135446Strhodes while (labels > 0 && nlen > 0) { 1664135446Strhodes labels--; 1665135446Strhodes count = *sndata++; 1666135446Strhodes *ndata++ = count; 1667135446Strhodes nlen--; 1668135446Strhodes if (count < 64) { 1669135446Strhodes INSIST(nlen >= count); 1670135446Strhodes while (count > 0) { 1671135446Strhodes *ndata++ = maptolower[(*sndata++)]; 1672135446Strhodes nlen--; 1673135446Strhodes count--; 1674135446Strhodes } 1675135446Strhodes } else { 1676135446Strhodes FATAL_ERROR(__FILE__, __LINE__, 1677135446Strhodes "Unexpected label type %02x", count); 1678135446Strhodes /* Does not return. */ 1679135446Strhodes } 1680135446Strhodes } 1681135446Strhodes 1682135446Strhodes if (source != name) { 1683135446Strhodes name->labels = source->labels; 1684135446Strhodes name->length = source->length; 1685135446Strhodes if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0) 1686135446Strhodes name->attributes = DNS_NAMEATTR_ABSOLUTE; 1687135446Strhodes else 1688135446Strhodes name->attributes = 0; 1689135446Strhodes if (name->labels > 0 && name->offsets != NULL) 1690135446Strhodes set_offsets(name, name->offsets, NULL); 1691135446Strhodes } 1692135446Strhodes 1693135446Strhodes isc_buffer_add(target, name->length); 1694135446Strhodes 1695135446Strhodes return (ISC_R_SUCCESS); 1696135446Strhodes} 1697135446Strhodes 1698135446Strhodesstatic void 1699135446Strhodesset_offsets(const dns_name_t *name, unsigned char *offsets, 1700135446Strhodes dns_name_t *set_name) 1701135446Strhodes{ 1702135446Strhodes unsigned int offset, count, length, nlabels; 1703135446Strhodes unsigned char *ndata; 1704135446Strhodes isc_boolean_t absolute; 1705135446Strhodes 1706135446Strhodes ndata = name->ndata; 1707135446Strhodes length = name->length; 1708135446Strhodes offset = 0; 1709135446Strhodes nlabels = 0; 1710135446Strhodes absolute = ISC_FALSE; 1711135446Strhodes while (offset != length) { 1712135446Strhodes INSIST(nlabels < 128); 1713135446Strhodes offsets[nlabels++] = offset; 1714135446Strhodes count = *ndata++; 1715135446Strhodes offset++; 1716135446Strhodes INSIST(count <= 63); 1717135446Strhodes offset += count; 1718135446Strhodes ndata += count; 1719135446Strhodes INSIST(offset <= length); 1720135446Strhodes if (count == 0) { 1721135446Strhodes absolute = ISC_TRUE; 1722135446Strhodes break; 1723135446Strhodes } 1724135446Strhodes } 1725135446Strhodes if (set_name != NULL) { 1726135446Strhodes INSIST(set_name == name); 1727135446Strhodes 1728135446Strhodes set_name->labels = nlabels; 1729135446Strhodes set_name->length = offset; 1730135446Strhodes if (absolute) 1731135446Strhodes set_name->attributes |= DNS_NAMEATTR_ABSOLUTE; 1732135446Strhodes else 1733135446Strhodes set_name->attributes &= ~DNS_NAMEATTR_ABSOLUTE; 1734135446Strhodes } 1735135446Strhodes INSIST(nlabels == name->labels); 1736135446Strhodes INSIST(offset == name->length); 1737135446Strhodes} 1738135446Strhodes 1739135446Strhodesisc_result_t 1740135446Strhodesdns_name_fromwire(dns_name_t *name, isc_buffer_t *source, 1741135446Strhodes dns_decompress_t *dctx, unsigned int options, 1742135446Strhodes isc_buffer_t *target) 1743135446Strhodes{ 1744135446Strhodes unsigned char *cdata, *ndata; 1745135446Strhodes unsigned int cused; /* Bytes of compressed name data used */ 1746170222Sdougb unsigned int nused, labels, n, nmax; 1747135446Strhodes unsigned int current, new_current, biggest_pointer; 1748135446Strhodes isc_boolean_t done; 1749135446Strhodes fw_state state = fw_start; 1750135446Strhodes unsigned int c; 1751135446Strhodes unsigned char *offsets; 1752135446Strhodes dns_offsets_t odata; 1753135446Strhodes isc_boolean_t downcase; 1754170222Sdougb isc_boolean_t seen_pointer; 1755135446Strhodes 1756135446Strhodes /* 1757135446Strhodes * Copy the possibly-compressed name at source into target, 1758170222Sdougb * decompressing it. Loop prevention is performed by checking 1759170222Sdougb * the new pointer against biggest_pointer. 1760135446Strhodes */ 1761135446Strhodes 1762135446Strhodes REQUIRE(VALID_NAME(name)); 1763135446Strhodes REQUIRE((target != NULL && ISC_BUFFER_VALID(target)) || 1764135446Strhodes (target == NULL && ISC_BUFFER_VALID(name->buffer))); 1765135446Strhodes 1766135446Strhodes downcase = ISC_TF((options & DNS_NAME_DOWNCASE) != 0); 1767135446Strhodes 1768135446Strhodes if (target == NULL && name->buffer != NULL) { 1769135446Strhodes target = name->buffer; 1770135446Strhodes isc_buffer_clear(target); 1771135446Strhodes } 1772135446Strhodes 1773135446Strhodes REQUIRE(dctx != NULL); 1774135446Strhodes REQUIRE(BINDABLE(name)); 1775135446Strhodes 1776135446Strhodes INIT_OFFSETS(name, offsets, odata); 1777135446Strhodes 1778135446Strhodes /* 1779135446Strhodes * Make 'name' empty in case of failure. 1780135446Strhodes */ 1781135446Strhodes MAKE_EMPTY(name); 1782135446Strhodes 1783135446Strhodes /* 1784135446Strhodes * Initialize things to make the compiler happy; they're not required. 1785135446Strhodes */ 1786135446Strhodes n = 0; 1787135446Strhodes new_current = 0; 1788135446Strhodes 1789135446Strhodes /* 1790135446Strhodes * Set up. 1791135446Strhodes */ 1792135446Strhodes labels = 0; 1793135446Strhodes done = ISC_FALSE; 1794135446Strhodes 1795135446Strhodes ndata = isc_buffer_used(target); 1796135446Strhodes nused = 0; 1797170222Sdougb seen_pointer = ISC_FALSE; 1798135446Strhodes 1799135446Strhodes /* 1800135446Strhodes * Find the maximum number of uncompressed target name 1801135446Strhodes * bytes we are willing to generate. This is the smaller 1802135446Strhodes * of the available target buffer length and the 1803135446Strhodes * maximum legal domain name length (255). 1804135446Strhodes */ 1805135446Strhodes nmax = isc_buffer_availablelength(target); 1806135446Strhodes if (nmax > DNS_NAME_MAXWIRE) 1807135446Strhodes nmax = DNS_NAME_MAXWIRE; 1808135446Strhodes 1809135446Strhodes cdata = isc_buffer_current(source); 1810135446Strhodes cused = 0; 1811135446Strhodes 1812135446Strhodes current = source->current; 1813135446Strhodes biggest_pointer = current; 1814135446Strhodes 1815135446Strhodes /* 1816135446Strhodes * Note: The following code is not optimized for speed, but 1817135446Strhodes * rather for correctness. Speed will be addressed in the future. 1818135446Strhodes */ 1819135446Strhodes 1820135446Strhodes while (current < source->active && !done) { 1821135446Strhodes c = *cdata++; 1822135446Strhodes current++; 1823170222Sdougb if (!seen_pointer) 1824135446Strhodes cused++; 1825135446Strhodes 1826135446Strhodes switch (state) { 1827135446Strhodes case fw_start: 1828135446Strhodes if (c < 64) { 1829135446Strhodes offsets[labels] = nused; 1830135446Strhodes labels++; 1831135446Strhodes if (nused + c + 1 > nmax) 1832135446Strhodes goto full; 1833135446Strhodes nused += c + 1; 1834135446Strhodes *ndata++ = c; 1835135446Strhodes if (c == 0) 1836135446Strhodes done = ISC_TRUE; 1837135446Strhodes n = c; 1838135446Strhodes state = fw_ordinary; 1839135446Strhodes } else if (c >= 128 && c < 192) { 1840135446Strhodes /* 1841135446Strhodes * 14 bit local compression pointer. 1842135446Strhodes * Local compression is no longer an 1843135446Strhodes * IETF draft. 1844135446Strhodes */ 1845135446Strhodes return (DNS_R_BADLABELTYPE); 1846135446Strhodes } else if (c >= 192) { 1847135446Strhodes /* 1848135446Strhodes * Ordinary 14-bit pointer. 1849135446Strhodes */ 1850135446Strhodes if ((dctx->allowed & DNS_COMPRESS_GLOBAL14) == 1851135446Strhodes 0) 1852135446Strhodes return (DNS_R_DISALLOWED); 1853135446Strhodes new_current = c & 0x3F; 1854135446Strhodes n = 1; 1855135446Strhodes state = fw_newcurrent; 1856135446Strhodes } else 1857135446Strhodes return (DNS_R_BADLABELTYPE); 1858135446Strhodes break; 1859135446Strhodes case fw_ordinary: 1860135446Strhodes if (downcase) 1861135446Strhodes c = maptolower[c]; 1862135446Strhodes /* FALLTHROUGH */ 1863135446Strhodes case fw_copy: 1864135446Strhodes *ndata++ = c; 1865135446Strhodes n--; 1866135446Strhodes if (n == 0) 1867135446Strhodes state = fw_start; 1868135446Strhodes break; 1869135446Strhodes case fw_newcurrent: 1870135446Strhodes new_current *= 256; 1871135446Strhodes new_current += c; 1872135446Strhodes n--; 1873135446Strhodes if (n != 0) 1874135446Strhodes break; 1875135446Strhodes if (new_current >= biggest_pointer) 1876135446Strhodes return (DNS_R_BADPOINTER); 1877135446Strhodes biggest_pointer = new_current; 1878135446Strhodes current = new_current; 1879170222Sdougb cdata = (unsigned char *)source->base + current; 1880170222Sdougb seen_pointer = ISC_TRUE; 1881135446Strhodes state = fw_start; 1882135446Strhodes break; 1883135446Strhodes default: 1884135446Strhodes FATAL_ERROR(__FILE__, __LINE__, 1885135446Strhodes "Unknown state %d", state); 1886135446Strhodes /* Does not return. */ 1887135446Strhodes } 1888135446Strhodes } 1889135446Strhodes 1890135446Strhodes if (!done) 1891135446Strhodes return (ISC_R_UNEXPECTEDEND); 1892135446Strhodes 1893135446Strhodes name->ndata = (unsigned char *)target->base + target->used; 1894135446Strhodes name->labels = labels; 1895135446Strhodes name->length = nused; 1896135446Strhodes name->attributes |= DNS_NAMEATTR_ABSOLUTE; 1897135446Strhodes 1898135446Strhodes isc_buffer_forward(source, cused); 1899135446Strhodes isc_buffer_add(target, name->length); 1900135446Strhodes 1901135446Strhodes return (ISC_R_SUCCESS); 1902135446Strhodes 1903135446Strhodes full: 1904135446Strhodes if (nmax == DNS_NAME_MAXWIRE) 1905135446Strhodes /* 1906135446Strhodes * The name did not fit even though we had a buffer 1907135446Strhodes * big enough to fit a maximum-length name. 1908135446Strhodes */ 1909135446Strhodes return (DNS_R_NAMETOOLONG); 1910135446Strhodes else 1911135446Strhodes /* 1912135446Strhodes * The name might fit if only the caller could give us a 1913135446Strhodes * big enough buffer. 1914135446Strhodes */ 1915135446Strhodes return (ISC_R_NOSPACE); 1916135446Strhodes} 1917135446Strhodes 1918135446Strhodesisc_result_t 1919165071Sdougbdns_name_towire(const dns_name_t *name, dns_compress_t *cctx, 1920165071Sdougb isc_buffer_t *target) 1921165071Sdougb{ 1922135446Strhodes unsigned int methods; 1923135446Strhodes isc_uint16_t offset; 1924135446Strhodes dns_name_t gp; /* Global compression prefix */ 1925135446Strhodes isc_boolean_t gf; /* Global compression target found */ 1926135446Strhodes isc_uint16_t go; /* Global compression offset */ 1927135446Strhodes dns_offsets_t clo; 1928135446Strhodes dns_name_t clname; 1929135446Strhodes 1930135446Strhodes /* 1931135446Strhodes * Convert 'name' into wire format, compressing it as specified by the 1932135446Strhodes * compression context 'cctx', and storing the result in 'target'. 1933135446Strhodes */ 1934135446Strhodes 1935135446Strhodes REQUIRE(VALID_NAME(name)); 1936135446Strhodes REQUIRE(cctx != NULL); 1937135446Strhodes REQUIRE(ISC_BUFFER_VALID(target)); 1938135446Strhodes 1939135446Strhodes /* 1940135446Strhodes * If 'name' doesn't have an offsets table, make a clone which 1941135446Strhodes * has one. 1942135446Strhodes */ 1943135446Strhodes if (name->offsets == NULL) { 1944135446Strhodes DNS_NAME_INIT(&clname, clo); 1945135446Strhodes dns_name_clone(name, &clname); 1946135446Strhodes name = &clname; 1947135446Strhodes } 1948135446Strhodes DNS_NAME_INIT(&gp, NULL); 1949135446Strhodes 1950135446Strhodes offset = target->used; /*XXX*/ 1951135446Strhodes 1952135446Strhodes methods = dns_compress_getmethods(cctx); 1953135446Strhodes 1954193149Sdougb if ((name->attributes & DNS_NAMEATTR_NOCOMPRESS) == 0 && 1955193149Sdougb (methods & DNS_COMPRESS_GLOBAL14) != 0) 1956135446Strhodes gf = dns_compress_findglobal(cctx, name, &gp, &go); 1957135446Strhodes else 1958135446Strhodes gf = ISC_FALSE; 1959135446Strhodes 1960135446Strhodes /* 1961135446Strhodes * If the offset is too high for 14 bit global compression, we're 1962135446Strhodes * out of luck. 1963135446Strhodes */ 1964135446Strhodes if (gf && go >= 0x4000) 1965135446Strhodes gf = ISC_FALSE; 1966135446Strhodes 1967135446Strhodes /* 1968135446Strhodes * Will the compression pointer reduce the message size? 1969135446Strhodes */ 1970135446Strhodes if (gf && (gp.length + 2) >= name->length) 1971135446Strhodes gf = ISC_FALSE; 1972135446Strhodes 1973135446Strhodes if (gf) { 1974135446Strhodes if (target->length - target->used < gp.length) 1975135446Strhodes return (ISC_R_NOSPACE); 1976135446Strhodes (void)memcpy((unsigned char *)target->base + target->used, 1977135446Strhodes gp.ndata, (size_t)gp.length); 1978135446Strhodes isc_buffer_add(target, gp.length); 1979135446Strhodes go |= 0xc000; 1980135446Strhodes if (target->length - target->used < 2) 1981135446Strhodes return (ISC_R_NOSPACE); 1982135446Strhodes isc_buffer_putuint16(target, go); 1983135446Strhodes if (gp.length != 0) 1984135446Strhodes dns_compress_add(cctx, name, &gp, offset); 1985135446Strhodes } else { 1986135446Strhodes if (target->length - target->used < name->length) 1987135446Strhodes return (ISC_R_NOSPACE); 1988135446Strhodes (void)memcpy((unsigned char *)target->base + target->used, 1989135446Strhodes name->ndata, (size_t)name->length); 1990135446Strhodes isc_buffer_add(target, name->length); 1991135446Strhodes dns_compress_add(cctx, name, name, offset); 1992135446Strhodes } 1993135446Strhodes return (ISC_R_SUCCESS); 1994135446Strhodes} 1995135446Strhodes 1996135446Strhodesisc_result_t 1997135446Strhodesdns_name_concatenate(dns_name_t *prefix, dns_name_t *suffix, dns_name_t *name, 1998135446Strhodes isc_buffer_t *target) 1999135446Strhodes{ 2000135446Strhodes unsigned char *ndata, *offsets; 2001135446Strhodes unsigned int nrem, labels, prefix_length, length; 2002135446Strhodes isc_boolean_t copy_prefix = ISC_TRUE; 2003135446Strhodes isc_boolean_t copy_suffix = ISC_TRUE; 2004135446Strhodes isc_boolean_t absolute = ISC_FALSE; 2005135446Strhodes dns_name_t tmp_name; 2006135446Strhodes dns_offsets_t odata; 2007135446Strhodes 2008135446Strhodes /* 2009135446Strhodes * Concatenate 'prefix' and 'suffix'. 2010135446Strhodes */ 2011135446Strhodes 2012135446Strhodes REQUIRE(prefix == NULL || VALID_NAME(prefix)); 2013135446Strhodes REQUIRE(suffix == NULL || VALID_NAME(suffix)); 2014135446Strhodes REQUIRE(name == NULL || VALID_NAME(name)); 2015135446Strhodes REQUIRE((target != NULL && ISC_BUFFER_VALID(target)) || 2016135446Strhodes (target == NULL && name != NULL && ISC_BUFFER_VALID(name->buffer))); 2017135446Strhodes if (prefix == NULL || prefix->labels == 0) 2018135446Strhodes copy_prefix = ISC_FALSE; 2019135446Strhodes if (suffix == NULL || suffix->labels == 0) 2020135446Strhodes copy_suffix = ISC_FALSE; 2021135446Strhodes if (copy_prefix && 2022135446Strhodes (prefix->attributes & DNS_NAMEATTR_ABSOLUTE) != 0) { 2023135446Strhodes absolute = ISC_TRUE; 2024135446Strhodes REQUIRE(!copy_suffix); 2025135446Strhodes } 2026135446Strhodes if (name == NULL) { 2027135446Strhodes DNS_NAME_INIT(&tmp_name, odata); 2028135446Strhodes name = &tmp_name; 2029135446Strhodes } 2030135446Strhodes if (target == NULL) { 2031135446Strhodes INSIST(name->buffer != NULL); 2032135446Strhodes target = name->buffer; 2033135446Strhodes isc_buffer_clear(name->buffer); 2034135446Strhodes } 2035135446Strhodes 2036135446Strhodes REQUIRE(BINDABLE(name)); 2037135446Strhodes 2038135446Strhodes /* 2039135446Strhodes * Set up. 2040135446Strhodes */ 2041135446Strhodes nrem = target->length - target->used; 2042135446Strhodes ndata = (unsigned char *)target->base + target->used; 2043135446Strhodes if (nrem > DNS_NAME_MAXWIRE) 2044135446Strhodes nrem = DNS_NAME_MAXWIRE; 2045135446Strhodes length = 0; 2046135446Strhodes prefix_length = 0; 2047135446Strhodes labels = 0; 2048135446Strhodes if (copy_prefix) { 2049135446Strhodes prefix_length = prefix->length; 2050135446Strhodes length += prefix_length; 2051135446Strhodes labels += prefix->labels; 2052135446Strhodes } 2053135446Strhodes if (copy_suffix) { 2054135446Strhodes length += suffix->length; 2055135446Strhodes labels += suffix->labels; 2056135446Strhodes } 2057135446Strhodes if (length > DNS_NAME_MAXWIRE) { 2058135446Strhodes MAKE_EMPTY(name); 2059135446Strhodes return (DNS_R_NAMETOOLONG); 2060135446Strhodes } 2061135446Strhodes if (length > nrem) { 2062135446Strhodes MAKE_EMPTY(name); 2063135446Strhodes return (ISC_R_NOSPACE); 2064135446Strhodes } 2065135446Strhodes 2066135446Strhodes if (copy_suffix) { 2067135446Strhodes if ((suffix->attributes & DNS_NAMEATTR_ABSOLUTE) != 0) 2068135446Strhodes absolute = ISC_TRUE; 2069135446Strhodes if (suffix == name && suffix->buffer == target) 2070135446Strhodes memmove(ndata + prefix_length, suffix->ndata, 2071135446Strhodes suffix->length); 2072135446Strhodes else 2073135446Strhodes memcpy(ndata + prefix_length, suffix->ndata, 2074135446Strhodes suffix->length); 2075135446Strhodes } 2076135446Strhodes 2077135446Strhodes /* 2078135446Strhodes * If 'prefix' and 'name' are the same object, and the object has 2079135446Strhodes * a dedicated buffer, and we're using it, then we don't have to 2080135446Strhodes * copy anything. 2081135446Strhodes */ 2082135446Strhodes if (copy_prefix && (prefix != name || prefix->buffer != target)) 2083135446Strhodes memcpy(ndata, prefix->ndata, prefix_length); 2084135446Strhodes 2085135446Strhodes name->ndata = ndata; 2086135446Strhodes name->labels = labels; 2087135446Strhodes name->length = length; 2088135446Strhodes if (absolute) 2089135446Strhodes name->attributes = DNS_NAMEATTR_ABSOLUTE; 2090135446Strhodes else 2091135446Strhodes name->attributes = 0; 2092135446Strhodes 2093135446Strhodes if (name->labels > 0 && name->offsets != NULL) { 2094135446Strhodes INIT_OFFSETS(name, offsets, odata); 2095135446Strhodes set_offsets(name, offsets, NULL); 2096135446Strhodes } 2097135446Strhodes 2098135446Strhodes isc_buffer_add(target, name->length); 2099135446Strhodes 2100135446Strhodes return (ISC_R_SUCCESS); 2101135446Strhodes} 2102135446Strhodes 2103135446Strhodesvoid 2104135446Strhodesdns_name_split(dns_name_t *name, unsigned int suffixlabels, 2105135446Strhodes dns_name_t *prefix, dns_name_t *suffix) 2106135446Strhodes 2107135446Strhodes{ 2108135446Strhodes unsigned int splitlabel; 2109135446Strhodes 2110135446Strhodes REQUIRE(VALID_NAME(name)); 2111135446Strhodes REQUIRE(suffixlabels > 0); 2112135446Strhodes REQUIRE(suffixlabels < name->labels); 2113135446Strhodes REQUIRE(prefix != NULL || suffix != NULL); 2114135446Strhodes REQUIRE(prefix == NULL || 2115135446Strhodes (VALID_NAME(prefix) && 2116135446Strhodes prefix->buffer != NULL && 2117135446Strhodes BINDABLE(prefix))); 2118135446Strhodes REQUIRE(suffix == NULL || 2119135446Strhodes (VALID_NAME(suffix) && 2120135446Strhodes suffix->buffer != NULL && 2121135446Strhodes BINDABLE(suffix))); 2122135446Strhodes 2123135446Strhodes splitlabel = name->labels - suffixlabels; 2124135446Strhodes 2125135446Strhodes if (prefix != NULL) 2126135446Strhodes dns_name_getlabelsequence(name, 0, splitlabel, prefix); 2127135446Strhodes 2128135446Strhodes if (suffix != NULL) 2129135446Strhodes dns_name_getlabelsequence(name, splitlabel, 2130135446Strhodes suffixlabels, suffix); 2131135446Strhodes 2132135446Strhodes return; 2133135446Strhodes} 2134135446Strhodes 2135135446Strhodesisc_result_t 2136165071Sdougbdns_name_dup(const dns_name_t *source, isc_mem_t *mctx, 2137165071Sdougb dns_name_t *target) 2138165071Sdougb{ 2139135446Strhodes /* 2140135446Strhodes * Make 'target' a dynamically allocated copy of 'source'. 2141135446Strhodes */ 2142135446Strhodes 2143135446Strhodes REQUIRE(VALID_NAME(source)); 2144135446Strhodes REQUIRE(source->length > 0); 2145135446Strhodes REQUIRE(VALID_NAME(target)); 2146135446Strhodes REQUIRE(BINDABLE(target)); 2147135446Strhodes 2148135446Strhodes /* 2149135446Strhodes * Make 'target' empty in case of failure. 2150135446Strhodes */ 2151135446Strhodes MAKE_EMPTY(target); 2152135446Strhodes 2153135446Strhodes target->ndata = isc_mem_get(mctx, source->length); 2154135446Strhodes if (target->ndata == NULL) 2155135446Strhodes return (ISC_R_NOMEMORY); 2156135446Strhodes 2157135446Strhodes memcpy(target->ndata, source->ndata, source->length); 2158135446Strhodes 2159135446Strhodes target->length = source->length; 2160135446Strhodes target->labels = source->labels; 2161135446Strhodes target->attributes = DNS_NAMEATTR_DYNAMIC; 2162135446Strhodes if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0) 2163135446Strhodes target->attributes |= DNS_NAMEATTR_ABSOLUTE; 2164135446Strhodes if (target->offsets != NULL) { 2165135446Strhodes if (source->offsets != NULL) 2166135446Strhodes memcpy(target->offsets, source->offsets, 2167135446Strhodes source->labels); 2168135446Strhodes else 2169135446Strhodes set_offsets(target, target->offsets, NULL); 2170135446Strhodes } 2171135446Strhodes 2172135446Strhodes return (ISC_R_SUCCESS); 2173135446Strhodes} 2174135446Strhodes 2175135446Strhodesisc_result_t 2176135446Strhodesdns_name_dupwithoffsets(dns_name_t *source, isc_mem_t *mctx, 2177135446Strhodes dns_name_t *target) 2178135446Strhodes{ 2179135446Strhodes /* 2180135446Strhodes * Make 'target' a read-only dynamically allocated copy of 'source'. 2181135446Strhodes * 'target' will also have a dynamically allocated offsets table. 2182135446Strhodes */ 2183135446Strhodes 2184135446Strhodes REQUIRE(VALID_NAME(source)); 2185135446Strhodes REQUIRE(source->length > 0); 2186135446Strhodes REQUIRE(VALID_NAME(target)); 2187135446Strhodes REQUIRE(BINDABLE(target)); 2188135446Strhodes REQUIRE(target->offsets == NULL); 2189135446Strhodes 2190135446Strhodes /* 2191135446Strhodes * Make 'target' empty in case of failure. 2192135446Strhodes */ 2193135446Strhodes MAKE_EMPTY(target); 2194135446Strhodes 2195135446Strhodes target->ndata = isc_mem_get(mctx, source->length + source->labels); 2196135446Strhodes if (target->ndata == NULL) 2197135446Strhodes return (ISC_R_NOMEMORY); 2198135446Strhodes 2199135446Strhodes memcpy(target->ndata, source->ndata, source->length); 2200135446Strhodes 2201135446Strhodes target->length = source->length; 2202135446Strhodes target->labels = source->labels; 2203135446Strhodes target->attributes = DNS_NAMEATTR_DYNAMIC | DNS_NAMEATTR_DYNOFFSETS | 2204135446Strhodes DNS_NAMEATTR_READONLY; 2205135446Strhodes if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0) 2206135446Strhodes target->attributes |= DNS_NAMEATTR_ABSOLUTE; 2207135446Strhodes target->offsets = target->ndata + source->length; 2208135446Strhodes if (source->offsets != NULL) 2209135446Strhodes memcpy(target->offsets, source->offsets, source->labels); 2210135446Strhodes else 2211135446Strhodes set_offsets(target, target->offsets, NULL); 2212135446Strhodes 2213135446Strhodes return (ISC_R_SUCCESS); 2214135446Strhodes} 2215135446Strhodes 2216135446Strhodesvoid 2217135446Strhodesdns_name_free(dns_name_t *name, isc_mem_t *mctx) { 2218135446Strhodes size_t size; 2219135446Strhodes 2220135446Strhodes /* 2221135446Strhodes * Free 'name'. 2222135446Strhodes */ 2223135446Strhodes 2224135446Strhodes REQUIRE(VALID_NAME(name)); 2225135446Strhodes REQUIRE((name->attributes & DNS_NAMEATTR_DYNAMIC) != 0); 2226135446Strhodes 2227135446Strhodes size = name->length; 2228135446Strhodes if ((name->attributes & DNS_NAMEATTR_DYNOFFSETS) != 0) 2229135446Strhodes size += name->labels; 2230135446Strhodes isc_mem_put(mctx, name->ndata, size); 2231135446Strhodes dns_name_invalidate(name); 2232135446Strhodes} 2233135446Strhodes 2234135446Strhodesisc_result_t 2235135446Strhodesdns_name_digest(dns_name_t *name, dns_digestfunc_t digest, void *arg) { 2236135446Strhodes dns_name_t downname; 2237135446Strhodes unsigned char data[256]; 2238135446Strhodes isc_buffer_t buffer; 2239135446Strhodes isc_result_t result; 2240135446Strhodes isc_region_t r; 2241135446Strhodes 2242135446Strhodes /* 2243135446Strhodes * Send 'name' in DNSSEC canonical form to 'digest'. 2244135446Strhodes */ 2245135446Strhodes 2246135446Strhodes REQUIRE(VALID_NAME(name)); 2247135446Strhodes REQUIRE(digest != NULL); 2248135446Strhodes 2249135446Strhodes DNS_NAME_INIT(&downname, NULL); 2250135446Strhodes isc_buffer_init(&buffer, data, sizeof(data)); 2251135446Strhodes 2252135446Strhodes result = dns_name_downcase(name, &downname, &buffer); 2253135446Strhodes if (result != ISC_R_SUCCESS) 2254135446Strhodes return (result); 2255135446Strhodes 2256135446Strhodes isc_buffer_usedregion(&buffer, &r); 2257135446Strhodes 2258135446Strhodes return ((digest)(arg, &r)); 2259135446Strhodes} 2260135446Strhodes 2261135446Strhodesisc_boolean_t 2262135446Strhodesdns_name_dynamic(dns_name_t *name) { 2263135446Strhodes REQUIRE(VALID_NAME(name)); 2264135446Strhodes 2265135446Strhodes /* 2266135446Strhodes * Returns whether there is dynamic memory associated with this name. 2267135446Strhodes */ 2268135446Strhodes 2269135446Strhodes return ((name->attributes & DNS_NAMEATTR_DYNAMIC) != 0 ? 2270135446Strhodes ISC_TRUE : ISC_FALSE); 2271135446Strhodes} 2272135446Strhodes 2273135446Strhodesisc_result_t 2274135446Strhodesdns_name_print(dns_name_t *name, FILE *stream) { 2275135446Strhodes isc_result_t result; 2276135446Strhodes isc_buffer_t b; 2277135446Strhodes isc_region_t r; 2278135446Strhodes char t[1024]; 2279135446Strhodes 2280135446Strhodes /* 2281135446Strhodes * Print 'name' on 'stream'. 2282135446Strhodes */ 2283135446Strhodes 2284135446Strhodes REQUIRE(VALID_NAME(name)); 2285135446Strhodes 2286135446Strhodes isc_buffer_init(&b, t, sizeof(t)); 2287135446Strhodes result = dns_name_totext(name, ISC_FALSE, &b); 2288135446Strhodes if (result != ISC_R_SUCCESS) 2289135446Strhodes return (result); 2290135446Strhodes isc_buffer_usedregion(&b, &r); 2291135446Strhodes fprintf(stream, "%.*s", (int)r.length, (char *)r.base); 2292135446Strhodes 2293135446Strhodes return (ISC_R_SUCCESS); 2294135446Strhodes} 2295135446Strhodes 2296170222Sdougbisc_result_t 2297170222Sdougbdns_name_settotextfilter(dns_name_totextfilter_t proc) { 2298170222Sdougb#ifdef ISC_PLATFORM_USETHREADS 2299170222Sdougb isc_result_t result; 2300170222Sdougb dns_name_totextfilter_t *mem; 2301170222Sdougb int res; 2302170222Sdougb 2303170222Sdougb result = totext_filter_proc_key_init(); 2304170222Sdougb if (result != ISC_R_SUCCESS) 2305170222Sdougb return (result); 2306170222Sdougb 2307170222Sdougb /* 2308170222Sdougb * If we already have been here set / clear as appropriate. 2309170222Sdougb * Otherwise allocate memory. 2310170222Sdougb */ 2311170222Sdougb mem = isc_thread_key_getspecific(totext_filter_proc_key); 2312170222Sdougb if (mem != NULL && proc != NULL) { 2313170222Sdougb *mem = proc; 2314170222Sdougb return (ISC_R_SUCCESS); 2315170222Sdougb } 2316170222Sdougb if (proc == NULL) { 2317170222Sdougb isc_mem_put(thread_key_mctx, mem, sizeof(*mem)); 2318170222Sdougb res = isc_thread_key_setspecific(totext_filter_proc_key, NULL); 2319170222Sdougb if (res != 0) 2320170222Sdougb result = ISC_R_UNEXPECTED; 2321170222Sdougb return (result); 2322170222Sdougb } 2323193149Sdougb 2324170222Sdougb mem = isc_mem_get(thread_key_mctx, sizeof(*mem)); 2325170222Sdougb if (mem == NULL) 2326170222Sdougb return (ISC_R_NOMEMORY); 2327170222Sdougb *mem = proc; 2328170222Sdougb if (isc_thread_key_setspecific(totext_filter_proc_key, mem) != 0) { 2329170222Sdougb isc_mem_put(thread_key_mctx, mem, sizeof(*mem)); 2330170222Sdougb result = ISC_R_UNEXPECTED; 2331170222Sdougb } 2332170222Sdougb return (result); 2333170222Sdougb#else 2334170222Sdougb totext_filter_proc = proc; 2335170222Sdougb return (ISC_R_SUCCESS); 2336170222Sdougb#endif 2337170222Sdougb} 2338170222Sdougb 2339135446Strhodesvoid 2340135446Strhodesdns_name_format(dns_name_t *name, char *cp, unsigned int size) { 2341135446Strhodes isc_result_t result; 2342135446Strhodes isc_buffer_t buf; 2343135446Strhodes 2344135446Strhodes REQUIRE(size > 0); 2345135446Strhodes 2346135446Strhodes /* 2347135446Strhodes * Leave room for null termination after buffer. 2348135446Strhodes */ 2349135446Strhodes isc_buffer_init(&buf, cp, size - 1); 2350135446Strhodes result = dns_name_totext(name, ISC_TRUE, &buf); 2351135446Strhodes if (result == ISC_R_SUCCESS) { 2352135446Strhodes /* 2353135446Strhodes * Null terminate. 2354135446Strhodes */ 2355135446Strhodes isc_region_t r; 2356135446Strhodes isc_buffer_usedregion(&buf, &r); 2357135446Strhodes ((char *) r.base)[r.length] = '\0'; 2358135446Strhodes 2359135446Strhodes } else 2360135446Strhodes snprintf(cp, size, "<unknown>"); 2361135446Strhodes} 2362135446Strhodes 2363224092Sdougb/* 2364224092Sdougb * dns_name_tostring() -- similar to dns_name_format() but allocates its own 2365224092Sdougb * memory. 2366224092Sdougb */ 2367135446Strhodesisc_result_t 2368224092Sdougbdns_name_tostring(dns_name_t *name, char **target, isc_mem_t *mctx) { 2369224092Sdougb isc_result_t result; 2370224092Sdougb isc_buffer_t buf; 2371224092Sdougb isc_region_t reg; 2372224092Sdougb char *p, txt[DNS_NAME_FORMATSIZE]; 2373224092Sdougb 2374224092Sdougb REQUIRE(VALID_NAME(name)); 2375224092Sdougb REQUIRE(target != NULL && *target == NULL); 2376224092Sdougb 2377224092Sdougb isc_buffer_init(&buf, txt, sizeof(txt)); 2378224092Sdougb result = dns_name_totext(name, ISC_FALSE, &buf); 2379224092Sdougb if (result != ISC_R_SUCCESS) 2380224092Sdougb return (result); 2381224092Sdougb 2382224092Sdougb isc_buffer_usedregion(&buf, ®); 2383224092Sdougb p = isc_mem_allocate(mctx, reg.length + 1); 2384224092Sdougb memcpy(p, (char *) reg.base, (int) reg.length); 2385224092Sdougb p[reg.length] = '\0'; 2386224092Sdougb 2387224092Sdougb *target = p; 2388224092Sdougb return (ISC_R_SUCCESS); 2389224092Sdougb} 2390224092Sdougb 2391224092Sdougb/* 2392224092Sdougb * dns_name_fromstring() -- convert directly from a string to a name, 2393224092Sdougb * allocating memory as needed 2394224092Sdougb */ 2395224092Sdougbisc_result_t 2396224092Sdougbdns_name_fromstring(dns_name_t *target, const char *src, unsigned int options, 2397224092Sdougb isc_mem_t *mctx) 2398224092Sdougb{ 2399224092Sdougb return (dns_name_fromstring2(target, src, dns_rootname, options, mctx)); 2400224092Sdougb} 2401224092Sdougb 2402224092Sdougbisc_result_t 2403224092Sdougbdns_name_fromstring2(dns_name_t *target, const char *src, 2404224092Sdougb const dns_name_t *origin, unsigned int options, 2405224092Sdougb isc_mem_t *mctx) 2406224092Sdougb{ 2407224092Sdougb isc_result_t result; 2408224092Sdougb isc_buffer_t buf; 2409224092Sdougb dns_fixedname_t fn; 2410224092Sdougb dns_name_t *name; 2411224092Sdougb 2412224092Sdougb REQUIRE(src != NULL); 2413224092Sdougb 2414224092Sdougb isc_buffer_init(&buf, src, strlen(src)); 2415224092Sdougb isc_buffer_add(&buf, strlen(src)); 2416224092Sdougb if (BINDABLE(target) && target->buffer != NULL) 2417224092Sdougb name = target; 2418224092Sdougb else { 2419224092Sdougb dns_fixedname_init(&fn); 2420224092Sdougb name = dns_fixedname_name(&fn); 2421224092Sdougb } 2422224092Sdougb 2423224092Sdougb result = dns_name_fromtext(name, &buf, origin, options, NULL); 2424224092Sdougb if (result != ISC_R_SUCCESS) 2425224092Sdougb return (result); 2426224092Sdougb 2427224092Sdougb if (name != target) 2428224092Sdougb result = dns_name_dupwithoffsets(name, mctx, target); 2429224092Sdougb return (result); 2430224092Sdougb} 2431224092Sdougb 2432224092Sdougbisc_result_t 2433135446Strhodesdns_name_copy(dns_name_t *source, dns_name_t *dest, isc_buffer_t *target) { 2434135446Strhodes unsigned char *ndata; 2435135446Strhodes 2436135446Strhodes /* 2437135446Strhodes * Make dest a copy of source. 2438135446Strhodes */ 2439135446Strhodes 2440135446Strhodes REQUIRE(VALID_NAME(source)); 2441135446Strhodes REQUIRE(VALID_NAME(dest)); 2442135446Strhodes REQUIRE(target != NULL || dest->buffer != NULL); 2443135446Strhodes 2444135446Strhodes if (target == NULL) { 2445135446Strhodes target = dest->buffer; 2446135446Strhodes isc_buffer_clear(dest->buffer); 2447135446Strhodes } 2448135446Strhodes 2449135446Strhodes REQUIRE(BINDABLE(dest)); 2450135446Strhodes 2451135446Strhodes /* 2452135446Strhodes * Set up. 2453135446Strhodes */ 2454135446Strhodes if (target->length - target->used < source->length) 2455135446Strhodes return (ISC_R_NOSPACE); 2456135446Strhodes 2457135446Strhodes ndata = (unsigned char *)target->base + target->used; 2458135446Strhodes dest->ndata = target->base; 2459135446Strhodes 2460135446Strhodes memcpy(ndata, source->ndata, source->length); 2461135446Strhodes 2462135446Strhodes dest->ndata = ndata; 2463135446Strhodes dest->labels = source->labels; 2464135446Strhodes dest->length = source->length; 2465135446Strhodes if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0) 2466135446Strhodes dest->attributes = DNS_NAMEATTR_ABSOLUTE; 2467135446Strhodes else 2468135446Strhodes dest->attributes = 0; 2469135446Strhodes 2470135446Strhodes if (dest->labels > 0 && dest->offsets != NULL) { 2471135446Strhodes if (source->offsets != NULL) 2472135446Strhodes memcpy(dest->offsets, source->offsets, source->labels); 2473135446Strhodes else 2474135446Strhodes set_offsets(dest, dest->offsets, NULL); 2475135446Strhodes } 2476135446Strhodes 2477135446Strhodes isc_buffer_add(target, dest->length); 2478135446Strhodes 2479135446Strhodes return (ISC_R_SUCCESS); 2480135446Strhodes} 2481135446Strhodes 2482170222Sdougbvoid 2483170222Sdougbdns_name_destroy(void) { 2484170222Sdougb#ifdef ISC_PLATFORM_USETHREADS 2485170222Sdougb RUNTIME_CHECK(isc_once_do(&once, thread_key_mutex_init) 2486170222Sdougb == ISC_R_SUCCESS); 2487170222Sdougb 2488170222Sdougb LOCK(&thread_key_mutex); 2489170222Sdougb if (thread_key_initialized) { 2490170222Sdougb isc_mem_detach(&thread_key_mctx); 2491170222Sdougb isc_thread_key_delete(totext_filter_proc_key); 2492170222Sdougb thread_key_initialized = 0; 2493170222Sdougb } 2494170222Sdougb UNLOCK(&thread_key_mutex); 2495170222Sdougb 2496170222Sdougb#endif 2497170222Sdougb} 2498