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
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
|
/*!
* \file dname.h
*
* \author Lubos Slovak <lubos.slovak@nic.cz>
*
* \brief Domain name structure and API for manipulating it.
*
* \addtogroup libknot
* @{
*/
/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _KNOT_DNAME_H_
#define _KNOT_DNAME_H_
#include <stdint.h>
#include <string.h>
#include "common/ref.h"
struct knot_node;
/*----------------------------------------------------------------------------*/
/*!
* \brief Structure for representing a domain name.
*
* Stores the domain name in wire format.
*
* \todo Consider restricting to FQDN only (see knot_dname_new_from_str()).
*/
struct knot_dname {
ref_t ref; /*!< Reference counting. */
uint8_t *name; /*!< Wire format of the domain name. */
/*!
* \brief Size of the domain name in octets.
* \todo Is this needed? Every dname should end with \0 or pointer.
*/
unsigned int size;
uint8_t *labels;
unsigned short label_count;
struct knot_node *node; /*!< Zone node the domain name belongs to. */
unsigned int id; /*!< ID of domain name used in zone dumping. */
};
typedef struct knot_dname knot_dname_t;
/*----------------------------------------------------------------------------*/
/*!
* \brief Creates empty dname structure (no name, no owner node).
*
* \note Newly created dname is referenced, caller is responsible for releasing
* it after use.
*
* \return Newly allocated and initialized dname structure.
*
* \todo Possibly useless.
*/
knot_dname_t *knot_dname_new();
/*!
* \brief Creates a dname structure from domain name given in presentation
* format.
*
* The resulting domain name is stored in wire format, but it may not end with
* root label (0).
*
* \note Newly created dname is referenced, caller is responsible for releasing
* it after use.
*
* \param name Domain name in presentation format (labels separated by dots).
* \param size Size of the domain name (count of characters with all dots).
* \param node Zone node the domain name belongs to. Set to NULL if not
* applicable.
*
* \return Newly allocated and initialized dname structure representing the
* given domain name.
*/
knot_dname_t *knot_dname_new_from_str(const char *name, unsigned int size,
struct knot_node *node);
/*!
* \brief Creates a dname structure from domain name given in wire format.
*
* \note The name is copied into the structure.
* \note If the given name is not a FQDN, the result will be neither.
* \note Newly created dname is referenced, caller is responsible for releasing
* it after use.
*
* \param name Domain name in wire format.
* \param size Size of the domain name in octets.
* \param node Zone node the domain name belongs to. Set to NULL if not
* applicable.
*
* \return Newly allocated and initialized dname structure representing the
* given domain name.
*
* \todo This function does not check if the given data is in correct wire
* format at all. It thus creates a invalid domain name, which if passed
* e.g. to knot_dname_to_str() may result in crash. Decide whether it
* is OK to retain this and check the data in other functions before
* calling this one, or if it should verify the given data.
*/
knot_dname_t *knot_dname_new_from_wire(const uint8_t *name,
unsigned int size,
struct knot_node *node);
knot_dname_t *knot_dname_parse_from_wire(const uint8_t *wire,
size_t *pos, size_t size,
struct knot_node *node);
/*!
* \brief Initializes domain name by the name given in wire format.
*
* \note The name is copied into the structure.
* \note If there is any name in the structure, it will be replaced.
* \note If the given name is not a FQDN, the result will be neither.
*
* \param name Domain name in wire format.
* \param size Size of the domain name in octets.
* \param node Zone node the domain name belongs to. Set to NULL if not
* applicable.
* \param target Domain name structure to initialize.
*
* \retval KNOT_EOK on success.
* \retval KNOT_ENOMEM if allocation of labels info failed.
* \retval KNOT_EBADARG if name or target is null.
*
* \todo This function does not check if the given data is in correct wire
* format at all. It thus creates a invalid domain name, which if passed
* e.g. to knot_dname_to_str() may result in crash. Decide whether it
* is OK to retain this and check the data in other functions before
* calling this one, or if it should verify the given data.
*/
int knot_dname_from_wire(const uint8_t *name, unsigned int size,
struct knot_node *node, knot_dname_t *target);
/*!
* \brief Duplicates the given domain name.
*
* \note Copied dname referense count is reset to 1, caller is responsible
* for releasing it after use.
*
* \param dname Domain name to be copied.
*
* \return New domain name which is an exact copy of \a dname.
*/
knot_dname_t *knot_dname_deep_copy(const knot_dname_t *dname);
/*!
* \brief Converts the given domain name to string representation.
*
* \note Allocates new memory, remember to free it.
*
* \param dname Domain name to be converted.
*
* \return 0-terminated string representing the given domain name in
* presentation format.
*/
char *knot_dname_to_str(const knot_dname_t *dname);
int knot_dname_to_lower(knot_dname_t *dname);
int knot_dname_to_lower_copy(const knot_dname_t *dname, char *name,
size_t size);
/*!
* \brief Returns the domain name in wire format.
*
* \param dname Domain name.
*
* \return Wire format of the domain name.
*/
const uint8_t *knot_dname_name(const knot_dname_t *dname);
/*!
* \brief Returns size of the given domain name.
*
* \param dname Domain name to get the size of.
*
* \return Size of the domain name in wire format in octets.
*/
unsigned int knot_dname_size(const knot_dname_t *dname);
unsigned int knot_dname_id(const knot_dname_t *dname);
/*!
* \brief Returns size of a part of domain name.
*
* \param dname Domain name.
* \param labels Count of labels to get the size of (counted from left).
*
* \return Size of first \a labels labels of \a dname, counted from left.
*/
uint8_t knot_dname_size_part(const knot_dname_t *dname, int labels);
/*!
* \brief Returns the zone node the domain name belongs to.
*
* \param dname Domain name to get the zone node of.
*
* \return Zone node the domain name belongs to or NULL if none.
*/
const struct knot_node *knot_dname_node(const knot_dname_t *dname,
int check_version);
struct knot_node *knot_dname_get_node(knot_dname_t *dname,
int check_version);
void knot_dname_set_node(knot_dname_t *dname, struct knot_node *node);
void knot_dname_update_node(knot_dname_t *dname);
void knot_dname_set_node(knot_dname_t *dname, struct knot_node *node);
/*!
* \brief Checks if the given domain name is a fully-qualified domain name.
*
* \param dname Domain name to check.
*
* \retval <> 0 if \a dname is a FQDN.
* \retval 0 otherwise.
*/
int knot_dname_is_fqdn(const knot_dname_t *dname);
/*!
* \brief Creates new domain name by removing leftmost label from \a dname.
*
* \note Newly created dname reference count is set to 1, caller is responsible
* for releasing it after use.
*
* \param dname Domain name to remove the first label from.
*
* \return New domain name with the same labels as \a dname, except for the
* leftmost label, which is removed.
*/
knot_dname_t *knot_dname_left_chop(const knot_dname_t *dname);
/*!
* \brief Removes leftmost label from \a dname.
*
* \param dname Domain name to remove the first label from.
*/
void knot_dname_left_chop_no_copy(knot_dname_t *dname);
/*!
* \brief Checks if one domain name is a subdomain of other.
*
* \param sub Domain name to be the possible subdomain.
* \param domain Domain name to be the possible parent domain.
*
* \retval <> 0 if \a sub is a subdomain of \a domain.
* \retval 0 otherwise.
*/
int knot_dname_is_subdomain(const knot_dname_t *sub,
const knot_dname_t *domain);
/*!
* \brief Checks if the domain name is a wildcard.
*
* \param dname Domain name to check.
*
* \retval <> 0 if \a dname is a wildcard domain name.
* \retval 0 otherwise.
*/
int knot_dname_is_wildcard(const knot_dname_t *dname);
/*!
* \brief Returns the number of labels common for the two domain names (counted
* from the rightmost label.
*
* \param dname1 First domain name.
* \param dname2 Second domain name.
*
* \return Number of labels common for the two domain names.
*/
int knot_dname_matched_labels(const knot_dname_t *dname1,
const knot_dname_t *dname2);
/*!
* \brief Returns the number of labels in the domain name.
*
* \param dname Domain name to get the label count of.
*
* \return Number of labels in \a dname.
*
* \todo Find out if this counts the root label also.
*/
int knot_dname_label_count(const knot_dname_t *dname);
/*!
* \brief Returns the size of the requested label in the domain name.
*
* \param dname Domain name to get the label size from.
* \param i Index of the label (0 is the leftmost label).
*
* \return Size of \a i-th label in \a dname (counted from left).
*/
uint8_t knot_dname_label_size(const knot_dname_t *dname, int i);
/*!
* \brief Replaces the suffix of given size in one domain name with other domain
* name.
*
* \param dname Domain name where to replace the suffix.
* \param size Size of the suffix to be replaced.
* \param suffix New suffix to be used as a replacement.
*
* \return New domain name created by replacing suffix of \a dname of size
* \a size with \a suffix.
*/
knot_dname_t *knot_dname_replace_suffix(const knot_dname_t *dname,
int size,
const knot_dname_t *suffix);
/*!
* \brief Destroys the given domain name.
*
* Frees also the data within the struct. This is somewhat different behaviour
* than that of RDATA and RRSet structures which do not deallocate their
* contents.
*
* Sets the given pointer to NULL.
*
* \param dname Domain name to be destroyed.
*/
void knot_dname_free(knot_dname_t **dname);
/*!
* \brief Compares two domain names (case insensitive).
*
* \param d1 First domain name.
* \param d2 Second domain name.
*
* \retval < 0 if \a d1 goes before \a d2 in canonical order.
* \retval > 0 if \a d1 goes after \a d2 in canonical order.
* \retval 0 if the domain names are identical.
*/
int knot_dname_compare(const knot_dname_t *d1, const knot_dname_t *d2);
/*!
* \brief Compares two domain names (case sensitive).
*
* \param d1 First domain name.
* \param d2 Second domain name.
*
* \retval < 0 if \a d1 goes before \a d2 in canonical order.
* \retval > 0 if \a d1 goes after \a d2 in canonical order.
* \retval 0 if the domain names are identical.
*/
int knot_dname_compare_cs(const knot_dname_t *d1, const knot_dname_t *d2);
/*!
* \brief Concatenates two domain names.
*
* \note Member \a node is ignored, i.e. preserved.
*
* \param d1 First domain name (will be modified).
* \param d2 Second domain name (will not be modified).
*
* \return The concatenated domain name (i.e. modified \a d1) or NULL if
* the operation is not valid (e.g. \a d1 is a FQDN).
*/
knot_dname_t *knot_dname_cat(knot_dname_t *d1, const knot_dname_t *d2);
void knot_dname_set_id(knot_dname_t *dname, unsigned int id);
unsigned int knot_dname_get_id(const knot_dname_t *dname);
/*!
* \brief Increment reference counter for dname.
*
* Function makes shallow copy (reference).
*
* \param dname Referenced dname.
*/
static inline void knot_dname_retain(knot_dname_t *dname) {
if (dname) {
ref_retain(&dname->ref);
// char *name = knot_dname_to_str(dname);
// printf("retain: %s %p %d\n", name, dname, dname->ref.count);
// free(name);
}
}
/*#define knot_dname_retain(d) \
knot_dname_retain_((d));\
if ((d))\
printf("dname_retain: %s() at %s:%d, %p refcount=%zu\n",\
__func__, __FILE__, __LINE__, d, (d)->ref.count) */
/*!
* \brief Decrement reference counter for dname.
*
* \param dname Referenced dname.
*/
static inline void knot_dname_release(knot_dname_t *dname) {
if (dname) {
// char *name = knot_dname_to_str(dname);
// printf("releasing: %p %s %d\n", dname, name, dname->ref.count - 1);
// free(name);
ref_release(&dname->ref);
}
}
/*#define knot_dname_release(d) \
if ((d))\
printf("dname_release: %s() at %s:%d, %p refcount=%zu\n",\
__func__, __FILE__, __LINE__, d, (d)->ref.count-1);\
knot_dname_release_((d)) */
#endif /* _KNOT_DNAME_H_ */
/*! @} */
|