summaryrefslogtreecommitdiffstats
path: root/usr.sbin/nsd/dname.h
blob: 188ade18dddb0e8b3ab3aa76a1ba7c15d6811b6c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
/*
 * dname.h -- Domain name handling.
 *
 * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
 *
 * See LICENSE for the license.
 *
 */

#ifndef _DNAME_H_
#define _DNAME_H_

#include <assert.h>
#include <stdio.h>

#include "buffer.h"
#include "region-allocator.h"

#if defined(NAMEDB_UPPERCASE) || defined(USE_NAMEDB_UPPERCASE)
#define DNAME_NORMALIZE        toupper
#else
#define DNAME_NORMALIZE        tolower
#endif


/*
 * Domain names stored in memory add some additional information to be
 * able to quickly index and compare by label.
 */
typedef struct dname dname_type;
struct dname
{
	/*
	 * The size (in bytes) of the domain name in wire format.
	 */
	uint8_t name_size;

	/*
	 * The number of labels in this domain name (including the
	 * root label).
	 */
	uint8_t label_count;

	/*
	  uint8_t label_offsets[label_count];
	  uint8_t name[name_size];
	*/
};


/*
 * Construct a new domain name based on NAME in wire format.  NAME
 * cannot contain compression pointers.
 *
 * Pre: NAME != NULL.
 */
const dname_type *dname_make(region_type *region, const uint8_t *name,
			     int normalize);

/*
 * Construct a new domain name based on wire format dname stored at
 * PACKET's current position.  Compression pointers are followed.  The
 * PACKET's current position is changed to the end of the wire format
 * dname or set to just after the first compression pointer.
 */
const dname_type *dname_make_from_packet(region_type *region,
					 buffer_type *packet,
					 int allow_pointers,
					 int normalize);

/*
 * parse wireformat from packet (following pointers) into the
 * given buffer. Returns length in buffer or 0 on error.
 * buffer must be MAXDOMAINLEN+1 long.
 */
int dname_make_wire_from_packet(uint8_t *buf,
				buffer_type *packet,
				int allow_pointers);

/*
 * Construct a new domain name based on the ASCII representation NAME.
 * If ORIGIN is not NULL and NAME is not terminated by a "." the
 * ORIGIN is appended to the result.  NAME can contain escape
 * sequences.
 *
 * Returns NULL on failure.  Otherwise a newly allocated domain name
 * is returned.
 *
 * Pre: name != NULL.
 */
const dname_type *dname_parse(region_type *region, const char *name);

/*
 * parse ascii string to wireformat domain name (without compression ptrs)
 * returns 0 on failure, the length of the wireformat on success.
 * the result is stored in the wirefmt which must be at least MAXDOMAINLEN
 * in size. On failure, the wirefmt can be altered.
 */
int dname_parse_wire(uint8_t* wirefmt, const char* name);

/*
 * Return NULL if DNAME is NULL or a copy of DNAME otherwise.
 */
const dname_type *dname_copy(region_type *region, const dname_type *dname);


/*
 * Copy the most significant LABEL_COUNT labels from dname.
 */
const dname_type *dname_partial_copy(region_type *region,
				     const dname_type *dname,
				     uint8_t label_count);


/*
 * The origin of DNAME.
 */
const dname_type *dname_origin(region_type *region, const dname_type *dname);

/*
 * Return true if LEFT is a subdomain of RIGHT.
 */
int dname_is_subdomain(const dname_type *left, const dname_type *right);


/*
 * Offsets into NAME for each label starting with the most
 * significant label (the root label, followed by the TLD,
 * etc).
 */
static inline const uint8_t *
dname_label_offsets(const dname_type *dname)
{
	return (const uint8_t *) ((const char *) dname + sizeof(dname_type));
}


/*
 * The actual name in wire format (a sequence of label, each
 * prefixed by a length byte, terminated by a zero length
 * label).
 */
static inline const uint8_t *
dname_name(const dname_type *dname)
{
	return (const uint8_t *) ((const char *) dname
				  + sizeof(dname_type)
				  + dname->label_count * sizeof(uint8_t));
}


/*
 * Return the label for DNAME specified by LABEL_INDEX.  The first
 * label (LABEL_INDEX == 0) is the root label, the next label is the
 * TLD, etc.
 *
 * Pre: dname != NULL && label_index < dname->label_count.
 */
static inline const uint8_t *
dname_label(const dname_type *dname, uint8_t label)
{
	uint8_t label_index;

	assert(dname != NULL);
	assert(label < dname->label_count);

	label_index = dname_label_offsets(dname)[label];
	assert(label_index < dname->name_size);

	return dname_name(dname) + label_index;
}


/*
 * Compare two domain names.  The comparison defines a lexicographical
 * ordering based on the domain name's labels, starting with the most
 * significant label.
 *
 * Return < 0 if LEFT < RIGHT, 0 if LEFT == RIGHT, and > 0 if LEFT >
 * RIGHT.  The comparison is case sensitive.
 *
 * Pre: left != NULL && right != NULL
 */
