name.h 30.7 KB
Newer Older
Bob Halley's avatar
Bob Halley committed
1
/*
Mark Andrews's avatar
Mark Andrews committed
2
 * Copyright (C) 2004, 2005  Internet Systems Consortium, Inc. ("ISC")
Mark Andrews's avatar
Mark Andrews committed
3
 * Copyright (C) 1998-2003  Internet Software Consortium.
4
 *
Bob Halley's avatar
Bob Halley committed
5 6 7
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
8
 *
Mark Andrews's avatar
Mark Andrews committed
9 10 11 12 13 14 15
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
Bob Halley's avatar
Bob Halley committed
16
 */
Bob Halley's avatar
add  
Bob Halley committed
17

Mark Andrews's avatar
Mark Andrews committed
18
/* $Id: name.h,v 1.113 2005/01/10 23:43:25 marka Exp $ */
David Lawrence's avatar
David Lawrence committed
19

Bob Halley's avatar
add  
Bob Halley committed
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
#ifndef DNS_NAME_H
#define DNS_NAME_H 1

/*****
 ***** Module Info
 *****/

/*
 * DNS Names and Labels
 *
 * 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
 * handles.
 *
 * MP:
 *	Clients of this module must impose any required synchronization.
 *
 * Reliability:
 *	This module deals with low-level byte streams.  Errors in any of
 *	the functions are likely to crash the server or corrupt memory.
 *
 * Resources:
 *	None.
 *
 * Security:
 *
 *	*** WARNING ***
 *
 *	dns_name_fromwire() deals with raw network data.  An error in
 *	this routine could result in the failure or hijacking of the server.
 *
 * Standards:
 *	RFC 1035
 *	Draft EDNS0 (0)
 *	Draft Binary Labels (2)
 *
 */

/***
 *** Imports
 ***/

75 76 77
#include <stdio.h>

#include <isc/boolean.h>
Bob Halley's avatar
Bob Halley committed
78
#include <isc/lang.h>
79
#include <isc/magic.h>
80
#include <isc/region.h>		/* Required for storage size of dns_label_t. */
81

Bob Halley's avatar
add  
Bob Halley committed
82 83
#include <dns/types.h>

Bob Halley's avatar
Bob Halley committed
84
ISC_LANG_BEGINDECLS
Bob Halley's avatar
add  
Bob Halley committed
85 86 87 88 89

/*****
 ***** Labels
 *****
 ***** A 'label' is basically a region.  It contains one DNS wire format
Mark Andrews's avatar
Mark Andrews committed
90
 ***** label of type 00 (ordinary).
Bob Halley's avatar
add  
Bob Halley committed
91 92 93 94 95 96
 *****/

/*****
 ***** Names
 *****
 ***** A 'name' is a handle to a binary region.  It contains a sequence of one
Mark Andrews's avatar
Mark Andrews committed
97 98 99
 ***** 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.
Bob Halley's avatar
add  
Bob Halley committed
100 101
 *****/

Bob Halley's avatar
Bob Halley committed
102 103 104 105 106 107
/***
 *** Compression pointer chaining limit
 ***/

#define DNS_POINTER_MAXHOPS		16

Bob Halley's avatar
add  
Bob Halley committed
108 109 110 111 112
/***
 *** Types
 ***/

/*
Bob Halley's avatar
Bob Halley committed
113 114 115
 * 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.
Bob Halley's avatar
add  
Bob Halley committed
116 117
 */
struct dns_name {
Bob Halley's avatar
Bob Halley committed
118 119 120 121
	unsigned int			magic;
	unsigned char *			ndata;
	unsigned int			length;
	unsigned int			labels;
122
	unsigned int			attributes;
Bob Halley's avatar
Bob Halley committed
123
	unsigned char *			offsets;
124
	isc_buffer_t *			buffer;
Bob Halley's avatar
Bob Halley committed
125
	ISC_LINK(dns_name_t)		link;
126
	ISC_LIST(dns_rdataset_t)	list;
Bob Halley's avatar
add  
Bob Halley committed
127 128
};

129
#define DNS_NAME_MAGIC			ISC_MAGIC('D','N','S','n')
130

Michael Graff's avatar
Michael Graff committed
131 132
#define DNS_NAMEATTR_ABSOLUTE		0x0001
#define DNS_NAMEATTR_READONLY		0x0002
133
#define DNS_NAMEATTR_DYNAMIC		0x0004
Bob Halley's avatar
Bob Halley committed
134
#define DNS_NAMEATTR_DYNOFFSETS		0x0008
Bob Halley's avatar
Bob Halley committed
135 136 137 138 139 140
/*
 * Attributes below 0x0100 reserved for name.c usage.
 */
#define DNS_NAMEATTR_CACHE		0x0100		/* Used by resolver. */
#define DNS_NAMEATTR_ANSWER		0x0200		/* Used by resolver. */
#define DNS_NAMEATTR_NCACHE		0x0400		/* Used by resolver. */
141
#define DNS_NAMEATTR_CHAINING		0x0800		/* Used by resolver. */
142
#define DNS_NAMEATTR_CHASE		0x1000		/* Used by resolver. */
143 144 145 146 147 148
#define DNS_NAMEATTR_WILDCARD		0x2000		/* Used by server. */

#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. */
149

Danny Mayer's avatar
Danny Mayer committed
150
LIBDNS_EXTERNAL_DATA extern dns_name_t *dns_rootname;
151
LIBDNS_EXTERNAL_DATA extern dns_name_t *dns_wildcardname;
Bob Halley's avatar
add  
Bob Halley committed
152

153 154 155 156 157
/*
 * Standard size of a wire format name
 */
#define DNS_NAME_MAXWIRE 255

