dname.h 11.4 KB
Newer Older
1
/*  Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
Lubos Slovak's avatar
Lubos Slovak committed
2 3 4 5 6 7 8 9 10 11 12 13 14 15

    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/>.
 */
16 17 18 19 20
/*!
 * \file
 *
 * \brief Domain name structure and API for manipulating it.
 *
21
 * \addtogroup dname
22 23
 * @{
 */
24

25
#pragma once
26 27

#include <stdint.h>
28 29
#include <stdbool.h>

30
#include "libknot/attribute.h"
31
#include "libknot/mm_ctx.h"
32

33
/*! \brief Type representing a domain name in wire format. */
34
typedef uint8_t knot_dname_t;
35

36
/*!
37 38 39
 * \brief Check dname on the wire for constraints.
 *
 * If the name passes such checks, it is safe to be used in rest of the functions.
40
 *
41 42 43
 * \param name Name on the wire.
 * \param endp Name boundary.
 * \param pkt Wire.
44
 *
Daniel Salzman's avatar
Daniel Salzman committed
45
 * \retval (compressed) size of the domain name.
46 47
 * \retval KNOT_EMALF
 * \retval KNOT_ESPACE
48
 */
49
_pure_ _mustcheck_
50 51
int knot_dname_wire_check(const uint8_t *name, const uint8_t *endp,
                          const uint8_t *pkt);
52 53

/*!
54
 * \brief Parse dname from wire.
55
 *
56 57 58
 * \param pkt Message in wire format.
 * \param pos Position of the domain name on wire.
 * \param maxpos Domain name length.
59
 * \param mm Memory context.
60
 *
61
 * \return parsed domain name or NULL.
62
 */
63
_mustcheck_
64
knot_dname_t *knot_dname_parse(const uint8_t *pkt, size_t *pos, size_t maxpos,
65
                               knot_mm_t *mm);
66 67

/*!
68
 * \brief Duplicates the given domain name.
69
 *
70
 * \param name Domain name to be copied.
71
 * \param mm Memory context.
72
 *
73 74
 * \return New domain name which is an exact copy of \a dname.
 */
75
_mustcheck_
76
knot_dname_t *knot_dname_copy(const knot_dname_t *name, knot_mm_t *mm);
77 78 79

/*!
 * \brief Duplicates part of the given domain name.
80
 *
81
 * \param name Domain name to be copied.
82
 * \param len Part length.
83
 * \param mm Memory context.
Lubos Slovak's avatar
Lubos Slovak committed
84
 *
85
 * \return New domain name which is an partial copy of \a dname.
86
 */
87
_mustcheck_
88
knot_dname_t *knot_dname_copy_part(const knot_dname_t *name, unsigned len,
89
                                   knot_mm_t *mm);
90

91
/*!
92
 * \brief Copy name to wire as is, no compression pointer expansion will be done.
93
 *
94 95 96
 * \param dst Destination wire.
 * \param src Source name.
 * \param maxlen Maximum wire length.
97
 *
98
 * \return number of bytes written
99
 */
100
int knot_dname_to_wire(uint8_t *dst, const knot_dname_t *src, size_t maxlen);
101

102
/*!
103
 * \brief Write unpacked name (i.e. compression pointers expanded)
104
 *
105 106 107 108 109 110
 * \note The function is very similar to the knot_dname_to_wire(), except
 *       it expands compression pointers. E.g. you want to use knot_dname_unpack()
 *       if you copy a dname from incoming packet to some persistent storage.
 *       And you want to use knot_dname_to_wire() if you know the name is not
 *       compressed or you want to copy it 1:1.
 *
111 112 113 114
 * \param dst Destination wire.
 * \param src Source name.
 * \param maxlen Maximum destination wire size.
 * \param pkt Name packet wire (for compression pointers).
115
 *
116
 * \return number of bytes written
117
 */
118 119
int knot_dname_unpack(uint8_t *dst, const knot_dname_t *src,
                      size_t maxlen, const uint8_t *pkt);
120

121
/*!
122
 * \brief Converts the given domain name to its string representation.
123
 *
124
 * \note Output buffer is allocated automatically if dst is NULL.
125
 *
126 127 128
 * \param dst    Output buffer.
 * \param name   Domain name to be converted.
 * \param maxlen Output buffer length.
129
 *
130 131 132 133 134 135 136
 * \return 0-terminated string if successful, NULL if error.
 */
char *knot_dname_to_str(char *dst, const knot_dname_t *name, size_t maxlen);

/*!
 * \brief This function is a shortcut for \ref knot_dname_to_str with
 *        no output buffer parameters.
137
 */
