summaryrefslogtreecommitdiffstats
path: root/src/libknot/packet/wire.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/libknot/packet/wire.h')
-rw-r--r--src/libknot/packet/wire.h1053
1 files changed, 1053 insertions, 0 deletions
diff --git a/src/libknot/packet/wire.h b/src/libknot/packet/wire.h
new file mode 100644
index 0000000..630cd83
--- /dev/null
+++ b/src/libknot/packet/wire.h
@@ -0,0 +1,1053 @@
+/* Copyright (C) 2024 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 <https://www.gnu.org/licenses/>.
+ */
+
+/*!
+ * \file
+ *
+ * \brief Functions for manipulating and parsing raw data in DNS packets.
+ *
+ * \addtogroup wire
+ * @{
+ */
+
+#pragma once
+
+#include <assert.h>
+#include <stdint.h>
+
+#include "libknot/attribute.h"
+#include "libknot/wire.h"
+
+/*! \brief Offset of DNS header fields in wireformat. */
+enum knot_wire_offsets {
+ KNOT_WIRE_OFFSET_ID = 0,
+ KNOT_WIRE_OFFSET_FLAGS1 = 2,
+ KNOT_WIRE_OFFSET_FLAGS2 = 3,
+ KNOT_WIRE_OFFSET_QDCOUNT = 4,
+ KNOT_WIRE_OFFSET_ANCOUNT = 6,
+ KNOT_WIRE_OFFSET_NSCOUNT = 8,
+ KNOT_WIRE_OFFSET_ARCOUNT = 10
+};
+
+/*! \brief Minimum size for some parts of the DNS packet. */
+enum knot_wire_sizes {
+ KNOT_WIRE_HEADER_SIZE = 12,
+ KNOT_WIRE_QUESTION_MIN_SIZE = 5,
+ KNOT_WIRE_RR_MIN_SIZE = 11,
+ KNOT_WIRE_MIN_PKTSIZE = 512,
+ KNOT_WIRE_MAX_PKTSIZE = 65535,
+ KNOT_WIRE_MAX_PAYLOAD = KNOT_WIRE_MAX_PKTSIZE
+ - KNOT_WIRE_HEADER_SIZE
+ - KNOT_WIRE_QUESTION_MIN_SIZE
+};
+
+/*
+ * Packet header manipulation functions.
+ */
+
+/*!
+ * \brief Returns the ID from wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return DNS packet ID.
+ */
+static inline uint16_t knot_wire_get_id(const uint8_t *packet)
+{
+ assert(packet);
+ return knot_wire_read_u16(packet + KNOT_WIRE_OFFSET_ID);
+}
+
+/*!
+ * \brief Sets the ID to the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ * \param id DNS packet ID.
+ */
+static inline void knot_wire_set_id(uint8_t *packet, uint16_t id)
+{
+ assert(packet);
+ knot_wire_write_u16(packet + KNOT_WIRE_OFFSET_ID, id);
+}
+
+/*!
+ * \brief Returns the first byte of flags from wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return First byte of DNS flags.
+ */
+static inline uint8_t knot_wire_get_flags1(const uint8_t *packet)
+{
+ assert(packet);
+ return *(packet + KNOT_WIRE_OFFSET_FLAGS1);
+}
+
+/*!
+ * \brief Sets the first byte of flags to the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ * \param flags1 First byte of the DNS flags.
+ */
+static inline uint8_t knot_wire_set_flags1(uint8_t *packet, uint8_t flags1)
+{
+ assert(packet);
+ return *(packet + KNOT_WIRE_OFFSET_FLAGS1) = flags1;
+}
+
+/*!
+ * \brief Returns the second byte of flags from wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return Second byte of DNS flags.
+ */
+static inline uint8_t knot_wire_get_flags2(const uint8_t *packet)
+{
+ assert(packet);
+ return *(packet + KNOT_WIRE_OFFSET_FLAGS2);
+}
+
+/*!
+ * \brief Sets the second byte of flags to the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ * \param flags2 Second byte of the DNS flags.
+ */
+static inline uint8_t knot_wire_set_flags2(uint8_t *packet, uint8_t flags2)
+{
+ assert(packet);
+ return *(packet + KNOT_WIRE_OFFSET_FLAGS2) = flags2;
+}
+
+/*!
+ * \brief Returns the QDCOUNT (count of Question entries) from wire format of
+ * the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return QDCOUNT (count of Question entries in the packet).
+ */
+static inline uint16_t knot_wire_get_qdcount(const uint8_t *packet)
+{
+ assert(packet);
+ return knot_wire_read_u16(packet + KNOT_WIRE_OFFSET_QDCOUNT);
+}
+
+/*!
+ * \brief Sets the QDCOUNT (count of Question entries) to wire format of the
+ * packet.
+ *
+ * \param packet Wire format of the packet.
+ * \param qdcount QDCOUNT (count of Question entries in the packet).
+ */
+static inline void knot_wire_set_qdcount(uint8_t *packet, uint16_t qdcount)
+{
+ assert(packet);
+ knot_wire_write_u16(packet + KNOT_WIRE_OFFSET_QDCOUNT, qdcount);
+}
+
+/*!
+ * \brief Adds to QDCOUNT.
+ */
+static inline void knot_wire_add_qdcount(uint8_t *packet, int16_t n)
+{
+ assert(packet);
+ knot_wire_write_u16(packet + KNOT_WIRE_OFFSET_QDCOUNT,
+ knot_wire_get_qdcount(packet) + n);
+}
+
+/*!
+ * \brief Returns the ANCOUNT (count of Answer entries) from wire format of
+ * the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return ANCOUNT (count of Answer entries in the packet).
+ */
+static inline uint16_t knot_wire_get_ancount(const uint8_t *packet)
+{
+ assert(packet);
+ return knot_wire_read_u16(packet + KNOT_WIRE_OFFSET_ANCOUNT);
+}
+
+/*!
+ * \brief Sets the ANCOUNT (count of Answer entries) to wire format of the
+ * packet.
+ *
+ * \param packet Wire format of the packet.
+ * \param ancount ANCOUNT (count of Answer entries in the packet).
+ */
+static inline void knot_wire_set_ancount(uint8_t *packet, uint16_t ancount)
+{
+ assert(packet);
+ knot_wire_write_u16(packet + KNOT_WIRE_OFFSET_ANCOUNT, ancount);
+}
+
+/*!
+ * \brief Adds to ANCOUNT.
+ */
+static inline void knot_wire_add_ancount(uint8_t *packet, int16_t n)
+{
+ assert(packet);
+ knot_wire_write_u16(packet + KNOT_WIRE_OFFSET_ANCOUNT,
+ knot_wire_get_ancount(packet) + n);
+}
+
+/*!
+ * \brief Returns the NSCOUNT (count of Authority entries) from wire format of
+ * the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return NSCOUNT (count of Authority entries in the packet).
+ */
+static inline uint16_t knot_wire_get_nscount(const uint8_t *packet)
+{
+ assert(packet);
+ return knot_wire_read_u16(packet + KNOT_WIRE_OFFSET_NSCOUNT);
+}
+
+/*!
+ * \brief Sets the NSCOUNT (count of Authority entries) to wire format of the
+ * packet.
+ *
+ * \param packet Wire format of the packet.
+ * \param nscount NSCOUNT (count of Authority entries in the packet).
+ */
+static inline void knot_wire_set_nscount(uint8_t *packet, uint16_t nscount)
+{
+ assert(packet);
+ knot_wire_write_u16(packet + KNOT_WIRE_OFFSET_NSCOUNT, nscount);
+}
+
+/*!
+ * \brief Adds to NSCOUNT.
+ */
+static inline void knot_wire_add_nscount(uint8_t *packet, int16_t n)
+{
+ assert(packet);
+ knot_wire_write_u16(packet + KNOT_WIRE_OFFSET_NSCOUNT,
+ knot_wire_get_nscount(packet) + n);
+}
+
+/*!
+ * \brief Returns the ARCOUNT (count of Additional entries) from wire format of
+ * the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return ARCOUNT (count of Additional entries in the packet).
+ */
+static inline uint16_t knot_wire_get_arcount(const uint8_t *packet)
+{
+ assert(packet);
+ return knot_wire_read_u16(packet + KNOT_WIRE_OFFSET_ARCOUNT);
+}
+
+/*!
+ * \brief Sets the ARCOUNT (count of Additional entries) to wire format of the
+ * packet.
+ *
+ * \param packet Wire format of the packet.
+ * \param arcount ARCOUNT (count of Additional entries in the packet).
+ */
+static inline void knot_wire_set_arcount(uint8_t *packet, uint16_t arcount)
+{
+ assert(packet);
+ knot_wire_write_u16(packet + KNOT_WIRE_OFFSET_ARCOUNT, arcount);
+}
+
+/*!
+ * \brief Adds to ARCOUNT.
+ */
+static inline void knot_wire_add_arcount(uint8_t *packet, int16_t n)
+{
+ assert(packet);
+ knot_wire_write_u16(packet + KNOT_WIRE_OFFSET_ARCOUNT,
+ knot_wire_get_arcount(packet) + n);
+}
+
+/*
+ * Packet header flags manipulation functions.
+ */
+/*! \brief Constants for DNS header flags in the first flags byte. */
+enum knot_wire_flags1_consts {
+ KNOT_WIRE_RD_MASK = (uint8_t)0x01U, /*!< RD bit mask. */
+ KNOT_WIRE_RD_SHIFT = 0, /*!< RD bit shift. */
+ KNOT_WIRE_TC_MASK = (uint8_t)0x02U, /*!< TC bit mask. */
+ KNOT_WIRE_TC_SHIFT = 1, /*!< TC bit shift. */
+ KNOT_WIRE_AA_MASK = (uint8_t)0x04U, /*!< AA bit mask. */
+ KNOT_WIRE_AA_SHIFT = 2, /*!< AA bit shift. */
+ KNOT_WIRE_OPCODE_MASK = (uint8_t)0x78U, /*!< OPCODE mask. */
+ KNOT_WIRE_OPCODE_SHIFT = 3, /*!< OPCODE shift. */
+ KNOT_WIRE_QR_MASK = (uint8_t)0x80U, /*!< QR bit mask. */
+ KNOT_WIRE_QR_SHIFT = 7 /*!< QR bit shift. */
+};
+
+/*! \brief Constants for DNS header flags in the second flags byte. */
+enum knot_wire_flags2_consts {
+ KNOT_WIRE_RCODE_MASK = (uint8_t)0x0fU, /*!< RCODE mask. */
+ KNOT_WIRE_RCODE_SHIFT = 0, /*!< RCODE shift. */
+ KNOT_WIRE_CD_MASK = (uint8_t)0x10U, /*!< CD bit mask. */
+ KNOT_WIRE_CD_SHIFT = 4, /*!< CD bit shift. */
+ KNOT_WIRE_AD_MASK = (uint8_t)0x20U, /*!< AD bit mask. */
+ KNOT_WIRE_AD_SHIFT = 5, /*!< AD bit shift. */
+ KNOT_WIRE_Z_MASK = (uint8_t)0x40U, /*!< Zero bit mask. */
+ KNOT_WIRE_Z_SHIFT = 6, /*!< Zero bit shift. */
+ KNOT_WIRE_RA_MASK = (uint8_t)0x80U, /*!< RA bit mask. */
+ KNOT_WIRE_RA_SHIFT = 7 /*!< RA bit shift. */
+};
+
+/*
+ * Functions for getting / setting / clearing flags and codes directly in packet
+ */
+
+/*!
+ * \brief Returns the RD bit from wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return Flags with only the RD bit according to its setting in the packet.
+ */
+static inline uint8_t knot_wire_get_rd(const uint8_t *packet)
+{
+ assert(packet);
+ return *(packet + KNOT_WIRE_OFFSET_FLAGS1) & KNOT_WIRE_RD_MASK;
+}
+
+/*!
+ * \brief Sets the RD bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_set_rd(uint8_t *packet)
+{
+ assert(packet);
+ *(packet + KNOT_WIRE_OFFSET_FLAGS1) |= KNOT_WIRE_RD_MASK;
+}
+
+/*!
+ * \brief Clears the RD bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_clear_rd(uint8_t *packet)
+{
+ assert(packet);
+ *(packet + KNOT_WIRE_OFFSET_FLAGS1) &= ~KNOT_WIRE_RD_MASK;
+}
+
+/*!
+ * \brief Returns the TC bit from wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return Flags with only the TC bit according to its setting in the packet.
+ */
+static inline uint8_t knot_wire_get_tc(const uint8_t *packet)
+{
+ assert(packet);
+ return *(packet + KNOT_WIRE_OFFSET_FLAGS1) & KNOT_WIRE_TC_MASK;
+}
+
+/*!
+ * \brief Sets the TC bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_set_tc(uint8_t *packet)
+{
+ assert(packet);
+ *(packet + KNOT_WIRE_OFFSET_FLAGS1) |= KNOT_WIRE_TC_MASK;
+}
+
+/*!
+ * \brief Clears the TC bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_clear_tc(uint8_t *packet)
+{
+ assert(packet);
+ *(packet + KNOT_WIRE_OFFSET_FLAGS1) &= ~KNOT_WIRE_TC_MASK;
+}
+
+/*!
+ * \brief Returns the AA bit from wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return Flags with only the AA bit according to its setting in the packet.
+ */
+static inline uint8_t knot_wire_get_aa(const uint8_t *packet)
+{
+ assert(packet);
+ return *(packet + KNOT_WIRE_OFFSET_FLAGS1) & KNOT_WIRE_AA_MASK;
+}
+
+/*!
+ * \brief Sets the AA bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_set_aa(uint8_t *packet)
+{
+ assert(packet);
+ *(packet + KNOT_WIRE_OFFSET_FLAGS1) |= KNOT_WIRE_AA_MASK;
+}
+
+/*!
+ * \brief Clears the AA bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_clear_aa(uint8_t *packet)
+{
+ assert(packet);
+ *(packet + KNOT_WIRE_OFFSET_FLAGS1) &= ~KNOT_WIRE_AA_MASK;
+}
+
+/*!
+ * \brief Returns the OPCODE from wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return OPCODE of the packet.
+ */
+static inline uint8_t knot_wire_get_opcode(const uint8_t *packet)
+{
+ assert(packet);
+ return (*(packet + KNOT_WIRE_OFFSET_FLAGS1)
+ & KNOT_WIRE_OPCODE_MASK) >> KNOT_WIRE_OPCODE_SHIFT;
+}
+
+/*!
+ * \brief Sets the OPCODE in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ * \param opcode OPCODE to set.
+ */
+static inline void knot_wire_set_opcode(uint8_t *packet, short opcode)
+{
+ assert(packet);
+ uint8_t *flags1 = packet + KNOT_WIRE_OFFSET_FLAGS1;
+ *flags1 = (*flags1 & ~KNOT_WIRE_OPCODE_MASK)
+ | ((opcode) << KNOT_WIRE_OPCODE_SHIFT);
+}
+
+/*!
+ * \brief Returns the QR bit from wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return Nonzero for responses and zero for queries.
+ */
+static inline uint8_t knot_wire_get_qr(const uint8_t *packet)
+{
+ assert(packet);
+ return *(packet + KNOT_WIRE_OFFSET_FLAGS1) & KNOT_WIRE_QR_MASK;
+}
+
+/*!
+ * \brief Sets the QR bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_set_qr(uint8_t *packet)
+{
+ assert(packet);
+ *(packet + KNOT_WIRE_OFFSET_FLAGS1) |= KNOT_WIRE_QR_MASK;
+}
+
+/*!
+ * \brief Clears the QR bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_clear_qr(uint8_t *packet)
+{
+ assert(packet);
+ *(packet + KNOT_WIRE_OFFSET_FLAGS1) &= ~KNOT_WIRE_QR_MASK;
+}
+
+/*!
+ * \brief Returns the RCODE from wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return RCODE of the packet.
+ */
+static inline uint8_t knot_wire_get_rcode(const uint8_t *packet)
+{
+ assert(packet);
+ return *(packet + KNOT_WIRE_OFFSET_FLAGS2)
+ & KNOT_WIRE_RCODE_MASK;
+}
+
+/*!
+ * \brief Sets the RCODE in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ * \param rcode RCODE to set.
+ */
+static inline void knot_wire_set_rcode(uint8_t *packet, short rcode)
+{
+ assert(packet);
+ uint8_t *flags2 = packet + KNOT_WIRE_OFFSET_FLAGS2;
+ *flags2 = (*flags2 & ~KNOT_WIRE_RCODE_MASK) | (rcode);
+}
+
+/*!
+ * \brief Returns the CD bit from wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return Flags with only the CD bit according to its setting in the packet.
+ */
+static inline uint8_t knot_wire_get_cd(const uint8_t *packet)
+{
+ assert(packet);
+ return *(packet + KNOT_WIRE_OFFSET_FLAGS2) & KNOT_WIRE_CD_MASK;
+}
+
+/*!
+ * \brief Sets the CD bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_set_cd(uint8_t *packet)
+{
+ assert(packet);
+ *(packet + KNOT_WIRE_OFFSET_FLAGS2) |= KNOT_WIRE_CD_MASK;
+}
+
+/*!
+ * \brief Clears the CD bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_clear_cd(uint8_t *packet)
+{
+ assert(packet);
+ *(packet + KNOT_WIRE_OFFSET_FLAGS2) &= ~KNOT_WIRE_CD_MASK;
+}
+
+/*!
+ * \brief Returns the AD bit from wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return Flags with only the AD bit according to its setting in the packet.
+ */
+static inline uint8_t knot_wire_get_ad(const uint8_t *packet)
+{
+ assert(packet);
+ return *(packet + KNOT_WIRE_OFFSET_FLAGS2) & KNOT_WIRE_AD_MASK;
+}
+
+/*!
+ * \brief Sets the AD bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_set_ad(uint8_t *packet)
+{
+ assert(packet);
+ *(packet + KNOT_WIRE_OFFSET_FLAGS2) |= KNOT_WIRE_AD_MASK;
+}
+
+/*!
+ * \brief Clears the AD bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_clear_ad(uint8_t *packet)
+{
+ assert(packet);
+ *(packet + KNOT_WIRE_OFFSET_FLAGS2) &= ~KNOT_WIRE_AD_MASK;
+}
+
+/*!
+ * \brief Returns the Zero bit from wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return Flags with only the Zero bit according to its setting in the packet.
+ */
+static inline uint8_t knot_wire_get_z(const uint8_t *packet)
+{
+ assert(packet);
+ return *(packet + KNOT_WIRE_OFFSET_FLAGS2) & KNOT_WIRE_Z_MASK;
+}
+
+/*!
+ * \brief Sets the Zero bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_set_z(uint8_t *packet)
+{
+ assert(packet);
+ *(packet + KNOT_WIRE_OFFSET_FLAGS2) |= KNOT_WIRE_Z_MASK;
+}
+
+/*!
+ * \brief Clears the Zero bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_clear_z(uint8_t *packet)
+{
+ assert(packet);
+ *(packet + KNOT_WIRE_OFFSET_FLAGS2) &= ~KNOT_WIRE_Z_MASK;
+}
+
+/*!
+ * \brief Returns the RA bit from wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return Flags with only the RA bit according to its setting in the packet.
+ */
+static inline uint8_t knot_wire_get_ra(const uint8_t *packet)
+{
+ assert(packet);
+ return *(packet + KNOT_WIRE_OFFSET_FLAGS2) & KNOT_WIRE_RA_MASK;
+}
+
+/*!
+ * \brief Sets the RA bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_set_ra(uint8_t *packet)
+{
+ assert(packet);
+ *(packet + KNOT_WIRE_OFFSET_FLAGS2) |= KNOT_WIRE_RA_MASK;
+}
+
+/*!
+ * \brief Clears the RA bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_clear_ra(uint8_t *packet)
+{
+ assert(packet);
+ *(packet + KNOT_WIRE_OFFSET_FLAGS2) &= ~KNOT_WIRE_RA_MASK;
+}
+
+/*
+ * Functions for getting / setting / clearing flags in flags variable
+ */
+
+/*!
+ * \brief Returns the RD bit from the first byte of flags.
+ *
+ * \param flags1 First byte of DNS header flags.
+ *
+ * \return Flags byte with only the RD bit according to its setting in
+ * \a flags1.
+ */
+static inline uint8_t knot_wire_flags_get_rd(uint8_t flags1)
+{
+ return flags1 & KNOT_WIRE_RD_MASK;
+}
+
+/*!
+ * \brief Sets the RD bit in the first byte of flags.
+ *
+ * \param flags1 First byte of DNS header flags.
+ */
+static inline void knot_wire_flags_set_rd(uint8_t *flags1)
+{
+ assert(flags1);
+ *flags1 |= KNOT_WIRE_RD_MASK;
+}
+
+/*!
+ * \brief Clears the RD bit in the first byte of flags.
+ *
+ * \param flags1 First byte of DNS header flags.
+ */
+static inline void knot_wire_flags_clear_rd(uint8_t *flags1)
+{
+ assert(flags1);
+ *flags1 &= ~KNOT_WIRE_RD_MASK;
+}
+
+/*!
+ * \brief Returns the TC bit from the first byte of flags.
+ *
+ * \param flags1 First byte of DNS header flags.
+ *
+ * \return Flags byte with only the TC bit according to its setting in
+ * \a flags1.
+ */
+static inline uint8_t knot_wire_flags_get_tc(uint8_t flags1)
+{
+ return flags1 & KNOT_WIRE_TC_MASK;
+}
+
+/*!
+ * \brief Sets the TC bit in the first byte of flags.
+ *
+ * \param flags1 First byte of DNS header flags.
+ */
+static inline void knot_wire_flags_set_tc(uint8_t *flags1)
+{
+ assert(flags1);
+ *flags1 |= KNOT_WIRE_TC_MASK;
+}
+
+/*!
+ * \brief Clears the TC bit in the first byte of flags.
+ *
+ * \param flags1 First byte of DNS header flags.
+ */
+static inline void knot_wire_flags_clear_tc(uint8_t *flags1)
+{
+ assert(flags1);
+ *flags1 &= ~KNOT_WIRE_TC_MASK;
+}
+
+/*!
+ * \brief Returns the AA bit from the first byte of flags.
+ *
+ * \param flags1 First byte of DNS header flags.
+ *
+ * \return Flags byte with only the AA bit according to its setting in
+ * \a flags1.
+ */
+static inline uint8_t knot_wire_flags_get_aa(uint8_t flags1)
+{
+ return flags1 & KNOT_WIRE_AA_MASK;
+}
+
+/*!
+ * \brief Sets the AA bit in the first byte of flags.
+ *
+ * \param flags1 First byte of DNS header flags.
+ */
+static inline void knot_wire_flags_set_aa(uint8_t *flags1)
+{
+ assert(flags1);
+ *flags1 |= KNOT_WIRE_AA_MASK;
+}
+
+/*!
+ * \brief Clears the AA bit in the first byte of flags.
+ *
+ * \param flags1 First byte of DNS header flags.
+ */
+static inline void knot_wire_flags_clear_aa(uint8_t *flags1)
+{
+ assert(flags1);
+ *flags1 &= ~KNOT_WIRE_AA_MASK;
+}
+
+/*!
+ * \brief Returns the OPCODE from the first byte of flags.
+ *
+ * \param flags1 First byte of DNS header flags.
+ *
+ * \return OPCODE
+ */
+static inline uint8_t knot_wire_flags_get_opcode(uint8_t flags1)
+{
+ return (flags1 & KNOT_WIRE_OPCODE_MASK)
+ >> KNOT_WIRE_OPCODE_SHIFT;
+}
+
+/*!
+ * \brief Sets the OPCODE in the first byte of flags.
+ *
+ * \param flags1 First byte of DNS header flags.
+ * \param opcode OPCODE to set.
+ */
+static inline void knot_wire_flags_set_opcode(uint8_t *flags1, short opcode)
+{
+ assert(flags1);
+ *flags1 = (*flags1 & ~KNOT_WIRE_OPCODE_MASK)
+ | ((opcode) << KNOT_WIRE_OPCODE_SHIFT);
+}
+
+/*!
+ * \brief Returns the QR bit from the first byte of flags.
+ *
+ * \param flags1 First byte of DNS header flags.
+ *
+ * \return Flags byte with only the QR bit according to its setting in
+ * \a flags1.
+ */
+static inline uint8_t knot_wire_flags_get_qr(uint8_t flags1)
+{
+ return flags1 & KNOT_WIRE_QR_MASK;
+}
+
+/*!
+ * \brief Sets the QR bit in the first byte of flags.
+ *
+ * \param flags1 First byte of DNS header flags.
+ */
+static inline void knot_wire_flags_set_qr(uint8_t *flags1)
+{
+ assert(flags1);
+ *flags1 |= KNOT_WIRE_QR_MASK;
+}
+
+/*!
+ * \brief Clears the QR bit in the first byte of flags.
+ *
+ * \param flags1 First byte of DNS header flags.
+ */
+static inline void knot_wire_flags_clear_qr(uint8_t *flags1)
+{
+ assert(flags1);
+ *flags1 &= ~KNOT_WIRE_QR_MASK;
+}
+
+/*!
+ * \brief Returns the RCODE from the second byte of flags.
+ *
+ * \param flags2 First byte of DNS header flags.
+ *
+ * \return RCODE
+ */
+static inline uint8_t knot_wire_flags_get_rcode(uint8_t flags2)
+{
+ return flags2 & KNOT_WIRE_RCODE_MASK;
+}
+
+/*!
+ * \brief Sets the RCODE in the second byte of flags.
+ *
+ * \param flags2 Second byte of DNS header flags.
+ * \param rcode RCODE to set.
+ */
+static inline void knot_wire_flags_set_rcode(uint8_t *flags2, short rcode)
+{
+ assert(flags2);
+ *flags2 = (*flags2 & ~KNOT_WIRE_RCODE_MASK) | (rcode);
+}
+
+/*!
+ * \brief Returns the CD bit from the second byte of flags.
+ *
+ * \param flags2 Second byte of DNS header flags.
+ *
+ * \return Flags byte with only the CD bit according to its setting in
+ * \a flags2.
+ */
+static inline uint8_t knot_wire_flags_get_cd(uint8_t flags2)
+{
+ return flags2 & KNOT_WIRE_CD_MASK;
+}
+
+/*!
+ * \brief Sets the CD bit in the second byte of flags.
+ *
+ * \param flags2 Second byte of DNS header flags.
+ */
+static inline void knot_wire_flags_set_cd(uint8_t *flags2)
+{
+ assert(flags2);
+ *flags2 |= KNOT_WIRE_CD_MASK;
+}
+
+/*!
+ * \brief Clears the CD bit in the second byte of flags.
+ *
+ * \param flags2 Second byte of DNS header flags.
+ */
+static inline void knot_wire_flags_clear_cd(uint8_t *flags2)
+{
+ assert(flags2);
+ *flags2 &= ~KNOT_WIRE_CD_MASK;
+}
+
+/*!
+ * \brief Returns the AD bit from the second byte of flags.
+ *
+ * \param flags2 Second byte of DNS header flags.
+ *
+ * \return Flags byte with only the AD bit according to its setting in
+ * \a flags2.
+ */
+static inline uint8_t knot_wire_flags_get_ad(uint8_t flags2)
+{
+ return flags2 & KNOT_WIRE_AD_MASK;
+}
+
+/*!
+ * \brief Sets the AD bit in the second byte of flags.
+ *
+ * \param flags2 Second byte of DNS header flags.
+ */
+static inline void knot_wire_flags_set_ad(uint8_t *flags2)
+{
+ assert(flags2);
+ *flags2 |= KNOT_WIRE_AD_MASK;
+}
+
+/*!
+ * \brief Clears the AD bit in the second byte of flags.
+ *
+ * \param flags2 Second byte of DNS header flags.
+ */
+static inline void knot_wire_flags_clear_ad(uint8_t *flags2)
+{
+ assert(flags2);
+ *flags2 &= ~KNOT_WIRE_AD_MASK;
+}
+
+/*!
+ * \brief Returns the Zero bit from the second byte of flags.
+ *
+ * \param flags2 Second byte of DNS header flags.
+ *
+ * \return Flags byte with only the Zero bit according to its setting in
+ * \a flags2.
+ */
+static inline uint8_t knot_wire_flags_get_z(uint8_t flags2)
+{
+ return flags2 & KNOT_WIRE_Z_MASK;
+}
+
+/*!
+ * \brief Sets the Zero bit in the second byte of flags.
+ *
+ * \param flags2 Second byte of DNS header flags.
+ */
+static inline void knot_wire_flags_set_z(uint8_t *flags2)
+{
+ assert(flags2);
+ *flags2 |= KNOT_WIRE_Z_MASK;
+}
+
+/*!
+ * \brief Clears the Zero bit in the second byte of flags.
+ *
+ * \param flags2 Second byte of DNS header flags.
+ */
+static inline void knot_wire_flags_clear_z(uint8_t *flags2)
+{
+ assert(flags2);
+ *flags2 &= ~KNOT_WIRE_Z_MASK;
+}
+
+/*!
+ * \brief Returns the RA bit from the second byte of flags.
+ *
+ * \param flags2 Second byte of DNS header flags.
+ *
+ * \return Flags byte with only the RA bit according to its setting in
+ * \a flags2.
+ */
+static inline uint8_t knot_wire_flags_get_ra(uint8_t flags2)
+{
+ return flags2 & KNOT_WIRE_RA_MASK;
+}
+
+/*!
+ * \brief Sets the RA bit in the second byte of flags.
+ *
+ * \param flags2 Second byte of DNS header flags.
+ */
+static inline void knot_wire_flags_set_ra(uint8_t *flags2)
+{
+ assert(flags2);
+ *flags2 |= KNOT_WIRE_RA_MASK;
+}
+
+/*!
+ * \brief Clears the RA bit in the second byte of flags.
+ *
+ * \param flags2 Second byte of DNS header flags.
+ */
+static inline void knot_wire_flags_clear_ra(uint8_t *flags2)
+{
+ assert(flags2);
+ *flags2 &= ~KNOT_WIRE_RA_MASK;
+}
+
+/*
+ * Pointer manipulation
+ */
+
+enum knot_wire_pointer_consts {
+ /*! \brief DNS packet pointer designation (first two bits set to 1). */
+ KNOT_WIRE_PTR = (uint8_t)0xC0,
+ /*! \brief DNS packet minimal pointer (KNOT_WIRE_PTR + 1 zero byte). */
+ KNOT_WIRE_PTR_BASE = (uint16_t)0xC000,
+ /*! \brief DNS packet maximal offset (KNOT_WIRE_BASE complement). */
+ KNOT_WIRE_PTR_MAX = (uint16_t)0x3FFF
+};
+
+static inline int knot_wire_is_pointer(const uint8_t *pos)
+{
+ return pos && ((pos[0] & KNOT_WIRE_PTR) == KNOT_WIRE_PTR);
+}
+
+/*!
+ * \brief Creates a DNS packet pointer and stores it in wire format.
+ *
+ * \param wire Beginning of the packet wire.
+ * \param pos Position where tu put the pointer.
+ * \param ptr Relative position of the item to which the pointer should point in
+ * the wire format of the packet.
+ */
+static inline void knot_wire_put_pointer(const uint8_t *wire, uint8_t *pos, uint16_t ptr)
+{
+ assert(wire + ptr < pos);
+ knot_wire_write_u16(pos, ptr); // Write pointer offset.
+ assert((pos[0] & KNOT_WIRE_PTR) == 0); // Check for maximal offset.
+ pos[0] |= KNOT_WIRE_PTR; // Add pointer mark.
+}
+
+static inline uint16_t knot_wire_get_pointer(const uint8_t *pos)
+{
+ assert(knot_wire_is_pointer(pos)); // Check pointer.
+ return (knot_wire_read_u16(pos) - KNOT_WIRE_PTR_BASE); // Return offset.
+}
+
+_pure_ _mustcheck_
+static inline const uint8_t *knot_wire_seek_label(const uint8_t *lp, const uint8_t *wire)
+{
+ while (knot_wire_is_pointer(lp)) {
+ if (!wire) {
+ return NULL;
+ }
+ const uint8_t *new_lp = wire + knot_wire_get_pointer(lp);
+ if (new_lp >= lp) {
+ assert(0);
+ return NULL;
+ }
+ lp = new_lp;
+ }
+ return lp;
+}
+
+_pure_ _mustcheck_
+static inline const uint8_t *knot_wire_next_label(const uint8_t *lp, const uint8_t *wire)
+{
+ if (!lp || !lp[0]) /* No label after final label. */
+ return NULL;
+ return knot_wire_seek_label(lp + (lp[0] + sizeof(uint8_t)), wire);
+}
+
+/*! @} */