xref: /openbsd-src/usr.sbin/nsd/dname.h (revision bf87c3c07c3ad89262e2b8cae09f17e70aa9e1ee)
162ac0c33Sjakob /*
262ac0c33Sjakob  * dname.h -- Domain name handling.
362ac0c33Sjakob  *
4d3fecca9Ssthen  * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
562ac0c33Sjakob  *
662ac0c33Sjakob  * See LICENSE for the license.
762ac0c33Sjakob  *
862ac0c33Sjakob  */
962ac0c33Sjakob 
103efee2e1Sflorian #ifndef DNAME_H
113efee2e1Sflorian #define DNAME_H
1262ac0c33Sjakob 
1362ac0c33Sjakob #include <assert.h>
1462ac0c33Sjakob #include <stdio.h>
1562ac0c33Sjakob 
1662ac0c33Sjakob #include "buffer.h"
1762ac0c33Sjakob #include "region-allocator.h"
18*bf87c3c0Sflorian #include "dns.h" /* for MAXDOMAINLEN */
1962ac0c33Sjakob 
2062ac0c33Sjakob #if defined(NAMEDB_UPPERCASE) || defined(USE_NAMEDB_UPPERCASE)
2162ac0c33Sjakob #define DNAME_NORMALIZE        toupper
2262ac0c33Sjakob #else
2362ac0c33Sjakob #define DNAME_NORMALIZE        tolower
2462ac0c33Sjakob #endif
2562ac0c33Sjakob 
2662ac0c33Sjakob 
2762ac0c33Sjakob /*
2862ac0c33Sjakob  * Domain names stored in memory add some additional information to be
2962ac0c33Sjakob  * able to quickly index and compare by label.
3062ac0c33Sjakob  */
3162ac0c33Sjakob typedef struct dname dname_type;
3262ac0c33Sjakob struct dname
3362ac0c33Sjakob {
3462ac0c33Sjakob 	/*
3562ac0c33Sjakob 	 * The size (in bytes) of the domain name in wire format.
3662ac0c33Sjakob 	 */
3762ac0c33Sjakob 	uint8_t name_size;
3862ac0c33Sjakob 
3962ac0c33Sjakob 	/*
4062ac0c33Sjakob 	 * The number of labels in this domain name (including the
4162ac0c33Sjakob 	 * root label).
4262ac0c33Sjakob 	 */
4362ac0c33Sjakob 	uint8_t label_count;
4462ac0c33Sjakob 
4562ac0c33Sjakob 	/*
4662ac0c33Sjakob 	  uint8_t label_offsets[label_count];
4762ac0c33Sjakob 	  uint8_t name[name_size];
4862ac0c33Sjakob 	*/
4962ac0c33Sjakob };
5062ac0c33Sjakob 
5162ac0c33Sjakob 
5262ac0c33Sjakob /*
5362ac0c33Sjakob  * Construct a new domain name based on NAME in wire format.  NAME
5462ac0c33Sjakob  * cannot contain compression pointers.
5562ac0c33Sjakob  *
5662ac0c33Sjakob  * Pre: NAME != NULL.
5762ac0c33Sjakob  */
5862ac0c33Sjakob const dname_type *dname_make(region_type *region, const uint8_t *name,
5962ac0c33Sjakob 			     int normalize);
6062ac0c33Sjakob 
6162ac0c33Sjakob /*
6262ac0c33Sjakob  * Construct a new domain name based on wire format dname stored at
6362ac0c33Sjakob  * PACKET's current position.  Compression pointers are followed.  The
6462ac0c33Sjakob  * PACKET's current position is changed to the end of the wire format
6562ac0c33Sjakob  * dname or set to just after the first compression pointer.
6662ac0c33Sjakob  */
6762ac0c33Sjakob const dname_type *dname_make_from_packet(region_type *region,
6862ac0c33Sjakob 					 buffer_type *packet,
6962ac0c33Sjakob 					 int allow_pointers,
7062ac0c33Sjakob 					 int normalize);
7162ac0c33Sjakob 
7262ac0c33Sjakob /*
7362ac0c33Sjakob  * parse wireformat from packet (following pointers) into the
7462ac0c33Sjakob  * given buffer. Returns length in buffer or 0 on error.
7562ac0c33Sjakob  * buffer must be MAXDOMAINLEN+1 long.
7662ac0c33Sjakob  */
7762ac0c33Sjakob int dname_make_wire_from_packet(uint8_t *buf,
7862ac0c33Sjakob 				buffer_type *packet,
7962ac0c33Sjakob 				int allow_pointers);
8062ac0c33Sjakob 
8162ac0c33Sjakob /*
8262ac0c33Sjakob  * Construct a new domain name based on the ASCII representation NAME.
8362ac0c33Sjakob  * If ORIGIN is not NULL and NAME is not terminated by a "." the
8462ac0c33Sjakob  * ORIGIN is appended to the result.  NAME can contain escape
8562ac0c33Sjakob  * sequences.
8662ac0c33Sjakob  *
8762ac0c33Sjakob  * Returns NULL on failure.  Otherwise a newly allocated domain name
8862ac0c33Sjakob  * is returned.
8962ac0c33Sjakob  *
9062ac0c33Sjakob  * Pre: name != NULL.
9162ac0c33Sjakob  */
9262ac0c33Sjakob const dname_type *dname_parse(region_type *region, const char *name);
9362ac0c33Sjakob 
9462ac0c33Sjakob /*
9562ac0c33Sjakob  * parse ascii string to wireformat domain name (without compression ptrs)
9662ac0c33Sjakob  * returns 0 on failure, the length of the wireformat on success.
9762ac0c33Sjakob  * the result is stored in the wirefmt which must be at least MAXDOMAINLEN
9862ac0c33Sjakob  * in size. On failure, the wirefmt can be altered.
9962ac0c33Sjakob  */
10062ac0c33Sjakob int dname_parse_wire(uint8_t* wirefmt, const char* name);
10162ac0c33Sjakob 
10262ac0c33Sjakob /*
10362ac0c33Sjakob  * Return NULL if DNAME is NULL or a copy of DNAME otherwise.
10462ac0c33Sjakob  */
10562ac0c33Sjakob const dname_type *dname_copy(region_type *region, const dname_type *dname);
10662ac0c33Sjakob 
10762ac0c33Sjakob 
10862ac0c33Sjakob /*
10962ac0c33Sjakob  * Copy the most significant LABEL_COUNT labels from dname.
11062ac0c33Sjakob  */
11162ac0c33Sjakob const dname_type *dname_partial_copy(region_type *region,
11262ac0c33Sjakob 				     const dname_type *dname,
11362ac0c33Sjakob 				     uint8_t label_count);
11462ac0c33Sjakob 
11562ac0c33Sjakob 
11662ac0c33Sjakob /*
11762ac0c33Sjakob  * The origin of DNAME.
11862ac0c33Sjakob  */
11962ac0c33Sjakob const dname_type *dname_origin(region_type *region, const dname_type *dname);
12062ac0c33Sjakob 
12162ac0c33Sjakob /*
12262ac0c33Sjakob  * Return true if LEFT is a subdomain of RIGHT.
12362ac0c33Sjakob  */
12462ac0c33Sjakob int dname_is_subdomain(const dname_type *left, const dname_type *right);
12562ac0c33Sjakob 
12662ac0c33Sjakob 
12762ac0c33Sjakob /*
12862ac0c33Sjakob  * Offsets into NAME for each label starting with the most
12962ac0c33Sjakob  * significant label (the root label, followed by the TLD,
13062ac0c33Sjakob  * etc).
13162ac0c33Sjakob  */
13262ac0c33Sjakob static inline const uint8_t *
dname_label_offsets(const dname_type * dname)13362ac0c33Sjakob dname_label_offsets(const dname_type *dname)
13462ac0c33Sjakob {
13562ac0c33Sjakob 	return (const uint8_t *) ((const char *) dname + sizeof(dname_type));
13662ac0c33Sjakob }
13762ac0c33Sjakob 
13862ac0c33Sjakob 
13962ac0c33Sjakob /*
14062ac0c33Sjakob  * The actual name in wire format (a sequence of label, each
14162ac0c33Sjakob  * prefixed by a length byte, terminated by a zero length
14262ac0c33Sjakob  * label).
14362ac0c33Sjakob  */
14462ac0c33Sjakob static inline const uint8_t *
dname_name(const dname_type * dname)14562ac0c33Sjakob dname_name(const dname_type *dname)
14662ac0c33Sjakob {
14762ac0c33Sjakob 	return (const uint8_t *) ((const char *) dname
14862ac0c33Sjakob 				  + sizeof(dname_type)
14962ac0c33Sjakob 				  + dname->label_count * sizeof(uint8_t));
15062ac0c33Sjakob }
15162ac0c33Sjakob 
15262ac0c33Sjakob 
15362ac0c33Sjakob /*
15462ac0c33Sjakob  * Return the label for DNAME specified by LABEL_INDEX.  The first
15562ac0c33Sjakob  * label (LABEL_INDEX == 0) is the root label, the next label is the
15662ac0c33Sjakob  * TLD, etc.
15762ac0c33Sjakob  *
15862ac0c33Sjakob  * Pre: dname != NULL && label_index < dname->label_count.
15962ac0c33Sjakob  */
16062ac0c33Sjakob static inline const uint8_t *
dname_label(const dname_type * dname,uint8_t label)16162ac0c33Sjakob dname_label(const dname_type *dname, uint8_t label)
16262ac0c33Sjakob {
16362ac0c33Sjakob 	uint8_t label_index;
16462ac0c33Sjakob 
16562ac0c33Sjakob 	assert(dname != NULL);
16662ac0c33Sjakob 	assert(label < dname->label_count);
16762ac0c33Sjakob 
16862ac0c33Sjakob 	label_index = dname_label_offsets(dname)[label];
16962ac0c33Sjakob 	assert(label_index < dname->name_size);
17062ac0c33Sjakob 
17162ac0c33Sjakob 	return dname_name(dname) + label_index;
17262ac0c33Sjakob }
17362ac0c33Sjakob 
17462ac0c33Sjakob 
17562ac0c33Sjakob /*
1762fd875a4Ssthen  * Compare two domain names.  The comparison defines a lexicographical
17762ac0c33Sjakob  * ordering based on the domain name's labels, starting with the most
17862ac0c33Sjakob  * significant label.
17962ac0c33Sjakob  *
18062ac0c33Sjakob  * Return < 0 if LEFT < RIGHT, 0 if LEFT == RIGHT, and > 0 if LEFT >
18162ac0c33Sjakob  * RIGHT.  The comparison is case sensitive.
18262ac0c33Sjakob  *
183d3fecca9Ssthen  * Pre: left != NULL && right != NULL
18462ac0c33Sjakob  */
185d3fecca9Ssthen int dname_compare(const dname_type *left, const dname_type *right);
18662ac0c33Sjakob 
18762ac0c33Sjakob 
18862ac0c33Sjakob /*
1892fd875a4Ssthen  * Compare two labels.  The comparison defines a lexicographical
19062ac0c33Sjakob  * ordering based on the characters in the labels.
19162ac0c33Sjakob  *
19262ac0c33Sjakob  * Return < 0 if LEFT < RIGHT, 0 if LEFT == RIGHT, and > 0 if LEFT >
19362ac0c33Sjakob  * RIGHT.  The comparison is case sensitive.
19462ac0c33Sjakob  *
19562ac0c33Sjakob  * Pre: left != NULL && right != NULL
19662ac0c33Sjakob  *      label_is_normal(left) && label_is_normal(right)
19762ac0c33Sjakob  */
19862ac0c33Sjakob int label_compare(const uint8_t *left, const uint8_t *right);
19962ac0c33Sjakob 
20062ac0c33Sjakob 
20162ac0c33Sjakob /*
20262ac0c33Sjakob  * Returns the number of labels that match in LEFT and RIGHT, starting
20362ac0c33Sjakob  * with the most significant label.  Because the root label always
20462ac0c33Sjakob  * matches, the result will always be >= 1.
20562ac0c33Sjakob  *
20662ac0c33Sjakob  * Pre: left != NULL && right != NULL
20762ac0c33Sjakob  */
20862ac0c33Sjakob uint8_t dname_label_match_count(const dname_type *left,
20962ac0c33Sjakob 				const dname_type *right);
21062ac0c33Sjakob 
21162ac0c33Sjakob 
21262ac0c33Sjakob /*
21362ac0c33Sjakob  * The total size (in bytes) allocated to store DNAME.
21462ac0c33Sjakob  *
21562ac0c33Sjakob  * Pre: dname != NULL
21662ac0c33Sjakob  */
21762ac0c33Sjakob static inline size_t
dname_total_size(const dname_type * dname)21862ac0c33Sjakob dname_total_size(const dname_type *dname)
21962ac0c33Sjakob {
22062ac0c33Sjakob 	return (sizeof(dname_type)
221c939baa4Ssthen 		+ ((((size_t)dname->label_count) + ((size_t)dname->name_size))
22262ac0c33Sjakob 		   * sizeof(uint8_t)));
22362ac0c33Sjakob }
22462ac0c33Sjakob 
22562ac0c33Sjakob 
22662ac0c33Sjakob /*
22762ac0c33Sjakob  * Is LABEL a normal LABEL (not a pointer or reserved)?
22862ac0c33Sjakob  *
22962ac0c33Sjakob  * Pre: label != NULL;
23062ac0c33Sjakob  */
23162ac0c33Sjakob static inline int
label_is_normal(const uint8_t * label)23262ac0c33Sjakob label_is_normal(const uint8_t *label)
23362ac0c33Sjakob {
23462ac0c33Sjakob 	assert(label);
23562ac0c33Sjakob 	return (label[0] & 0xc0) == 0;
23662ac0c33Sjakob }
23762ac0c33Sjakob 
23862ac0c33Sjakob 
23962ac0c33Sjakob /*
24062ac0c33Sjakob  * Is LABEL a pointer?
24162ac0c33Sjakob  *
24262ac0c33Sjakob  * Pre: label != NULL;
24362ac0c33Sjakob  */
24462ac0c33Sjakob static inline int
label_is_pointer(const uint8_t * label)24562ac0c33Sjakob label_is_pointer(const uint8_t *label)
24662ac0c33Sjakob {
24762ac0c33Sjakob 	assert(label);
24862ac0c33Sjakob 	return (label[0] & 0xc0) == 0xc0;
24962ac0c33Sjakob }
25062ac0c33Sjakob 
25162ac0c33Sjakob 
25262ac0c33Sjakob /*
25362ac0c33Sjakob  * LABEL's pointer location.
25462ac0c33Sjakob  *
25562ac0c33Sjakob  * Pre: label != NULL && label_is_pointer(label)
25662ac0c33Sjakob  */
25762ac0c33Sjakob static inline uint16_t
label_pointer_location(const uint8_t * label)25862ac0c33Sjakob label_pointer_location(const uint8_t *label)
25962ac0c33Sjakob {
26062ac0c33Sjakob 	assert(label);
26162ac0c33Sjakob 	assert(label_is_pointer(label));
26262ac0c33Sjakob 	return ((uint16_t) (label[0] & ~0xc0) << 8) | (uint16_t) label[1];
26362ac0c33Sjakob }
26462ac0c33Sjakob 
26562ac0c33Sjakob 
26662ac0c33Sjakob /*
26762ac0c33Sjakob  * Length of LABEL.
26862ac0c33Sjakob  *
26962ac0c33Sjakob  * Pre: label != NULL && label_is_normal(label)
27062ac0c33Sjakob  */
27162ac0c33Sjakob static inline uint8_t
label_length(const uint8_t * label)27262ac0c33Sjakob label_length(const uint8_t *label)
27362ac0c33Sjakob {
27462ac0c33Sjakob 	assert(label);
27562ac0c33Sjakob 	assert(label_is_normal(label));
27662ac0c33Sjakob 	return label[0];
27762ac0c33Sjakob }
27862ac0c33Sjakob 
27962ac0c33Sjakob 
28062ac0c33Sjakob /*
28162ac0c33Sjakob  * The data of LABEL.
28262ac0c33Sjakob  *
28362ac0c33Sjakob  * Pre: label != NULL && label_is_normal(label)
28462ac0c33Sjakob  */
28562ac0c33Sjakob static inline const uint8_t *
label_data(const uint8_t * label)28662ac0c33Sjakob label_data(const uint8_t *label)
28762ac0c33Sjakob {
28862ac0c33Sjakob 	assert(label);
28962ac0c33Sjakob 	assert(label_is_normal(label));
29062ac0c33Sjakob 	return label + 1;
29162ac0c33Sjakob }
29262ac0c33Sjakob 
29362ac0c33Sjakob 
29462ac0c33Sjakob /*
29562ac0c33Sjakob  * Is LABEL the root label?
29662ac0c33Sjakob  *
29762ac0c33Sjakob  * Pre: label != NULL
29862ac0c33Sjakob  */
29962ac0c33Sjakob static inline int
label_is_root(const uint8_t * label)30062ac0c33Sjakob label_is_root(const uint8_t *label)
30162ac0c33Sjakob {
30262ac0c33Sjakob 	assert(label);
30362ac0c33Sjakob 	return label[0] == 0;
30462ac0c33Sjakob }
30562ac0c33Sjakob 
30662ac0c33Sjakob 
30762ac0c33Sjakob /*
30862ac0c33Sjakob  * Is LABEL the wildcard label?
30962ac0c33Sjakob  *
31062ac0c33Sjakob  * Pre: label != NULL
31162ac0c33Sjakob  */
31262ac0c33Sjakob static inline int
label_is_wildcard(const uint8_t * label)31362ac0c33Sjakob label_is_wildcard(const uint8_t *label)
31462ac0c33Sjakob {
31562ac0c33Sjakob 	assert(label);
31662ac0c33Sjakob 	return label[0] == 1 && label[1] == '*';
31762ac0c33Sjakob }
31862ac0c33Sjakob 
31962ac0c33Sjakob 
32062ac0c33Sjakob /*
32162ac0c33Sjakob  * The next label of LABEL.
32262ac0c33Sjakob  *
32362ac0c33Sjakob  * Pre: label != NULL
32462ac0c33Sjakob  *      label_is_normal(label)
32562ac0c33Sjakob  *      !label_is_root(label)
32662ac0c33Sjakob  */
32762ac0c33Sjakob static inline const uint8_t *
label_next(const uint8_t * label)32862ac0c33Sjakob label_next(const uint8_t *label)
32962ac0c33Sjakob {
33062ac0c33Sjakob 	assert(label);
33162ac0c33Sjakob 	assert(label_is_normal(label));
33262ac0c33Sjakob 	assert(!label_is_root(label));
33362ac0c33Sjakob 	return label + label_length(label) + 1;
33462ac0c33Sjakob }
33562ac0c33Sjakob 
33662ac0c33Sjakob 
33762ac0c33Sjakob /*
33862ac0c33Sjakob  * Convert DNAME to its string representation.  The result points to a
33962ac0c33Sjakob  * static buffer that is overwritten the next time this function is
34062ac0c33Sjakob  * invoked.
34162ac0c33Sjakob  *
34262ac0c33Sjakob  * If ORIGIN is provided and DNAME is a subdomain of ORIGIN the dname
34362ac0c33Sjakob  * will be represented relative to ORIGIN.
34462ac0c33Sjakob  *
34562ac0c33Sjakob  * Pre: dname != NULL
34662ac0c33Sjakob  */
34762ac0c33Sjakob const char *dname_to_string(const dname_type *dname,
34862ac0c33Sjakob 			    const dname_type *origin);
34962ac0c33Sjakob 
350*bf87c3c0Sflorian /*
351*bf87c3c0Sflorian  * Convert DNAME to its string representation.  The result if written
352*bf87c3c0Sflorian  * to the provided buffer buf, which must be at least 5 times
353*bf87c3c0Sflorian  * MAXDOMAINNAMELEN.
354*bf87c3c0Sflorian  *
355*bf87c3c0Sflorian  * If ORIGIN is provided and DNAME is a subdomain of ORIGIN the dname
356*bf87c3c0Sflorian  * will be represented relative to ORIGIN.
357*bf87c3c0Sflorian  *
358*bf87c3c0Sflorian  * Pre: dname != NULL
359*bf87c3c0Sflorian  */
360*bf87c3c0Sflorian const char *dname_to_string_buf(const dname_type *dname,
361*bf87c3c0Sflorian                                 const dname_type *origin,
362*bf87c3c0Sflorian                                 char buf[MAXDOMAINLEN * 5]);
36362ac0c33Sjakob 
36462ac0c33Sjakob /*
36562ac0c33Sjakob  * Create a dname containing the single label specified by STR
36662ac0c33Sjakob  * followed by the root label.
36762ac0c33Sjakob  */
36862ac0c33Sjakob const dname_type *dname_make_from_label(region_type *region,
36962ac0c33Sjakob 					const uint8_t *label,
37062ac0c33Sjakob 					const size_t length);
37162ac0c33Sjakob 
37262ac0c33Sjakob 
37362ac0c33Sjakob /*
37462ac0c33Sjakob  * Concatenate two dnames.
37562ac0c33Sjakob  */
37662ac0c33Sjakob const dname_type *dname_concatenate(region_type *region,
37762ac0c33Sjakob 				    const dname_type *left,
37862ac0c33Sjakob 				    const dname_type *right);
37962ac0c33Sjakob 
38062ac0c33Sjakob 
38162ac0c33Sjakob /*
38262ac0c33Sjakob  * Perform DNAME substitution on a name, replace src with dest.
38362ac0c33Sjakob  * Name must be a subdomain of src. The returned name is a subdomain of dest.
38462ac0c33Sjakob  * Returns NULL if the result domain name is too long.
38562ac0c33Sjakob  */
38662ac0c33Sjakob const dname_type *dname_replace(region_type* region,
38762ac0c33Sjakob 				const dname_type* name,
38862ac0c33Sjakob 				const dname_type* src,
38962ac0c33Sjakob 				const dname_type* dest);
39062ac0c33Sjakob 
391d3fecca9Ssthen /** Convert uncompressed wireformat dname to a string */
392d3fecca9Ssthen char* wiredname2str(const uint8_t* dname);
393d3fecca9Ssthen /** convert uncompressed label to string */
394d3fecca9Ssthen char* wirelabel2str(const uint8_t* label);
395d3fecca9Ssthen /** check if two uncompressed dnames of the same total length are equal */
396d3fecca9Ssthen int dname_equal_nocase(uint8_t* a, uint8_t* b, uint16_t len);
3970c2b6c02Sjakob 
3983efee2e1Sflorian #endif /* DNAME_H */
399