Bob Halley's avatar
add  
Bob Halley committed
158 159 160 161
/***
 *** Initialization
 ***/

David Lawrence's avatar
David Lawrence committed
162 163
void
dns_name_init(dns_name_t *name, unsigned char *offsets);
Bob Halley's avatar
add  
Bob Halley committed
164
/*
165
 * Initialize 'name'.
Bob Halley's avatar
add  
Bob Halley committed
166
 *
167 168 169 170 171
 * Notes:
 *	'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.
 *
Bob Halley's avatar
add  
Bob Halley committed
172
 * Requires:
173
 *	'name' is not NULL and points to a struct dns_name.
Bob Halley's avatar
add  
Bob Halley committed
174
 *
175 176
 *	offsets == NULL or offsets is a dns_offsets_t.
 *
Bob Halley's avatar
add  
Bob Halley committed
177
 * Ensures:
178
 *	'name' is a valid name.
Bob Halley's avatar
add  
Bob Halley committed
179
 *	dns_name_countlabels(name) == 0
180 181 182 183 184 185 186 187 188 189 190 191 192 193
 *	dns_name_isabsolute(name) == ISC_FALSE
 */

void
dns_name_reset(dns_name_t *name);
/*
 * Reinitialize 'name'.
 *
 * Notes:
 *	This function distinguishes itself from dns_name_init() in two
 *	key ways:
 *
 *	+ 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
194
 *	  is retained but the buffer itself is cleared.
195 196 197 198 199 200 201 202 203 204 205
 *
 *	+ Of the attributes associated with 'name', all are retained except
 *	  DNS_NAMEATTR_ABSOLUTE.
 *
 * Requires:
 *	'name' is a valid name.
 *
 * Ensures:
 *	'name' is a valid name.
 *	dns_name_countlabels(name) == 0
 *	dns_name_isabsolute(name) == ISC_FALSE
Bob Halley's avatar
add  
Bob Halley committed
206 207
 */

David Lawrence's avatar
David Lawrence committed
208 209
void
dns_name_invalidate(dns_name_t *name);
Bob Halley's avatar
Bob Halley committed
210 211 212 213 214 215 216
/*
 * Make 'name' invalid.
 *
 * Requires:
 *	'name' is a valid name.
 *
 * Ensures:
217 218
 *	If assertion checking is enabled, future attempts to use 'name'
 *	without initializing it will cause an assertion failure.
219 220 221 222 223 224 225 226 227 228 229 230
 *
 *	If the name had a dedicated buffer, that association is ended.
 */


/***
 *** Dedicated Buffers
 ***/

void
dns_name_setbuffer(dns_name_t *name, isc_buffer_t *buffer);
/*
231
 * Dedicate a buffer for use with 'name'.
232 233 234 235 236 237 238 239 240
 *
 * Notes:
 *	Specification of a target buffer in dns_name_fromwire(),
 *	dns_name_fromtext(), and dns_name_concatentate() is optional if
 *	'name' has a dedicated buffer.
 *
 *	The caller must not write to buffer until the name has been
 *	invalidated or is otherwise known not to be in use.
 *
241 242 243 244 245
 *	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.
 *
246 247 248
 * Requires:
 *	'name' is a valid name.
 *
249 250
 *	'buffer' is a valid binary buffer and 'name' doesn't have a
 *	dedicated buffer already, or 'buffer' is NULL.
Bob Halley's avatar
Bob Halley committed
251
 */
Bob Halley's avatar
add  
Bob Halley committed
252

253
isc_boolean_t
David Lawrence's avatar
David Lawrence committed
254
dns_name_hasbuffer(const dns_name_t *name);
255 256 257 258 259 260 261 262 263 264 265 266
/*
 * Does 'name' have a dedicated buffer?
 *
 * Requires:
 *	'name' is a valid name.
 *
 * Returns:
 *	ISC_TRUE	'name' has a dedicated buffer.
 *	ISC_FALSE	'name' does not have a dedicated buffer.
 */


Bob Halley's avatar
add  
Bob Halley committed
267 268 269 270
/***
 *** Properties
 ***/

David Lawrence's avatar
David Lawrence committed
271 272
isc_boolean_t
dns_name_isabsolute(const dns_name_t *name);
Bob Halley's avatar
add  
Bob Halley committed
273 274 275 276 277 278 279 280 281 282 283
/*
 * Does 'name' end in the root label?
 *
 * Requires:
 *	'name' is a valid name
 *
 * Returns:
 *	TRUE		The last label in 'name' is the root label.
 *	FALSE		The last label in 'name' is not the root label.
 */

David Lawrence's avatar
David Lawrence committed
284 285
isc_boolean_t
dns_name_iswildcard(const dns_name_t *name);
Bob Halley's avatar
Bob Halley committed
286 287 288 289 290 291 292 293 294 295 296 297 298
/*
 * Is 'name' a wildcard name?
 *
 * Requires:
 *	'name' is a valid name
 *
 *	dns_name_countlabels(name) > 0
 *
 * Returns:
 *	TRUE		The least significant label of 'name' is '*'.
 *	FALSE		The least significant label of 'name' is not '*'.
 */

David Lawrence's avatar
David Lawrence committed
299 300
unsigned int
dns_name_hash(dns_name_t *name, isc_boolean_t case_sensitive);
Bob Halley's avatar
Bob Halley committed
301 302 303
/*
 * Provide a hash value for 'name'.
 *
Bob Halley's avatar
Bob Halley committed
304 305 306
 * Note: if 'case_sensitive' is ISC_FALSE, then names which differ only in
 * case will have the same hash value.
 *
Bob Halley's avatar
Bob Halley committed
307 308 309 310 311 312
 * Requires:
 *	'name' is a valid name
 *
 * Returns:
 *	A hash value
 */
