pkt.h 9.51 KB
Newer Older
1
/*  Copyright (C) 2017 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 21 22 23
/*!
 * \file
 *
 * \brief Structure for holding DNS packet data and metadata.
 *
 * \addtogroup libknot
 * @{
 */
24

25
#pragma once
26 27 28 29

#include <stdint.h>
#include <string.h>

30
#include "libknot/consts.h"
31
#include "libknot/dname.h"
32
#include "libknot/mm_ctx.h"
33
#include "libknot/rrset.h"
34
#include "libknot/rrtype/opt.h"
35 36
#include "libknot/packet/wire.h"
#include "libknot/packet/compr.h"
37

38
/* Number of packet sections (ANSWER, AUTHORITY, ADDITIONAL). */
39
#define KNOT_PKT_SECTIONS 3
40

41 42
/* Forward decls */
struct knot_pkt;
43 44 45 46 47

/*!
 * \brief Packet flags.
 */
enum {
48
	KNOT_PF_NULL      = 0 << 0, /*!< No flags. */
49 50
	KNOT_PF_FREE      = 1 << 1, /*!< Free with packet. */
	KNOT_PF_NOTRUNC   = 1 << 2, /*!< Don't truncate. */
51
	KNOT_PF_CHECKDUP  = 1 << 3, /*!< Check for duplicates. */
52 53
	KNOT_PF_KEEPWIRE  = 1 << 4, /*!< Keep wireformat untouched when parsing. */
	KNOT_PF_NOCANON   = 1 << 5, /*!< Don't canonicalize rrsets during parsing. */
54 55
};

56
/*!
57
 * \brief Packet section.
58 59
 * Points to RRSet and RRSet info arrays in the packet.
 * This structure is required for random access to packet sections.
60
 */
61
typedef struct {
62
	struct knot_pkt *pkt; /*!< Owner. */
63 64
	uint16_t pos;         /*!< Position in the rr/rrinfo fields in packet. */
	uint16_t count;       /*!< Number of RRSets in this section. */
65
} knot_pktsection_t;
66

67
/*!
68
 * \brief Structure representing a DNS packet.
69
 */
70
typedef struct knot_pkt {
71

72 73 74 75
	uint8_t *wire;         /*!< Wire format of the packet. */
	size_t size;           /*!< Current wire size of the packet. */
	size_t max_size;       /*!< Maximum allowed size of the packet. */
	size_t parsed;         /*!< Parsed size. */
76
	uint16_t reserved;     /*!< Reserved space. */
77 78 79
	uint16_t qname_size;   /*!< QNAME size. */
	uint16_t rrset_count;  /*!< Packet RRSet count. */
	uint16_t flags;        /*!< Packet flags. */
80

81
	knot_rrset_t *opt_rr;   /*!< OPT RR included in the packet. */
82
	knot_rrset_t *tsig_rr;  /*!< TSIG RR stored in the packet. */
83

84 85 86 87 88 89
	/* TSIG RR position in the wire (if parsed from wire). */
	struct {
		uint8_t *pos;
		size_t len;
	} tsig_wire;

90
	/* Packet sections. */
91 92
	knot_section_t current;
	knot_pktsection_t sections[KNOT_PKT_SECTIONS];
93

94
	/* Packet RRSet (meta)data. */
95 96 97
	size_t rrset_allocd;
	knot_rrinfo_t *rr_info;
	knot_rrset_t *rr;
98

99
	knot_mm_t mm; /*!< Memory allocation context. */
100
} knot_pkt_t;
101

102 103 104 105 106 107 108 109 110 111 112
/*!
 * \brief Create new packet over existing memory, or allocate new from memory context.
 *
 * \note Packet is allocated from given memory context.
 *
 * \param wire If NULL, memory of 'len' size shall be allocated.
 *        Otherwise pointer is used for the wire format of the packet.
 * \param len Wire format length.
 * \param mm Memory context (NULL for default).
 * \return New packet or NULL.
 */
113
knot_pkt_t *knot_pkt_new(void *wire, uint16_t len, knot_mm_t *mm);
114

115 116 117 118 119
/*!
 * \brief Copy packet.
 *
 * \note Current implementation is not very efficient, as it re-parses the wire.
 *
120 121
 * \param dst Target packet.
 * \param src Source packet.
122 123 124
 *
 * \return new packet or NULL
 */
125
int knot_pkt_copy(knot_pkt_t *dst, const knot_pkt_t *src);
126

