1135446Strhodes/* 2262706Serwin * Copyright (C) 2004-2014 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 18234010Sdougb/* $Id$ */ 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 581262706Serwin if (name1 == name2) { 582262706Serwin *orderp = 0; 583262706Serwin return (dns_namereln_equal); 584262706Serwin } 585262706Serwin 586135446Strhodes SETUP_OFFSETS(name1, offsets1, odata1); 587135446Strhodes SETUP_OFFSETS(name2, offsets2, odata2); 588135446Strhodes 589135446Strhodes nlabels = 0; 590135446Strhodes l1 = name1->labels; 591135446Strhodes l2 = name2->labels; 592254402Serwin if (l2 > l1) { 593135446Strhodes l = l1; 594254402Serwin ldiff = 0 - (l2 - l1); 595254402Serwin } else { 596135446Strhodes l = l2; 597254402Serwin ldiff = l1 - l2; 598254402Serwin } 599135446Strhodes 600135446Strhodes while (l > 0) { 601135446Strhodes l--; 602135446Strhodes l1--; 603135446Strhodes l2--; 604135446Strhodes label1 = &name1->ndata[offsets1[l1]]; 605135446Strhodes label2 = &name2->ndata[offsets2[l2]]; 606135446Strhodes count1 = *label1++; 607135446Strhodes count2 = *label2++; 608135446Strhodes 609135446Strhodes /* 610135446Strhodes * We dropped bitstring labels, and we don't support any 611135446Strhodes * other extended label types. 612135446Strhodes */ 613135446Strhodes INSIST(count1 <= 63 && count2 <= 63); 614135446Strhodes 615135446Strhodes cdiff = (int)count1 - (int)count2; 616135446Strhodes if (cdiff < 0) 617135446Strhodes count = count1; 618135446Strhodes else 619135446Strhodes count = count2; 620135446Strhodes 621135446Strhodes while (count > 0) { 622135446Strhodes chdiff = (int)maptolower[*label1] - 623135446Strhodes (int)maptolower[*label2]; 624135446Strhodes if (chdiff != 0) { 625135446Strhodes *orderp = chdiff; 626135446Strhodes goto done; 627135446Strhodes } 628135446Strhodes count--; 629135446Strhodes label1++; 630135446Strhodes label2++; 631135446Strhodes } 632135446Strhodes if (cdiff != 0) { 633135446Strhodes *orderp = cdiff; 634135446Strhodes goto done; 635135446Strhodes } 636135446Strhodes nlabels++; 637135446Strhodes } 638135446Strhodes 639135446Strhodes *orderp = ldiff; 640135446Strhodes if (ldiff < 0) 641135446Strhodes namereln = dns_namereln_contains; 642135446Strhodes else if (ldiff > 0) 643135446Strhodes namereln = dns_namereln_subdomain; 644135446Strhodes else 645135446Strhodes namereln = dns_namereln_equal; 646135446Strhodes 647135446Strhodes done: 648135446Strhodes *nlabelsp = nlabels; 649135446Strhodes 650135446Strhodes if (nlabels > 0 && namereln == dns_namereln_none) 651135446Strhodes namereln = dns_namereln_commonancestor; 652135446Strhodes 653135446Strhodes return (namereln); 654135446Strhodes} 655135446Strhodes 656135446Strhodesint 657135446Strhodesdns_name_compare(const dns_name_t *name1, const dns_name_t *name2) { 658135446Strhodes int order; 659135446Strhodes unsigned int nlabels; 660135446Strhodes 661135446Strhodes /* 662135446Strhodes * Determine the relative ordering under the DNSSEC order relation of 663135446Strhodes * 'name1' and 'name2'. 664135446Strhodes * 665135446Strhodes * Note: It makes no sense for one of the names to be relative and the 666135446Strhodes * other absolute. If both names are relative, then to be meaningfully 667135446Strhodes * compared the caller must ensure that they are both relative to the 668135446Strhodes * same domain. 669135446Strhodes */ 670135446Strhodes 671135446Strhodes (void)dns_name_fullcompare(name1, name2, &order, &nlabels); 672135446Strhodes 673135446Strhodes return (order); 674135446Strhodes} 675135446Strhodes 676135446Strhodesisc_boolean_t 677135446Strhodesdns_name_equal(const dns_name_t *name1, const dns_name_t *name2) { 678135446Strhodes unsigned int l, count; 679135446Strhodes unsigned char c; 680135446Strhodes unsigned char *label1, *label2; 681135446Strhodes 682135446Strhodes /* 683135446Strhodes * Are 'name1' and 'name2' equal? 684135446Strhodes * 685135446Strhodes * Note: It makes no sense for one of the names to be relative and the 686135446Strhodes * other absolute. If both names are relative, then to be meaningfully 687135446Strhodes * compared the caller must ensure that they are both relative to the 688135446Strhodes * same domain. 689135446Strhodes */ 690135446Strhodes 691135446Strhodes REQUIRE(VALID_NAME(name1)); 692135446Strhodes REQUIRE(VALID_NAME(name2)); 693135446Strhodes /* 694135446Strhodes * Either name1 is absolute and name2 is absolute, or neither is. 695135446Strhodes */ 696135446Strhodes REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) == 697135446Strhodes (name2->attributes & DNS_NAMEATTR_ABSOLUTE)); 698135446Strhodes 699262706Serwin if (name1 == name2) 700262706Serwin return (ISC_TRUE); 701262706Serwin 702135446Strhodes if (name1->length != name2->length) 703135446Strhodes return (ISC_FALSE); 704135446Strhodes 705135446Strhodes l = name1->labels; 706135446Strhodes 707135446Strhodes if (l != name2->labels) 708135446Strhodes return (ISC_FALSE); 709135446Strhodes 710135446Strhodes label1 = name1->ndata; 711135446Strhodes label2 = name2->ndata; 712135446Strhodes while (l > 0) { 713135446Strhodes l--; 714135446Strhodes count = *label1++; 715135446Strhodes if (count != *label2++) 716135446Strhodes return (ISC_FALSE); 717135446Strhodes 718135446Strhodes INSIST(count <= 63); /* no bitstring support */ 719135446Strhodes 720135446Strhodes while (count > 0) { 721135446Strhodes count--; 722135446Strhodes c = maptolower[*label1++]; 723135446Strhodes if (c != maptolower[*label2++]) 724135446Strhodes return (ISC_FALSE); 725135446Strhodes } 726135446Strhodes } 727135446Strhodes 728135446Strhodes return (ISC_TRUE); 729135446Strhodes} 730135446Strhodes 731170222Sdougbisc_boolean_t 732170222Sdougbdns_name_caseequal(const dns_name_t *name1, const dns_name_t *name2) { 733170222Sdougb 734170222Sdougb /* 735170222Sdougb * Are 'name1' and 'name2' equal? 736170222Sdougb * 737170222Sdougb * Note: It makes no sense for one of the names to be relative and the 738170222Sdougb * other absolute. If both names are relative, then to be meaningfully 739170222Sdougb * compared the caller must ensure that they are both relative to the 740170222Sdougb * same domain. 741170222Sdougb */ 742170222Sdougb 743170222Sdougb REQUIRE(VALID_NAME(name1)); 744170222Sdougb REQUIRE(VALID_NAME(name2)); 745170222Sdougb /* 746170222Sdougb * Either name1 is absolute and name2 is absolute, or neither is. 747170222Sdougb */ 748170222Sdougb REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) == 749170222Sdougb (name2->attributes & DNS_NAMEATTR_ABSOLUTE)); 750170222Sdougb 751170222Sdougb if (name1->length != name2->length) 752170222Sdougb return (ISC_FALSE); 753170222Sdougb 754170222Sdougb if (memcmp(name1->ndata, name2->ndata, name1->length) != 0) 755170222Sdougb return (ISC_FALSE); 756170222Sdougb 757170222Sdougb return (ISC_TRUE); 758170222Sdougb} 759170222Sdougb 760135446Strhodesint 761135446Strhodesdns_name_rdatacompare(const dns_name_t *name1, const dns_name_t *name2) { 762135446Strhodes unsigned int l1, l2, l, count1, count2, count; 763135446Strhodes unsigned char c1, c2; 764135446Strhodes unsigned char *label1, *label2; 765135446Strhodes 766135446Strhodes /* 767135446Strhodes * Compare two absolute names as rdata. 768135446Strhodes */ 769135446Strhodes 770135446Strhodes REQUIRE(VALID_NAME(name1)); 771135446Strhodes REQUIRE(name1->labels > 0); 772135446Strhodes REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) != 0); 773135446Strhodes REQUIRE(VALID_NAME(name2)); 774135446Strhodes REQUIRE(name2->labels > 0); 775135446Strhodes REQUIRE((name2->attributes & DNS_NAMEATTR_ABSOLUTE) != 0); 776135446Strhodes 777135446Strhodes l1 = name1->labels; 778135446Strhodes l2 = name2->labels; 779135446Strhodes 780135446Strhodes l = (l1 < l2) ? l1 : l2; 781135446Strhodes 782135446Strhodes label1 = name1->ndata; 783135446Strhodes label2 = name2->ndata; 784135446Strhodes while (l > 0) { 785135446Strhodes l--; 786135446Strhodes count1 = *label1++; 787135446Strhodes count2 = *label2++; 788135446Strhodes 789135446Strhodes /* no bitstring support */ 790135446Strhodes INSIST(count1 <= 63 && count2 <= 63); 791135446Strhodes 792135446Strhodes if (count1 != count2) 793135446Strhodes return ((count1 < count2) ? -1 : 1); 794135446Strhodes count = count1; 795135446Strhodes while (count > 0) { 796135446Strhodes count--; 797135446Strhodes c1 = maptolower[*label1++]; 798135446Strhodes c2 = maptolower[*label2++]; 799135446Strhodes if (c1 < c2) 800135446Strhodes return (-1); 801135446Strhodes else if (c1 > c2) 802135446Strhodes return (1); 803135446Strhodes } 804135446Strhodes } 805135446Strhodes 806135446Strhodes /* 807135446Strhodes * If one name had more labels than the other, their common 808135446Strhodes * prefix must have been different because the shorter name 809135446Strhodes * ended with the root label and the longer one can't have 810135446Strhodes * a root label in the middle of it. Therefore, if we get 811135446Strhodes * to this point, the lengths must be equal. 812135446Strhodes */ 813135446Strhodes INSIST(l1 == l2); 814135446Strhodes 815135446Strhodes return (0); 816135446Strhodes} 817135446Strhodes 818135446Strhodesisc_boolean_t 819135446Strhodesdns_name_issubdomain(const dns_name_t *name1, const dns_name_t *name2) { 820135446Strhodes int order; 821135446Strhodes unsigned int nlabels; 822135446Strhodes dns_namereln_t namereln; 823135446Strhodes 824135446Strhodes /* 825135446Strhodes * Is 'name1' a subdomain of 'name2'? 826135446Strhodes * 827135446Strhodes * Note: It makes no sense for one of the names to be relative and the 828135446Strhodes * other absolute. If both names are relative, then to be meaningfully 829135446Strhodes * compared the caller must ensure that they are both relative to the 830135446Strhodes * same domain. 831135446Strhodes */ 832135446Strhodes 833135446Strhodes namereln = dns_name_fullcompare(name1, name2, &order, &nlabels); 834135446Strhodes if (namereln == dns_namereln_subdomain || 835135446Strhodes namereln == dns_namereln_equal) 836135446Strhodes return (ISC_TRUE); 837135446Strhodes 838135446Strhodes return (ISC_FALSE); 839135446Strhodes} 840135446Strhodes 841135446Strhodesisc_boolean_t 842135446Strhodesdns_name_matcheswildcard(const dns_name_t *name, const dns_name_t *wname) { 843135446Strhodes int order; 844135446Strhodes unsigned int nlabels, labels; 845135446Strhodes dns_name_t tname; 846135446Strhodes 847135446Strhodes REQUIRE(VALID_NAME(name)); 848135446Strhodes REQUIRE(name->labels > 0); 849135446Strhodes REQUIRE(VALID_NAME(wname)); 850135446Strhodes labels = wname->labels; 851135446Strhodes REQUIRE(labels > 0); 852135446Strhodes REQUIRE(dns_name_iswildcard(wname)); 853135446Strhodes 854254402Serwin#if defined(__clang__) && \ 855254402Serwin ( __clang_major__ < 3 || (__clang_major__ == 3 && __clang_minor__ < 2)) 856254402Serwin memset(&tname, 0, sizeof(tname)); 857254402Serwin#endif 858135446Strhodes DNS_NAME_INIT(&tname, NULL); 859135446Strhodes dns_name_getlabelsequence(wname, 1, labels - 1, &tname); 860135446Strhodes if (dns_name_fullcompare(name, &tname, &order, &nlabels) == 861135446Strhodes dns_namereln_subdomain) 862135446Strhodes return (ISC_TRUE); 863135446Strhodes return (ISC_FALSE); 864135446Strhodes} 865135446Strhodes 866135446Strhodesunsigned int 867135446Strhodesdns_name_countlabels(const dns_name_t *name) { 868135446Strhodes /* 869135446Strhodes * How many labels does 'name' have? 870135446Strhodes */ 871135446Strhodes 872135446Strhodes REQUIRE(VALID_NAME(name)); 873135446Strhodes 874135446Strhodes ENSURE(name->labels <= 128); 875135446Strhodes 876135446Strhodes return (name->labels); 877135446Strhodes} 878135446Strhodes 879135446Strhodesvoid 880135446Strhodesdns_name_getlabel(const dns_name_t *name, unsigned int n, dns_label_t *label) { 881135446Strhodes unsigned char *offsets; 882135446Strhodes dns_offsets_t odata; 883135446Strhodes 884135446Strhodes /* 885135446Strhodes * Make 'label' refer to the 'n'th least significant label of 'name'. 886135446Strhodes */ 887135446Strhodes 888135446Strhodes REQUIRE(VALID_NAME(name)); 889135446Strhodes REQUIRE(name->labels > 0); 890135446Strhodes REQUIRE(n < name->labels); 891135446Strhodes REQUIRE(label != NULL); 892135446Strhodes 893135446Strhodes SETUP_OFFSETS(name, offsets, odata); 894135446Strhodes 895135446Strhodes label->base = &name->ndata[offsets[n]]; 896135446Strhodes if (n == name->labels - 1) 897135446Strhodes label->length = name->length - offsets[n]; 898135446Strhodes else 899135446Strhodes label->length = offsets[n + 1] - offsets[n]; 900135446Strhodes} 901135446Strhodes 902135446Strhodesvoid 903135446Strhodesdns_name_getlabelsequence(const dns_name_t *source, 904135446Strhodes unsigned int first, unsigned int n, 905135446Strhodes dns_name_t *target) 906135446Strhodes{ 907135446Strhodes unsigned char *offsets; 908135446Strhodes dns_offsets_t odata; 909135446Strhodes unsigned int firstoffset, endoffset; 910135446Strhodes 911135446Strhodes /* 912135446Strhodes * Make 'target' refer to the 'n' labels including and following 913135446Strhodes * 'first' in 'source'. 914135446Strhodes */ 915135446Strhodes 916135446Strhodes REQUIRE(VALID_NAME(source)); 917135446Strhodes REQUIRE(VALID_NAME(target)); 918135446Strhodes REQUIRE(first <= source->labels); 919218384Sdougb REQUIRE(n <= source->labels - first); /* note first+n could overflow */ 920135446Strhodes REQUIRE(BINDABLE(target)); 921135446Strhodes 922135446Strhodes SETUP_OFFSETS(source, offsets, odata); 923135446Strhodes 924135446Strhodes if (first == source->labels) 925135446Strhodes firstoffset = source->length; 926135446Strhodes else 927135446Strhodes firstoffset = offsets[first]; 928135446Strhodes 929135446Strhodes if (first + n == source->labels) 930135446Strhodes endoffset = source->length; 931135446Strhodes else 932135446Strhodes endoffset = offsets[first + n]; 933135446Strhodes 934135446Strhodes target->ndata = &source->ndata[firstoffset]; 935135446Strhodes target->length = endoffset - firstoffset; 936193149Sdougb 937135446Strhodes if (first + n == source->labels && n > 0 && 938135446Strhodes (source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0) 939135446Strhodes target->attributes |= DNS_NAMEATTR_ABSOLUTE; 940135446Strhodes else 941135446Strhodes target->attributes &= ~DNS_NAMEATTR_ABSOLUTE; 942135446Strhodes 943135446Strhodes target->labels = n; 944135446Strhodes 945135446Strhodes /* 946135446Strhodes * If source and target are the same, and we're making target 947135446Strhodes * a prefix of source, the offsets table is correct already 948135446Strhodes * so we don't need to call set_offsets(). 949135446Strhodes */ 950135446Strhodes if (target->offsets != NULL && 951135446Strhodes (target != source || first != 0)) 952135446Strhodes set_offsets(target, target->offsets, NULL); 953135446Strhodes} 954135446Strhodes 955135446Strhodesvoid 956165071Sdougbdns_name_clone(const dns_name_t *source, dns_name_t *target) { 957135446Strhodes 958135446Strhodes /* 959135446Strhodes * Make 'target' refer to the same name as 'source'. 960135446Strhodes */ 961135446Strhodes 962135446Strhodes REQUIRE(VALID_NAME(source)); 963135446Strhodes REQUIRE(VALID_NAME(target)); 964135446Strhodes REQUIRE(BINDABLE(target)); 965135446Strhodes 966135446Strhodes target->ndata = source->ndata; 967135446Strhodes target->length = source->length; 968135446Strhodes target->labels = source->labels; 969135446Strhodes target->attributes = source->attributes & 970135446Strhodes (unsigned int)~(DNS_NAMEATTR_READONLY | DNS_NAMEATTR_DYNAMIC | 971135446Strhodes DNS_NAMEATTR_DYNOFFSETS); 972135446Strhodes if (target->offsets != NULL && source->labels > 0) { 973135446Strhodes if (source->offsets != NULL) 974262706Serwin memmove(target->offsets, source->offsets, 975262706Serwin source->labels); 976135446Strhodes else 977135446Strhodes set_offsets(target, target->offsets, NULL); 978135446Strhodes } 979135446Strhodes} 980135446Strhodes 981135446Strhodesvoid 982135446Strhodesdns_name_fromregion(dns_name_t *name, const isc_region_t *r) { 983135446Strhodes unsigned char *offsets; 984135446Strhodes dns_offsets_t odata; 985135446Strhodes unsigned int len; 986135446Strhodes isc_region_t r2; 987135446Strhodes 988135446Strhodes /* 989135446Strhodes * Make 'name' refer to region 'r'. 990135446Strhodes */ 991135446Strhodes 992135446Strhodes REQUIRE(VALID_NAME(name)); 993135446Strhodes REQUIRE(r != NULL); 994135446Strhodes REQUIRE(BINDABLE(name)); 995135446Strhodes 996135446Strhodes INIT_OFFSETS(name, offsets, odata); 997135446Strhodes 998135446Strhodes if (name->buffer != NULL) { 999135446Strhodes isc_buffer_clear(name->buffer); 1000135446Strhodes isc_buffer_availableregion(name->buffer, &r2); 1001135446Strhodes len = (r->length < r2.length) ? r->length : r2.length; 1002135446Strhodes if (len > DNS_NAME_MAXWIRE) 1003135446Strhodes len = DNS_NAME_MAXWIRE; 1004262706Serwin memmove(r2.base, r->base, len); 1005135446Strhodes name->ndata = r2.base; 1006135446Strhodes name->length = len; 1007135446Strhodes } else { 1008135446Strhodes name->ndata = r->base; 1009193149Sdougb name->length = (r->length <= DNS_NAME_MAXWIRE) ? 1010135446Strhodes r->length : DNS_NAME_MAXWIRE; 1011135446Strhodes } 1012135446Strhodes 1013135446Strhodes if (r->length > 0) 1014135446Strhodes set_offsets(name, offsets, name); 1015135446Strhodes else { 1016135446Strhodes name->labels = 0; 1017135446Strhodes name->attributes &= ~DNS_NAMEATTR_ABSOLUTE; 1018135446Strhodes } 1019135446Strhodes 1020135446Strhodes if (name->buffer != NULL) 1021135446Strhodes isc_buffer_add(name->buffer, name->length); 1022135446Strhodes} 1023135446Strhodes 1024135446Strhodesvoid 1025135446Strhodesdns_name_toregion(dns_name_t *name, isc_region_t *r) { 1026135446Strhodes /* 1027135446Strhodes * Make 'r' refer to 'name'. 1028135446Strhodes */ 1029135446Strhodes 1030135446Strhodes REQUIRE(VALID_NAME(name)); 1031135446Strhodes REQUIRE(r != NULL); 1032135446Strhodes 1033135446Strhodes DNS_NAME_TOREGION(name, r); 1034135446Strhodes} 1035135446Strhodes 1036135446Strhodesisc_result_t 1037135446Strhodesdns_name_fromtext(dns_name_t *name, isc_buffer_t *source, 1038224092Sdougb const dns_name_t *origin, unsigned int options, 1039135446Strhodes isc_buffer_t *target) 1040135446Strhodes{ 1041225361Sdougb unsigned char *ndata, *label = NULL; 1042135446Strhodes char *tdata; 1043135446Strhodes char c; 1044153816Sdougb ft_state state; 1045225361Sdougb unsigned int value = 0, count = 0; 1046225361Sdougb unsigned int n1 = 0, n2 = 0; 1047225361Sdougb unsigned int tlen, nrem, nused, digits = 0, labels, tused; 1048135446Strhodes isc_boolean_t done; 1049135446Strhodes unsigned char *offsets; 1050135446Strhodes dns_offsets_t odata; 1051135446Strhodes isc_boolean_t downcase; 1052135446Strhodes 1053135446Strhodes /* 1054135446Strhodes * Convert the textual representation of a DNS name at source 1055135446Strhodes * into uncompressed wire form stored in target. 1056135446Strhodes * 1057135446Strhodes * Notes: 1058135446Strhodes * Relative domain names will have 'origin' appended to them 1059135446Strhodes * unless 'origin' is NULL, in which case relative domain names 1060135446Strhodes * will remain relative. 1061135446Strhodes */ 1062135446Strhodes 1063135446Strhodes REQUIRE(VALID_NAME(name)); 1064135446Strhodes REQUIRE(ISC_BUFFER_VALID(source)); 1065135446Strhodes REQUIRE((target != NULL && ISC_BUFFER_VALID(target)) || 1066135446Strhodes (target == NULL && ISC_BUFFER_VALID(name->buffer))); 1067193149Sdougb 1068135446Strhodes downcase = ISC_TF((options & DNS_NAME_DOWNCASE) != 0); 1069135446Strhodes 1070135446Strhodes if (target == NULL && name->buffer != NULL) { 1071135446Strhodes target = name->buffer; 1072135446Strhodes isc_buffer_clear(target); 1073135446Strhodes } 1074135446Strhodes 1075135446Strhodes REQUIRE(BINDABLE(name)); 1076135446Strhodes 1077135446Strhodes INIT_OFFSETS(name, offsets, odata); 1078135446Strhodes offsets[0] = 0; 1079135446Strhodes 1080135446Strhodes /* 1081135446Strhodes * Make 'name' empty in case of failure. 1082135446Strhodes */ 1083135446Strhodes MAKE_EMPTY(name); 1084135446Strhodes 1085135446Strhodes /* 1086135446Strhodes * Set up the state machine. 1087135446Strhodes */ 1088135446Strhodes tdata = (char *)source->base + source->current; 1089135446Strhodes tlen = isc_buffer_remaininglength(source); 1090135446Strhodes tused = 0; 1091135446Strhodes ndata = isc_buffer_used(target); 1092135446Strhodes nrem = isc_buffer_availablelength(target); 1093135446Strhodes if (nrem > 255) 1094135446Strhodes nrem = 255; 1095135446Strhodes nused = 0; 1096135446Strhodes labels = 0; 1097135446Strhodes done = ISC_FALSE; 1098135446Strhodes state = ft_init; 1099135446Strhodes 1100135446Strhodes while (nrem > 0 && tlen > 0 && !done) { 1101135446Strhodes c = *tdata++; 1102135446Strhodes tlen--; 1103135446Strhodes tused++; 1104135446Strhodes 1105135446Strhodes switch (state) { 1106135446Strhodes case ft_init: 1107135446Strhodes /* 1108135446Strhodes * Is this the root name? 1109135446Strhodes */ 1110135446Strhodes if (c == '.') { 1111135446Strhodes if (tlen != 0) 1112135446Strhodes return (DNS_R_EMPTYLABEL); 1113135446Strhodes labels++; 1114135446Strhodes *ndata++ = 0; 1115135446Strhodes nrem--; 1116135446Strhodes nused++; 1117135446Strhodes done = ISC_TRUE; 1118135446Strhodes break; 1119135446Strhodes } 1120135446Strhodes if (c == '@' && tlen == 0) { 1121135446Strhodes state = ft_at; 1122135446Strhodes break; 1123135446Strhodes } 1124135446Strhodes 1125135446Strhodes /* FALLTHROUGH */ 1126135446Strhodes case ft_start: 1127135446Strhodes label = ndata; 1128135446Strhodes ndata++; 1129135446Strhodes nrem--; 1130135446Strhodes nused++; 1131135446Strhodes count = 0; 1132135446Strhodes if (c == '\\') { 1133135446Strhodes state = ft_initialescape; 1134135446Strhodes break; 1135135446Strhodes } 1136135446Strhodes state = ft_ordinary; 1137135446Strhodes if (nrem == 0) 1138135446Strhodes return (ISC_R_NOSPACE); 1139135446Strhodes /* FALLTHROUGH */ 1140135446Strhodes case ft_ordinary: 1141135446Strhodes if (c == '.') { 1142135446Strhodes if (count == 0) 1143135446Strhodes return (DNS_R_EMPTYLABEL); 1144135446Strhodes *label = count; 1145135446Strhodes labels++; 1146135446Strhodes INSIST(labels <= 127); 1147135446Strhodes offsets[labels] = nused; 1148135446Strhodes if (tlen == 0) { 1149135446Strhodes labels++; 1150135446Strhodes *ndata++ = 0; 1151135446Strhodes nrem--; 1152135446Strhodes nused++; 1153135446Strhodes done = ISC_TRUE; 1154135446Strhodes } 1155135446Strhodes state = ft_start; 1156135446Strhodes } else if (c == '\\') { 1157135446Strhodes state = ft_escape; 1158135446Strhodes } else { 1159135446Strhodes if (count >= 63) 1160135446Strhodes return (DNS_R_LABELTOOLONG); 1161135446Strhodes count++; 1162135446Strhodes CONVERTTOASCII(c); 1163135446Strhodes if (downcase) 1164135446Strhodes c = maptolower[(int)c]; 1165135446Strhodes *ndata++ = c; 1166135446Strhodes nrem--; 1167135446Strhodes nused++; 1168135446Strhodes } 1169135446Strhodes break; 1170135446Strhodes case ft_initialescape: 1171135446Strhodes if (c == '[') { 1172135446Strhodes /* 1173135446Strhodes * This looks like a bitstring label, which 1174135446Strhodes * was deprecated. Intentionally drop it. 1175135446Strhodes */ 1176135446Strhodes return (DNS_R_BADLABELTYPE); 1177135446Strhodes } 1178135446Strhodes state = ft_escape; 1179225361Sdougb POST(state); 1180135446Strhodes /* FALLTHROUGH */ 1181135446Strhodes case ft_escape: 1182135446Strhodes if (!isdigit(c & 0xff)) { 1183135446Strhodes if (count >= 63) 1184135446Strhodes return (DNS_R_LABELTOOLONG); 1185135446Strhodes count++; 1186135446Strhodes CONVERTTOASCII(c); 1187135446Strhodes if (downcase) 1188135446Strhodes c = maptolower[(int)c]; 1189135446Strhodes *ndata++ = c; 1190135446Strhodes nrem--; 1191135446Strhodes nused++; 1192135446Strhodes state = ft_ordinary; 1193135446Strhodes break; 1194135446Strhodes } 1195135446Strhodes digits = 0; 1196135446Strhodes value = 0; 1197135446Strhodes state = ft_escdecimal; 1198135446Strhodes /* FALLTHROUGH */ 1199135446Strhodes case ft_escdecimal: 1200135446Strhodes if (!isdigit(c & 0xff)) 1201135446Strhodes return (DNS_R_BADESCAPE); 1202135446Strhodes value *= 10; 1203135446Strhodes value += digitvalue[(int)c]; 1204135446Strhodes digits++; 1205135446Strhodes if (digits == 3) { 1206135446Strhodes if (value > 255) 1207135446Strhodes return (DNS_R_BADESCAPE); 1208135446Strhodes if (count >= 63) 1209135446Strhodes return (DNS_R_LABELTOOLONG); 1210135446Strhodes count++; 1211135446Strhodes if (downcase) 1212135446Strhodes value = maptolower[value]; 1213135446Strhodes *ndata++ = value; 1214135446Strhodes nrem--; 1215135446Strhodes nused++; 1216135446Strhodes state = ft_ordinary; 1217135446Strhodes } 1218135446Strhodes break; 1219135446Strhodes default: 1220135446Strhodes FATAL_ERROR(__FILE__, __LINE__, 1221135446Strhodes "Unexpected state %d", state); 1222135446Strhodes /* Does not return. */ 1223135446Strhodes } 1224135446Strhodes } 1225135446Strhodes 1226135446Strhodes if (!done) { 1227135446Strhodes if (nrem == 0) 1228135446Strhodes return (ISC_R_NOSPACE); 1229135446Strhodes INSIST(tlen == 0); 1230135446Strhodes if (state != ft_ordinary && state != ft_at) 1231135446Strhodes return (ISC_R_UNEXPECTEDEND); 1232135446Strhodes if (state == ft_ordinary) { 1233135446Strhodes INSIST(count != 0); 1234135446Strhodes *label = count; 1235135446Strhodes labels++; 1236135446Strhodes INSIST(labels <= 127); 1237135446Strhodes offsets[labels] = nused; 1238135446Strhodes } 1239135446Strhodes if (origin != NULL) { 1240135446Strhodes if (nrem < origin->length) 1241135446Strhodes return (ISC_R_NOSPACE); 1242135446Strhodes label = origin->ndata; 1243135446Strhodes n1 = origin->length; 1244135446Strhodes nrem -= n1; 1245225361Sdougb POST(nrem); 1246135446Strhodes while (n1 > 0) { 1247135446Strhodes n2 = *label++; 1248135446Strhodes INSIST(n2 <= 63); /* no bitstring support */ 1249135446Strhodes *ndata++ = n2; 1250135446Strhodes n1 -= n2 + 1; 1251135446Strhodes nused += n2 + 1; 1252135446Strhodes while (n2 > 0) { 1253135446Strhodes c = *label++; 1254135446Strhodes if (downcase) 1255135446Strhodes c = maptolower[(int)c]; 1256135446Strhodes *ndata++ = c; 1257135446Strhodes n2--; 1258135446Strhodes } 1259135446Strhodes labels++; 1260135446Strhodes if (n1 > 0) { 1261135446Strhodes INSIST(labels <= 127); 1262135446Strhodes offsets[labels] = nused; 1263135446Strhodes } 1264135446Strhodes } 1265135446Strhodes if ((origin->attributes & DNS_NAMEATTR_ABSOLUTE) != 0) 1266135446Strhodes name->attributes |= DNS_NAMEATTR_ABSOLUTE; 1267135446Strhodes } 1268135446Strhodes } else 1269135446Strhodes name->attributes |= DNS_NAMEATTR_ABSOLUTE; 1270135446Strhodes 1271135446Strhodes name->ndata = (unsigned char *)target->base + target->used; 1272135446Strhodes name->labels = labels; 1273135446Strhodes name->length = nused; 1274135446Strhodes 1275135446Strhodes isc_buffer_forward(source, tused); 1276135446Strhodes isc_buffer_add(target, name->length); 1277135446Strhodes 1278135446Strhodes return (ISC_R_SUCCESS); 1279135446Strhodes} 1280135446Strhodes 1281170222Sdougb#ifdef ISC_PLATFORM_USETHREADS 1282170222Sdougbstatic void 1283170222Sdougbfree_specific(void *arg) { 1284170222Sdougb dns_name_totextfilter_t *mem = arg; 1285170222Sdougb isc_mem_put(thread_key_mctx, mem, sizeof(*mem)); 1286170222Sdougb /* Stop use being called again. */ 1287170222Sdougb (void)isc_thread_key_setspecific(totext_filter_proc_key, NULL); 1288170222Sdougb} 1289170222Sdougb 1290170222Sdougbstatic void 1291170222Sdougbthread_key_mutex_init(void) { 1292170222Sdougb RUNTIME_CHECK(isc_mutex_init(&thread_key_mutex) == ISC_R_SUCCESS); 1293170222Sdougb} 1294170222Sdougb 1295170222Sdougbstatic isc_result_t 1296170222Sdougbtotext_filter_proc_key_init(void) { 1297170222Sdougb isc_result_t result; 1298170222Sdougb 1299170222Sdougb /* 1300170222Sdougb * We need the call to isc_once_do() to support profiled mutex 1301170222Sdougb * otherwise thread_key_mutex could be initialized at compile time. 1302170222Sdougb */ 1303170222Sdougb result = isc_once_do(&once, thread_key_mutex_init); 1304170222Sdougb if (result != ISC_R_SUCCESS) 1305170222Sdougb return (result); 1306170222Sdougb 1307193149Sdougb if (!thread_key_initialized) { 1308170222Sdougb LOCK(&thread_key_mutex); 1309170222Sdougb if (thread_key_mctx == NULL) 1310170222Sdougb result = isc_mem_create2(0, 0, &thread_key_mctx, 0); 1311170222Sdougb if (result != ISC_R_SUCCESS) 1312170222Sdougb goto unlock; 1313193149Sdougb isc_mem_setname(thread_key_mctx, "threadkey", NULL); 1314170222Sdougb isc_mem_setdestroycheck(thread_key_mctx, ISC_FALSE); 1315193149Sdougb 1316170222Sdougb if (!thread_key_initialized && 1317170222Sdougb isc_thread_key_create(&totext_filter_proc_key, 1318193149Sdougb free_specific) != 0) { 1319170222Sdougb result = ISC_R_FAILURE; 1320170222Sdougb isc_mem_detach(&thread_key_mctx); 1321170222Sdougb } else 1322170222Sdougb thread_key_initialized = 1; 1323170222Sdougb unlock: 1324170222Sdougb UNLOCK(&thread_key_mutex); 1325193149Sdougb } 1326170222Sdougb return (result); 1327170222Sdougb} 1328170222Sdougb#endif 1329170222Sdougb 1330135446Strhodesisc_result_t 1331135446Strhodesdns_name_totext(dns_name_t *name, isc_boolean_t omit_final_dot, 1332135446Strhodes isc_buffer_t *target) 1333135446Strhodes{ 1334218384Sdougb unsigned int options = DNS_NAME_MASTERFILE; 1335218384Sdougb 1336218384Sdougb if (omit_final_dot) 1337218384Sdougb options |= DNS_NAME_OMITFINALDOT; 1338218384Sdougb return (dns_name_totext2(name, options, target)); 1339218384Sdougb} 1340218384Sdougb 1341218384Sdougbisc_result_t 1342218384Sdougbdns_name_toprincipal(dns_name_t *name, isc_buffer_t *target) { 1343218384Sdougb return (dns_name_totext2(name, DNS_NAME_OMITFINALDOT, target)); 1344218384Sdougb} 1345218384Sdougb 1346218384Sdougbisc_result_t 1347218384Sdougbdns_name_totext2(dns_name_t *name, unsigned int options, isc_buffer_t *target) 1348218384Sdougb{ 1349135446Strhodes unsigned char *ndata; 1350135446Strhodes char *tdata; 1351135446Strhodes unsigned int nlen, tlen; 1352135446Strhodes unsigned char c; 1353135446Strhodes unsigned int trem, count; 1354135446Strhodes unsigned int labels; 1355135446Strhodes isc_boolean_t saw_root = ISC_FALSE; 1356170222Sdougb unsigned int oused = target->used; 1357170222Sdougb#ifdef ISC_PLATFORM_USETHREADS 1358170222Sdougb dns_name_totextfilter_t *mem; 1359170222Sdougb dns_name_totextfilter_t totext_filter_proc = NULL; 1360170222Sdougb isc_result_t result; 1361170222Sdougb#endif 1362218384Sdougb isc_boolean_t omit_final_dot = 1363218384Sdougb ISC_TF(options & DNS_NAME_OMITFINALDOT); 1364135446Strhodes 1365135446Strhodes /* 1366135446Strhodes * This function assumes the name is in proper uncompressed 1367135446Strhodes * wire format. 1368135446Strhodes */ 1369135446Strhodes REQUIRE(VALID_NAME(name)); 1370135446Strhodes REQUIRE(ISC_BUFFER_VALID(target)); 1371135446Strhodes 1372170222Sdougb#ifdef ISC_PLATFORM_USETHREADS 1373170222Sdougb result = totext_filter_proc_key_init(); 1374170222Sdougb if (result != ISC_R_SUCCESS) 1375170222Sdougb return (result); 1376170222Sdougb#endif 1377135446Strhodes ndata = name->ndata; 1378135446Strhodes nlen = name->length; 1379135446Strhodes labels = name->labels; 1380135446Strhodes tdata = isc_buffer_used(target); 1381135446Strhodes tlen = isc_buffer_availablelength(target); 1382135446Strhodes 1383135446Strhodes trem = tlen; 1384135446Strhodes 1385135446Strhodes if (labels == 0 && nlen == 0) { 1386135446Strhodes /* 1387135446Strhodes * Special handling for an empty name. 1388135446Strhodes */ 1389135446Strhodes if (trem == 0) 1390135446Strhodes return (ISC_R_NOSPACE); 1391135446Strhodes 1392135446Strhodes /* 1393135446Strhodes * The names of these booleans are misleading in this case. 1394135446Strhodes * This empty name is not necessarily from the root node of 1395135446Strhodes * the DNS root zone, nor is a final dot going to be included. 1396135446Strhodes * They need to be set this way, though, to keep the "@" 1397135446Strhodes * from being trounced. 1398135446Strhodes */ 1399135446Strhodes saw_root = ISC_TRUE; 1400135446Strhodes omit_final_dot = ISC_FALSE; 1401135446Strhodes *tdata++ = '@'; 1402135446Strhodes trem--; 1403135446Strhodes 1404135446Strhodes /* 1405135446Strhodes * Skip the while() loop. 1406135446Strhodes */ 1407135446Strhodes nlen = 0; 1408135446Strhodes } else if (nlen == 1 && labels == 1 && *ndata == '\0') { 1409135446Strhodes /* 1410135446Strhodes * Special handling for the root label. 1411135446Strhodes */ 1412135446Strhodes if (trem == 0) 1413135446Strhodes return (ISC_R_NOSPACE); 1414135446Strhodes 1415135446Strhodes saw_root = ISC_TRUE; 1416135446Strhodes omit_final_dot = ISC_FALSE; 1417135446Strhodes *tdata++ = '.'; 1418135446Strhodes trem--; 1419135446Strhodes 1420135446Strhodes /* 1421135446Strhodes * Skip the while() loop. 1422135446Strhodes */ 1423135446Strhodes nlen = 0; 1424135446Strhodes } 1425135446Strhodes 1426135446Strhodes while (labels > 0 && nlen > 0 && trem > 0) { 1427135446Strhodes labels--; 1428135446Strhodes count = *ndata++; 1429135446Strhodes nlen--; 1430135446Strhodes if (count == 0) { 1431135446Strhodes saw_root = ISC_TRUE; 1432135446Strhodes break; 1433135446Strhodes } 1434135446Strhodes if (count < 64) { 1435135446Strhodes INSIST(nlen >= count); 1436135446Strhodes while (count > 0) { 1437135446Strhodes c = *ndata; 1438135446Strhodes switch (c) { 1439218384Sdougb /* Special modifiers in zone files. */ 1440218384Sdougb case 0x40: /* '@' */ 1441218384Sdougb case 0x24: /* '$' */ 1442218384Sdougb if ((options & DNS_NAME_MASTERFILE) == 0) 1443218384Sdougb goto no_escape; 1444254402Serwin /* FALLTHROUGH */ 1445135446Strhodes case 0x22: /* '"' */ 1446135446Strhodes case 0x28: /* '(' */ 1447135446Strhodes case 0x29: /* ')' */ 1448135446Strhodes case 0x2E: /* '.' */ 1449135446Strhodes case 0x3B: /* ';' */ 1450135446Strhodes case 0x5C: /* '\\' */ 1451135446Strhodes if (trem < 2) 1452135446Strhodes return (ISC_R_NOSPACE); 1453135446Strhodes *tdata++ = '\\'; 1454135446Strhodes CONVERTFROMASCII(c); 1455135446Strhodes *tdata++ = c; 1456135446Strhodes ndata++; 1457135446Strhodes trem -= 2; 1458135446Strhodes nlen--; 1459135446Strhodes break; 1460218384Sdougb no_escape: 1461135446Strhodes default: 1462135446Strhodes if (c > 0x20 && c < 0x7f) { 1463135446Strhodes if (trem == 0) 1464135446Strhodes return (ISC_R_NOSPACE); 1465135446Strhodes CONVERTFROMASCII(c); 1466135446Strhodes *tdata++ = c; 1467135446Strhodes ndata++; 1468135446Strhodes trem--; 1469135446Strhodes nlen--; 1470135446Strhodes } else { 1471135446Strhodes if (trem < 4) 1472135446Strhodes return (ISC_R_NOSPACE); 1473153816Sdougb *tdata++ = 0x5c; 1474153816Sdougb *tdata++ = 0x30 + 1475153816Sdougb ((c / 100) % 10); 1476153816Sdougb *tdata++ = 0x30 + 1477153816Sdougb ((c / 10) % 10); 1478153816Sdougb *tdata++ = 0x30 + (c % 10); 1479135446Strhodes trem -= 4; 1480135446Strhodes ndata++; 1481135446Strhodes nlen--; 1482135446Strhodes } 1483135446Strhodes } 1484135446Strhodes count--; 1485135446Strhodes } 1486135446Strhodes } else { 1487135446Strhodes FATAL_ERROR(__FILE__, __LINE__, 1488135446Strhodes "Unexpected label type %02x", count); 1489135446Strhodes /* NOTREACHED */ 1490135446Strhodes } 1491135446Strhodes 1492135446Strhodes /* 1493135446Strhodes * The following assumes names are absolute. If not, we 1494135446Strhodes * fix things up later. Note that this means that in some 1495135446Strhodes * cases one more byte of text buffer is required than is 1496135446Strhodes * needed in the final output. 1497135446Strhodes */ 1498135446Strhodes if (trem == 0) 1499135446Strhodes return (ISC_R_NOSPACE); 1500135446Strhodes *tdata++ = '.'; 1501135446Strhodes trem--; 1502135446Strhodes } 1503135446Strhodes 1504135446Strhodes if (nlen != 0 && trem == 0) 1505135446Strhodes return (ISC_R_NOSPACE); 1506135446Strhodes 1507135446Strhodes if (!saw_root || omit_final_dot) 1508135446Strhodes trem++; 1509135446Strhodes 1510135446Strhodes isc_buffer_add(target, tlen - trem); 1511135446Strhodes 1512170222Sdougb#ifdef ISC_PLATFORM_USETHREADS 1513170222Sdougb mem = isc_thread_key_getspecific(totext_filter_proc_key); 1514170222Sdougb if (mem != NULL) 1515170222Sdougb totext_filter_proc = *mem; 1516170222Sdougb#endif 1517170222Sdougb if (totext_filter_proc != NULL) 1518170222Sdougb return ((*totext_filter_proc)(target, oused, saw_root)); 1519170222Sdougb 1520135446Strhodes return (ISC_R_SUCCESS); 1521135446Strhodes} 1522135446Strhodes 1523135446Strhodesisc_result_t 1524135446Strhodesdns_name_tofilenametext(dns_name_t *name, isc_boolean_t omit_final_dot, 1525135446Strhodes isc_buffer_t *target) 1526135446Strhodes{ 1527135446Strhodes unsigned char *ndata; 1528135446Strhodes char *tdata; 1529135446Strhodes unsigned int nlen, tlen; 1530135446Strhodes unsigned char c; 1531135446Strhodes unsigned int trem, count; 1532135446Strhodes unsigned int labels; 1533135446Strhodes 1534135446Strhodes /* 1535135446Strhodes * This function assumes the name is in proper uncompressed 1536135446Strhodes * wire format. 1537135446Strhodes */ 1538135446Strhodes REQUIRE(VALID_NAME(name)); 1539135446Strhodes REQUIRE((name->attributes & DNS_NAMEATTR_ABSOLUTE) != 0); 1540135446Strhodes REQUIRE(ISC_BUFFER_VALID(target)); 1541135446Strhodes 1542135446Strhodes ndata = name->ndata; 1543135446Strhodes nlen = name->length; 1544135446Strhodes labels = name->labels; 1545135446Strhodes tdata = isc_buffer_used(target); 1546135446Strhodes tlen = isc_buffer_availablelength(target); 1547135446Strhodes 1548135446Strhodes trem = tlen; 1549135446Strhodes 1550135446Strhodes if (nlen == 1 && labels == 1 && *ndata == '\0') { 1551135446Strhodes /* 1552135446Strhodes * Special handling for the root label. 1553135446Strhodes */ 1554135446Strhodes if (trem == 0) 1555135446Strhodes return (ISC_R_NOSPACE); 1556135446Strhodes 1557135446Strhodes omit_final_dot = ISC_FALSE; 1558135446Strhodes *tdata++ = '.'; 1559135446Strhodes trem--; 1560135446Strhodes 1561135446Strhodes /* 1562135446Strhodes * Skip the while() loop. 1563135446Strhodes */ 1564135446Strhodes nlen = 0; 1565135446Strhodes } 1566135446Strhodes 1567135446Strhodes while (labels > 0 && nlen > 0 && trem > 0) { 1568135446Strhodes labels--; 1569135446Strhodes count = *ndata++; 1570135446Strhodes nlen--; 1571135446Strhodes if (count == 0) 1572135446Strhodes break; 1573135446Strhodes if (count < 64) { 1574135446Strhodes INSIST(nlen >= count); 1575135446Strhodes while (count > 0) { 1576135446Strhodes c = *ndata; 1577135446Strhodes if ((c >= 0x30 && c <= 0x39) || /* digit */ 1578135446Strhodes (c >= 0x41 && c <= 0x5A) || /* uppercase */ 1579135446Strhodes (c >= 0x61 && c <= 0x7A) || /* lowercase */ 1580135446Strhodes c == 0x2D || /* hyphen */ 1581135446Strhodes c == 0x5F) /* underscore */ 1582135446Strhodes { 1583135446Strhodes if (trem == 0) 1584135446Strhodes return (ISC_R_NOSPACE); 1585135446Strhodes /* downcase */ 1586135446Strhodes if (c >= 0x41 && c <= 0x5A) 1587135446Strhodes c += 0x20; 1588135446Strhodes CONVERTFROMASCII(c); 1589135446Strhodes *tdata++ = c; 1590135446Strhodes ndata++; 1591135446Strhodes trem--; 1592135446Strhodes nlen--; 1593135446Strhodes } else { 1594135446Strhodes if (trem < 3) 1595135446Strhodes return (ISC_R_NOSPACE); 1596135446Strhodes sprintf(tdata, "%%%02X", c); 1597135446Strhodes tdata += 3; 1598135446Strhodes trem -= 3; 1599135446Strhodes ndata++; 1600135446Strhodes nlen--; 1601135446Strhodes } 1602135446Strhodes count--; 1603135446Strhodes } 1604135446Strhodes } else { 1605135446Strhodes FATAL_ERROR(__FILE__, __LINE__, 1606135446Strhodes "Unexpected label type %02x", count); 1607135446Strhodes /* NOTREACHED */ 1608135446Strhodes } 1609135446Strhodes 1610135446Strhodes /* 1611135446Strhodes * The following assumes names are absolute. If not, we 1612135446Strhodes * fix things up later. Note that this means that in some 1613135446Strhodes * cases one more byte of text buffer is required than is 1614135446Strhodes * needed in the final output. 1615135446Strhodes */ 1616135446Strhodes if (trem == 0) 1617135446Strhodes return (ISC_R_NOSPACE); 1618135446Strhodes *tdata++ = '.'; 1619135446Strhodes trem--; 1620135446Strhodes } 1621135446Strhodes 1622135446Strhodes if (nlen != 0 && trem == 0) 1623135446Strhodes return (ISC_R_NOSPACE); 1624135446Strhodes 1625135446Strhodes if (omit_final_dot) 1626135446Strhodes trem++; 1627135446Strhodes 1628135446Strhodes isc_buffer_add(target, tlen - trem); 1629135446Strhodes 1630135446Strhodes return (ISC_R_SUCCESS); 1631135446Strhodes} 1632135446Strhodes 1633135446Strhodesisc_result_t 1634135446Strhodesdns_name_downcase(dns_name_t *source, dns_name_t *name, isc_buffer_t *target) { 1635135446Strhodes unsigned char *sndata, *ndata; 1636135446Strhodes unsigned int nlen, count, labels; 1637135446Strhodes isc_buffer_t buffer; 1638135446Strhodes 1639135446Strhodes /* 1640135446Strhodes * Downcase 'source'. 1641135446Strhodes */ 1642135446Strhodes 1643135446Strhodes REQUIRE(VALID_NAME(source)); 1644135446Strhodes REQUIRE(VALID_NAME(name)); 1645135446Strhodes if (source == name) { 1646135446Strhodes REQUIRE((name->attributes & DNS_NAMEATTR_READONLY) == 0); 1647135446Strhodes isc_buffer_init(&buffer, source->ndata, source->length); 1648135446Strhodes target = &buffer; 1649135446Strhodes ndata = source->ndata; 1650135446Strhodes } else { 1651135446Strhodes REQUIRE(BINDABLE(name)); 1652135446Strhodes REQUIRE((target != NULL && ISC_BUFFER_VALID(target)) || 1653135446Strhodes (target == NULL && ISC_BUFFER_VALID(name->buffer))); 1654135446Strhodes if (target == NULL) { 1655135446Strhodes target = name->buffer; 1656135446Strhodes isc_buffer_clear(name->buffer); 1657135446Strhodes } 1658135446Strhodes ndata = (unsigned char *)target->base + target->used; 1659135446Strhodes name->ndata = ndata; 1660135446Strhodes } 1661135446Strhodes 1662135446Strhodes sndata = source->ndata; 1663135446Strhodes nlen = source->length; 1664135446Strhodes labels = source->labels; 1665135446Strhodes 1666135446Strhodes if (nlen > (target->length - target->used)) { 1667135446Strhodes MAKE_EMPTY(name); 1668135446Strhodes return (ISC_R_NOSPACE); 1669135446Strhodes } 1670135446Strhodes 1671135446Strhodes while (labels > 0 && nlen > 0) { 1672135446Strhodes labels--; 1673135446Strhodes count = *sndata++; 1674135446Strhodes *ndata++ = count; 1675135446Strhodes nlen--; 1676135446Strhodes if (count < 64) { 1677135446Strhodes INSIST(nlen >= count); 1678135446Strhodes while (count > 0) { 1679135446Strhodes *ndata++ = maptolower[(*sndata++)]; 1680135446Strhodes nlen--; 1681135446Strhodes count--; 1682135446Strhodes } 1683135446Strhodes } else { 1684135446Strhodes FATAL_ERROR(__FILE__, __LINE__, 1685135446Strhodes "Unexpected label type %02x", count); 1686135446Strhodes /* Does not return. */ 1687135446Strhodes } 1688135446Strhodes } 1689135446Strhodes 1690135446Strhodes if (source != name) { 1691135446Strhodes name->labels = source->labels; 1692135446Strhodes name->length = source->length; 1693135446Strhodes if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0) 1694135446Strhodes name->attributes = DNS_NAMEATTR_ABSOLUTE; 1695135446Strhodes else 1696135446Strhodes name->attributes = 0; 1697135446Strhodes if (name->labels > 0 && name->offsets != NULL) 1698135446Strhodes set_offsets(name, name->offsets, NULL); 1699135446Strhodes } 1700135446Strhodes 1701135446Strhodes isc_buffer_add(target, name->length); 1702135446Strhodes 1703135446Strhodes return (ISC_R_SUCCESS); 1704135446Strhodes} 1705135446Strhodes 1706135446Strhodesstatic void 1707135446Strhodesset_offsets(const dns_name_t *name, unsigned char *offsets, 1708135446Strhodes dns_name_t *set_name) 1709135446Strhodes{ 1710135446Strhodes unsigned int offset, count, length, nlabels; 1711135446Strhodes unsigned char *ndata; 1712135446Strhodes isc_boolean_t absolute; 1713135446Strhodes 1714135446Strhodes ndata = name->ndata; 1715135446Strhodes length = name->length; 1716135446Strhodes offset = 0; 1717135446Strhodes nlabels = 0; 1718135446Strhodes absolute = ISC_FALSE; 1719135446Strhodes while (offset != length) { 1720135446Strhodes INSIST(nlabels < 128); 1721135446Strhodes offsets[nlabels++] = offset; 1722135446Strhodes count = *ndata++; 1723135446Strhodes offset++; 1724135446Strhodes INSIST(count <= 63); 1725135446Strhodes offset += count; 1726135446Strhodes ndata += count; 1727135446Strhodes INSIST(offset <= length); 1728135446Strhodes if (count == 0) { 1729135446Strhodes absolute = ISC_TRUE; 1730135446Strhodes break; 1731135446Strhodes } 1732135446Strhodes } 1733135446Strhodes if (set_name != NULL) { 1734135446Strhodes INSIST(set_name == name); 1735135446Strhodes 1736135446Strhodes set_name->labels = nlabels; 1737135446Strhodes set_name->length = offset; 1738135446Strhodes if (absolute) 1739135446Strhodes set_name->attributes |= DNS_NAMEATTR_ABSOLUTE; 1740135446Strhodes else 1741135446Strhodes set_name->attributes &= ~DNS_NAMEATTR_ABSOLUTE; 1742135446Strhodes } 1743135446Strhodes INSIST(nlabels == name->labels); 1744135446Strhodes INSIST(offset == name->length); 1745135446Strhodes} 1746135446Strhodes 1747135446Strhodesisc_result_t 1748135446Strhodesdns_name_fromwire(dns_name_t *name, isc_buffer_t *source, 1749135446Strhodes dns_decompress_t *dctx, unsigned int options, 1750135446Strhodes isc_buffer_t *target) 1751135446Strhodes{ 1752135446Strhodes unsigned char *cdata, *ndata; 1753135446Strhodes unsigned int cused; /* Bytes of compressed name data used */ 1754170222Sdougb unsigned int nused, labels, n, nmax; 1755135446Strhodes unsigned int current, new_current, biggest_pointer; 1756135446Strhodes isc_boolean_t done; 1757135446Strhodes fw_state state = fw_start; 1758135446Strhodes unsigned int c; 1759135446Strhodes unsigned char *offsets; 1760135446Strhodes dns_offsets_t odata; 1761135446Strhodes isc_boolean_t downcase; 1762170222Sdougb isc_boolean_t seen_pointer; 1763135446Strhodes 1764135446Strhodes /* 1765135446Strhodes * Copy the possibly-compressed name at source into target, 1766170222Sdougb * decompressing it. Loop prevention is performed by checking 1767170222Sdougb * the new pointer against biggest_pointer. 1768135446Strhodes */ 1769135446Strhodes 1770135446Strhodes REQUIRE(VALID_NAME(name)); 1771135446Strhodes REQUIRE((target != NULL && ISC_BUFFER_VALID(target)) || 1772135446Strhodes (target == NULL && ISC_BUFFER_VALID(name->buffer))); 1773135446Strhodes 1774135446Strhodes downcase = ISC_TF((options & DNS_NAME_DOWNCASE) != 0); 1775135446Strhodes 1776135446Strhodes if (target == NULL && name->buffer != NULL) { 1777135446Strhodes target = name->buffer; 1778135446Strhodes isc_buffer_clear(target); 1779135446Strhodes } 1780135446Strhodes 1781135446Strhodes REQUIRE(dctx != NULL); 1782135446Strhodes REQUIRE(BINDABLE(name)); 1783135446Strhodes 1784135446Strhodes INIT_OFFSETS(name, offsets, odata); 1785135446Strhodes 1786135446Strhodes /* 1787135446Strhodes * Make 'name' empty in case of failure. 1788135446Strhodes */ 1789135446Strhodes MAKE_EMPTY(name); 1790135446Strhodes 1791135446Strhodes /* 1792135446Strhodes * Initialize things to make the compiler happy; they're not required. 1793135446Strhodes */ 1794135446Strhodes n = 0; 1795135446Strhodes new_current = 0; 1796135446Strhodes 1797135446Strhodes /* 1798135446Strhodes * Set up. 1799135446Strhodes */ 1800135446Strhodes labels = 0; 1801135446Strhodes done = ISC_FALSE; 1802135446Strhodes 1803135446Strhodes ndata = isc_buffer_used(target); 1804135446Strhodes nused = 0; 1805170222Sdougb seen_pointer = ISC_FALSE; 1806135446Strhodes 1807135446Strhodes /* 1808135446Strhodes * Find the maximum number of uncompressed target name 1809135446Strhodes * bytes we are willing to generate. This is the smaller 1810135446Strhodes * of the available target buffer length and the 1811135446Strhodes * maximum legal domain name length (255). 1812135446Strhodes */ 1813135446Strhodes nmax = isc_buffer_availablelength(target); 1814135446Strhodes if (nmax > DNS_NAME_MAXWIRE) 1815135446Strhodes nmax = DNS_NAME_MAXWIRE; 1816135446Strhodes 1817135446Strhodes cdata = isc_buffer_current(source); 1818135446Strhodes cused = 0; 1819135446Strhodes 1820135446Strhodes current = source->current; 1821135446Strhodes biggest_pointer = current; 1822135446Strhodes 1823135446Strhodes /* 1824135446Strhodes * Note: The following code is not optimized for speed, but 1825135446Strhodes * rather for correctness. Speed will be addressed in the future. 1826135446Strhodes */ 1827135446Strhodes 1828135446Strhodes while (current < source->active && !done) { 1829135446Strhodes c = *cdata++; 1830135446Strhodes current++; 1831170222Sdougb if (!seen_pointer) 1832135446Strhodes cused++; 1833135446Strhodes 1834135446Strhodes switch (state) { 1835135446Strhodes case fw_start: 1836135446Strhodes if (c < 64) { 1837135446Strhodes offsets[labels] = nused; 1838135446Strhodes labels++; 1839135446Strhodes if (nused + c + 1 > nmax) 1840135446Strhodes goto full; 1841135446Strhodes nused += c + 1; 1842135446Strhodes *ndata++ = c; 1843135446Strhodes if (c == 0) 1844135446Strhodes done = ISC_TRUE; 1845135446Strhodes n = c; 1846135446Strhodes state = fw_ordinary; 1847135446Strhodes } else if (c >= 128 && c < 192) { 1848135446Strhodes /* 1849135446Strhodes * 14 bit local compression pointer. 1850135446Strhodes * Local compression is no longer an 1851135446Strhodes * IETF draft. 1852135446Strhodes */ 1853135446Strhodes return (DNS_R_BADLABELTYPE); 1854135446Strhodes } else if (c >= 192) { 1855135446Strhodes /* 1856135446Strhodes * Ordinary 14-bit pointer. 1857135446Strhodes */ 1858135446Strhodes if ((dctx->allowed & DNS_COMPRESS_GLOBAL14) == 1859135446Strhodes 0) 1860135446Strhodes return (DNS_R_DISALLOWED); 1861135446Strhodes new_current = c & 0x3F; 1862135446Strhodes n = 1; 1863135446Strhodes state = fw_newcurrent; 1864135446Strhodes } else 1865135446Strhodes return (DNS_R_BADLABELTYPE); 1866135446Strhodes break; 1867135446Strhodes case fw_ordinary: 1868135446Strhodes if (downcase) 1869135446Strhodes c = maptolower[c]; 1870135446Strhodes /* FALLTHROUGH */ 1871135446Strhodes case fw_copy: 1872135446Strhodes *ndata++ = c; 1873135446Strhodes n--; 1874135446Strhodes if (n == 0) 1875135446Strhodes state = fw_start; 1876135446Strhodes break; 1877135446Strhodes case fw_newcurrent: 1878135446Strhodes new_current *= 256; 1879135446Strhodes new_current += c; 1880135446Strhodes n--; 1881135446Strhodes if (n != 0) 1882135446Strhodes break; 1883135446Strhodes if (new_current >= biggest_pointer) 1884135446Strhodes return (DNS_R_BADPOINTER); 1885135446Strhodes biggest_pointer = new_current; 1886135446Strhodes current = new_current; 1887170222Sdougb cdata = (unsigned char *)source->base + current; 1888170222Sdougb seen_pointer = ISC_TRUE; 1889135446Strhodes state = fw_start; 1890135446Strhodes break; 1891135446Strhodes default: 1892135446Strhodes FATAL_ERROR(__FILE__, __LINE__, 1893135446Strhodes "Unknown state %d", state); 1894135446Strhodes /* Does not return. */ 1895135446Strhodes } 1896135446Strhodes } 1897135446Strhodes 1898135446Strhodes if (!done) 1899135446Strhodes return (ISC_R_UNEXPECTEDEND); 1900135446Strhodes 1901135446Strhodes name->ndata = (unsigned char *)target->base + target->used; 1902135446Strhodes name->labels = labels; 1903135446Strhodes name->length = nused; 1904135446Strhodes name->attributes |= DNS_NAMEATTR_ABSOLUTE; 1905135446Strhodes 1906135446Strhodes isc_buffer_forward(source, cused); 1907135446Strhodes isc_buffer_add(target, name->length); 1908135446Strhodes 1909135446Strhodes return (ISC_R_SUCCESS); 1910135446Strhodes 1911135446Strhodes full: 1912135446Strhodes if (nmax == DNS_NAME_MAXWIRE) 1913135446Strhodes /* 1914135446Strhodes * The name did not fit even though we had a buffer 1915135446Strhodes * big enough to fit a maximum-length name. 1916135446Strhodes */ 1917135446Strhodes return (DNS_R_NAMETOOLONG); 1918135446Strhodes else 1919135446Strhodes /* 1920135446Strhodes * The name might fit if only the caller could give us a 1921135446Strhodes * big enough buffer. 1922135446Strhodes */ 1923135446Strhodes return (ISC_R_NOSPACE); 1924135446Strhodes} 1925135446Strhodes 1926135446Strhodesisc_result_t 1927165071Sdougbdns_name_towire(const dns_name_t *name, dns_compress_t *cctx, 1928165071Sdougb isc_buffer_t *target) 1929165071Sdougb{ 1930135446Strhodes unsigned int methods; 1931135446Strhodes isc_uint16_t offset; 1932135446Strhodes dns_name_t gp; /* Global compression prefix */ 1933135446Strhodes isc_boolean_t gf; /* Global compression target found */ 1934135446Strhodes isc_uint16_t go; /* Global compression offset */ 1935135446Strhodes dns_offsets_t clo; 1936135446Strhodes dns_name_t clname; 1937135446Strhodes 1938135446Strhodes /* 1939135446Strhodes * Convert 'name' into wire format, compressing it as specified by the 1940135446Strhodes * compression context 'cctx', and storing the result in 'target'. 1941135446Strhodes */ 1942135446Strhodes 1943135446Strhodes REQUIRE(VALID_NAME(name)); 1944135446Strhodes REQUIRE(cctx != NULL); 1945135446Strhodes REQUIRE(ISC_BUFFER_VALID(target)); 1946135446Strhodes 1947135446Strhodes /* 1948135446Strhodes * If 'name' doesn't have an offsets table, make a clone which 1949135446Strhodes * has one. 1950135446Strhodes */ 1951135446Strhodes if (name->offsets == NULL) { 1952254402Serwin#if defined(__clang__) && \ 1953254402Serwin ( __clang_major__ < 3 || (__clang_major__ == 3 && __clang_minor__ < 2)) 1954254402Serwin memset(&clname, 0, sizeof(clname)); 1955254402Serwin#endif 1956135446Strhodes DNS_NAME_INIT(&clname, clo); 1957135446Strhodes dns_name_clone(name, &clname); 1958135446Strhodes name = &clname; 1959135446Strhodes } 1960135446Strhodes DNS_NAME_INIT(&gp, NULL); 1961135446Strhodes 1962135446Strhodes offset = target->used; /*XXX*/ 1963135446Strhodes 1964135446Strhodes methods = dns_compress_getmethods(cctx); 1965135446Strhodes 1966193149Sdougb if ((name->attributes & DNS_NAMEATTR_NOCOMPRESS) == 0 && 1967193149Sdougb (methods & DNS_COMPRESS_GLOBAL14) != 0) 1968135446Strhodes gf = dns_compress_findglobal(cctx, name, &gp, &go); 1969135446Strhodes else 1970135446Strhodes gf = ISC_FALSE; 1971135446Strhodes 1972135446Strhodes /* 1973135446Strhodes * If the offset is too high for 14 bit global compression, we're 1974135446Strhodes * out of luck. 1975135446Strhodes */ 1976135446Strhodes if (gf && go >= 0x4000) 1977135446Strhodes gf = ISC_FALSE; 1978135446Strhodes 1979135446Strhodes /* 1980135446Strhodes * Will the compression pointer reduce the message size? 1981135446Strhodes */ 1982135446Strhodes if (gf && (gp.length + 2) >= name->length) 1983135446Strhodes gf = ISC_FALSE; 1984135446Strhodes 1985135446Strhodes if (gf) { 1986135446Strhodes if (target->length - target->used < gp.length) 1987135446Strhodes return (ISC_R_NOSPACE); 1988262706Serwin (void)memmove((unsigned char *)target->base + target->used, 1989262706Serwin gp.ndata, (size_t)gp.length); 1990135446Strhodes isc_buffer_add(target, gp.length); 1991135446Strhodes go |= 0xc000; 1992135446Strhodes if (target->length - target->used < 2) 1993135446Strhodes return (ISC_R_NOSPACE); 1994135446Strhodes isc_buffer_putuint16(target, go); 1995135446Strhodes if (gp.length != 0) 1996135446Strhodes dns_compress_add(cctx, name, &gp, offset); 1997135446Strhodes } else { 1998135446Strhodes if (target->length - target->used < name->length) 1999135446Strhodes return (ISC_R_NOSPACE); 2000262706Serwin (void)memmove((unsigned char *)target->base + target->used, 2001262706Serwin name->ndata, (size_t)name->length); 2002135446Strhodes isc_buffer_add(target, name->length); 2003135446Strhodes dns_compress_add(cctx, name, name, offset); 2004135446Strhodes } 2005135446Strhodes return (ISC_R_SUCCESS); 2006135446Strhodes} 2007135446Strhodes 2008135446Strhodesisc_result_t 2009135446Strhodesdns_name_concatenate(dns_name_t *prefix, dns_name_t *suffix, dns_name_t *name, 2010135446Strhodes isc_buffer_t *target) 2011135446Strhodes{ 2012135446Strhodes unsigned char *ndata, *offsets; 2013135446Strhodes unsigned int nrem, labels, prefix_length, length; 2014135446Strhodes isc_boolean_t copy_prefix = ISC_TRUE; 2015135446Strhodes isc_boolean_t copy_suffix = ISC_TRUE; 2016135446Strhodes isc_boolean_t absolute = ISC_FALSE; 2017135446Strhodes dns_name_t tmp_name; 2018135446Strhodes dns_offsets_t odata; 2019135446Strhodes 2020135446Strhodes /* 2021135446Strhodes * Concatenate 'prefix' and 'suffix'. 2022135446Strhodes */ 2023135446Strhodes 2024135446Strhodes REQUIRE(prefix == NULL || VALID_NAME(prefix)); 2025135446Strhodes REQUIRE(suffix == NULL || VALID_NAME(suffix)); 2026135446Strhodes REQUIRE(name == NULL || VALID_NAME(name)); 2027135446Strhodes REQUIRE((target != NULL && ISC_BUFFER_VALID(target)) || 2028135446Strhodes (target == NULL && name != NULL && ISC_BUFFER_VALID(name->buffer))); 2029135446Strhodes if (prefix == NULL || prefix->labels == 0) 2030135446Strhodes copy_prefix = ISC_FALSE; 2031135446Strhodes if (suffix == NULL || suffix->labels == 0) 2032135446Strhodes copy_suffix = ISC_FALSE; 2033135446Strhodes if (copy_prefix && 2034135446Strhodes (prefix->attributes & DNS_NAMEATTR_ABSOLUTE) != 0) { 2035135446Strhodes absolute = ISC_TRUE; 2036135446Strhodes REQUIRE(!copy_suffix); 2037135446Strhodes } 2038135446Strhodes if (name == NULL) { 2039135446Strhodes DNS_NAME_INIT(&tmp_name, odata); 2040135446Strhodes name = &tmp_name; 2041135446Strhodes } 2042135446Strhodes if (target == NULL) { 2043135446Strhodes INSIST(name->buffer != NULL); 2044135446Strhodes target = name->buffer; 2045135446Strhodes isc_buffer_clear(name->buffer); 2046135446Strhodes } 2047135446Strhodes 2048135446Strhodes REQUIRE(BINDABLE(name)); 2049135446Strhodes 2050135446Strhodes /* 2051135446Strhodes * Set up. 2052135446Strhodes */ 2053135446Strhodes nrem = target->length - target->used; 2054135446Strhodes ndata = (unsigned char *)target->base + target->used; 2055135446Strhodes if (nrem > DNS_NAME_MAXWIRE) 2056135446Strhodes nrem = DNS_NAME_MAXWIRE; 2057135446Strhodes length = 0; 2058135446Strhodes prefix_length = 0; 2059135446Strhodes labels = 0; 2060135446Strhodes if (copy_prefix) { 2061135446Strhodes prefix_length = prefix->length; 2062135446Strhodes length += prefix_length; 2063135446Strhodes labels += prefix->labels; 2064135446Strhodes } 2065135446Strhodes if (copy_suffix) { 2066135446Strhodes length += suffix->length; 2067135446Strhodes labels += suffix->labels; 2068135446Strhodes } 2069135446Strhodes if (length > DNS_NAME_MAXWIRE) { 2070135446Strhodes MAKE_EMPTY(name); 2071135446Strhodes return (DNS_R_NAMETOOLONG); 2072135446Strhodes } 2073135446Strhodes if (length > nrem) { 2074135446Strhodes MAKE_EMPTY(name); 2075135446Strhodes return (ISC_R_NOSPACE); 2076135446Strhodes } 2077135446Strhodes 2078135446Strhodes if (copy_suffix) { 2079135446Strhodes if ((suffix->attributes & DNS_NAMEATTR_ABSOLUTE) != 0) 2080135446Strhodes absolute = ISC_TRUE; 2081262706Serwin memmove(ndata + prefix_length, suffix->ndata, suffix->length); 2082135446Strhodes } 2083135446Strhodes 2084135446Strhodes /* 2085135446Strhodes * If 'prefix' and 'name' are the same object, and the object has 2086135446Strhodes * a dedicated buffer, and we're using it, then we don't have to 2087135446Strhodes * copy anything. 2088135446Strhodes */ 2089135446Strhodes if (copy_prefix && (prefix != name || prefix->buffer != target)) 2090262706Serwin memmove(ndata, prefix->ndata, prefix_length); 2091135446Strhodes 2092135446Strhodes name->ndata = ndata; 2093135446Strhodes name->labels = labels; 2094135446Strhodes name->length = length; 2095135446Strhodes if (absolute) 2096135446Strhodes name->attributes = DNS_NAMEATTR_ABSOLUTE; 2097135446Strhodes else 2098135446Strhodes name->attributes = 0; 2099135446Strhodes 2100135446Strhodes if (name->labels > 0 && name->offsets != NULL) { 2101135446Strhodes INIT_OFFSETS(name, offsets, odata); 2102135446Strhodes set_offsets(name, offsets, NULL); 2103135446Strhodes } 2104135446Strhodes 2105135446Strhodes isc_buffer_add(target, name->length); 2106135446Strhodes 2107135446Strhodes return (ISC_R_SUCCESS); 2108135446Strhodes} 2109135446Strhodes 2110135446Strhodesvoid 2111135446Strhodesdns_name_split(dns_name_t *name, unsigned int suffixlabels, 2112135446Strhodes dns_name_t *prefix, dns_name_t *suffix) 2113135446Strhodes 2114135446Strhodes{ 2115135446Strhodes unsigned int splitlabel; 2116135446Strhodes 2117135446Strhodes REQUIRE(VALID_NAME(name)); 2118135446Strhodes REQUIRE(suffixlabels > 0); 2119135446Strhodes REQUIRE(suffixlabels < name->labels); 2120135446Strhodes REQUIRE(prefix != NULL || suffix != NULL); 2121135446Strhodes REQUIRE(prefix == NULL || 2122135446Strhodes (VALID_NAME(prefix) && 2123135446Strhodes prefix->buffer != NULL && 2124135446Strhodes BINDABLE(prefix))); 2125135446Strhodes REQUIRE(suffix == NULL || 2126135446Strhodes (VALID_NAME(suffix) && 2127135446Strhodes suffix->buffer != NULL && 2128135446Strhodes BINDABLE(suffix))); 2129135446Strhodes 2130135446Strhodes splitlabel = name->labels - suffixlabels; 2131135446Strhodes 2132135446Strhodes if (prefix != NULL) 2133135446Strhodes dns_name_getlabelsequence(name, 0, splitlabel, prefix); 2134135446Strhodes 2135135446Strhodes if (suffix != NULL) 2136135446Strhodes dns_name_getlabelsequence(name, splitlabel, 2137135446Strhodes suffixlabels, suffix); 2138135446Strhodes 2139135446Strhodes return; 2140135446Strhodes} 2141135446Strhodes 2142135446Strhodesisc_result_t 2143165071Sdougbdns_name_dup(const dns_name_t *source, isc_mem_t *mctx, 2144165071Sdougb dns_name_t *target) 2145165071Sdougb{ 2146135446Strhodes /* 2147135446Strhodes * Make 'target' a dynamically allocated copy of 'source'. 2148135446Strhodes */ 2149135446Strhodes 2150135446Strhodes REQUIRE(VALID_NAME(source)); 2151135446Strhodes REQUIRE(source->length > 0); 2152135446Strhodes REQUIRE(VALID_NAME(target)); 2153135446Strhodes REQUIRE(BINDABLE(target)); 2154135446Strhodes 2155135446Strhodes /* 2156135446Strhodes * Make 'target' empty in case of failure. 2157135446Strhodes */ 2158135446Strhodes MAKE_EMPTY(target); 2159135446Strhodes 2160135446Strhodes target->ndata = isc_mem_get(mctx, source->length); 2161135446Strhodes if (target->ndata == NULL) 2162135446Strhodes return (ISC_R_NOMEMORY); 2163135446Strhodes 2164262706Serwin memmove(target->ndata, source->ndata, source->length); 2165135446Strhodes 2166135446Strhodes target->length = source->length; 2167135446Strhodes target->labels = source->labels; 2168135446Strhodes target->attributes = DNS_NAMEATTR_DYNAMIC; 2169135446Strhodes if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0) 2170135446Strhodes target->attributes |= DNS_NAMEATTR_ABSOLUTE; 2171135446Strhodes if (target->offsets != NULL) { 2172135446Strhodes if (source->offsets != NULL) 2173262706Serwin memmove(target->offsets, source->offsets, 2174262706Serwin source->labels); 2175135446Strhodes else 2176135446Strhodes set_offsets(target, target->offsets, NULL); 2177135446Strhodes } 2178135446Strhodes 2179135446Strhodes return (ISC_R_SUCCESS); 2180135446Strhodes} 2181135446Strhodes 2182135446Strhodesisc_result_t 2183135446Strhodesdns_name_dupwithoffsets(dns_name_t *source, isc_mem_t *mctx, 2184135446Strhodes dns_name_t *target) 2185135446Strhodes{ 2186135446Strhodes /* 2187135446Strhodes * Make 'target' a read-only dynamically allocated copy of 'source'. 2188135446Strhodes * 'target' will also have a dynamically allocated offsets table. 2189135446Strhodes */ 2190135446Strhodes 2191135446Strhodes REQUIRE(VALID_NAME(source)); 2192135446Strhodes REQUIRE(source->length > 0); 2193135446Strhodes REQUIRE(VALID_NAME(target)); 2194135446Strhodes REQUIRE(BINDABLE(target)); 2195135446Strhodes REQUIRE(target->offsets == NULL); 2196135446Strhodes 2197135446Strhodes /* 2198135446Strhodes * Make 'target' empty in case of failure. 2199135446Strhodes */ 2200135446Strhodes MAKE_EMPTY(target); 2201135446Strhodes 2202135446Strhodes target->ndata = isc_mem_get(mctx, source->length + source->labels); 2203135446Strhodes if (target->ndata == NULL) 2204135446Strhodes return (ISC_R_NOMEMORY); 2205135446Strhodes 2206262706Serwin memmove(target->ndata, source->ndata, source->length); 2207135446Strhodes 2208135446Strhodes target->length = source->length; 2209135446Strhodes target->labels = source->labels; 2210135446Strhodes target->attributes = DNS_NAMEATTR_DYNAMIC | DNS_NAMEATTR_DYNOFFSETS | 2211135446Strhodes DNS_NAMEATTR_READONLY; 2212135446Strhodes if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0) 2213135446Strhodes target->attributes |= DNS_NAMEATTR_ABSOLUTE; 2214135446Strhodes target->offsets = target->ndata + source->length; 2215135446Strhodes if (source->offsets != NULL) 2216262706Serwin memmove(target->offsets, source->offsets, source->labels); 2217135446Strhodes else 2218135446Strhodes set_offsets(target, target->offsets, NULL); 2219135446Strhodes 2220135446Strhodes return (ISC_R_SUCCESS); 2221135446Strhodes} 2222135446Strhodes 2223135446Strhodesvoid 2224135446Strhodesdns_name_free(dns_name_t *name, isc_mem_t *mctx) { 2225135446Strhodes size_t size; 2226135446Strhodes 2227135446Strhodes /* 2228135446Strhodes * Free 'name'. 2229135446Strhodes */ 2230135446Strhodes 2231135446Strhodes REQUIRE(VALID_NAME(name)); 2232135446Strhodes REQUIRE((name->attributes & DNS_NAMEATTR_DYNAMIC) != 0); 2233135446Strhodes 2234135446Strhodes size = name->length; 2235135446Strhodes if ((name->attributes & DNS_NAMEATTR_DYNOFFSETS) != 0) 2236135446Strhodes size += name->labels; 2237135446Strhodes isc_mem_put(mctx, name->ndata, size); 2238135446Strhodes dns_name_invalidate(name); 2239135446Strhodes} 2240135446Strhodes 2241135446Strhodesisc_result_t 2242135446Strhodesdns_name_digest(dns_name_t *name, dns_digestfunc_t digest, void *arg) { 2243135446Strhodes dns_name_t downname; 2244135446Strhodes unsigned char data[256]; 2245135446Strhodes isc_buffer_t buffer; 2246135446Strhodes isc_result_t result; 2247135446Strhodes isc_region_t r; 2248135446Strhodes 2249135446Strhodes /* 2250135446Strhodes * Send 'name' in DNSSEC canonical form to 'digest'. 2251135446Strhodes */ 2252135446Strhodes 2253135446Strhodes REQUIRE(VALID_NAME(name)); 2254135446Strhodes REQUIRE(digest != NULL); 2255135446Strhodes 2256254402Serwin#if defined(__clang__) && \ 2257254402Serwin ( __clang_major__ < 3 || (__clang_major__ == 3 && __clang_minor__ < 2)) 2258254402Serwin memset(&downname, 0, sizeof(downname)); 2259254402Serwin#endif 2260135446Strhodes DNS_NAME_INIT(&downname, NULL); 2261254402Serwin 2262135446Strhodes isc_buffer_init(&buffer, data, sizeof(data)); 2263135446Strhodes 2264135446Strhodes result = dns_name_downcase(name, &downname, &buffer); 2265135446Strhodes if (result != ISC_R_SUCCESS) 2266135446Strhodes return (result); 2267135446Strhodes 2268135446Strhodes isc_buffer_usedregion(&buffer, &r); 2269135446Strhodes 2270135446Strhodes return ((digest)(arg, &r)); 2271135446Strhodes} 2272135446Strhodes 2273135446Strhodesisc_boolean_t 2274135446Strhodesdns_name_dynamic(dns_name_t *name) { 2275135446Strhodes REQUIRE(VALID_NAME(name)); 2276135446Strhodes 2277135446Strhodes /* 2278135446Strhodes * Returns whether there is dynamic memory associated with this name. 2279135446Strhodes */ 2280135446Strhodes 2281135446Strhodes return ((name->attributes & DNS_NAMEATTR_DYNAMIC) != 0 ? 2282135446Strhodes ISC_TRUE : ISC_FALSE); 2283135446Strhodes} 2284135446Strhodes 2285135446Strhodesisc_result_t 2286135446Strhodesdns_name_print(dns_name_t *name, FILE *stream) { 2287135446Strhodes isc_result_t result; 2288135446Strhodes isc_buffer_t b; 2289135446Strhodes isc_region_t r; 2290135446Strhodes char t[1024]; 2291135446Strhodes 2292135446Strhodes /* 2293135446Strhodes * Print 'name' on 'stream'. 2294135446Strhodes */ 2295135446Strhodes 2296135446Strhodes REQUIRE(VALID_NAME(name)); 2297135446Strhodes 2298135446Strhodes isc_buffer_init(&b, t, sizeof(t)); 2299135446Strhodes result = dns_name_totext(name, ISC_FALSE, &b); 2300135446Strhodes if (result != ISC_R_SUCCESS) 2301135446Strhodes return (result); 2302135446Strhodes isc_buffer_usedregion(&b, &r); 2303135446Strhodes fprintf(stream, "%.*s", (int)r.length, (char *)r.base); 2304135446Strhodes 2305135446Strhodes return (ISC_R_SUCCESS); 2306135446Strhodes} 2307135446Strhodes 2308170222Sdougbisc_result_t 2309170222Sdougbdns_name_settotextfilter(dns_name_totextfilter_t proc) { 2310170222Sdougb#ifdef ISC_PLATFORM_USETHREADS 2311170222Sdougb isc_result_t result; 2312170222Sdougb dns_name_totextfilter_t *mem; 2313170222Sdougb int res; 2314170222Sdougb 2315170222Sdougb result = totext_filter_proc_key_init(); 2316170222Sdougb if (result != ISC_R_SUCCESS) 2317170222Sdougb return (result); 2318170222Sdougb 2319170222Sdougb /* 2320170222Sdougb * If we already have been here set / clear as appropriate. 2321170222Sdougb * Otherwise allocate memory. 2322170222Sdougb */ 2323170222Sdougb mem = isc_thread_key_getspecific(totext_filter_proc_key); 2324170222Sdougb if (mem != NULL && proc != NULL) { 2325170222Sdougb *mem = proc; 2326170222Sdougb return (ISC_R_SUCCESS); 2327170222Sdougb } 2328170222Sdougb if (proc == NULL) { 2329170222Sdougb isc_mem_put(thread_key_mctx, mem, sizeof(*mem)); 2330170222Sdougb res = isc_thread_key_setspecific(totext_filter_proc_key, NULL); 2331170222Sdougb if (res != 0) 2332170222Sdougb result = ISC_R_UNEXPECTED; 2333170222Sdougb return (result); 2334170222Sdougb } 2335193149Sdougb 2336170222Sdougb mem = isc_mem_get(thread_key_mctx, sizeof(*mem)); 2337170222Sdougb if (mem == NULL) 2338170222Sdougb return (ISC_R_NOMEMORY); 2339170222Sdougb *mem = proc; 2340170222Sdougb if (isc_thread_key_setspecific(totext_filter_proc_key, mem) != 0) { 2341170222Sdougb isc_mem_put(thread_key_mctx, mem, sizeof(*mem)); 2342170222Sdougb result = ISC_R_UNEXPECTED; 2343170222Sdougb } 2344170222Sdougb return (result); 2345170222Sdougb#else 2346170222Sdougb totext_filter_proc = proc; 2347170222Sdougb return (ISC_R_SUCCESS); 2348170222Sdougb#endif 2349170222Sdougb} 2350170222Sdougb 2351135446Strhodesvoid 2352135446Strhodesdns_name_format(dns_name_t *name, char *cp, unsigned int size) { 2353135446Strhodes isc_result_t result; 2354135446Strhodes isc_buffer_t buf; 2355135446Strhodes 2356135446Strhodes REQUIRE(size > 0); 2357135446Strhodes 2358135446Strhodes /* 2359135446Strhodes * Leave room for null termination after buffer. 2360135446Strhodes */ 2361135446Strhodes isc_buffer_init(&buf, cp, size - 1); 2362135446Strhodes result = dns_name_totext(name, ISC_TRUE, &buf); 2363135446Strhodes if (result == ISC_R_SUCCESS) { 2364135446Strhodes /* 2365135446Strhodes * Null terminate. 2366135446Strhodes */ 2367135446Strhodes isc_region_t r; 2368135446Strhodes isc_buffer_usedregion(&buf, &r); 2369135446Strhodes ((char *) r.base)[r.length] = '\0'; 2370135446Strhodes 2371135446Strhodes } else 2372135446Strhodes snprintf(cp, size, "<unknown>"); 2373135446Strhodes} 2374135446Strhodes 2375224092Sdougb/* 2376224092Sdougb * dns_name_tostring() -- similar to dns_name_format() but allocates its own 2377224092Sdougb * memory. 2378224092Sdougb */ 2379135446Strhodesisc_result_t 2380224092Sdougbdns_name_tostring(dns_name_t *name, char **target, isc_mem_t *mctx) { 2381224092Sdougb isc_result_t result; 2382224092Sdougb isc_buffer_t buf; 2383224092Sdougb isc_region_t reg; 2384224092Sdougb char *p, txt[DNS_NAME_FORMATSIZE]; 2385224092Sdougb 2386224092Sdougb REQUIRE(VALID_NAME(name)); 2387224092Sdougb REQUIRE(target != NULL && *target == NULL); 2388224092Sdougb 2389224092Sdougb isc_buffer_init(&buf, txt, sizeof(txt)); 2390224092Sdougb result = dns_name_totext(name, ISC_FALSE, &buf); 2391224092Sdougb if (result != ISC_R_SUCCESS) 2392224092Sdougb return (result); 2393224092Sdougb 2394224092Sdougb isc_buffer_usedregion(&buf, ®); 2395224092Sdougb p = isc_mem_allocate(mctx, reg.length + 1); 2396262706Serwin memmove(p, (char *) reg.base, (int) reg.length); 2397224092Sdougb p[reg.length] = '\0'; 2398224092Sdougb 2399224092Sdougb *target = p; 2400224092Sdougb return (ISC_R_SUCCESS); 2401224092Sdougb} 2402224092Sdougb 2403224092Sdougb/* 2404224092Sdougb * dns_name_fromstring() -- convert directly from a string to a name, 2405224092Sdougb * allocating memory as needed 2406224092Sdougb */ 2407224092Sdougbisc_result_t 2408224092Sdougbdns_name_fromstring(dns_name_t *target, const char *src, unsigned int options, 2409224092Sdougb isc_mem_t *mctx) 2410224092Sdougb{ 2411224092Sdougb return (dns_name_fromstring2(target, src, dns_rootname, options, mctx)); 2412224092Sdougb} 2413224092Sdougb 2414224092Sdougbisc_result_t 2415224092Sdougbdns_name_fromstring2(dns_name_t *target, const char *src, 2416224092Sdougb const dns_name_t *origin, unsigned int options, 2417224092Sdougb isc_mem_t *mctx) 2418224092Sdougb{ 2419224092Sdougb isc_result_t result; 2420224092Sdougb isc_buffer_t buf; 2421224092Sdougb dns_fixedname_t fn; 2422224092Sdougb dns_name_t *name; 2423224092Sdougb 2424224092Sdougb REQUIRE(src != NULL); 2425224092Sdougb 2426254402Serwin isc_buffer_constinit(&buf, src, strlen(src)); 2427224092Sdougb isc_buffer_add(&buf, strlen(src)); 2428224092Sdougb if (BINDABLE(target) && target->buffer != NULL) 2429224092Sdougb name = target; 2430224092Sdougb else { 2431224092Sdougb dns_fixedname_init(&fn); 2432224092Sdougb name = dns_fixedname_name(&fn); 2433224092Sdougb } 2434224092Sdougb 2435224092Sdougb result = dns_name_fromtext(name, &buf, origin, options, NULL); 2436224092Sdougb if (result != ISC_R_SUCCESS) 2437224092Sdougb return (result); 2438224092Sdougb 2439224092Sdougb if (name != target) 2440224092Sdougb result = dns_name_dupwithoffsets(name, mctx, target); 2441224092Sdougb return (result); 2442224092Sdougb} 2443224092Sdougb 2444224092Sdougbisc_result_t 2445135446Strhodesdns_name_copy(dns_name_t *source, dns_name_t *dest, isc_buffer_t *target) { 2446135446Strhodes unsigned char *ndata; 2447135446Strhodes 2448135446Strhodes /* 2449135446Strhodes * Make dest a copy of source. 2450135446Strhodes */ 2451135446Strhodes 2452135446Strhodes REQUIRE(VALID_NAME(source)); 2453135446Strhodes REQUIRE(VALID_NAME(dest)); 2454135446Strhodes REQUIRE(target != NULL || dest->buffer != NULL); 2455135446Strhodes 2456135446Strhodes if (target == NULL) { 2457135446Strhodes target = dest->buffer; 2458135446Strhodes isc_buffer_clear(dest->buffer); 2459135446Strhodes } 2460135446Strhodes 2461135446Strhodes REQUIRE(BINDABLE(dest)); 2462135446Strhodes 2463135446Strhodes /* 2464135446Strhodes * Set up. 2465135446Strhodes */ 2466135446Strhodes if (target->length - target->used < source->length) 2467135446Strhodes return (ISC_R_NOSPACE); 2468135446Strhodes 2469135446Strhodes ndata = (unsigned char *)target->base + target->used; 2470135446Strhodes dest->ndata = target->base; 2471135446Strhodes 2472262706Serwin memmove(ndata, source->ndata, source->length); 2473135446Strhodes 2474135446Strhodes dest->ndata = ndata; 2475135446Strhodes dest->labels = source->labels; 2476135446Strhodes dest->length = source->length; 2477135446Strhodes if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0) 2478135446Strhodes dest->attributes = DNS_NAMEATTR_ABSOLUTE; 2479135446Strhodes else 2480135446Strhodes dest->attributes = 0; 2481135446Strhodes 2482135446Strhodes if (dest->labels > 0 && dest->offsets != NULL) { 2483135446Strhodes if (source->offsets != NULL) 2484262706Serwin memmove(dest->offsets, source->offsets, source->labels); 2485135446Strhodes else 2486135446Strhodes set_offsets(dest, dest->offsets, NULL); 2487135446Strhodes } 2488135446Strhodes 2489135446Strhodes isc_buffer_add(target, dest->length); 2490135446Strhodes 2491135446Strhodes return (ISC_R_SUCCESS); 2492135446Strhodes} 2493135446Strhodes 2494170222Sdougbvoid 2495170222Sdougbdns_name_destroy(void) { 2496170222Sdougb#ifdef ISC_PLATFORM_USETHREADS 2497170222Sdougb RUNTIME_CHECK(isc_once_do(&once, thread_key_mutex_init) 2498170222Sdougb == ISC_R_SUCCESS); 2499170222Sdougb 2500170222Sdougb LOCK(&thread_key_mutex); 2501170222Sdougb if (thread_key_initialized) { 2502170222Sdougb isc_mem_detach(&thread_key_mctx); 2503170222Sdougb isc_thread_key_delete(totext_filter_proc_key); 2504170222Sdougb thread_key_initialized = 0; 2505170222Sdougb } 2506170222Sdougb UNLOCK(&thread_key_mutex); 2507170222Sdougb 2508170222Sdougb#endif 2509170222Sdougb} 2510