Bob Halley's avatar
add  
Bob Halley committed
313

314
unsigned int
315
dns_name_fullhash(dns_name_t *name, isc_boolean_t case_sensitive);
316 317 318 319 320 321 322 323 324 325 326 327 328 329
/*
 * 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 ISC_FALSE, then names which differ only in
 * case will have the same hash value.
 *
 * Requires:
 *	'name' is a valid name
 *
 * Returns:
 *	A hash value
 */

330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345
unsigned int
dns_name_hashbylabel(dns_name_t *name, isc_boolean_t case_sensitive);
/*
 * Provide a hash value for 'name', where the hash value is the sum
 * of the hash values of each label.
 *
 * Note: if 'case_sensitive' is ISC_FALSE, then names which differ only in
 * case will have the same hash value.
 *
 * Requires:
 *	'name' is a valid name
 *
 * Returns:
 *	A hash value
 */

Bob Halley's avatar
add  
Bob Halley committed
346 347 348 349
/***
 *** Comparisons
 ***/

350
dns_namereln_t
David Lawrence's avatar
David Lawrence committed
351
dns_name_fullcompare(const dns_name_t *name1, const dns_name_t *name2,
352
		     int *orderp, unsigned int *nlabelsp);
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371
/*
 * 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
 * same domain.
 *
 * Requires:
 *	'name1' is a valid name
 *
 *	dns_name_countlabels(name1) > 0
 *
 *	'name2' is a valid name
 *
 *	dns_name_countlabels(name2) > 0
 *
372
 *	orderp and nlabelsp are valid pointers.
373 374 375
 *
 *	Either name1 is absolute and name2 is absolute, or neither is.
 *
376 377
 * Ensures:
 *
378
 *	*orderp is < 0 if name1 < name2, 0 if name1 = name2, > 0 if
379 380 381 382
 *	name1 > name2.
 *
 *	*nlabelsp is the number of common significant labels.
 *
383
 * Returns:
Bob Halley's avatar
Bob Halley committed
384
 *	dns_namereln_none		There's no hierarchical relationship
385
 *					between name1 and name2.
Bob Halley's avatar
Bob Halley committed
386
 *	dns_namereln_contains		name1 properly contains name2; i.e.
387
 *					name2 is a proper subdomain of name1.
Bob Halley's avatar
Bob Halley committed
388 389 390
 *	dns_namereln_subdomain		name1 is a proper subdomain of name2.
 *	dns_namereln_equal		name1 and name2 are equal.
 *	dns_namereln_commonancestor	name1 and name2 share a common
391 392 393
 *					ancestor.
 */

Bob Halley's avatar
Bob Halley committed
394
int
David Lawrence's avatar
David Lawrence committed
395
dns_name_compare(const dns_name_t *name1, const dns_name_t *name2);
Bob Halley's avatar
add  
Bob Halley committed
396 397 398 399
/*
 * Determine the relative ordering under the DNSSEC order relation of
 * 'name1' and 'name2'.
 *
400 401 402 403 404
 * 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
 * same domain.
 *
Bob Halley's avatar
add  
Bob Halley committed
405 406 407 408 409
 * Requires:
 *	'name1' is a valid name
 *
 *	'name2' is a valid name
 *
410 411
 *	Either name1 is absolute and name2 is absolute, or neither is.
 *
Bob Halley's avatar
add  
Bob Halley committed
412
 * Returns:
413
 *	< 0		'name1' is less than 'name2'
Bob Halley's avatar
add  
Bob Halley committed
414
 *	0		'name1' is equal to 'name2'
415
 *	> 0		'name1' is greater than 'name2'
Bob Halley's avatar
add  
Bob Halley committed
416 417
 */

Bob Halley's avatar
Bob Halley committed
418
isc_boolean_t
David Lawrence's avatar
David Lawrence committed
419
dns_name_equal(const dns_name_t *name1, const dns_name_t *name2);
Bob Halley's avatar
Bob Halley committed
420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445
/*
 * Are 'name1' and 'name2' equal?
 *
 * Notes:
 *	Because it only needs to test for equality, dns_name_equal() can be
 *	significantly faster than dns_name_fullcompare() or dns_name_compare().
 *
 *	Offsets tables are not used in the comparision.
 *
 * 	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
 * 	same domain.
 *
 * Requires:
 *	'name1' is a valid name
 *
 *	'name2' is a valid name
 *
 *	Either name1 is absolute and name2 is absolute, or neither is.
 *
 * Returns:
 *	ISC_TRUE	'name1' and 'name2' are equal
 *	ISC_FALSE	'name1' and 'name2' are not equal
 */

446
int
David Lawrence's avatar
David Lawrence committed
447
dns_name_rdatacompare(const dns_name_t *name1, const dns_name_t *name2);
448
/*
Andreas Gustafsson's avatar
Andreas Gustafsson committed
449
 * Compare two names as if they are part of rdata in DNSSEC canonical
450
 * form.
451 452 453 454 455 456 457 458 459 460 461
 *
 * Requires:
 *	'name1' is a valid absolute name
 *
 *	dns_name_countlabels(name1) > 0
 *
 *	'name2' is a valid absolute name
 *
 *	dns_name_countlabels(name2) > 0
 *
 * Returns:
462
 *	< 0		'name1' is less than 'name2'
463
 *	0		'name1' is equal to 'name2'
464
 *	> 0		'name1' is greater than 'name2'
465 466
 */