127 128 129 130 131 132 133 134 135
/*!
 * \brief Initialized response from query packet.
 *
 * \note Question is not checked, it is expected to be checked already.
 *
 * \param pkt Given packet.
 * \param query Query.
 * \return KNOT_EOK, KNOT_EINVAL, KNOT_ESPACE
 */
136
int knot_pkt_init_response(knot_pkt_t *pkt, const knot_pkt_t *query);
137

138 139 140
/*! \brief Clear packet payload and free allocated data. */
void knot_pkt_clear_payload(knot_pkt_t *pkt);

141
/*! \brief Reinitialize packet for another use. */
142
void knot_pkt_clear(knot_pkt_t *pkt);
143

144
/*! \brief Begone you foul creature of the underworld. */
145 146
void knot_pkt_free(knot_pkt_t **pkt);

147 148 149 150 151 152 153 154
/*!
 * \brief Reserve an arbitrary amount of space in the packet.
 *
 * \return KNOT_EOK
 * \return KNOT_ERANGE if size can't be reserved
 */
int knot_pkt_reserve(knot_pkt_t *pkt, uint16_t size);

155 156 157 158 159 160 161 162
/*!
 * \brief Reclaim reserved size.
 *
 * \return KNOT_EOK
 * \return KNOT_ERANGE if size can't be reclaimed
 */
int knot_pkt_reclaim(knot_pkt_t *pkt, uint16_t size);

163 164 165
/*
 * Packet QUESTION accessors.
 */
166
/*! \todo Documentation */
167
uint16_t knot_pkt_question_size(const knot_pkt_t *pkt);
168 169

/*! \todo Documentation */
170
const knot_dname_t *knot_pkt_qname(const knot_pkt_t *pkt);
171 172

/*! \todo Documentation */
173
uint16_t knot_pkt_qtype(const knot_pkt_t *pkt);
174 175

/*! \todo Documentation */
176 177 178 179 180
uint16_t knot_pkt_qclass(const knot_pkt_t *pkt);

/*
 * Packet writing API.
 */
181

182
/*!
183
 * \brief Begin reading/writing packet section.
184
 *
185 186 187 188
 * \note You must proceed in the natural order (ANSWER, AUTHORITY, ADDITIONAL).
 *
 * \param pkt
 * \param section_id
189
 * \return KNOT_EOK or KNOT_EINVAL
190
 */
191
int knot_pkt_begin(knot_pkt_t *pkt, knot_section_t section_id);
192 193 194 195 196

/*!
 * \brief Put QUESTION in the packet.
 *
 * \note Since we support QD=1 only, QUESTION is a special type of packet section.
197
 * \note Must not be used after putting RRsets into the packet.
198 199 200 201 202 203 204
 *
 * \param pkt
 * \param qname
 * \param qclass
 * \param qtype
 * \return KNOT_EOK or various errors
 */
205 206
int knot_pkt_put_question(knot_pkt_t *pkt, const knot_dname_t *qname,
                          uint16_t qclass, uint16_t qtype);
207 208 209 210 211 212 213 214

/*!
 * \brief Put RRSet into packet.
 *
 * \note See compr.h for description on how compression hints work.
 * \note Available flags: PF_FREE, KNOT_PF_CHECKDUP, KNOT_PF_NOTRUNC
 *
 * \param pkt
215 216
 * \param compr_hint Compression hint, see enum knot_compr_hint or absolute
 *                   position.
217
 * \param rr Given RRSet.
218 219
 * \param flags RRSet flags (set PF_FREE if you want RRSet to be freed with the
 *              packet).
220 221
 * \return KNOT_EOK, KNOT_ESPACE, various errors
 */
222 223
int knot_pkt_put(knot_pkt_t *pkt, uint16_t compr_hint, const knot_rrset_t *rr,
                 uint16_t flags);
224

225
/*! \brief Get description of the given packet section. */
226 227 228
const knot_pktsection_t *knot_pkt_section(const knot_pkt_t *pkt,
                                          knot_section_t section_id);

229 230
/*! \brief Get RRSet from the packet section. */
const knot_rrset_t *knot_pkt_rr(const knot_pktsection_t *section, uint16_t i);
231 232 233 234

/*! \brief Get RRSet offset in the packet wire. */
uint16_t knot_pkt_rr_offset(const knot_pktsection_t *section, uint16_t i);

235 236 237 238 239 240 241 242 243 244
/*
 * Packet parsing API.
 */

