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