467
isc_boolean_t
David Lawrence's avatar
David Lawrence committed
468
dns_name_issubdomain(const dns_name_t *name1, const dns_name_t *name2);
Bob Halley's avatar
add  
Bob Halley committed
469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485
/*
 * Is 'name1' a subdomain of 'name2'?
 *
 * Notes:
 *	name1 is a subdomain of name2 if name1 is contained in name2, or
 *	name1 equals name2.
 *
 *	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
 *	same domain.
 *
 * Requires:
 *	'name1' is a valid name
 *
 *	'name2' is a valid name
 *
486 487
 *	Either name1 is absolute and name2 is absolute, or neither is.
 *
Bob Halley's avatar
add  
Bob Halley committed
488 489 490 491 492
 * Returns:
 *	TRUE		'name1' is a subdomain of 'name2'
 *	FALSE		'name1' is not a subdomain of 'name2'
 */

493
isc_boolean_t
David Lawrence's avatar
David Lawrence committed
494
dns_name_matcheswildcard(const dns_name_t *name, const dns_name_t *wname);
495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525
/*
 * Does 'name' match the wildcard specified in 'wname'?
 *
 * Notes:
 *	name matches the wildcard specified in wname if all labels
 *	following the wildcard in wname are identical to the same number
 *	of labels at the end of name.
 *
 *	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
 *	same domain.
 *
 * Requires:
 *	'name' is a valid name
 *
 *	dns_name_countlabels(name) > 0
 *
 *	'wname' is a valid name
 *
 *	dns_name_countlabels(wname) > 0
 *
 *	dns_name_iswildcard(wname) is true
 *
 *	Either name is absolute and wname is absolute, or neither is.
 *
 * Returns:
 *	TRUE		'name' matches the wildcard specified in 'wname'
 *	FALSE		'name' does not match the wildcard specified in 'wname'
 */

Bob Halley's avatar
add  
Bob Halley committed
526 527 528
/***
 *** Labels
 ***/
529

David Lawrence's avatar
David Lawrence committed
530 531
unsigned int
dns_name_countlabels(const dns_name_t *name);
Bob Halley's avatar
add  
Bob Halley committed
532 533 534 535
/*
 * How many labels does 'name' have?
 *
 * Notes:
Mark Andrews's avatar
Mark Andrews committed
536
 *	In this case, as in other places, a 'label' is an ordinary label.
Bob Halley's avatar
add  
Bob Halley committed
537 538 539 540 541 542 543 544 545 546 547
 *
 * Requires:
 *	'name' is a valid name
 *
 * Ensures:
 *	The result is <= 128.
 *
 * Returns:
 *	The number of labels in 'name'.
 */

David Lawrence's avatar
David Lawrence committed
548 549
void
dns_name_getlabel(const dns_name_t *name, unsigned int n, dns_label_t *label);
Bob Halley's avatar
add  
Bob Halley committed
550 551 552 553 554 555 556 557 558 559 560 561 562
/*
 * Make 'label' refer to the 'n'th least significant label of 'name'.
 *
 * Notes:
 *	Numbering starts at 0.
 *
 *	Given "rc.vix.com.", the label 0 is "rc", and label 3 is the
 *	root label.
 *
 *	'label' refers to the same memory as 'name', so 'name' must not
 *	be changed while 'label' is still in use.
 *
 * Requires:
563
 *	n < dns_name_countlabels(name)
Bob Halley's avatar
add  
Bob Halley committed
564 565
 */

David Lawrence's avatar
David Lawrence committed
566 567 568
void
dns_name_getlabelsequence(const dns_name_t *source, unsigned int first,
			  unsigned int n, dns_name_t *target);
Bob Halley's avatar
add  
Bob Halley committed
569 570 571 572 573 574 575
/*
 * Make 'target' refer to the 'n' labels including and following 'first'
 * in 'source'.
 *
 * Notes:
 *	Numbering starts at 0.
 *
576 577 578
 *	Given "rc.vix.com.", the label 0 is "rc", and label 3 is the
 *	root label.
 *
Bob Halley's avatar
add  
Bob Halley committed
579 580 581 582
 *	'target' refers to the same memory as 'source', so 'source'
 *	must not be changed while 'target' is still in use.
 *
 * Requires:
583 584
 *	'source' and 'target' are valid names.
 *
585
 *	first < dns_name_countlabels(name)
586
 *
587
 *	first + n <= dns_name_countlabels(name)
Bob Halley's avatar
add  
Bob Halley committed
588 589
 */

Bob Halley's avatar
Bob Halley committed
590 591 592 593 594 595 596 597 598 599 600 601 602

void
dns_name_clone(dns_name_t *source, dns_name_t *target);
/*
 * Make 'target' refer to the same name as 'source'.
 *
 * Notes:
 *
 *	'target' refers to the same memory as 'source', so 'source'
 *	must not be changed while 'target' is still in use.
 *
 *	This call is functionally equivalent to:
 *
603
 *		dns_name_getlabelsequence(source, 0,
604
 *					  dns_name_countlabels(source),
Bob Halley's avatar
Bob Halley committed
605 606 607 608 609 610 611 612 613 614 615 616
 *					  target);
 *
 *	but is more efficient.  Also, dns_name_clone() works even if 'source'
 *	is empty.
 *
 * Requires:
 *
 *	'source' is a valid name.
 *
 *	'target' is a valid name that is not read-only.
 */

Bob Halley's avatar
add  
Bob Halley committed
617 618 619 620
/***
 *** Conversions
 ***/

David Lawrence's avatar
David Lawrence committed
621
void
622
dns_name_fromregion(dns_name_t *name, const isc_region_t *r);
Bob Halley's avatar
add  
Bob Halley committed
623 624 625
/*
 * Make 'name' refer to region 'r'.
 *
626 627 628
 * Note:
 *	If the conversion encounters a root label before the end of the
 *	region the conversion stops and the length is set to the length
629
 *	so far converted.  A maximum of 255 bytes is converted.
630
 *
Bob Halley's avatar
add  
Bob Halley committed
631 632 633 634 635
 * Requires:
 *	The data in 'r' is a sequence of one or more type 00 or type 01000001
 *	labels.
 */