/*!
 * \brief Parse both packet question and payload.
 *
 * Parses both QUESTION and all packet sections,
 * includes semantic checks over specific RRs (TSIG, OPT).
 *
245 246
 * \note For KNOT_PF_KEEPWIRE see note for \fn knot_pkt_parse_rr
 *
247
 * \param pkt Given packet.
248
 * \param flags Parsing flags (allowed KNOT_PF_KEEPWIRE)
249 250
 * \return KNOT_EOK, KNOT_EMALF and other errors
 */
251
int knot_pkt_parse(knot_pkt_t *pkt, unsigned flags);
252

253 254 255
/*!
 * \brief Parse packet header and a QUESTION section.
 */
256
int knot_pkt_parse_question(knot_pkt_t *pkt);
257 258 259 260

/*!
 * \brief Parse single resource record.
 *
261 262 263
 * \note When KNOT_PF_KEEPWIRE is set, TSIG RR is not stripped from the wire
 *       and is processed as any other RR.
 *
264 265 266 267
 * \param pkt
 * \param flags
 * \return KNOT_EOK, KNOT_EFEWDATA if not enough data or various errors
 */
268
int knot_pkt_parse_rr(knot_pkt_t *pkt, unsigned flags);
269

270 271 272 273 274 275 276 277 278
/*!
 * \brief Parse current packet section.
 *
 * \note For KNOT_PF_KEEPWIRE see note for \fn knot_pkt_parse_rr
 *
 * \param pkt
 * \param flags
 * \return KNOT_EOK, KNOT_EFEWDATA if not enough data or various errors
 */
279
int knot_pkt_parse_section(knot_pkt_t *pkt, unsigned flags);
280

281 282 283 284 285 286 287 288 289
/*!
 * \brief Parse whole packet payload.
 *
 * \note For KNOT_PF_KEEPWIRE see note for \fn knot_pkt_parse_rr
 *
 * \param pkt
 * \param flags
 * \return KNOT_EOK, KNOT_EFEWDATA if not enough data or various errors
 */
290
int knot_pkt_parse_payload(knot_pkt_t *pkt, unsigned flags);
291

292
/*!
293
 * \brief Get packet extended RCODE.
294
 *
295 296
 * Extended RCODE is created by considering TSIG RCODE, EDNS RCODE and
 * DNS Header RCODE. (See RFC 6895, Section 2.3).
297 298 299
 *
 * \param pkt Packet to get the response code from.
 *
300
 * \return Whole extended RCODE (0 if pkt == NULL).
301
 */
302 303 304 305 306 307 308 309 310 311 312 313
uint16_t knot_pkt_ext_rcode(const knot_pkt_t *pkt);

/*!
 * \brief Get packet extended RCODE name.
 *
 * The packet parameter is important as the name depends on TSIG.
 *
 * \param pkt Packet to get the response code from.
 *
 * \return RCODE name (or empty string if not known).
 */
const char *knot_pkt_ext_rcode_name(const knot_pkt_t *pkt);
314

315
/*!
Lubos Slovak's avatar
Lubos Slovak committed
316
 * \brief Checks if there is an OPT RR in the packet.
317
 */
Lubos Slovak's avatar
Lubos Slovak committed
318
static inline bool knot_pkt_has_edns(const knot_pkt_t *pkt)
319
{
Lubos Slovak's avatar
Lubos Slovak committed
320
	return pkt != NULL && pkt->opt_rr != NULL;
321
}
322

323
/*!
324
 * \brief Checks if TSIG is present.
325
 */
Lubos Slovak's avatar
Lubos Slovak committed
326
static inline bool knot_pkt_has_tsig(const knot_pkt_t *pkt)
327 328 329 330
{
	return pkt && pkt->tsig_rr;
}

331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
/*!
 * \brief Checks if DO bit is set in the packet's OPT RR.
 */
static inline bool knot_pkt_has_dnssec(const knot_pkt_t *pkt)
{
	return knot_pkt_has_edns(pkt) && knot_edns_do(pkt->opt_rr);
}

/*!
 * \brief Checks if there is an NSID OPTION in the packet's OPT RR.
 */
static inline bool knot_pkt_has_nsid(const knot_pkt_t *pkt)
{
	return knot_pkt_has_edns(pkt)
	       && knot_edns_has_option(pkt->opt_rr, KNOT_EDNS_OPTION_NSID);
}

348
/*! @} */