int dname_compare(const dname_type *left, const dname_type *right);


/*
 * Compare two labels.  The comparison defines a lexicographical
 * ordering based on the characters in the labels.
 *
 * Return < 0 if LEFT < RIGHT, 0 if LEFT == RIGHT, and > 0 if LEFT >
 * RIGHT.  The comparison is case sensitive.
 *
 * Pre: left != NULL && right != NULL
 *      label_is_normal(left) && label_is_normal(right)
 */
int label_compare(const uint8_t *left, const uint8_t *right);


/*
 * Returns the number of labels that match in LEFT and RIGHT, starting
 * with the most significant label.  Because the root label always
 * matches, the result will always be >= 1.
 *
 * Pre: left != NULL && right != NULL
 */
uint8_t dname_label_match_count(const dname_type *left,
				const dname_type *right);


/*
 * The total size (in bytes) allocated to store DNAME.
 *
 * Pre: dname != NULL
 */
static inline size_t
dname_total_size(const dname_type *dname)
{
	return (sizeof(dname_type)
		+ ((((size_t)dname->label_count) + ((size_t)dname->name_size))
		   * sizeof(uint8_t)));
}


/*
 * Is LABEL a normal LABEL (not a pointer or reserved)?
 *
 * Pre: label != NULL;
 */
static inline int
label_is_normal(const uint8_t *label)
{
	assert(label);
	return (label[0] & 0xc0) == 0;
}


/*
 * Is LABEL a pointer?
 *
 * Pre: label != NULL;
 */
static inline int
label_is_pointer(const uint8_t *label)
{
	assert(label);
	return (label[0] & 0xc0) == 0xc0;
}


/*
 * LABEL's pointer location.
 *
 * Pre: label != NULL && label_is_pointer(label)
 */
static inline uint16_t
label_pointer_location(const uint8_t *label)
{
	assert(label);
	assert(label_is_pointer(label));
	return ((uint16_t) (label[0] & ~0xc0) << 8) | (uint16_t) label[1];
}


/*
 * Length of LABEL.
 *
 * Pre: label != NULL && label_is_normal(label)
 */
static inline uint8_t
label_length(const uint8_t *label)
{
	assert(label);
	assert(label_is_normal(label));
	return label[0];
}


/*
 * The data of LABEL.
 *
 * Pre: label != NULL && label_is_normal(label)
 */
static inline const uint8_t *
label_data(const uint8_t *label)
{
	assert(label);
	assert(label_is_normal(label));
	return label + 1;
}


/*
 * Is LABEL the root label?
 *
 * Pre: label != NULL
 */
static inline int
label_is_root(const uint8_t *label)
{
	assert(label);
	return label[0] == 0;
}


/*
 * Is LABEL the wildcard label?
 *
 * Pre: label != NULL
 */
static inline int
label_is_wildcard(const uint8_t *label)
{
	assert(label);
	return label[0] == 1 && label[1] == '*';
}


/*
 * The next label of LABEL.
 *
 * Pre: label != NULL
 *      label_is_normal(label)
 *      !label_is_root(label)
 */
static inline const uint8_t *
label_next(const uint8_t *label)
{
	assert(label);
	assert(label_is_normal(label));
	assert(!label_is_root(label));
	return label + label_length(label) + 1;
}


/*
 * Convert DNAME to its string representation.  The result points to a
 * static buffer that is overwritten the next time this function is
 * invoked.
 *
 * If ORIGIN is provided and DNAME is a subdomain of ORIGIN the dname
 * will be represented relative to ORIGIN.
 *
 * Pre: dname != NULL
 */
const char *dname_to_string(const dname_type *dname,
			    const dname_type *origin);


/*
 * Create a dname containing the single label specified by STR
 * followed by the root label.
 */
const dname_type *dname_make_from_label(region_type *region,
					const uint8_t *label,
					const size_t length);


/*
 * Concatenate two dnames.
 */
const dname_type *dname_concatenate(region_type *region,
				    const dname_type *left,
				    const dname_type *right);


/*
 * Perform DNAME substitution on a name, replace src with dest.
 * Name must be a subdomain of src. The returned name is a subdomain of dest.
 * Returns NULL if the result domain name is too long.
 */
const dname_type *dname_replace(region_type* region,
				const dname_type* name,
				const dname_type* src,
				const dname_type* dest);

/** Convert uncompressed wireformat dname to a string */
char* wiredname2str(const uint8_t* dname);
/** convert uncompressed label to string */
char* wirelabel2str(const uint8_t* label);
/** check if two uncompressed dnames of the same total length are equal */
int dname_equal_nocase(uint8_t* a, uint8_t* b, uint16_t len);

#endif /* _DNAME_H_ */