* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
* Provides facilities for manipulating DNS names and labels, including
* conversions to and from wire format and text format.
* Given the large number of names possible in a nameserver, and because
* names occur in rdata, it was important to come up with a very efficient
* way of storing name data, but at the same time allow names to be
* manipulated. The decision was to store names in uncompressed wire format,
* and not to make them fully abstracted objects; i.e. certain parts of the
* server know names are stored that way. This saves a lot of memory, and
* makes adding names to messages easy. Having much of the server know
* the representation would be perilous, and we certainly don't want each
* user of names to be manipulating such a low-level structure. This is
* where the Names and Labels module comes in. The module allows name or
* label handles to be created and attached to uncompressed wire format
* regions. All name operations and conversions are done through these
*\li Clients of this module must impose any required synchronization.
*\li This module deals with low-level byte streams. Errors in any of
* the functions are likely to crash the server or corrupt memory.
*\li dns_name_fromwire() deals with raw network data. An error in
* this routine could result in the failure or hijacking of the server.
*\li Draft Binary Labels (2)
#include <isc/region.h> /* Required for storage size of dns_label_t. */
***** A 'label' is basically a region. It contains one DNS wire format
***** label of type 00 (ordinary).
***** A 'name' is a handle to a binary region. It contains a sequence of one
***** or more DNS wire format labels of type 00 (ordinary).
***** Note that all names are not required to end with the root label,
***** as they are in the actual DNS wire protocol.
* Clients are strongly discouraged from using this type directly, with
* the exception of the 'link' and 'list' fields which may be used directly
* for whatever purpose the client desires.
ISC_LINK(dns_name_t) link;
ISC_LIST(dns_rdataset_t) list;
#define DNS_NAME_MAGIC ISC_MAGIC('D','N','S','n')
#define DNS_NAMEATTR_ABSOLUTE 0x00000001
#define DNS_NAMEATTR_READONLY 0x00000002
#define DNS_NAMEATTR_DYNAMIC 0x00000004
#define DNS_NAMEATTR_DYNOFFSETS 0x00000008
#define DNS_NAMEATTR_NOCOMPRESS 0x00000010
* Attributes below 0x0100 reserved for name.c usage.
#define DNS_NAMEATTR_CACHE 0x00000100 /*%< Used by resolver. */
#define DNS_NAMEATTR_ANSWER 0x00000200 /*%< Used by resolver. */
#define DNS_NAMEATTR_NCACHE 0x00000400 /*%< Used by resolver. */
#define DNS_NAMEATTR_CHAINING 0x00000800 /*%< Used by resolver. */
#define DNS_NAMEATTR_CHASE 0x00001000 /*%< Used by resolver. */
#define DNS_NAMEATTR_WILDCARD 0x00002000 /*%< Used by server. */
#define DNS_NAMEATTR_PREREQUISITE 0x00004000 /*%< Used by client. */
#define DNS_NAMEATTR_UPDATE 0x00008000 /*%< Used by client. */
#define DNS_NAMEATTR_HASUPDATEREC 0x00010000 /*%< Used by client. */
#define DNS_NAME_DOWNCASE 0x0001
#define DNS_NAME_CHECKNAMES 0x0002 /*%< Used by rdata. */
#define DNS_NAME_CHECKNAMESFAIL 0x0004 /*%< Used by rdata. */
#define DNS_NAME_CHECKREVERSE 0x0008 /*%< Used by rdata. */
#define DNS_NAME_CHECKMX 0x0010 /*%< Used by rdata. */
#define DNS_NAME_CHECKMXFAIL 0x0020 /*%< Used by rdata. */
LIBDNS_EXTERNAL_DATA extern dns_name_t *dns_rootname;
LIBDNS_EXTERNAL_DATA extern dns_name_t *dns_wildcardname;
* DNS_NAME_INITNONABSOLUTE and DNS_NAME_INITABSOLUTE are macros for
* initializing dns_name_t structures.
* Note[1]: 'length' is set to (sizeof(A) - 1) in DNS_NAME_INITNONABSOLUTE
* and sizeof(A) in DNS_NAME_INITABSOLUTE to allow C strings to be used
* Note[2]: The final value of offsets for DNS_NAME_INITABSOLUTE should
* match (sizeof(A) - 1) which is the offset of the root label.
* unsigned char data[] = "\005value";
* unsigned char offsets[] = { 0 };
* dns_name_t value = DNS_NAME_INITNONABSOLUTE(data, offsets);
* unsigned char data[] = "\005value";
* unsigned char offsets[] = { 0, 6 };
* dns_name_t value = DNS_NAME_INITABSOLUTE(data, offsets);
#define DNS_NAME_INITNONABSOLUTE(A,B) { \
A, (sizeof(A) - 1), sizeof(B), \
B, NULL, { (void *)-1, (void *)-1}, \
#define DNS_NAME_INITABSOLUTE(A,B) { \
A, sizeof(A), sizeof(B), \
DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE, \
B, NULL, { (void *)-1, (void *)-1}, \
#define DNS_NAME_INITEMPTY { \
DNS_NAME_MAGIC, NULL, 0, 0, 0, NULL, NULL, \
{ (void *)-1, (void *)-1 }, { NULL, NULL }, NULL \
* Standard size of a wire format name
#define DNS_NAME_MAXWIRE 255
* Text output filter procedure.
* 'target' is the buffer to be converted. The region to be converted
* is from 'buffer'->base + 'used_org' to the end of the used region.
typedef isc_result_t (*dns_name_totextfilter_t)(isc_buffer_t *target,
dns_name_init(dns_name_t *name, unsigned char *offsets);
* \li 'offsets' is never required to be non-NULL, but specifying a
* dns_offsets_t for 'offsets' will improve the performance of most
* name operations if the name is used more than once.
* \li 'name' is not NULL and points to a struct dns_name.
* \li offsets == NULL or offsets is a dns_offsets_t.
* \li 'name' is a valid name.
* \li dns_name_countlabels(name) == 0
* \li dns_name_isabsolute(name) == false
dns_name_reset(dns_name_t *name);
* \li This function distinguishes itself from dns_name_init() in two
* \li + If any buffer is associated with 'name' (via dns_name_setbuffer()
* or by being part of a dns_fixedname_t) the link to the buffer
* is retained but the buffer itself is cleared.
* \li + Of the attributes associated with 'name', all are retained except
* \li 'name' is a valid name.
* \li 'name' is a valid name.
* \li dns_name_countlabels(name) == 0
* \li dns_name_isabsolute(name) == false
dns_name_invalidate(dns_name_t *name);
* \li 'name' is a valid name.
* \li If assertion checking is enabled, future attempts to use 'name'
* without initializing it will cause an assertion failure.
* \li If the name had a dedicated buffer, that association is ended.
dns_name_isvalid(const dns_name_t *name);
* Check whether 'name' points to a valid dns_name
dns_name_setbuffer(dns_name_t *name, isc_buffer_t *buffer);
* Dedicate a buffer for use with 'name'.
* \li Specification of a target buffer in dns_name_fromwire(),
* dns_name_fromtext(), and dns_name_concatenate() is optional if
* 'name' has a dedicated buffer.
* \li The caller must not write to buffer until the name has been
* invalidated or is otherwise known not to be in use.
* \li If buffer is NULL and the name previously had a dedicated buffer,
* than that buffer is no longer dedicated to use with this name.
* The caller is responsible for ensuring that the storage used by
* the name remains valid.
* \li 'name' is a valid name.
* \li 'buffer' is a valid binary buffer and 'name' doesn't have a
* dedicated buffer already, or 'buffer' is NULL.
dns_name_hasbuffer(const dns_name_t *name);
* Does 'name' have a dedicated buffer?
* \li 'name' is a valid name.
* \li true 'name' has a dedicated buffer.
* \li false 'name' does not have a dedicated buffer.
dns_name_isabsolute(const dns_name_t *name);
* Does 'name' end in the root label?
* \li 'name' is a valid name
* \li TRUE The last label in 'name' is the root label.
* \li FALSE The last label in 'name' is not the root label.
dns_name_iswildcard(const dns_name_t *name);
* Is 'name' a wildcard name?
* \li 'name' is a valid name
* \li dns_name_countlabels(name) > 0
* \li TRUE The least significant label of 'name' is '*'.
* \li FALSE The least significant label of 'name' is not '*'.
dns_name_hash(dns_name_t *name, bool case_sensitive);
* Provide a hash value for 'name'.
* Note: if 'case_sensitive' is false, then names which differ only in
* case will have the same hash value.
* \li 'name' is a valid name
dns_name_fullhash(dns_name_t *name, bool case_sensitive);
* Provide a hash value for 'name'. Unlike dns_name_hash(), this function
* always takes into account of the entire name to calculate the hash value.
* Note: if 'case_sensitive' is false, then names which differ only in
* case will have the same hash value.
*\li 'name' is a valid name
dns_name_hashbylabel(dns_name_t *name, bool case_sensitive);
* Provide a hash value for 'name', where the hash value is the sum
* of the hash values of each label. This function should only be used
* when incremental hashing is necessary, for example, during RBT
* traversal. It is not currently used in BIND. Generally,
* dns_name_fullhash() is the correct function to use for name
* Note: if 'case_sensitive' is false, then names which differ only in
* case will have the same hash value.
*\li 'name' is a valid name
dns_name_fullcompare(const dns_name_t *name1, const dns_name_t *name2,
int *orderp, unsigned int *nlabelsp);
* Determine the relative ordering under the DNSSEC order relation of
* 'name1' and 'name2', and also determine the hierarchical
* relationship of the names.
* Note: It makes no sense for one of the names to be relative and the
* other absolute. If both names are relative, then to be meaningfully
* compared the caller must ensure that they are both relative to the
*\li 'name1' is a valid name
*\li dns_name_countlabels(name1) > 0
*\li 'name2' is a valid name
*\li dns_name_countlabels(name2) > 0
*\li orderp and nlabelsp are valid pointers.
*\li Either name1 is absolute and name2 is absolute, or neither is.
*\li *orderp is < 0 if name1 < name2, 0 if name1 = name2, > 0 if
*\li *nlabelsp is the number of common significant labels.
*\li dns_namereln_none There's no hierarchical relationship
* between name1 and name2.
*\li dns_namereln_contains name1 properly contains name2; i.e.
* name2 is a proper subdomain of name1.
*\li dns_namereln_subdomain name1 is a proper subdomain of name2.
*\li dns_namereln_equal name1 and name2 are equal.
*\li dns_namereln_commonancestor name1 and name2 share a common
dns_name_compare(const dns_name_t *name1, const dns_name_t *name2);
* Determine the relative ordering under the DNSSEC order relation of
* Note: It makes no sense for one of the names to be relative and the
* other absolute. If both names are relative, then to be meaningfully
* compared the caller must ensure that they are both relative to the
* \li 'name1' is a valid name
* \li 'name2' is a valid name
* \li Either name1 is absolute and name2 is absolute, or neither is.
* \li < 0 'name1' is less than 'name2'
* \li 0 'name1' is equal to 'name2'
* \li > 0 'name1' is greater than 'name2'
dns_name_equal(const dns_name_t *name1, const dns_name_t *name2);
* Are 'name1' and 'name2' equal?
* \li Because it only needs to test for equality, dns_name_equal() can be
* significantly faster than dns_name_fullcompare() or dns_name_compare().
* \li Offsets tables are not used in the comparison.
* \li It makes no sense for one of the names to be relative and the
* other absolute. If both names are relative, then to be meaningfully
* compared the caller must ensure that they are both relative to the
* \li 'name1' is a valid name
* \li 'name2' is a valid name
* \li Either name1 is absolute and name2 is absolute, or neither is.
* \li true 'name1' and 'name2' are equal
* \li false 'name1' and 'name2' are not equal