David Lawrence's avatar
David Lawrence committed
636 637
void
dns_name_toregion(dns_name_t *name, isc_region_t *r);
Bob Halley's avatar
add  
Bob Halley committed
638 639 640 641 642 643 644 645 646 647
/*
 * Make 'r' refer to 'name'.
 *
 * Requires:
 *
 *	'name' is a valid name.
 *
 *	'r' is a valid region.
 */

David Lawrence's avatar
David Lawrence committed
648 649
isc_result_t
dns_name_fromwire(dns_name_t *name, isc_buffer_t *source,
650
		  dns_decompress_t *dctx, unsigned int options,
David Lawrence's avatar
David Lawrence committed
651
		  isc_buffer_t *target);
Bob Halley's avatar
add  
Bob Halley committed
652
/*
653 654
 * Copy the possibly-compressed name at source (active region) into target,
 * decompressing it.
Bob Halley's avatar
add  
Bob Halley committed
655 656 657 658
 *
 * Notes:
 *	Decompression policy is controlled by 'dctx'.
 *
659
 *	If DNS_NAME_DOWNCASE is set, any uppercase letters in 'source' will be
Bob Halley's avatar
add  
Bob Halley committed
660 661 662 663 664 665 666
 *	downcased when they are copied into 'target'.
 *
 * Security:
 *
 *	*** WARNING ***
 *
 *	This routine will often be used when 'source' contains raw network
667 668
 *	data.  A programming error in this routine could result in a denial
 *	of service, or in the hijacking of the server.
Bob Halley's avatar
add  
Bob Halley committed
669 670 671
 *
 * Requires:
 *
672 673
 *	'name' is a valid name.
 *
674 675
 *	'source' is a valid buffer and the first byte of the active
 *	region should be the first byte of a DNS wire format domain name.
Bob Halley's avatar
Bob Halley committed
676
 *
677 678
 *	'target' is a valid buffer or 'target' is NULL and 'name' has
 *	a dedicated buffer.
Bob Halley's avatar
add  
Bob Halley committed
679 680 681 682 683 684
 *
 *	'dctx' is a valid decompression context.
 *
 * Ensures:
 *
 *	If result is success:
685
 *	 	If 'target' is not NULL, 'name' is attached to it.
Bob Halley's avatar
add  
Bob Halley committed
686
 *
687 688
 *		Uppercase letters are downcased in the copy iff
 *		DNS_NAME_DOWNCASE is set in options.
Bob Halley's avatar
add  
Bob Halley committed
689
 *
Bob Halley's avatar
Bob Halley committed
690 691 692
 *		The current location in source is advanced, and the used space
 *		in target is updated.
 *
Bob Halley's avatar
add  
Bob Halley committed
693 694 695 696 697
 * Result:
 *	Success
 *	Bad Form: Label Length
 *	Bad Form: Unknown Label Type
 *	Bad Form: Name Length
Bob Halley's avatar
Bob Halley committed
698 699
 *	Bad Form: Compression type not allowed
 *	Bad Form: Bad compression pointer
Bob Halley's avatar
add  
Bob Halley committed
700 701
 *	Bad Form: Input too short
 *	Resource Limit: Too many compression pointers
702 703
 *	Resource Limit: Not enough space in buffer
 */
Bob Halley's avatar
add  
Bob Halley committed
704

David Lawrence's avatar
David Lawrence committed
705 706
isc_result_t
dns_name_towire(dns_name_t *name, dns_compress_t *cctx, isc_buffer_t *target);
Bob Halley's avatar
add  
Bob Halley committed
707 708 709
/*
 * Convert 'name' into wire format, compressing it as specified by the
 * compression context 'cctx', and storing the result in 'target'.
710
 *
Bob Halley's avatar
add  
Bob Halley committed
711 712 713 714 715 716 717 718 719 720 721
 * Notes:
 *	If the compression context allows global compression, then the
 *	global compression table may be updated.
 *
 * Requires:
 *	'name' is a valid name
 *
 *	dns_name_countlabels(name) > 0
 *
 *	dns_name_isabsolute(name) == TRUE
 *
722
 *	target is a valid buffer.
Bob Halley's avatar
add  
Bob Halley committed
723 724 725 726 727
 *
 *	Any offsets specified in a global compression table are valid
 *	for buffer.
 *
 * Ensures:
Bob Halley's avatar
Bob Halley committed
728
 *
Bob Halley's avatar
add  
Bob Halley committed
729
 *	If the result is success:
Bob Halley's avatar
Bob Halley committed
730 731
 *
 *		The used space in target is updated.
Bob Halley's avatar
add  
Bob Halley committed
732 733 734 735 736 737
 *
 * Returns:
 *	Success
 *	Resource Limit: Not enough space in buffer
 */

David Lawrence's avatar
David Lawrence committed
738 739
isc_result_t
dns_name_fromtext(dns_name_t *name, isc_buffer_t *source,
740
		  dns_name_t *origin, unsigned int options,
David Lawrence's avatar
David Lawrence committed
741
		  isc_buffer_t *target);