138
_mustcheck_
139 140 141 142
static inline char *knot_dname_to_str_alloc(const knot_dname_t *name)
{
	return knot_dname_to_str(NULL, name, 0);
}
Lubos Slovak's avatar
Lubos Slovak committed
143

144
/*!
145 146
 * \brief Creates a dname structure from domain name given in presentation
 *        format.
147
 *
148 149
 * \note The resulting FQDN is stored in the wire format.
 * \note Output buffer is allocated automatically if dst is NULL.
150
 *
151 152 153 154
 * \param dst    Output buffer.
 * \param name   Domain name in presentation format (labels separated by dots,
 *               '\0' terminated).
 * \param maxlen Output buffer length.
155
 *
156
 * \return New dname if successful, NULL if error.
157
 */
158 159 160 161 162
knot_dname_t *knot_dname_from_str(uint8_t *dst, const char *name, size_t maxlen);

/*!
 * \brief This function is a shortcut for \ref knot_dname_from_str with
 *        no output buffer parameters.
163
 */
164
_mustcheck_
165 166 167 168
static inline knot_dname_t *knot_dname_from_str_alloc(const char *name)
{
	return knot_dname_from_str(NULL, name, 0);
}
169

170
/*!
171
 * \brief Convert name to lowercase.
172
 *
173 174 175
 * \note Name must not be compressed.
 *
 * \param name Domain name to be converted.
176
 *
177 178
 * \return KNOT_EOK
 * \retval KNOT_EINVAL
179
 */
180
int knot_dname_to_lower(knot_dname_t *name);
181

182
/*!
183
 * \brief Returns size of the given domain name.
184
 *
Daniel Salzman's avatar
Daniel Salzman committed
185 186 187
 * \note If the domain name is compressed, the length of not compressed part
 *       is returned.
 *
188
 * \param name Domain name to get the size of.
189
 *
Marek Vavrusa's avatar
Marek Vavrusa committed
190
 * \retval size of the domain name.
191
 * \retval 0 if invalid argument.
192
 */
193
_pure_
194
size_t knot_dname_size(const knot_dname_t *name);
195

196
/*!
197
 * \brief Returns full size of the given domain name (expanded compression ptrs).
198
 *
199
 * \param name Domain name to get the size of.
200
 * \param pkt Related packet (or NULL if unpacked)
201
 *
Daniel Salzman's avatar
Daniel Salzman committed
202
 * \retval size of the domain name.
203
 * \retval 0 if invalid argument.
204
 */
205
_pure_
206
size_t knot_dname_realsize(const knot_dname_t *name, const uint8_t *pkt);
207

208 209 210 211 212 213
/*!
 * \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.
 *
214 215
 * \retval true \a sub is a subdomain of \a domain.
 * \retval false otherwise.
216
 */
217
_pure_
218
bool knot_dname_is_sub(const knot_dname_t *sub, const knot_dname_t *domain);
219

220 221 222 223 224 225 226 227 228
/*!
 * \brief Check if the domain name is a subdomain of or equal to other.
 *
 * \param domain Domain name to be the possible parent domain.
 * \param sub Domain name to be the possible subdomain.
 *
 * \retval true \a sub us a subdomain or equal to \a domain.
 * \retval false otherwise.
 */
229
_pure_
230 231
bool knot_dname_in(const knot_dname_t *domain, const knot_dname_t *sub);

232 233 234
/*!
 * \brief Checks if the domain name is a wildcard.
 *
235
 * \param name Domain name to check.
236
 *
237 238
 * \retval true if \a dname is a wildcard domain name.
 * \retval false otherwise.
239
 */
240
_pure_
241
bool knot_dname_is_wildcard(const knot_dname_t *name);
242

243 244 245 246
/*!
 * \brief Returns the number of labels common for the two domain names (counted
 *        from the rightmost label.
 *
247 248
 * \param d1 First domain name.
 * \param d2 Second domain name.
249 250 251
 *
 * \return Number of labels common for the two domain names.
 */
252
_pure_
253
size_t knot_dname_matched_labels(const knot_dname_t *d1, const knot_dname_t *d2);
Lubos Slovak's avatar
Lubos Slovak committed
254

255 256 257 258
/*!
 * \brief Replaces the suffix of given size in one domain name with other domain
 *        name.
 *
259
 * \param name Domain name where to replace the suffix.
260
 * \param labels Size of the suffix to be replaced.
261 262 263 264 265
 * \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.
 */
266
_mustcheck_
267
knot_dname_t *knot_dname_replace_suffix(const knot_dname_t *name, unsigned labels,
268
                                        const knot_dname_t *suffix);
269

