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
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
|
/*!
* \file packet.h
*
* \author Lubos Slovak <lubos.slovak@nic.cz>
*
* \brief Structure for holding DNS packet data and metadata.
*
* \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_PACKET_H_
#define _KNOT_PACKET_H_
#include <stdint.h>
#include <string.h>
#include "libknot/dname.h"
#include "libknot/rrset.h"
#include "libknot/edns.h"
#include "libknot/zone/node.h"
#include "libknot/zone/zone.h"
/*----------------------------------------------------------------------------*/
/* How many RRs pointers to alloc in one step. */
#define RRSET_ALLOC_STEP 8
struct knot_wildcard_nodes {
const knot_node_t **nodes; /*!< Wildcard nodes from CNAME processing. */
const knot_dname_t **snames; /*!< SNAMEs related to the nodes. */
short count; /*!< Count of items in the previous arrays. */
short max; /*!< Capacity of the structure (allocated). */
};
typedef struct knot_wildcard_nodes knot_wildcard_nodes_t;
/*----------------------------------------------------------------------------*/
/* Maximum number of compressed names. */
#define COMPR_MAXLEN 64
/* Volatile portion of the compression table. */
#define COMPR_VOLATILE (COMPR_MAXLEN / 4)
#define COMPR_FIXEDLEN (COMPR_MAXLEN - COMPR_VOLATILE)
/* Compression table pointer. */
typedef struct {
uint16_t off; /*!< Packet data offset. */
uint8_t lbcount; /*!< Dname label count. */
} knot_compr_ptr_t;
/*----------------------------------------------------------------------------*/
/*!
* \brief Structure representing a DNS packet.
*/
struct knot_packet {
const knot_rrset_t **answer; /*!< Answer RRSets. */
const knot_rrset_t **authority; /*!< Authority RRSets. */
const knot_rrset_t **additional; /*!< Additional RRSets. */
short an_rrsets; /*!< Count of Answer RRSets in the response. */
short ns_rrsets; /*!< Count of Authority RRSets in the response. */
short ar_rrsets; /*!< Count of Additional RRSets in the response. */
short max_an_rrsets; /*!< Allocated space for Answer RRsets. */
short max_ns_rrsets; /*!< Allocated space for Authority RRsets. */
short max_ar_rrsets; /*!< Allocated space for Additional RRsets. */
knot_opt_rr_t opt_rr; /*!< OPT RR included in the packet. */
uint8_t *wireformat; /*!< Wire format of the packet. */
size_t parsed;
uint16_t parsed_an;
uint16_t parsed_ns;
uint16_t parsed_ar;
uint8_t *qname;
uint8_t qname_size; /*!< QNAME size. */
size_t size; /*!< Current wire size of the packet. */
size_t max_size; /*!< Maximum allowed size of the packet. */
/*! \brief Information needed for compressing domain names in packet. */
knot_compr_ptr_t compression[COMPR_MAXLEN];
/*! \brief Wildcard nodes to be processed for NSEC/NSEC3. */
knot_wildcard_nodes_t wildcard_nodes;
/*! \brief RRSets to be destroyed with the packet structure. */
const knot_rrset_t **tmp_rrsets;
short tmp_rrsets_count; /*!< Count of temporary RRSets. */
short tmp_rrsets_max; /*!< Allocated space for temporary RRSets. */
struct knot_packet *query; /*!< Associated query. */
size_t tsig_size; /*!< Space to reserve for the TSIG RR. */
knot_rrset_t *tsig_rr; /*!< TSIG RR stored in the packet. */
uint16_t flags; /*!< Packet flags. */
const knot_zone_t *zone; /*!< Associated zone. */
mm_ctx_t mm; /*!< Memory allocation context. */
};
typedef struct knot_packet knot_packet_t;
/*----------------------------------------------------------------------------*/
/*!
* \brief Packet flags.
*/
enum {
KNOT_PF_NULL = 0 << 0, /*!< No flags. */
KNOT_PF_WILDCARD = 1 << 1, /*!< Query to wildcard name. */
KNOT_PF_FREE_WIRE = 1 << 2, /*!< Free wire. */
KNOT_PF_NOTRUNC = 1 << 3, /*!< Don't truncate. */
KNOT_PF_CHECKDUP = 1 << 4 /*!< Check for duplicates. */
};
/*----------------------------------------------------------------------------*/
/*! \brief Flags which control packet parsing. */
typedef enum {
// Don't add duplicate rdata to rrset.
KNOT_PACKET_DUPL_NO_MERGE = 1,
// Skip RR if RRSet is not empty
KNOT_PACKET_DUPL_SKIP = 2
} knot_packet_flag_t;
/*----------------------------------------------------------------------------*/
/*!
* \brief Creates new empty packet structure.
*
* \return New packet structure or NULL if an error occured.
*/
knot_packet_t *knot_packet_new();
/*!
* \brief Memory managed version of new packet create.
*/
knot_packet_t *knot_packet_new_mm(mm_ctx_t *mm);
/*!
* \brief Parses the DNS packet from wire format.
*
* \param packet Packet structure to parse into.
* \param wireformat Wire format of the DNS packet.
* \param size Size of the wire format in bytes.
* \param question_only Set to <> 0 if you do not want to parse the whole
* packet. In such case the parsing will end after the
* Question section. Set to 0 to parse the whole packet.
* \param flags Can control packet processing.
*
* \retval KNOT_EOK
*/
int knot_packet_parse_from_wire(knot_packet_t *packet,
const uint8_t *wireformat, size_t size,
int question_only, knot_packet_flag_t flags);
int knot_packet_parse_rest(knot_packet_t *packet, knot_packet_flag_t flags);
int knot_packet_parse_next_rr_answer(knot_packet_t *packet,
knot_rrset_t **rr);
int knot_packet_parse_next_rr_additional(knot_packet_t *packet,
knot_rrset_t **rr);
size_t knot_packet_size(const knot_packet_t *packet);
size_t knot_packet_max_size(const knot_packet_t *packet);
/*! \brief Returns size of the wireformat of Header and Question sections. */
size_t knot_packet_question_size(const knot_packet_t *packet);
size_t knot_packet_parsed(const knot_packet_t *packet);
/*!
* \brief Sets the maximum size of the packet and allocates space for wire
* format (if needed).
*
* This function also allocates space for the wireformat of the packet, if
* the given max size is larger than the current maximum size of the packet
* and copies the current wireformat over to the new space.
*
* \warning Do not call this function if you are not completely sure that the
* current wire format of the packet fits into the new space.
* It does not update the current size of the wire format, so the
* produced packet may be larger than the given max size.
*
* \param packet Packet to set the maximum size of.
* \param max_size Maximum size of the packet in bytes.
*
* \retval KNOT_EOK
* \retval KNOT_EINVAL
* \retval KNOT_ENOMEM
*
* \todo Needs test.
*/
int knot_packet_set_max_size(knot_packet_t *packet, int max_size);
int knot_packet_set_size(knot_packet_t *packet, int size);
uint16_t knot_packet_id(const knot_packet_t *packet);
void knot_packet_set_random_id(knot_packet_t *packet);
/*!
* \brief Returns the OPCODE of the packet.
*
* \param packet Packet (with parsed query) to get the OPCODE from.
*
* \return OPCODE stored in the packet.
*/
uint8_t knot_packet_opcode(const knot_packet_t *packet);
/*!
* \brief Returns the QNAME from the packet.
*
* \param packet Packet (with parsed query) to get the QNAME from.
*
* \return QNAME stored in the packet.
*/
const knot_dname_t *knot_packet_qname(const knot_packet_t *packet);
/*!
* \brief Returns the QTYPE from the packet.
*
* \param packet Packet (with parsed query) to get the QTYPE from.
*
* \return QTYPE stored in the packet.
*/
uint16_t knot_packet_qtype(const knot_packet_t *packet);
/*!
* \brief Set the QTYPE of the packet.
*
* \param packet Packet containing question.
* \param qtype New QTYPE for question.
*/
void knot_packet_set_qtype(knot_packet_t *packet, uint16_t qtype);
/*!
* \brief Returns the QCLASS from the packet.
*
* \param response Packet (with parsed query) to get the QCLASS from.
*
* \return QCLASS stored in the packet.
*/
uint16_t knot_packet_qclass(const knot_packet_t *packet);
int knot_packet_is_query(const knot_packet_t *packet);
const knot_packet_t *knot_packet_query(const knot_packet_t *packet);
int knot_packet_rcode(const knot_packet_t *packet);
int knot_packet_tc(const knot_packet_t *packet);
int knot_packet_qdcount(const knot_packet_t *packet);
int knot_packet_ancount(const knot_packet_t *packet);
int knot_packet_nscount(const knot_packet_t *packet);
int knot_packet_arcount(const knot_packet_t *packet);
void knot_packet_set_tsig_size(knot_packet_t *packet, size_t tsig_size);
const knot_rrset_t *knot_packet_tsig(const knot_packet_t *packet);
void knot_packet_set_tsig(knot_packet_t *packet, const knot_rrset_t *tsig_rr);
/*!
* \brief Returns number of RRSets in Answer section of the packet.
*
* \param response Packet to get the Answer RRSet count from.
*/
short knot_packet_answer_rrset_count(const knot_packet_t *packet);
/*!
* \brief Returns number of RRSets in Authority section of the packet.
*
* \param response Packet to get the Authority RRSet count from.
*/
short knot_packet_authority_rrset_count(const knot_packet_t *packet);
/*!
* \brief Returns number of RRSets in Additional section of the packet.
*
* \param response Packet to get the Additional RRSet count from.
*/
short knot_packet_additional_rrset_count(const knot_packet_t *packet);
/*!
* \brief Returns the requested Answer RRset.
*
* \param packet Packet to get the RRSet from.
* \param pos Position of the RRSet in the Answer section (RRSets are stored
* in the order they were added to the response or parsed from the
* query).
*
* \return The RRSet on position \a pos in the Answer section of \a packet
* or NULL if there is no such RRSet.
*/
const knot_rrset_t *knot_packet_answer_rrset(
const knot_packet_t *packet, short pos);
/*!
* \brief Returns the requested Authority RRset.
*
* \param packet Packet to get the RRSet from.
* \param pos Position of the RRSet in the Authority section (RRSets are stored
* in the order they were added to the response or parsed from the
* query).
*
* \return The RRSet on position \a pos in the Authority section of \a packet
* or NULL if there is no such RRSet.
*/
const knot_rrset_t *knot_packet_authority_rrset(
const knot_packet_t *packet, short pos);
/*!
* \brief Returns the requested Additional RRset.
*
* \param packet Packet to get the RRSet from.
* \param pos Position of the RRSet in the Additional section (RRSets are stored
* in the order they were added to the response or parsed from the
* query).
*
* \return The RRSet on position \a pos in the Additional section of \a packet
* or NULL if there is no such RRSet.
*/
const knot_rrset_t *knot_packet_additional_rrset(
const knot_packet_t *packet, short pos);
/*!
* \brief Checks if the packet already contains the given RRSet.
*
* It searches for the RRSet in the three lists of RRSets corresponding to
* Answer, Authority and Additional sections of the packet.
*
* \note Only pointers are compared, i.e. two instances of knot_rrset_t with
* the same data will be considered different.
*
* \param packet Packet to look for the RRSet in.
* \param rrset RRSet to look for.
*
* \retval 0 if \a resp does not contain \a rrset.
* \retval <> 0 if \a resp does contain \a rrset.
*/
int knot_packet_contains(const knot_packet_t *packet,
const knot_rrset_t *rrset,
knot_rrset_compare_type_t cmp);
/*!
* \brief Adds RRSet to the list of temporary RRSets.
*
* Temporary RRSets are fully freed when the response structure is destroyed.
*
* \param response Response to which the temporary RRSet should be added.
* \param tmp_rrset Temporary RRSet to be stored in the response.
*
* \retval KNOT_EOK
* \retval KNOT_ENOMEM
*/
int knot_packet_add_tmp_rrset(knot_packet_t *response,
knot_rrset_t *tmp_rrset);
void knot_packet_free_tmp_rrsets(knot_packet_t *pkt);
int knot_packet_question_to_wire(knot_packet_t *packet);
/*!
* \brief Converts the stored response OPT RR to wire format and adds it to
* the response wire format.
*
* \param resp Response structure.
*/
int knot_packet_edns_to_wire(knot_packet_t *packet);
/*!
* \brief Converts the packet to wire format.
*
* \param packet Packet to be converted to wire format.
* \param wire Here the wire format of the packet will be stored.
* Space for the packet will be allocated. *resp_wire must
* be set to NULL (to avoid leaks).
* \param wire_size The size of the packet in wire format will be stored here.
*
* \retval KNOT_EOK
* \retval KNOT_EINVAL
*/
int knot_packet_to_wire(knot_packet_t *packet, uint8_t **wire,
size_t *wire_size);
const uint8_t *knot_packet_wireformat(const knot_packet_t *packet);
/*!
* \brief Properly destroys the packet structure.
*
* \param response Packet to be destroyed.
*/
void knot_packet_free(knot_packet_t **packet);
/*!
* \brief Dumps the whole packet in human-readable form.
*
* \note This function is empty unless KNOT_PACKET_DEBUG is defined.
*
* \param resp Packet to dump.
*/
void knot_packet_dump(const knot_packet_t *packet);
/*!
* \brief Free all rrsets associated with packet.
*/
int knot_packet_free_rrsets(knot_packet_t *packet);
/*!
* \brief (Temporary) realloc RRs array size.
*/
int knot_packet_realloc_rrsets(const knot_rrset_t ***rrsets,
short *max_count,
mm_ctx_t *mm);
#endif /* _KNOT_PACKET_H_ */
/*! @} */
|