Bob Halley's avatar
add  
Bob Halley committed
742 743 744 745 746 747 748 749 750
/*
 * Convert the textual representation of a DNS name at source
 * into uncompressed wire form stored in target.
 *
 * Notes:
 *	Relative domain names will have 'origin' appended to them
 *	unless 'origin' is NULL, in which case relative domain names
 *	will remain relative.
 *
751 752
 *	If DNS_NAME_DOWNCASE is set in 'options', any uppercase letters
 *	in 'source' will be downcased when they are copied into 'target'.
Bob Halley's avatar
add  
Bob Halley committed
753 754 755
 *
 * Requires:
 *
756 757
 *	'name' is a valid name.
 *
758
 *	'source' is a valid buffer.
Bob Halley's avatar
Bob Halley committed
759
 *
760 761
 *	'target' is a valid buffer or 'target' is NULL and 'name' has
 *	a dedicated buffer.
Bob Halley's avatar
Bob Halley committed
762
 *
Bob Halley's avatar
add  
Bob Halley committed
763
 * Ensures:
Bob Halley's avatar
Bob Halley committed
764
 *
Bob Halley's avatar
add  
Bob Halley committed
765
 *	If result is success:
766
 *	 	If 'target' is not NULL, 'name' is attached to it.
Bob Halley's avatar
add  
Bob Halley committed
767
 *
768 769
 *		Uppercase letters are downcased in the copy iff
 *		DNS_NAME_DOWNCASE is set in 'options'.
Bob Halley's avatar
add  
Bob Halley committed
770 771 772 773 774
 *
 *		The current location in source is advanced, and the used space
 *		in target is updated.
 *
 * Result:
775
 *	ISC_R_SUCCESS
Bob Halley's avatar
Bob Halley committed
776 777 778
 *	DNS_R_EMPTYLABEL
 *	DNS_R_LABELTOOLONG
 *	DNS_R_BADESCAPE
Mark Andrews's avatar
Mark Andrews committed
779 780
 *	(DNS_R_BADBITSTRING: should not be returned)
 *	(DNS_R_BITSTRINGTOOLONG: should not be returned)
Bob Halley's avatar
Bob Halley committed
781
 *	DNS_R_BADDOTTEDQUAD
782
 *	ISC_R_NOSPACE
783 784
 *	ISC_R_UNEXPECTEDEND
 */
Bob Halley's avatar
add  
Bob Halley committed
785

David Lawrence's avatar
David Lawrence committed
786 787 788
isc_result_t
dns_name_totext(dns_name_t *name, isc_boolean_t omit_final_dot,
		isc_buffer_t *target);
Bob Halley's avatar
add  
Bob Halley committed
789 790
/*
 * Convert 'name' into text format, storing the result in 'target'.
791
 *
792 793 794 795 796 797 798 799
 * Notes:
 *	If 'omit_final_dot' is true, then the final '.' in absolute
 *	names other than the root name will be omitted.
 *
 *	If dns_name_countlabels == 0, the name will be "@", representing the
 *	current origin as described by RFC 1035.
 *
 *	The name is not NUL terminated.
Bob Halley's avatar
add  
Bob Halley committed
800 801
 *
 * Requires:
Bob Halley's avatar
Bob Halley committed
802
 *
Bob Halley's avatar
add  
Bob Halley committed
803 804
 *	'name' is a valid name
 *
805
 *	'target' is a valid buffer.
Bob Halley's avatar
add  
Bob Halley committed
806 807 808 809
 *
 *	if dns_name_isabsolute == FALSE, then omit_final_dot == FALSE
 *
 * Ensures:
Bob Halley's avatar
Bob Halley committed
810
 *
Bob Halley's avatar
add  
Bob Halley committed
811
 *	If the result is success:
Bob Halley's avatar
Bob Halley committed
812 813
 *
 *		The used space in target is updated.
Bob Halley's avatar
add  
Bob Halley committed
814 815
 *
 * Returns:
816 817
 *	ISC_R_SUCCESS
 *	ISC_R_NOSPACE
Bob Halley's avatar
add  
Bob Halley committed
818 819
 */

820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842
#define DNS_NAME_MAXTEXT 1023
/*
 * The maximum length of the text representation of a domain
 * name as generated by dns_name_totext().  This does not
 * include space for a terminating NULL.
 *
 * This definition is conservative - the actual maximum 
 * is 1004, derived as follows:
 *
 *   A backslash-decimal escaped character takes 4 bytes.
 *   A wire-encoded name can be up to 255 bytes and each
 *   label is one length byte + at most 63 bytes of data.
 *   Maximizing the label lengths gives us a name of
 *   three 63-octet labels, one 61-octet label, and the
 *   root label:
 *
 *      1 + 63 + 1 + 63 + 1 + 63 + 1 + 61 + 1 = 255
 *
 *   When printed, this is (3 * 63 + 61) * 4
 *   bytes for the escaped label data + 4 bytes for the
 *   dot terminating each label = 1004 bytes total.
 */

843 844 845 846 847
isc_result_t
dns_name_tofilenametext(dns_name_t *name, isc_boolean_t omit_final_dot,
			isc_buffer_t *target);
/*
 * Convert 'name' into an alternate text format appropriate for filenames,
848 849
 * storing the result in 'target'.  The name data is downcased, guaranteeing
 * that the filename does not depend on the case of the converted name.
850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873
 *
 * Notes:
 *	If 'omit_final_dot' is true, then the final '.' in absolute
 *	names other than the root name will be omitted.
 *
 *	The name is not NUL terminated.
 *
 * Requires:
 *
 *	'name' is a valid absolute name
 *
 *	'target' is a valid buffer.
 *
 * Ensures:
 *
 *	If the result is success:
 *
 *		The used space in target is updated.
 *
 * Returns:
 *	ISC_R_SUCCESS
 *	ISC_R_NOSPACE
 */

874 875 876
isc_result_t
dns_name_downcase(dns_name_t *source, dns_name_t *name,
		  isc_buffer_t *target);