270
/*!
271 272
 * \brief Destroys the given domain name.
 *
273 274 275 276 277
 * 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.
278
 *
279
 * \param name Domain name to be destroyed.
280
 * \param mm Memory context.
281
 */
282
void knot_dname_free(knot_dname_t **name, knot_mm_t *mm);
283

284
/*!
285
 * \brief Compares two domain names by labels (case insensitive).
286 287 288 289
 *
 * \warning Since it would be hard to catch errors, because negative value
 *          is also a good result, there are assertions that expect neither
 *          d1 or d2 to be NULL.
290 291 292 293
 *
 * \param d1 First domain name.
 * \param d2 Second domain name.
 *
294 295
 * \retval < 0 if \a d1 goes before \a d2 in canonical order.
 * \retval > 0 if \a d1 goes after \a d2 in canonical order.
296 297
 * \retval 0 if the domain names are identical.
 */
298
_pure_
299 300
int knot_dname_cmp(const knot_dname_t *d1, const knot_dname_t *d2);

301 302 303
/*!
 * \brief Compares two domain names (case sensitive).
 *
304 305
 * \warning d1 and d2 must not be NULL.
 *
306 307 308
 * \param d1 First domain name.
 * \param d2 Second domain name.
 *
309 310
 * \retval true if the domain names are identical
 * \retval false if the domain names are NOT identical
311
 */
312
_pure_
313
bool knot_dname_is_equal(const knot_dname_t *d1, const knot_dname_t *d2);
314

315 316 317 318 319 320 321 322 323 324 325 326 327 328
/*!
 * \brief Compares two domain name labels (case insensitive).
 *
 * \warning label1 and label2 must not be NULL.
 *
 * \param label1  First label.
 * \param label2  Second label.
 *
 * \retval true if the labels are identical
 * \retval false if the labels are NOT identical
 */
_pure_
bool knot_dname_label_is_equal(const uint8_t *label1, const uint8_t *label2);

329 330 331
/*!
 * \brief Concatenates two domain names.
 *
332
 * \param d1 First domain name (will be modified).
333 334
 * \param d2 Second domain name (will not be modified).
 *
335
 * \return The concatenated domain name or NULL
336
 */
337
knot_dname_t *knot_dname_cat(knot_dname_t *d1, const knot_dname_t *d2);
338

339
/*!
Daniel Salzman's avatar
Daniel Salzman committed
340
 * \brief Count length of the N first labels.
341
 *
342 343 344
 * \param name Domain name.
 * \param nlabels N first labels.
 * \param pkt Related packet (or NULL if not compressed).
345
 *
346
 * \return Length of the prefix.
347
 */
348
_pure_
349
size_t knot_dname_prefixlen(const uint8_t *name, unsigned nlabels, const uint8_t *pkt);
350 351

/*!
352
 * \brief Return number of labels in the domain name.
353
 *
354 355 356 357
 * Terminal nullbyte is not counted.
 *
 * \param name Domain name.
 * \param pkt Related packet (or NULL if not compressed).
358 359
 *
 * \return Number of labels.
360
 */
361
_pure_
362
size_t knot_dname_labels(const uint8_t *name, const uint8_t *pkt);
363

364
/*!
365
 * \brief Align name end-to-end and return number of common suffix labels.
366 367 368 369 370 371
 *
 * \param d1 Domain name.
 * \param d1_labels Number of labels in d1.
 * \param d2 Domain name.
 * \param d2_labels Number of labels in d2.
 * \param wire Packet wire related to names (or NULL).
372 373 374 375 376 377 378 379 380
 */
int knot_dname_align(const uint8_t **d1, uint8_t d1_labels,
                     const uint8_t **d2, uint8_t d2_labels,
                     uint8_t *wire);

/*!
 * \brief Convert domain name from wire to lookup format.
 *
 * Formats names from rightmost label to the leftmost, separated by the lowest
381
 * possible character (\\x00). Sorting such formatted names also gives
382 383 384
 * correct canonical order (for NSEC/NSEC3).
 *
 * Example:
385 386
 * Name: lake.example.com. Wire: \\x04lake\\x07example\\x03com\\x00
 * Lookup format \\x11com\\x00example\\x00lake\\x00
387
 *
388
 * Maximum length of such a domain name is KNOT_DNAME_MAXLEN characters.
389
 *
390
 * \param dst Memory to store converted name into. dst[0] will contain the length.
391
 * \param src Source domain name.
392
 * \param pkt Source name packet (NULL if not any).
393 394 395 396
 *
 * \retval KNOT_EOK if successful
 * \retval KNOT_EINVAL on invalid parameters
 */
397
int knot_dname_lf(uint8_t *dst, const knot_dname_t *src, const uint8_t *pkt);
398

399
/*! @} */