xref: /openbsd/usr.sbin/nsd/dname.h (revision bf87c3c0)
1 /*
2  * dname.h -- Domain name handling.
3  *
4  * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
5  *
6  * See LICENSE for the license.
7  *
8  */
9 
10 #ifndef DNAME_H
11 #define DNAME_H
12 
13 #include <assert.h>
14 #include <stdio.h>
15 
16 #include "buffer.h"
17 #include "region-allocator.h"
18 #include "dns.h" /* for MAXDOMAINLEN */
19 
20 #if defined(NAMEDB_UPPERCASE) || defined(USE_NAMEDB_UPPERCASE)
21 #define DNAME_NORMALIZE        toupper
22 #else
23 #define DNAME_NORMALIZE        tolower
24 #endif
25 
26 
27 /*
28  * Domain names stored in memory add some additional information to be
29  * able to quickly index and compare by label.
30  */
31 typedef struct dname dname_type;
32 struct dname
33 {
34 	/*
35 	 * The size (in bytes) of the domain name in wire format.
36 	 */
37 	uint8_t name_size;
38 
39 	/*
40 	 * The number of labels in this domain name (including the
41 	 * root label).
42 	 */
43 	uint8_t label_count;
44 
45 	/*
46 	  uint8_t label_offsets[label_count];
47 	  uint8_t name[name_size];
48 	*/
49 };
50 
51 
52 /*
53  * Construct a new domain name based on NAME in wire format.  NAME
54  * cannot contain compression pointers.
55  *
56  * Pre: NAME != NULL.
57  */
58 const dname_type *dname_make(region_type *region, const uint8_t *name,
59 			     int normalize);
60 
61 /*
62  * Construct a new domain name based on wire format dname stored at
63  * PACKET's current position.  Compression pointers are followed.  The
64  * PACKET's current position is changed to the end of the wire format
65  * dname or set to just after the first compression pointer.
66  */
67 const dname_type *dname_make_from_packet(region_type *region,
68 					 buffer_type *packet,
69 					 int allow_pointers,
70 					 int normalize);
71 
72 /*
73  * parse wireformat from packet (following pointers) into the
74  * given buffer. Returns length in buffer or 0 on error.
75  * buffer must be MAXDOMAINLEN+1 long.
76  */
77 int dname_make_wire_from_packet(uint8_t *buf,
78 				buffer_type *packet,
79 				int allow_pointers);
80 
81 /*
82  * Construct a new domain name based on the ASCII representation NAME.
83  * If ORIGIN is not NULL and NAME is not terminated by a "." the
84  * ORIGIN is appended to the result.  NAME can contain escape
85  * sequences.
86  *
87  * Returns NULL on failure.  Otherwise a newly allocated domain name
88  * is returned.
89  *
90  * Pre: name != NULL.
91  */
92 const dname_type *dname_parse(region_type *region, const char *name);
93 
94 /*
95  * parse ascii string to wireformat domain name (without compression ptrs)
96  * returns 0 on failure, the length of the wireformat on success.
97  * the result is stored in the wirefmt which must be at least MAXDOMAINLEN
98  * in size. On failure, the wirefmt can be altered.
99  */
100 int dname_parse_wire(uint8_t* wirefmt, const char* name);
101 
102 /*
103  * Return NULL if DNAME is NULL or a copy of DNAME otherwise.
104  */
105 const dname_type *dname_copy(region_type *region, const dname_type *dname);
106 
107 
108 /*
109  * Copy the most significant LABEL_COUNT labels from dname.
110  */
111 const dname_type *dname_partial_copy(region_type *region,
112 				     const dname_type *dname,
113 				     uint8_t label_count);
114 
115 
116 /*
117  * The origin of DNAME.
118  */
119 const dname_type *dname_origin(region_type *region, const dname_type *dname);
120 
121 /*
122  * Return true if LEFT is a subdomain of RIGHT.
123  */
124 int dname_is_subdomain(const dname_type *left, const dname_type *right);
125 
126 
127 /*
128  * Offsets into NAME for each label starting with the most
129  * significant label (the root label, followed by the TLD,
130  * etc).
131  */
132 static inline const uint8_t *
dname_label_offsets(const dname_type * dname)133 dname_label_offsets(const dname_type *dname)
134 {
135 	return (const uint8_t *) ((const char *) dname + sizeof(dname_type));
136 }
137 
138 
139 /*
140  * The actual name in wire format (a sequence of label, each
141  * prefixed by a length byte, terminated by a zero length
142  * label).
143  */
144 static inline const uint8_t *
dname_name(const dname_type * dname)145 dname_name(const dname_type *dname)
146 {
147 	return (const uint8_t *) ((const char *) dname
148 				  + sizeof(dname_type)
149 				  + dname->label_count * sizeof(uint8_t));
150 }
151 
152 
153 /*
154  * Return the label for DNAME specified by LABEL_INDEX.  The first
155  * label (LABEL_INDEX == 0) is the root label, the next label is the
156  * TLD, etc.
157  *
158  * Pre: dname != NULL && label_index < dname->label_count.
159  */
160 static inline const uint8_t *
dname_label(const dname_type * dname,uint8_t label)161 dname_label(const dname_type *dname, uint8_t label)
162 {
163 	uint8_t label_index;
164 
165 	assert(dname != NULL);
166 	assert(label < dname->label_count);
167 
168 	label_index = dname_label_offsets(dname)[label];
169 	assert(label_index < dname->name_size);
170 
171 	return dname_name(dname) + label_index;
172 }
173 
174 
175 /*
176  * Compare two domain names.  The comparison defines a lexicographical
177  * ordering based on the domain name's labels, starting with the most
178  * significant label.
179  *
180  * Return < 0 if LEFT < RIGHT, 0 if LEFT == RIGHT, and > 0 if LEFT >
181  * RIGHT.  The comparison is case sensitive.
182  *
183  * Pre: left != NULL && right != NULL
184  */
185 int dname_compare(const dname_type *left, const dname_type *right);
186 
187 
188 /*
189  * Compare two labels.  The comparison defines a lexicographical
190  * ordering based on the characters in the labels.
191  *
192  * Return < 0 if LEFT < RIGHT, 0 if LEFT == RIGHT, and > 0 if LEFT >
193  * RIGHT.  The comparison is case sensitive.
194  *
195  * Pre: left != NULL && right != NULL
196  *      label_is_normal(left) && label_is_normal(right)
197  */
198 int label_compare(const uint8_t *left, const uint8_t *right);
199 
200 
201 /*
202  * Returns the number of labels that match in LEFT and RIGHT, starting
203  * with the most significant label.  Because the root label always
204  * matches, the result will always be >= 1.
205  *
206  * Pre: left != NULL && right != NULL
207  */
208 uint8_t dname_label_match_count(const dname_type *left,
209 				const dname_type *right);
210 
211 
212 /*
213  * The total size (in bytes) allocated to store DNAME.
214  *
215  * Pre: dname != NULL
216  */
217 static inline size_t
dname_total_size(const dname_type * dname)218 dname_total_size(const dname_type *dname)
219 {
220 	return (sizeof(dname_type)
221 		+ ((((size_t)dname->label_count) + ((size_t)dname->name_size))
222 		   * sizeof(uint8_t)));
223 }
224 
225 
226 /*
227  * Is LABEL a normal LABEL (not a pointer or reserved)?
228  *
229  * Pre: label != NULL;
230  */
231 static inline int
label_is_normal(const uint8_t * label)232 label_is_normal(const uint8_t *label)
233 {
234 	assert(label);
235 	return (label[0] & 0xc0) == 0;
236 }
237 
238 
239 /*
240  * Is LABEL a pointer?
241  *
242  * Pre: label != NULL;
243  */
244 static inline int
label_is_pointer(const uint8_t * label)245 label_is_pointer(const uint8_t *label)
246 {
247 	assert(label);
248 	return (label[0] & 0xc0) == 0xc0;
249 }
250 
251 
252 /*
253  * LABEL's pointer location.
254  *
255  * Pre: label != NULL && label_is_pointer(label)
256  */
257 static inline uint16_t
label_pointer_location(const uint8_t * label)258 label_pointer_location(const uint8_t *label)
259 {
260 	assert(label);
261 	assert(label_is_pointer(label));
262 	return ((uint16_t) (label[0] & ~0xc0) << 8) | (uint16_t) label[1];
263 }
264 
265 
266 /*
267  * Length of LABEL.
268  *
269  * Pre: label != NULL && label_is_normal(label)
270  */
271 static inline uint8_t
label_length(const uint8_t * label)272 label_length(const uint8_t *label)
273 {
274 	assert(label);
275 	assert(label_is_normal(label));
276 	return label[0];
277 }
278 
279 
280 /*
281  * The data of LABEL.
282  *
283  * Pre: label != NULL && label_is_normal(label)
284  */
285 static inline const uint8_t *
label_data(const uint8_t * label)286 label_data(const uint8_t *label)
287 {
288 	assert(label);
289 	assert(label_is_normal(label));
290 	return label + 1;
291 }
292 
293 
294 /*
295  * Is LABEL the root label?
296  *
297  * Pre: label != NULL
298  */
299 static inline int
label_is_root(const uint8_t * label)300 label_is_root(const uint8_t *label)
301 {
302 	assert(label);
303 	return label[0] == 0;
304 }
305 
306 
307 /*
308  * Is LABEL the wildcard label?
309  *
310  * Pre: label != NULL
311  */
312 static inline int
label_is_wildcard(const uint8_t * label)313 label_is_wildcard(const uint8_t *label)
314 {
315 	assert(label);
316 	return label[0] == 1 && label[1] == '*';
317 }
318 
319 
320 /*
321  * The next label of LABEL.
322  *
323  * Pre: label != NULL
324  *      label_is_normal(label)
325  *      !label_is_root(label)
326  */
327 static inline const uint8_t *
label_next(const uint8_t * label)328 label_next(const uint8_t *label)
329 {
330 	assert(label);
331 	assert(label_is_normal(label));
332 	assert(!label_is_root(label));
333 	return label + label_length(label) + 1;
334 }
335 
336 
337 /*
338  * Convert DNAME to its string representation.  The result points to a
339  * static buffer that is overwritten the next time this function is
340  * invoked.
341  *
342  * If ORIGIN is provided and DNAME is a subdomain of ORIGIN the dname
343  * will be represented relative to ORIGIN.
344  *
345  * Pre: dname != NULL
346  */
347 const char *dname_to_string(const dname_type *dname,
348 			    const dname_type *origin);
349 
350 /*
351  * Convert DNAME to its string representation.  The result if written
352  * to the provided buffer buf, which must be at least 5 times
353  * MAXDOMAINNAMELEN.
354  *
355  * If ORIGIN is provided and DNAME is a subdomain of ORIGIN the dname
356  * will be represented relative to ORIGIN.
357  *
358  * Pre: dname != NULL
359  */
360 const char *dname_to_string_buf(const dname_type *dname,
361                                 const dname_type *origin,
362                                 char buf[MAXDOMAINLEN * 5]);
363 
364 /*
365  * Create a dname containing the single label specified by STR
366  * followed by the root label.
367  */
368 const dname_type *dname_make_from_label(region_type *region,
369 					const uint8_t *label,
370 					const size_t length);
371 
372 
373 /*
374  * Concatenate two dnames.
375  */
376 const dname_type *dname_concatenate(region_type *region,
377 				    const dname_type *left,
378 				    const dname_type *right);
379 
380 
381 /*
382  * Perform DNAME substitution on a name, replace src with dest.
383  * Name must be a subdomain of src. The returned name is a subdomain of dest.
384  * Returns NULL if the result domain name is too long.
385  */
386 const dname_type *dname_replace(region_type* region,
387 				const dname_type* name,
388 				const dname_type* src,
389 				const dname_type* dest);
390 
391 /** Convert uncompressed wireformat dname to a string */
392 char* wiredname2str(const uint8_t* dname);
393 /** convert uncompressed label to string */
394 char* wirelabel2str(const uint8_t* label);
395 /** check if two uncompressed dnames of the same total length are equal */
396 int dname_equal_nocase(uint8_t* a, uint8_t* b, uint16_t len);
397 
398 #endif /* DNAME_H */
399