Brian Wellington's avatar
Brian Wellington committed
877
/*
878
 * Downcase 'source'.
Brian Wellington's avatar
Brian Wellington committed
879 880 881
 *
 * Requires:
 *
882 883 884 885 886 887 888 889
 *	'source' and 'name' are valid names.
 *
 *	If source == name, then
 *
 *		'source' must not be read-only
 *
 *	Otherwise,
 *
890 891
 *		'target' is a valid buffer or 'target' is NULL and
 *		'name' has a dedicated buffer.
892 893
 *
 * Returns:
894 895
 *	ISC_R_SUCCESS
 *	ISC_R_NOSPACE
896
 *
897 898
 * Note: if source == name, then the result will always be ISC_R_SUCCESS.
 */
Brian Wellington's avatar
Brian Wellington committed
899

David Lawrence's avatar
David Lawrence committed
900 901 902
isc_result_t
dns_name_concatenate(dns_name_t *prefix, dns_name_t *suffix,
		     dns_name_t *name, isc_buffer_t *target);
Mark Andrews's avatar
Mark Andrews committed
903
/*
Bob Halley's avatar
Bob Halley committed
904
 *	Concatenate 'prefix' and 'suffix'.
905 906
 *
 * Requires:
907
 *
Bob Halley's avatar
Bob Halley committed
908
 *	'prefix' is a valid name or NULL.
909
 *
Bob Halley's avatar
Bob Halley committed
910
 *	'suffix' is a valid name or NULL.
911
 *
Bob Halley's avatar
Bob Halley committed
912
 *	'name' is a valid name or NULL.
913
 *
914 915
 *	'target' is a valid buffer or 'target' is NULL and 'name' has
 *	a dedicated buffer.
916
 *
Bob Halley's avatar
Bob Halley committed
917 918
 *	If 'prefix' is absolute, 'suffix' must be NULL or the empty name.
 *
919
 * Ensures:
Bob Halley's avatar
Bob Halley committed
920
 *
921
 *	On success,
Bob Halley's avatar
Bob Halley committed
922 923 924 925
 *	 	If 'target' is not NULL and 'name' is not NULL, then 'name'
 *		is attached to it.
 *
 *		The used space in target is updated.
Mark Andrews's avatar
Mark Andrews committed
926 927
 *
 * Returns:
928
 *	ISC_R_SUCCESS
929
 *	ISC_R_NOSPACE
930
 *	DNS_R_NAMETOOLONG
931
 */
932

933 934
void
dns_name_split(dns_name_t *name, unsigned int suffixlabels,
David Lawrence's avatar
David Lawrence committed
935 936 937
	       dns_name_t *prefix, dns_name_t *suffix);
/*
 *
938
 * Split 'name' into two pieces on a label boundary.
David Lawrence's avatar
David Lawrence committed
939 940
 *
 * Notes:
941
 *      'name' is split such that 'suffix' holds the most significant
942
 *      'suffixlabels' labels.  All other labels are stored in 'prefix'. 
943
 *
David Lawrence's avatar
David Lawrence committed
944
 *	Copying name data is avoided as much as possible, so 'prefix'
Mark Andrews's avatar
Mark Andrews committed
945
 *	and 'suffix' will end up pointing at the data for 'name'.
David Lawrence's avatar
David Lawrence committed
946 947
 *
 *	It is legitimate to pass a 'prefix' or 'suffix' that has
948
 *	its name data stored someplace other than the dedicated buffer.
David Lawrence's avatar
David Lawrence committed
949 950 951
 *	This is useful to avoid name copying in the calling function.
 *
 *	It is also legitimate to pass a 'prefix' or 'suffix' that is
Mark Andrews's avatar
Mark Andrews committed
952
 *	the same dns_name_t as 'name'.
David Lawrence's avatar
David Lawrence committed
953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969
 *
 * Requires:
 *	'name' is a valid name.
 *
 * 	'suffixlabels' cannot exceed the number of labels in 'name'.
 *
 *	'prefix' is a valid name or NULL, and cannot be read-only.
 *
 *	'suffix' is a valid name or NULL, and cannot be read-only.
 *
 *	If non-NULL, 'prefix' and 'suffix' must have dedicated buffers.
 *
 *	'prefix' and 'suffix' cannot point to the same buffer.
 *
 * Ensures:
 *
 *	On success:
970
 *		If 'prefix' is not NULL it will contain the least significant
Mark Andrews's avatar
Mark Andrews committed
971
 *		labels.
David Lawrence's avatar
David Lawrence committed
972 973
 *
 *		If 'suffix' is not NULL it will contain the most significant
Mark Andrews's avatar
Mark Andrews committed
974 975
 *		labels.  dns_name_countlabels(suffix) will be equal to
 *		suffixlabels.
David Lawrence's avatar
David Lawrence committed
976 977 978 979 980 981
 *
 *	On failure:
 *		Either 'prefix' or 'suffix' is invalidated (depending
 *		on which one the problem was encountered with).
 *
 * Returns:
Mark Andrews's avatar
Mark Andrews committed
982
 *	ISC_R_SUCCESS	No worries.  (This function should always success).
David Lawrence's avatar
David Lawrence committed
983 984
 */

985
isc_result_t
986
dns_name_dup(dns_name_t *source, isc_mem_t *mctx, dns_name_t *target);
987 988 989 990 991 992
/*
 * Make 'target' a dynamically allocated copy of 'source'.
 *
 * Requires:
 *
 *	'source' is a valid non-empty name.
993
 *
994
 *	'target' is a valid name that is not read-only.
995
 *
996 997 998
 *	'mctx' is a valid memory context.
 */

Bob Halley's avatar
Bob Halley committed
999 1000 1001 1002 1003 1004 1005 1006 1007 1008
isc_result_t
dns_name_dupwithoffsets(dns_name_t *source, isc_mem_t *mctx,
			dns_name_t *target);
