Home | History | Annotate | Line # | Download | only in dns
      1 /*	$NetBSD: name.h,v 1.14 2025/05/21 14:48:04 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
      5  *
      6  * SPDX-License-Identifier: MPL-2.0
      7  *
      8  * This Source Code Form is subject to the terms of the Mozilla Public
      9  * License, v. 2.0. If a copy of the MPL was not distributed with this
     10  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
     11  *
     12  * See the COPYRIGHT file distributed with this work for additional
     13  * information regarding copyright ownership.
     14  */
     15 
     16 #pragma once
     17 
     18 /*****
     19 ***** Module Info
     20 *****/
     21 
     22 /*! \file dns/name.h
     23  * \brief
     24  * Provides facilities for manipulating DNS names and labels, including
     25  * conversions to and from wire format and text format.
     26  *
     27  * Given the large number of names possible in a nameserver, and because
     28  * names occur in rdata, it was important to come up with a very efficient
     29  * way of storing name data, but at the same time allow names to be
     30  * manipulated.  The decision was to store names in uncompressed wire format,
     31  * and not to make them fully abstracted objects; i.e. certain parts of the
     32  * server know names are stored that way.  This saves a lot of memory, and
     33  * makes adding names to messages easy.  Having much of the server know
     34  * the representation would be perilous, and we certainly don't want each
     35  * user of names to be manipulating such a low-level structure.  This is
     36  * where the Names and Labels module comes in. The module allows name
     37  * handles to be created and attached to uncompressed wire format
     38  * regions. All name operations and conversions are done through these
     39  * handles.
     40  *
     41  * MP:
     42  *\li	Clients of this module must impose any required synchronization.
     43  *
     44  * Reliability:
     45  *\li	This module deals with low-level byte streams.  Errors in any of
     46  *	the functions are likely to crash the server or corrupt memory.
     47  *
     48  * Resources:
     49  *\li	None.
     50  *
     51  * Security:
     52  *
     53  *\li	*** WARNING ***
     54  *
     55  *\li	dns_name_fromwire() deals with raw network data.  An error in
     56  *	this routine could result in the failure or hijacking of the server.
     57  *
     58  * Standards:
     59  *\li	RFC1035
     60  *\li	Draft EDNS0 (0)
     61  *
     62  */
     63 
     64 /***
     65  *** Imports
     66  ***/
     67 
     68 #include <inttypes.h>
     69 #include <stdbool.h>
     70 #include <stdio.h>
     71 
     72 #include <isc/buffer.h>
     73 #include <isc/hashmap.h>
     74 #include <isc/lang.h>
     75 #include <isc/magic.h>
     76 #include <isc/region.h> /* Required for storage size of dns_label_t. */
     77 
     78 #include <dns/types.h>
     79 
     80 ISC_LANG_BEGINDECLS
     81 
     82 /*****
     83 ***** Names
     84 *****
     85 ***** A 'name' is a handle to a binary region.  It contains a sequence of one
     86 ***** or more DNS wire format labels.
     87 ***** Note that all names are not required to end with the root label,
     88 ***** as they are in the actual DNS wire protocol.
     89 *****/
     90 
     91 /***
     92  *** Types
     93  ***/
     94 
     95 /*%
     96  * Clients are strongly discouraged from using this type directly,  with
     97  * the exception of the 'link' and 'list' fields which may be used directly
     98  * for whatever purpose the client desires.
     99  */
    100 struct dns_name {
    101 	unsigned int magic;
    102 	uint8_t	     length;
    103 	uint8_t	     labels;
    104 	struct dns_name_attrs {
    105 		bool absolute	  : 1; /*%< Used by name.c */
    106 		bool readonly	  : 1; /*%< Used by name.c */
    107 		bool dynamic	  : 1; /*%< Used by name.c */
    108 		bool dynoffsets	  : 1; /*%< Used by name.c */
    109 		bool nocompress	  : 1; /*%< Used by name.c */
    110 		bool cache	  : 1; /*%< Used by resolver. */
    111 		bool answer	  : 1; /*%< Used by resolver. */
    112 		bool ncache	  : 1; /*%< Used by resolver. */
    113 		bool chaining	  : 1; /*%< Used by resolver. */
    114 		bool chase	  : 1; /*%< Used by resolver. */
    115 		bool wildcard	  : 1; /*%< Used by server. */
    116 		bool prerequisite : 1; /*%< Used by client. */
    117 		bool update	  : 1; /*%< Used by client. */
    118 		bool hasupdaterec : 1; /*%< Used by client. */
    119 	} attributes;
    120 	unsigned char *ndata;
    121 	unsigned char *offsets;
    122 	isc_buffer_t  *buffer;
    123 	ISC_LINK(dns_name_t) link;
    124 	ISC_LIST(dns_rdataset_t) list;
    125 	isc_hashmap_t *hashmap;
    126 };
    127 
    128 #define DNS_NAME_MAGIC	  ISC_MAGIC('D', 'N', 'S', 'n')
    129 #define DNS_NAME_VALID(n) ISC_MAGIC_VALID(n, DNS_NAME_MAGIC)
    130 
    131 /*%
    132  * A name is "bindable" if it can be set to point to a new value, i.e.
    133  * name->ndata and name->length may be changed.
    134  */
    135 #define DNS_NAME_BINDABLE(name) \
    136 	(!name->attributes.readonly && !name->attributes.dynamic)
    137 
    138 /*
    139  * Various flags.
    140  */
    141 #define DNS_NAME_DOWNCASE	0x0001
    142 #define DNS_NAME_CHECKNAMES	0x0002 /*%< Used by rdata. */
    143 #define DNS_NAME_CHECKNAMESFAIL 0x0004 /*%< Used by rdata. */
    144 #define DNS_NAME_CHECKREVERSE	0x0008 /*%< Used by rdata. */
    145 #define DNS_NAME_CHECKMX	0x0010 /*%< Used by rdata. */
    146 #define DNS_NAME_CHECKMXFAIL	0x0020 /*%< Used by rdata. */
    147 
    148 extern const dns_name_t *dns_rootname;
    149 extern const dns_name_t *dns_wildcardname;
    150 
    151 /*%<
    152  * DNS_NAME_INITNONABSOLUTE and DNS_NAME_INITABSOLUTE are macros for
    153  * initializing dns_name_t structures.
    154  *
    155  * Note[1]: 'length' is set to (sizeof(A) - 1) in DNS_NAME_INITNONABSOLUTE
    156  * and sizeof(A) in DNS_NAME_INITABSOLUTE to allow C strings to be used
    157  * to initialize 'ndata'.
    158  *
    159  * Note[2]: The final value of offsets for DNS_NAME_INITABSOLUTE should
    160  * match (sizeof(A) - 1) which is the offset of the root label.
    161  *
    162  * Typical usage:
    163  *	unsigned char data[] = "\005value";
    164  *	unsigned char offsets[] = { 0 };
    165  *	dns_name_t value = DNS_NAME_INITNONABSOLUTE(data, offsets);
    166  *
    167  *	unsigned char data[] = "\005value";
    168  *	unsigned char offsets[] = { 0, 6 };
    169  *	dns_name_t value = DNS_NAME_INITABSOLUTE(data, offsets);
    170  */
    171 #define DNS_NAME_INITNONABSOLUTE(A, B)              \
    172 	{                                           \
    173 		.magic = DNS_NAME_MAGIC,            \
    174 		.ndata = A,                         \
    175 		.length = (sizeof(A) - 1),          \
    176 		.labels = sizeof(B),                \
    177 		.attributes = { .readonly = true }, \
    178 		.offsets = B,                       \
    179 		.link = ISC_LINK_INITIALIZER,       \
    180 		.list = ISC_LIST_INITIALIZER,       \
    181 	}
    182 
    183 #define DNS_NAME_INITABSOLUTE(A, B)                                   \
    184 	{                                                             \
    185 		.magic = DNS_NAME_MAGIC,                              \
    186 		.ndata = A,                                           \
    187 		.length = sizeof(A),                                  \
    188 		.labels = sizeof(B),                                  \
    189 		.attributes = { .readonly = true, .absolute = true }, \
    190 		.offsets = B,                                         \
    191 		.link = ISC_LINK_INITIALIZER,                         \
    192 		.list = ISC_LIST_INITIALIZER,                         \
    193 	}
    194 
    195 #define DNS_NAME_INITEMPTY              \
    196 	{ .magic = DNS_NAME_MAGIC,      \
    197 	  .link = ISC_LINK_INITIALIZER, \
    198 	  .list = ISC_LIST_INITIALIZER }
    199 
    200 /*%
    201  * Standard sizes of a wire format name
    202  */
    203 #define DNS_NAME_MAXWIRE   255
    204 #define DNS_NAME_MAXLABELS 128
    205 #define DNS_NAME_LABELLEN  63
    206 
    207 typedef unsigned char dns_offsets_t[DNS_NAME_MAXLABELS];
    208 
    209 /*
    210  * Text output filter procedure.
    211  * 'target' is the buffer to be converted.  The region to be converted
    212  * is from 'buffer'->base + 'used_org' to the end of the used region.
    213  */
    214 typedef isc_result_t(dns_name_totextfilter_t)(isc_buffer_t *target,
    215 					      unsigned int  used_org);
    216 
    217 /***
    218  *** Initialization
    219  ***/
    220 
    221 static inline void
    222 dns_name_init(dns_name_t *name, unsigned char *offsets) {
    223 	*name = (dns_name_t){
    224 		.magic = DNS_NAME_MAGIC,
    225 		.offsets = (offsets),
    226 		.link = ISC_LINK_INITIALIZER,
    227 		.list = ISC_LIST_INITIALIZER,
    228 	};
    229 }
    230 /*%<
    231  * Initialize 'name'.
    232  *
    233  * Notes:
    234  * \li	'offsets' is never required to be non-NULL, but specifying a
    235  *	dns_offsets_t for 'offsets' will improve the performance of most
    236  *	name operations if the name is used more than once.
    237  *
    238  * Requires:
    239  * \li	'name' is not NULL and points to a struct dns_name.
    240  *
    241  * \li	offsets == NULL or offsets is a dns_offsets_t.
    242  *
    243  * Ensures:
    244  * \li	'name' is a valid name.
    245  * \li	dns_name_countlabels(name) == 0
    246  * \li	dns_name_isabsolute(name) == false
    247  */
    248 
    249 static inline void
    250 dns_name_reset(dns_name_t *name) {
    251 	REQUIRE(DNS_NAME_VALID(name));
    252 	REQUIRE(DNS_NAME_BINDABLE(name));
    253 
    254 	name->ndata = NULL;
    255 	name->length = 0;
    256 	name->labels = 0;
    257 	name->attributes.absolute = false;
    258 	if (name->buffer != NULL) {
    259 		isc_buffer_clear(name->buffer);
    260 	}
    261 }
    262 /*%<
    263  * Reinitialize 'name'.
    264  *
    265  * Notes:
    266  * \li	This function distinguishes itself from dns_name_init() in two
    267  *	key ways:
    268  *
    269  * \li	+ If any buffer is associated with 'name' (via dns_name_setbuffer()
    270  *	  or by being part of a dns_fixedname_t) the link to the buffer
    271  *	  is retained but the buffer itself is cleared.
    272  *
    273  * \li	+ Of the attributes associated with 'name', all are retained except
    274  *	  the absolute flag.
    275  *
    276  * Requires:
    277  * \li	'name' is a valid name.
    278  *
    279  * Ensures:
    280  * \li	'name' is a valid name.
    281  * \li	dns_name_countlabels(name) == 0
    282  * \li	dns_name_isabsolute(name) == false
    283  */
    284 
    285 static inline void
    286 dns_name_invalidate(dns_name_t *name) {
    287 	REQUIRE(DNS_NAME_VALID(name));
    288 
    289 	name->magic = 0;
    290 	name->ndata = NULL;
    291 	name->length = 0;
    292 	name->labels = 0;
    293 	name->attributes = (struct dns_name_attrs){};
    294 	name->offsets = NULL;
    295 	name->buffer = NULL;
    296 	ISC_LINK_INIT(name, link);
    297 }
    298 /*%<
    299  * Make 'name' invalid.
    300  *
    301  * Requires:
    302  * \li	'name' is a valid name.
    303  *
    304  * Ensures:
    305  * \li	If assertion checking is enabled, future attempts to use 'name'
    306  *	without initializing it will cause an assertion failure.
    307  *
    308  * \li	If the name had a dedicated buffer, that association is ended.
    309  */
    310 
    311 bool
    312 dns_name_isvalid(const dns_name_t *name);
    313 /*%<
    314  * Check whether 'name' points to a valid dns_name
    315  */
    316 
    317 /***
    318  *** Dedicated Buffers
    319  ***/
    320 
    321 static inline void
    322 dns_name_setbuffer(dns_name_t *name, isc_buffer_t *buffer) {
    323 	REQUIRE(DNS_NAME_VALID(name));
    324 	REQUIRE((buffer != NULL && name->buffer == NULL) || (buffer == NULL));
    325 
    326 	name->buffer = buffer;
    327 }
    328 /*%<
    329  * Dedicate a buffer for use with 'name'.
    330  *
    331  * Notes:
    332  * \li	Specification of a target buffer in dns_name_fromwire(),
    333  *	dns_name_fromtext(), and dns_name_concatenate() is optional if
    334  *	'name' has a dedicated buffer.
    335  *
    336  * \li	The caller must not write to buffer until the name has been
    337  *	invalidated or is otherwise known not to be in use.
    338  *
    339  * \li	If buffer is NULL and the name previously had a dedicated buffer,
    340  *	than that buffer is no longer dedicated to use with this name.
    341  *	The caller is responsible for ensuring that the storage used by
    342  *	the name remains valid.
    343  *
    344  * Requires:
    345  * \li	'name' is a valid name.
    346  *
    347  * \li	'buffer' is a valid binary buffer and 'name' doesn't have a
    348  *	dedicated buffer already, or 'buffer' is NULL.
    349  */
    350 
    351 bool
    352 dns_name_hasbuffer(const dns_name_t *name);
    353 /*%<
    354  * Does 'name' have a dedicated buffer?
    355  *
    356  * Requires:
    357  * \li	'name' is a valid name.
    358  *
    359  * Returns:
    360  * \li	true	'name' has a dedicated buffer.
    361  * \li	false	'name' does not have a dedicated buffer.
    362  */
    363 
    364 /***
    365  *** Properties
    366  ***/
    367 
    368 bool
    369 dns_name_isabsolute(const dns_name_t *name);
    370 /*%<
    371  * Does 'name' end in the root label?
    372  *
    373  * Requires:
    374  * \li	'name' is a valid name
    375  *
    376  * Returns:
    377  * \li	TRUE		The last label in 'name' is the root label.
    378  * \li	FALSE		The last label in 'name' is not the root label.
    379  */
    380 
    381 bool
    382 dns_name_iswildcard(const dns_name_t *name);
    383 /*%<
    384  * Is 'name' a wildcard name?
    385  *
    386  * Requires:
    387  * \li	'name' is a valid name
    388  *
    389  * \li	dns_name_countlabels(name) > 0
    390  *
    391  * Returns:
    392  * \li	TRUE		The least significant label of 'name' is '*'.
    393  * \li	FALSE		The least significant label of 'name' is not '*'.
    394  */
    395 
    396 uint32_t
    397 dns_name_hash(const dns_name_t *name);
    398 /*%<
    399  * Provide a hash value for 'name'.
    400  *
    401  * Note: This function always takes into account of the entire name to calculate
    402  * the hash value. The names which differ only in case will have the same hash
    403  * value.
    404  *
    405  * Requires:
    406  *\li	'name' is a valid name
    407  *
    408  * Returns:
    409  *\li	A hash value
    410  */
    411 
    412 /*
    413  *** Comparisons
    414  ***/
    415 
    416 dns_namereln_t
    417 dns_name_fullcompare(const dns_name_t *name1, const dns_name_t *name2,
    418 		     int *orderp, unsigned int *nlabelsp);
    419 /*%<
    420  * Determine the relative ordering under the DNSSEC order relation of
    421  * 'name1' and 'name2', and also determine the hierarchical
    422  * relationship of the names.
    423  *
    424  * Note: It makes no sense for one of the names to be relative and the
    425  * other absolute.  If both names are relative, then to be meaningfully
    426  * compared the caller must ensure that they are both relative to the
    427  * same domain.
    428  *
    429  * Requires:
    430  *\li	'name1' is a valid name
    431  *
    432  *\li	dns_name_countlabels(name1) > 0
    433  *
    434  *\li	'name2' is a valid name
    435  *
    436  *\li	dns_name_countlabels(name2) > 0
    437  *
    438  *\li	orderp and nlabelsp are valid pointers.
    439  *
    440  *\li	Either name1 is absolute and name2 is absolute, or neither is.
    441  *
    442  * Ensures:
    443  *
    444  *\li	*orderp is < 0 if name1 < name2, 0 if name1 = name2, > 0 if
    445  *	name1 > name2.
    446  *
    447  *\li	*nlabelsp is the number of common significant labels.
    448  *
    449  * Returns:
    450  *\li	dns_namereln_none		There's no hierarchical relationship
    451  *					between name1 and name2.
    452  *\li	dns_namereln_contains		name1 properly contains name2; i.e.
    453  *					name2 is a proper subdomain of name1.
    454  *\li	dns_namereln_subdomain		name1 is a proper subdomain of name2.
    455  *\li	dns_namereln_equal		name1 and name2 are equal.
    456  *\li	dns_namereln_commonancestor	name1 and name2 share a common
    457  *					ancestor.
    458  */
    459 
    460 int
    461 dns_name_compare(const dns_name_t *name1, const dns_name_t *name2);
    462 /*%<
    463  * Determine the relative ordering under the DNSSEC order relation of
    464  * 'name1' and 'name2'.
    465  *
    466  * Note: It makes no sense for one of the names to be relative and the
    467  * other absolute.  If both names are relative, then to be meaningfully
    468  * compared the caller must ensure that they are both relative to the
    469  * same domain.
    470  *
    471  * Requires:
    472  * \li	'name1' is a valid name
    473  *
    474  * \li	'name2' is a valid name
    475  *
    476  * \li	Either name1 is absolute and name2 is absolute, or neither is.
    477  *
    478  * Returns:
    479  * \li	< 0		'name1' is less than 'name2'
    480  * \li	0		'name1' is equal to 'name2'
    481  * \li	> 0		'name1' is greater than 'name2'
    482  */
    483 
    484 bool
    485 dns_name_equal(const dns_name_t *name1, const dns_name_t *name2);
    486 /*%<
    487  * Are 'name1' and 'name2' equal?
    488  *
    489  * Notes:
    490  * \li	Because it only needs to test for equality, dns_name_equal() can be
    491  *	significantly faster than dns_name_fullcompare() or dns_name_compare().
    492  *
    493  * \li	Offsets tables are not used in the comparison.
    494  *
    495  * \li	It makes no sense for one of the names to be relative and the
    496  *	other absolute.  If both names are relative, then to be meaningfully
    497  * 	compared the caller must ensure that they are both relative to the
    498  * 	same domain.
    499  *
    500  * Requires:
    501  * \li	'name1' is a valid name
    502  *
    503  * \li	'name2' is a valid name
    504  *
    505  * \li	Either name1 is absolute and name2 is absolute, or neither is.
    506  *
    507  * Returns:
    508  * \li	true	'name1' and 'name2' are equal
    509  * \li	false	'name1' and 'name2' are not equal
    510  */
    511 
    512 bool
    513 dns_name_caseequal(const dns_name_t *name1, const dns_name_t *name2);
    514 /*%<
    515  * Case sensitive version of dns_name_equal().
    516  */
    517 
    518 int
    519 dns_name_rdatacompare(const dns_name_t *name1, const dns_name_t *name2);
    520 /*%<
    521  * Compare two names as if they are part of rdata in DNSSEC canonical
    522  * form.
    523  *
    524  * Requires:
    525  * \li	'name1' is a valid absolute name
    526  *
    527  * \li	dns_name_countlabels(name1) > 0
    528  *
    529  * \li	'name2' is a valid absolute name
    530  *
    531  * \li	dns_name_countlabels(name2) > 0
    532  *
    533  * Returns:
    534  * \li	< 0		'name1' is less than 'name2'
    535  * \li	0		'name1' is equal to 'name2'
    536  * \li	> 0		'name1' is greater than 'name2'
    537  */
    538 
    539 bool
    540 dns_name_issubdomain(const dns_name_t *name1, const dns_name_t *name2);
    541 /*%<
    542  * Is 'name1' a subdomain of 'name2'?
    543  *
    544  * Notes:
    545  * \li	name1 is a subdomain of name2 if name1 is contained in name2, or
    546  *	name1 equals name2.
    547  *
    548  * \li	It makes no sense for one of the names to be relative and the
    549  *	other absolute.  If both names are relative, then to be meaningfully
    550  *	compared the caller must ensure that they are both relative to the
    551  *	same domain.
    552  *
    553  * Requires:
    554  * \li	'name1' is a valid name
    555  *
    556  * \li	'name2' is a valid name
    557  *
    558  * \li	Either name1 is absolute and name2 is absolute, or neither is.
    559  *
    560  * Returns:
    561  * \li	TRUE		'name1' is a subdomain of 'name2'
    562  * \li	FALSE		'name1' is not a subdomain of 'name2'
    563  */
    564 
    565 bool
    566 dns_name_matcheswildcard(const dns_name_t *name, const dns_name_t *wname);
    567 /*%<
    568  * Does 'name' match the wildcard specified in 'wname'?
    569  *
    570  * Notes:
    571  * \li	name matches the wildcard specified in wname if all labels
    572  *	following the wildcard in wname are identical to the same number
    573  *	of labels at the end of name.
    574  *
    575  * \li	It makes no sense for one of the names to be relative and the
    576  *	other absolute.  If both names are relative, then to be meaningfully
    577  *	compared the caller must ensure that they are both relative to the
    578  *	same domain.
    579  *
    580  * Requires:
    581  * \li	'name' is a valid name
    582  *
    583  * \li	dns_name_countlabels(name) > 0
    584  *
    585  * \li	'wname' is a valid name
    586  *
    587  * \li	dns_name_countlabels(wname) > 0
    588  *
    589  * \li	dns_name_iswildcard(wname) is true
    590  *
    591  * \li	Either name is absolute and wname is absolute, or neither is.
    592  *
    593  * Returns:
    594  * \li	TRUE		'name' matches the wildcard specified in 'wname'
    595  * \li	FALSE		'name' does not match the wildcard specified in 'wname'
    596  */
    597 
    598 /***
    599  *** Labels
    600  ***/
    601 
    602 static inline unsigned int
    603 dns_name_countlabels(const dns_name_t *name) {
    604 	REQUIRE(DNS_NAME_VALID(name));
    605 	REQUIRE(name->labels <= DNS_NAME_MAXLABELS);
    606 
    607 	return name->labels;
    608 }
    609 /*%<
    610  * How many labels does 'name' have?
    611  *
    612  * Notes:
    613  * \li	In this case, as in other places, a 'label' is an ordinary label.
    614  *
    615  * Requires:
    616  * \li	'name' is a valid name
    617  *
    618  * Ensures:
    619  * \li	The result is <= 128.
    620  *
    621  * Returns:
    622  * \li	The number of labels in 'name'.
    623  */
    624 
    625 void
    626 dns_name_getlabel(const dns_name_t *name, unsigned int n, dns_label_t *label);
    627 /*%<
    628  * Make 'label' refer to the 'n'th least significant label of 'name'.
    629  *
    630  * Notes:
    631  * \li	Numbering starts at 0.
    632  *
    633  * \li	Given "rc.vix.com.", the label 0 is "rc", and label 3 is the
    634  *	root label.
    635  *
    636  * \li	'label' refers to the same memory as 'name', so 'name' must not
    637  *	be changed while 'label' is still in use.
    638  *
    639  * Requires:
    640  * \li	n < dns_name_countlabels(name)
    641  */
    642 
    643 void
    644 dns_name_getlabelsequence(const dns_name_t *source, unsigned int first,
    645 			  unsigned int n, dns_name_t *target);
    646 /*%<
    647  * Make 'target' refer to the 'n' labels including and following 'first'
    648  * in 'source'.
    649  *
    650  * Notes:
    651  * \li	Numbering starts at 0.
    652  *
    653  * \li	Given "rc.vix.com.", the label 0 is "rc", and label 3 is the
    654  *	root label.
    655  *
    656  * \li	'target' refers to the same memory as 'source', so 'source'
    657  *	must not be changed while 'target' is still in use.
    658  *
    659  * Requires:
    660  * \li	'source' and 'target' are valid names.
    661  *
    662  * \li	first < dns_name_countlabels(name)
    663  *
    664  * \li	first + n <= dns_name_countlabels(name)
    665  */
    666 
    667 void
    668 dns_name_clone(const dns_name_t *source, dns_name_t *target);
    669 /*%<
    670  * Make 'target' refer to the same name as 'source'.
    671  *
    672  * Notes:
    673  *
    674  * \li	'target' refers to the same memory as 'source', so 'source'
    675  *	must not be changed or freed while 'target' is still in use.
    676  *
    677  * \li	This call is functionally equivalent to:
    678  *
    679  * \code
    680  *		dns_name_getlabelsequence(source, 0,
    681  *					  dns_name_countlabels(source),
    682  *					  target);
    683  * \endcode
    684  *
    685  *	but is more efficient.  Also, dns_name_clone() works even if 'source'
    686  *	is empty.
    687  *
    688  * Requires:
    689  *
    690  * \li	'source' is a valid name.
    691  *
    692  * \li	'target' is a valid name that is not read-only.
    693  */
    694 
    695 /***
    696  *** Conversions
    697  ***/
    698 
    699 void
    700 dns_name_fromregion(dns_name_t *name, const isc_region_t *r);
    701 /*%<
    702  * Make 'name' refer to region 'r'.
    703  *
    704  * Note:
    705  * \li	If the conversion encounters a root label before the end of the
    706  *	region the conversion stops and the length is set to the length
    707  *	so far converted.  A maximum of 255 bytes is converted.
    708  *
    709  * Requires:
    710  * \li	The data in 'r' is a sequence of one or more type 00 labels.
    711  */
    712 
    713 static inline void
    714 dns_name_toregion(const dns_name_t *name, isc_region_t *r) {
    715 	REQUIRE(DNS_NAME_VALID(name));
    716 	REQUIRE(r != NULL);
    717 
    718 	r->base = name->ndata;
    719 	r->length = name->length;
    720 }
    721 /*%<
    722  * Make 'r' refer to 'name'.
    723  *
    724  * Requires:
    725  *
    726  * \li	'name' is a valid name.
    727  *
    728  * \li	'r' is a valid region.
    729  */
    730 
    731 isc_result_t
    732 dns_name_fromwire(dns_name_t *name, isc_buffer_t *source, dns_decompress_t dctx,
    733 		  isc_buffer_t *target);
    734 /*%<
    735  * Copy the possibly-compressed name at source (active region) into target,
    736  * decompressing it.
    737  *
    738  * Notes:
    739  * \li	Decompression policy is controlled by 'dctx'.
    740  *
    741  * Security:
    742  *
    743  * \li	*** WARNING ***
    744  *
    745  * \li	This routine will often be used when 'source' contains raw network
    746  *	data.  A programming error in this routine could result in a denial
    747  *	of service, or in the hijacking of the server.
    748  *
    749  * Requires:
    750  *
    751  * \li	'name' is a valid name.
    752  *
    753  * \li	'source' is a valid buffer and the first byte of the active
    754  *	region should be the first byte of a DNS wire format domain name.
    755  *
    756  * \li	'target' is a valid buffer or 'target' is NULL and 'name' has
    757  *	a dedicated buffer.
    758  *
    759  * \li	'dctx' is a valid decompression context.
    760  *
    761  * \li	DNS_NAME_DOWNCASE is not set.
    762  *
    763  * Ensures:
    764  *
    765  *	If result is success:
    766  * \li		If 'target' is not NULL, 'name' is attached to it.
    767  *
    768  * \li		The current location in source is advanced, and the used space
    769  *		in target is updated.
    770  *
    771  * Result:
    772  * \li	Success
    773  * \li	Bad Form: Label Length
    774  * \li	Bad Form: Unknown Label Type
    775  * \li	Bad Form: Name Length
    776  * \li	Bad Form: Compression type not allowed
    777  * \li	Bad Form: Bad compression pointer
    778  * \li	Bad Form: Input too short
    779  * \li	Resource Limit: Not enough space in buffer
    780  */
    781 
    782 isc_result_t
    783 dns_name_towire(const dns_name_t *name, dns_compress_t *cctx,
    784 		isc_buffer_t *target, uint16_t *comp_offsetp);
    785 /*%<
    786  * Convert 'name' into wire format, compressing it as specified by the
    787  * compression context 'cctx', and storing the result in 'target'.
    788  *
    789  * Notes:
    790  * \li	If compression is permitted, then the cctx table may be updated.
    791  *
    792  * Requires:
    793  * \li	'name' is a valid name
    794  *
    795  * \li	dns_name_countlabels(name) > 0
    796  *
    797  * \li	dns_name_isabsolute(name) == TRUE
    798  *
    799  * \li	target is a valid buffer.
    800  *
    801  * \li	Any offsets in the compression table are valid for buffer.
    802  *
    803  * Ensures:
    804  *
    805  *	If the result is success:
    806  *
    807  * \li		The used space in target is updated.
    808  *
    809  * Returns:
    810  * \li	Success
    811  * \li	Resource Limit: Not enough space in buffer
    812  */
    813 
    814 isc_result_t
    815 dns_name_fromtext(dns_name_t *name, isc_buffer_t *source,
    816 		  const dns_name_t *origin, unsigned int options,
    817 		  isc_buffer_t *target);
    818 /*%<
    819  * Convert the textual representation of a DNS name at source
    820  * into uncompressed wire form stored in target.
    821  *
    822  * Notes:
    823  * \li	Relative domain names will have 'origin' appended to them
    824  *	unless 'origin' is NULL, in which case relative domain names
    825  *	will remain relative.
    826  *
    827  * \li	If DNS_NAME_DOWNCASE is set in 'options', any uppercase letters
    828  *	in 'source' will be downcased when they are copied into 'target'.
    829  *
    830  * Requires:
    831  *
    832  * \li	'name' is a valid name.
    833  *
    834  * \li	'source' is a valid buffer.
    835  *
    836  * \li	'target' is a valid buffer or 'target' is NULL and 'name' has
    837  *	a dedicated buffer.
    838  *
    839  * Ensures:
    840  *
    841  *	If result is success:
    842  * \li	 	If 'target' is not NULL, 'name' is attached to it.
    843  *
    844  * \li		Uppercase letters are downcased in the copy iff
    845  *		DNS_NAME_DOWNCASE is set in 'options'.
    846  *
    847  * \li		The current location in source is advanced, and the used space
    848  *		in target is updated.
    849  *
    850  * Result:
    851  *\li	#ISC_R_SUCCESS
    852  *\li	#DNS_R_EMPTYLABEL
    853  *\li	#DNS_R_LABELTOOLONG
    854  *\li	#DNS_R_BADESCAPE
    855  *\li	#DNS_R_BADDOTTEDQUAD
    856  *\li	#ISC_R_NOSPACE
    857  *\li	#ISC_R_UNEXPECTEDEND
    858  */
    859 
    860 #define DNS_NAME_OMITFINALDOT 0x01U
    861 #define DNS_NAME_PRINCIPAL    0x02U /* do not escape $ and @ */
    862 
    863 isc_result_t
    864 dns_name_totext(const dns_name_t *name, unsigned int options,
    865 		isc_buffer_t *target);
    866 /*%<
    867  * Convert 'name' into text format, storing the result in 'target'.
    868  *
    869  * Notes:
    870  *\li	If DNS_NAME_OMITFINALDOT is set in options, then the final '.'
    871  *	in absolute names other than the root name will be omitted.
    872  *
    873  *\li	If DNS_NAME_PRINCIPAL is set in options, '$' and '@' will *not*
    874  *	be escaped; otherwise they will, along with other characters that
    875  *	are special in zone files ('"', '(', ')', '.', ';', and '\'),
    876  *	which are always escaped.
    877  *
    878  *\li	If dns_name_countlabels == 0, the name will be "@", representing the
    879  *	current origin as described by RFC1035.
    880  *
    881  *\li	The name is not NUL terminated.
    882  *
    883  * Requires:
    884  *
    885  *\li	'name' is a valid name
    886  *
    887  *\li	'target' is a valid buffer
    888  *
    889  *\li	if dns_name_isabsolute is false, then omit_final_dot is false
    890  *
    891  * Ensures:
    892  *
    893  *\li	If the result is success:
    894  *		the used space in target is updated.
    895  *
    896  * Returns:
    897  *\li	#ISC_R_SUCCESS
    898  *\li	#ISC_R_NOSPACE
    899  */
    900 
    901 #define DNS_NAME_MAXTEXT 1023
    902 /*%<
    903  * The maximum length of the text representation of a domain
    904  * name as generated by dns_name_totext().  This does not
    905  * include space for a terminating NULL.
    906  *
    907  * This definition is conservative - the actual maximum
    908  * is 1004, derived as follows:
    909  *
    910  *   A backslash-decimal escaped character takes 4 bytes.
    911  *   A wire-encoded name can be up to 255 bytes and each
    912  *   label is one length byte + at most 63 bytes of data.
    913  *   Maximizing the label lengths gives us a name of
    914  *   three 63-octet labels, one 61-octet label, and the
    915  *   root label:
    916  *
    917  *      1 + 63 + 1 + 63 + 1 + 63 + 1 + 61 + 1 = 255
    918  *
    919  *   When printed, this is (3 * 63 + 61) * 4
    920  *   bytes for the escaped label data + 4 bytes for the
    921  *   dot terminating each label = 1004 bytes total.
    922  */
    923 
    924 isc_result_t
    925 dns_name_tofilenametext(const dns_name_t *name, bool omit_final_dot,
    926 			isc_buffer_t *target);
    927 /*%<
    928  * Convert 'name' into an alternate text format appropriate for filenames,
    929  * storing the result in 'target'.  The name data is downcased, guaranteeing
    930  * that the filename does not depend on the case of the converted name.
    931  *
    932  * Notes:
    933  *\li	If 'omit_final_dot' is true, then the final '.' in absolute
    934  *	names other than the root name will be omitted.
    935  *
    936  *\li	The name is not NUL terminated.
    937  *
    938  * Requires:
    939  *
    940  *\li	'name' is a valid absolute name
    941  *
    942  *\li	'target' is a valid buffer.
    943  *
    944  * Ensures:
    945  *
    946  *\li	If the result is success:
    947  *		the used space in target is updated.
    948  *
    949  * Returns:
    950  *\li	#ISC_R_SUCCESS
    951  *\li	#ISC_R_NOSPACE
    952  */
    953 
    954 isc_result_t
    955 dns_name_downcase(const dns_name_t *source, dns_name_t *name,
    956 		  isc_buffer_t *target);
    957 /*%<
    958  * Downcase 'source'.
    959  *
    960  * Requires:
    961  *
    962  *\li	'source' and 'name' are valid names.
    963  *
    964  *\li	If source == name, then
    965  *		'source' must not be read-only
    966  *
    967  *\li	Otherwise,
    968  *		'target' is a valid buffer or 'target' is NULL and
    969  *		'name' has a dedicated buffer.
    970  *
    971  * Returns:
    972  *\li	#ISC_R_SUCCESS
    973  *\li	#ISC_R_NOSPACE
    974  *
    975  * Note: if source == name, then the result will always be ISC_R_SUCCESS.
    976  */
    977 
    978 isc_result_t
    979 dns_name_concatenate(const dns_name_t *prefix, const dns_name_t *suffix,
    980 		     dns_name_t *name, isc_buffer_t *target);
    981 /*%<
    982  *	Concatenate 'prefix' and 'suffix'.
    983  *
    984  * Requires:
    985  *
    986  *\li	'prefix' is a valid name or NULL.
    987  *
    988  *\li	'suffix' is a valid name or NULL.
    989  *
    990  *\li	'name' is a valid name or NULL.
    991  *
    992  *\li	'target' is a valid buffer or 'target' is NULL and 'name' has
    993  *	a dedicated buffer.
    994  *
    995  *\li	If 'prefix' is absolute, 'suffix' must be NULL or the empty name.
    996  *
    997  * Ensures:
    998  *
    999  *\li	On success,
   1000  *	 	If 'target' is not NULL and 'name' is not NULL, then 'name'
   1001  *		is attached to it.
   1002  *		The used space in target is updated.
   1003  *
   1004  * Returns:
   1005  *\li	#ISC_R_SUCCESS
   1006  *\li	#ISC_R_NOSPACE
   1007  *\li	#DNS_R_NAMETOOLONG
   1008  */
   1009 
   1010 static inline void
   1011 dns_name_split(const dns_name_t *name, unsigned int suffixlabels,
   1012 	       dns_name_t *prefix, dns_name_t *suffix) {
   1013 	REQUIRE(DNS_NAME_VALID(name));
   1014 	REQUIRE(suffixlabels > 0);
   1015 	REQUIRE(suffixlabels <= name->labels);
   1016 	REQUIRE(prefix != NULL || suffix != NULL);
   1017 	REQUIRE(prefix == NULL ||
   1018 		(DNS_NAME_VALID(prefix) && DNS_NAME_BINDABLE(prefix)));
   1019 	REQUIRE(suffix == NULL ||
   1020 		(DNS_NAME_VALID(suffix) && DNS_NAME_BINDABLE(suffix)));
   1021 
   1022 	if (prefix != NULL) {
   1023 		dns_name_getlabelsequence(name, 0, name->labels - suffixlabels,
   1024 					  prefix);
   1025 	}
   1026 	if (suffix != NULL) {
   1027 		dns_name_getlabelsequence(name, name->labels - suffixlabels,
   1028 					  suffixlabels, suffix);
   1029 	}
   1030 }
   1031 /*%<
   1032  *
   1033  * Split 'name' into two pieces on a label boundary.
   1034  *
   1035  * Notes:
   1036  * \li     'name' is split such that 'suffix' holds the most significant
   1037  *      'suffixlabels' labels.  All other labels are stored in 'prefix'.
   1038  *
   1039  *\li	Copying name data is avoided as much as possible, so 'prefix'
   1040  *	and 'suffix' will end up pointing at the data for 'name'.
   1041  *
   1042  *\li	It is legitimate to pass a 'prefix' or 'suffix' that has
   1043  *	its name data stored someplace other than the dedicated buffer.
   1044  *	This is useful to avoid name copying in the calling function.
   1045  *
   1046  *\li	It is also legitimate to pass a 'prefix' or 'suffix' that is
   1047  *	the same dns_name_t as 'name'.
   1048  *
   1049  * Requires:
   1050  *\li	'name' is a valid name.
   1051  *
   1052  *\li	'suffixlabels' cannot exceed the number of labels in 'name'.
   1053  *
   1054  * \li	'prefix' is a valid name or NULL, and cannot be read-only.
   1055  *
   1056  *\li	'suffix' is a valid name or NULL, and cannot be read-only.
   1057  *
   1058  * Ensures:
   1059  *
   1060  *\li	On success:
   1061  *		If 'prefix' is not NULL it will contain the least significant
   1062  *		labels.
   1063  *		If 'suffix' is not NULL it will contain the most significant
   1064  *		labels.  dns_name_countlabels(suffix) will be equal to
   1065  *		suffixlabels.
   1066  *
   1067  *\li	On failure:
   1068  *		Either 'prefix' or 'suffix' is invalidated (depending
   1069  *		on which one the problem was encountered with).
   1070  *
   1071  * Returns:
   1072  *\li	#ISC_R_SUCCESS	No worries.  (This function should always success).
   1073  */
   1074 
   1075 void
   1076 dns_name_dup(const dns_name_t *source, isc_mem_t *mctx, dns_name_t *target);
   1077 /*%<
   1078  * Make 'target' a dynamically allocated copy of 'source'.
   1079  *
   1080  * Requires:
   1081  *
   1082  *\li	'source' is a valid non-empty name.
   1083  *
   1084  *\li	'target' is a valid name that is not read-only.
   1085  *
   1086  *\li	'mctx' is a valid memory context.
   1087  */
   1088 
   1089 void
   1090 dns_name_dupwithoffsets(const dns_name_t *source, isc_mem_t *mctx,
   1091 			dns_name_t *target);
   1092 /*%<
   1093  * Make 'target' a read-only dynamically allocated copy of 'source'.
   1094  * 'target' will also have a dynamically allocated offsets table.
   1095  *
   1096  * Requires:
   1097  *
   1098  *\li	'source' is a valid non-empty name.
   1099  *
   1100  *\li	'target' is a valid name that is not read-only.
   1101  *
   1102  *\li	'target' has no offsets table.
   1103  *
   1104  *\li	'mctx' is a valid memory context.
   1105  */
   1106 
   1107 void
   1108 dns_name_free(dns_name_t *name, isc_mem_t *mctx);
   1109 /*%<
   1110  * Free 'name'.
   1111  *
   1112  * Requires:
   1113  *
   1114  *\li	'name' is a valid name created previously in 'mctx' by dns_name_dup().
   1115  *
   1116  *\li	'mctx' is a valid memory context.
   1117  *
   1118  * Ensures:
   1119  *
   1120  *\li	All dynamic resources used by 'name' are freed and the name is
   1121  *	invalidated.
   1122  */
   1123 
   1124 isc_result_t
   1125 dns_name_digest(const dns_name_t *name, dns_digestfunc_t digest, void *arg);
   1126 /*%<
   1127  * Send 'name' in DNSSEC canonical form to 'digest'.
   1128  *
   1129  * Requires:
   1130  *
   1131  *\li	'name' is a valid name.
   1132  *
   1133  *\li	'digest' is a valid dns_digestfunc_t.
   1134  *
   1135  * Ensures:
   1136  *
   1137  *\li	If successful, the DNSSEC canonical form of 'name' will have been
   1138  *	sent to 'digest'.
   1139  *
   1140  *\li	If digest() returns something other than ISC_R_SUCCESS, that result
   1141  *	will be returned as the result of dns_name_digest().
   1142  *
   1143  * Returns:
   1144  *
   1145  *\li	#ISC_R_SUCCESS
   1146  *
   1147  *\li	Many other results are possible if not successful.
   1148  *
   1149  */
   1150 
   1151 bool
   1152 dns_name_dynamic(const dns_name_t *name);
   1153 /*%<
   1154  * Returns whether there is dynamic memory associated with this name.
   1155  *
   1156  * Requires:
   1157  *
   1158  *\li	'name' is a valid name.
   1159  *
   1160  * Returns:
   1161  *
   1162  *\li	'true' if the name is dynamic otherwise 'false'.
   1163  */
   1164 
   1165 isc_result_t
   1166 dns_name_print(const dns_name_t *name, FILE *stream);
   1167 /*%<
   1168  * Print 'name' on 'stream'.
   1169  *
   1170  * Requires:
   1171  *
   1172  *\li	'name' is a valid name.
   1173  *
   1174  *\li	'stream' is a valid stream.
   1175  *
   1176  * Returns:
   1177  *
   1178  *\li	#ISC_R_SUCCESS
   1179  *
   1180  *\li	Any error that dns_name_totext() can return.
   1181  */
   1182 
   1183 void
   1184 dns_name_format(const dns_name_t *name, char *cp, unsigned int size);
   1185 /*%<
   1186  * Format 'name' as text appropriate for use in log messages.
   1187  *
   1188  * Store the formatted name at 'cp', writing no more than
   1189  * 'size' bytes.  The resulting string is guaranteed to be
   1190  * null terminated.
   1191  *
   1192  * The formatted name will have a terminating dot only if it is
   1193  * the root.
   1194  *
   1195  * This function cannot fail, instead any errors are indicated
   1196  * in the returned text.
   1197  *
   1198  * Requires:
   1199  *
   1200  *\li	'name' is a valid name.
   1201  *
   1202  *\li	'cp' points a valid character array of size 'size'.
   1203  *
   1204  *\li	'size' > 0.
   1205  *
   1206  */
   1207 
   1208 isc_result_t
   1209 dns_name_tostring(const dns_name_t *source, char **target, isc_mem_t *mctx);
   1210 /*%<
   1211  * Convert 'name' to string format, allocating sufficient memory to
   1212  * hold it (free with isc_mem_free()).
   1213  *
   1214  * Differs from dns_name_format in that it allocates its own memory.
   1215  *
   1216  * Requires:
   1217  *
   1218  *\li	'name' is a valid name.
   1219  *\li	'target' is not NULL.
   1220  *\li	'*target' is NULL.
   1221  *
   1222  * Returns:
   1223  *
   1224  *\li	ISC_R_SUCCESS
   1225  *\li	ISC_R_NOMEMORY
   1226  *
   1227  *\li	Any error that dns_name_totext() can return.
   1228  */
   1229 
   1230 isc_result_t
   1231 dns_name_fromstring(dns_name_t *target, const char *src,
   1232 		    const dns_name_t *origin, unsigned int options,
   1233 		    isc_mem_t *mctx);
   1234 /*%<
   1235  * Convert a string to a name and place it in target, allocating memory
   1236  * as necessary.  'options' has the same semantics as that of
   1237  * dns_name_fromtext().
   1238  *
   1239  * If 'target' has a buffer then the name will be copied into it rather than
   1240  * memory being allocated.
   1241  *
   1242  * Requires:
   1243  *
   1244  * \li	'target' is a valid name that is not read-only.
   1245  * \li	'src' is not NULL.
   1246  *
   1247  * Returns:
   1248  *
   1249  *\li	#ISC_R_SUCCESS
   1250  *
   1251  *\li	Any error that dns_name_fromtext() can return.
   1252  *
   1253  *\li	Any error that dns_name_dup() can return.
   1254  */
   1255 
   1256 isc_result_t
   1257 dns_name_settotextfilter(dns_name_totextfilter_t *proc);
   1258 /*%<
   1259  * Set / clear a thread specific function 'proc' to be called at the
   1260  * end of dns_name_totext().
   1261  *
   1262  * Note: It's a good practice to call "dns_name_settotextfilter(NULL);"
   1263  * prior to exiting the thread.
   1264  *
   1265  * Returns
   1266  *\li	#ISC_R_SUCCESS
   1267  *\li	#ISC_R_UNEXPECTED
   1268  */
   1269 
   1270 #define DNS_NAME_FORMATSIZE (DNS_NAME_MAXTEXT + 1)
   1271 /*%<
   1272  * Suggested size of buffer passed to dns_name_format().
   1273  * Includes space for the terminating NULL.
   1274  */
   1275 
   1276 void
   1277 dns_name_copy(const dns_name_t *source, dns_name_t *dest);
   1278 /*%<
   1279  * Copies the name in 'source' into 'dest'.  The name data is copied to
   1280  * the dedicated buffer for 'dest'. (If copying to a name that doesn't
   1281  * have a dedicated buffer, use dns_name_setbuffer() first.)
   1282  *
   1283  * Requires:
   1284  * \li	'source' is a valid name.
   1285  *
   1286  * \li	'dest' is an initialized name with a dedicated buffer.
   1287  */
   1288 
   1289 bool
   1290 dns_name_ishostname(const dns_name_t *name, bool wildcard);
   1291 /*%<
   1292  * Return if 'name' is a valid hostname.  RFC 952 / RFC 1123.
   1293  * If 'wildcard' is true then allow the first label of name to
   1294  * be a wildcard.
   1295  * The root is also accepted.
   1296  *
   1297  * Requires:
   1298  *	'name' to be valid.
   1299  */
   1300 
   1301 bool
   1302 dns_name_ismailbox(const dns_name_t *name);
   1303 /*%<
   1304  * Return if 'name' is a valid mailbox.  RFC 821.
   1305  *
   1306  * Requires:
   1307  * \li	'name' to be valid.
   1308  */
   1309 
   1310 bool
   1311 dns_name_internalwildcard(const dns_name_t *name);
   1312 /*%<
   1313  * Return if 'name' contains a internal wildcard name.
   1314  *
   1315  * Requires:
   1316  * \li	'name' to be valid.
   1317  */
   1318 
   1319 bool
   1320 dns_name_isdnssd(const dns_name_t *owner);
   1321 /*%<
   1322  * Determine if the 'owner' is a DNS-SD prefix.
   1323  */
   1324 
   1325 bool
   1326 dns_name_isrfc1918(const dns_name_t *owner);
   1327 /*%<
   1328  * Determine if the 'name' is in the RFC 1918 reverse namespace.
   1329  */
   1330 
   1331 bool
   1332 dns_name_isula(const dns_name_t *owner);
   1333 /*%<
   1334  * Determine if the 'name' is in the ULA reverse namespace.
   1335  */
   1336 
   1337 bool
   1338 dns_name_istat(const dns_name_t *name);
   1339 /*%<
   1340  * Determine if 'name' is a potential 'trust-anchor-telemetry' name.
   1341  */
   1342 
   1343 bool
   1344 dns_name_isdnssvcb(const dns_name_t *name);
   1345 /*%<
   1346  * Determine if 'name' is a dns service name,
   1347  * i.e. it starts with and optional _port label followed by a _dns label.
   1348  */
   1349 
   1350 size_t
   1351 dns_name_size(const dns_name_t *name);
   1352 /*%<
   1353  * Return the amount of dynamically allocated memory associated with
   1354  * 'name' (which is 0 if 'name' is not dynamic).
   1355  *
   1356  * Requires:
   1357  * \li	'name' to be valid.
   1358  */
   1359 
   1360 ISC_LANG_ENDDECLS
   1361