/*
 * Make 'target' a read-only dynamically allocated copy of 'source'.
 * 'target' will also have a dynamically allocated offsets table.
 *
 * Requires:
 *
 *	'source' is a valid non-empty name.
1009
 *
Bob Halley's avatar
Bob Halley committed
1010 1011 1012
 *	'target' is a valid name that is not read-only.
 *
 *	'target' has no offsets table.
1013
 *
Bob Halley's avatar
Bob Halley committed
1014 1015 1016
 *	'mctx' is a valid memory context.
 */

1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033
void
dns_name_free(dns_name_t *name, isc_mem_t *mctx);
/*
 * Free 'name'.
 *
 * Requires:
 *
 *	'name' is a valid name created previously in 'mctx' by dns_name_dup().
 *
 *	'mctx' is a valid memory context.
 *
 * Ensures:
 *
 *	All dynamic resources used by 'name' are freed and the name is
 *	invalidated.
 */

1034
isc_result_t
Bob Halley's avatar
Bob Halley committed
1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049
dns_name_digest(dns_name_t *name, dns_digestfunc_t digest, void *arg);
/*
 * Send 'name' in DNSSEC canonical form to 'digest'.
 *
 * Requires:
 *
 *	'name' is a valid name.
 *
 *	'digest' is a valid dns_digestfunc_t.
 *
 * Ensures:
 *
 *	If successful, the DNSSEC canonical form of 'name' will have been
 *	sent to 'digest'.
 *
1050
 *	If digest() returns something other than ISC_R_SUCCESS, that result
Bob Halley's avatar
Bob Halley committed
1051 1052 1053 1054
 *	will be returned as the result of dns_name_digest().
 *
 * Returns:
 *
1055
 *	ISC_R_SUCCESS
Bob Halley's avatar
Bob Halley committed
1056 1057
 *
 *	Many other results are possible if not successful.
1058
 *
Bob Halley's avatar
Bob Halley committed
1059 1060
 */

1061 1062 1063
isc_boolean_t
dns_name_dynamic(dns_name_t *name);
/*
Bob Halley's avatar
Bob Halley committed
1064
 * Returns whether there is dynamic memory associated with this name.
1065 1066 1067 1068 1069 1070 1071 1072 1073 1074
 *
 * Requires:
 *
 *	'name' is a valid name.
 *
 * Returns:
 *
 *	'ISC_TRUE' if the name is dynamic othewise 'ISC_FALSE'.
 */

Bob Halley's avatar
Bob Halley committed
1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092
isc_result_t
dns_name_print(dns_name_t *name, FILE *stream);
/*
 * Print 'name' on 'stream'.
 *
 * Requires:
 *
 *	'name' is a valid name.
 *
 *	'stream' is a valid stream.
 *
 * Returns:
 *
 *	ISC_R_SUCCESS
 *
 *	Any error that dns_name_totext() can return.
 */

1093 1094 1095 1096 1097 1098 1099 1100 1101
void
dns_name_format(dns_name_t *name, char *cp, unsigned int size);
/*
 * Format 'name' as text appropriate for use in log messages.
 *
 * Store the formatted name at 'cp', writing no more than
 * 'size' bytes.  The resulting string is guaranteed to be
 * null terminated.
 *
1102
 * The formatted name will have a terminating dot only if it is
1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117
 * the root.
 *
 * This function cannot fail, instead any errors are indicated
 * in the returned text.
 *
 * Requires:
 *
 *	'name' is a valid name.
 *
 *	'cp' points a valid character array of size 'size'.
 *
 *	'size' > 0.
 *
 */

1118 1119 1120 1121 1122 1123
#define DNS_NAME_FORMATSIZE (DNS_NAME_MAXTEXT + 1)
/*
 * Suggested size of buffer passed to dns_name_format().
 * Includes space for the terminating NULL.
 */

Brian Wellington's avatar
Brian Wellington committed
1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147
isc_result_t
dns_name_copy(dns_name_t *source, dns_name_t *dest, isc_buffer_t *target);
/*
 * Makes 'dest' refer to a copy of the name in 'source'.  The data are
 * either copied to 'target' or the dedicated buffer in 'dest'.
 *
 * Requires:
 * 	'source' is a valid name.
 *
 * 	'dest' is an initialized name with a dedicated buffer.
 *
 * 	'target' is NULL or an initialized buffer.
 *
 * 	Either dest has a dedicated buffer or target != NULL.
 *
 * Ensures:
 *
 *	On success, the used space in target is updated.
 *
 * Returns:
 *	ISC_R_SUCCESS
 *	ISC_R_NOSPACE
 */

1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169
isc_boolean_t
dns_name_ishostname(const dns_name_t *name, isc_boolean_t wildcard);
/*
 * Return if 'name' is a valid hostname.  RFC 952 / RFC 1123.
 * If 'wildcard' is ISC_TRUE then allow the first label of name to
 * be a wildcard.
 * The root is also accepted.
 *
 * Requires:
 *	'name' to be valid.
 */
 

isc_boolean_t
dns_name_ismailbox(const dns_name_t *name);
/*
 * Return if 'name' is a valid mailbox.  RFC 821.
 *
 * Requires:
 *	'name' to be valid.
 */

1170 1171 1172 1173 1174 1175 1176 1177 1178
isc_boolean_t
dns_name_internalwildcard(const dns_name_t *name);
/*
 * Return if 'name' contains a internal wildcard name.
 *
 * Requires:
 *	'name' to be valid.
 */

David Lawrence's avatar
David Lawrence committed
1179 1180
ISC_LANG_ENDDECLS

Bob Halley's avatar
Bob Halley committed
1181 1182 1183 1184 1185 1186 1187