diff --git a/Knot.files b/Knot.files
index ead382f77cc630cd51b4a373840cad7c42f3e9f1..fb84e7e102e4687e1f25622306d647a2367fb8cc 100644
--- a/Knot.files
+++ b/Knot.files
@@ -229,6 +229,8 @@ src/libknot/packet/compr.c
 src/libknot/packet/compr.h
 src/libknot/packet/pkt.c
 src/libknot/packet/pkt.h
+src/libknot/packet/rrset-wire.c
+src/libknot/packet/rrset-wire.h
 src/libknot/packet/wire.h
 src/libknot/processing/process.c
 src/libknot/processing/process.h
diff --git a/src/Makefile.am b/src/Makefile.am
index c68efb99c5b7196be3c9fefea5adc95e72e5e748..81bbbe915d1d164a36a6f8fcb4829b88a0177893 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -171,6 +171,8 @@ libknot_la_SOURCES =				\
 	libknot/packet/compr.h			\
 	libknot/packet/pkt.c			\
 	libknot/packet/pkt.h			\
+	libknot/packet/rrset-wire.c		\
+	libknot/packet/rrset-wire.h		\
 	libknot/packet/wire.h			\
 	libknot/processing/process.c		\
 	libknot/processing/process.h		\
diff --git a/src/libknot/dnssec/rrset-sign.c b/src/libknot/dnssec/rrset-sign.c
index 425d61496e143f8fac8ad992bc35864dc8f6a298..c665cc0eaa446de57fecfd4ccaff37ddef4befa3 100644
--- a/src/libknot/dnssec/rrset-sign.c
+++ b/src/libknot/dnssec/rrset-sign.c
@@ -28,6 +28,7 @@
 #include "libknot/packet/wire.h"
 #include "libknot/rrset.h"
 #include "libknot/rrtype/rrsig.h"
+#include "libknot/packet/rrset-wire.h"
 
 #define RRSIG_RDATA_SIGNER_OFFSET 18
 
diff --git a/src/libknot/dnssec/sig0.c b/src/libknot/dnssec/sig0.c
index 5a9342fc0f0dcbbc0488136707f5be2f40313048..f7c36691e13208c998ed2e193399f115b8e26929 100644
--- a/src/libknot/dnssec/sig0.c
+++ b/src/libknot/dnssec/sig0.c
@@ -22,6 +22,7 @@
 #include "libknot/dnssec/sig0.h"
 #include "libknot/dnssec/sign.h"
 #include "libknot/packet/wire.h"
+#include "libknot/packet/rrset-wire.h"
 
 /*!
  * \brief Lifetime fudge of the SIG(0) packets in seconds.
diff --git a/src/libknot/packet/pkt.c b/src/libknot/packet/pkt.c
index 7720010b6f3c427832fb360460d53eec1616cdfc..cb04b33c18776a016b1c37d2233611d8ebfaafc0 100644
--- a/src/libknot/packet/pkt.c
+++ b/src/libknot/packet/pkt.c
@@ -27,6 +27,7 @@
 #include "libknot/packet/wire.h"
 #include "libknot/rrtype/tsig.h"
 #include "libknot/tsig-op.h"
+#include "libknot/packet/rrset-wire.h"
 
 /*! \brief Scan packet for RRSet existence. */
 static bool pkt_contains(const knot_pkt_t *packet,
diff --git a/src/libknot/packet/pkt.h b/src/libknot/packet/pkt.h
index 03a24b1b0bee72a20abd5ff5033df49ad9a8b482..42adf6df8e8368e61493fbb2059b112029fc12e1 100644
--- a/src/libknot/packet/pkt.h
+++ b/src/libknot/packet/pkt.h
@@ -1,7 +1,7 @@
 /*!
  * \file pkt.h
  *
- * \author Lubos Slovak <lubos.slovak@nic.cz>
+ * \author Marek Vavrusa <marek.vavrusa@nic.cz>
  *
  * \brief Structure for holding DNS packet data and metadata.
  *
diff --git a/src/libknot/packet/rrset-wire.c b/src/libknot/packet/rrset-wire.c
new file mode 100644
index 0000000000000000000000000000000000000000..8c4622b710e318838b3895b6c4e1cdd9918f1755
--- /dev/null
+++ b/src/libknot/packet/rrset-wire.c
@@ -0,0 +1,630 @@
+/*  Copyright (C) 2014 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/>.
+ */
+
+#include <assert.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "libknot/packet/rrset-wire.h"
+
+#include "libknot/consts.h"
+#include "libknot/common.h"
+#include "libknot/rrset.h"
+#include "libknot/descriptor.h"
+#include "libknot/packet/wire.h"
+#include "libknot/packet/pkt.h"
+#include "libknot/dname.h"
+
+/*!
+ * \brief Get maximal size of a domain name in a wire with given capacity.
+ */
+#define dname_max(wire_capacity) MIN(wire_capacity, KNOT_DNAME_MAXLEN)
+
+/*!
+ * \brief Get compression pointer for a given hint.
+ */
+static uint16_t compr_get_ptr(knot_compr_t *compr, int hint)
+{
+	if (compr == NULL) {
+		return 0;
+	}
+
+	return compr->rrinfo->compress_ptr[hint];
+}
+
+/*!
+ * \brief Set compression pointer for a given hint.
+ */
+static void compr_set_ptr(knot_compr_t *compr, int hint,
+                          const uint8_t *written_at, uint16_t written_size)
+{
+	if (compr == NULL) {
+		return;
+	}
+
+	assert(written_at >= compr->wire);
+
+	uint16_t offset = written_at - compr->wire;
+
+	knot_pkt_compr_hint_set(compr->rrinfo, hint, offset, written_size);
+}
+
+/*!
+ * \brief Write a fixed block of binary data to wire.
+ */
+static int write_rdata_fixed(const uint8_t **src, size_t *src_avail,
+                             uint8_t **wire, size_t *capacity,
+                             size_t size)
+{
+	assert(src && *src);
+	assert(src_avail);
+	assert(wire && *wire);
+	assert(capacity);
+
+	/* Check input/output buffer boundaries */
+
+	if (size > *src_avail) {
+		return KNOT_EMALF;
+	}
+
+	if (size > *capacity) {
+		return KNOT_ESPACE;
+	}
+
+	/* Data binary copy */
+
+	memcpy(*wire, *src, size);
+
+	/* Update buffers */
+
+	*src += size;
+	*src_avail -= size;
+
+	*wire += size;
+	*capacity -= size;
+
+	return KNOT_EOK;
+}
+
+/*!
+ * \brief Count size of NAPTR RDATA header.
+ */
+static int naptr_header_size(const uint8_t **src, size_t *src_avail)
+{
+	assert(src && *src);
+	assert(src_avail);
+
+	size_t size = 0;
+
+	/* Fixed fields size (order, preference) */
+
+	size += 2 * sizeof(uint16_t);
+
+	/* Variable fields size (flags, services, regexp) */
+
+	for (int i = 0; i < 3; i++) {
+		const uint8_t *len_ptr = *src + size;
+		if (len_ptr >= *src + *src_avail) {
+			return KNOT_EMALF;
+		}
+
+		size += 1 + *len_ptr;
+	}
+
+	return size;
+}
+
+typedef int (*dname_callback_t)(const uint8_t **, size_t *, uint8_t **,
+                                size_t *, knot_compr_t *, int, int,
+                                knot_rrset_wire_flags_t, const uint8_t *);
+
+/*!
+ * \brief Generic function from processing RDATA with de/compression of dnames.
+ */
+static int traverse_rdata(const rdata_descriptor_t *desc, const uint8_t **src,
+                          size_t *src_avail, uint8_t **wire, size_t *capacity,
+                          knot_compr_t *compr, int compr_hint,
+                          knot_rrset_wire_flags_t flags, const uint8_t *pkt_wire,
+                          dname_callback_t dname_callback)
+{
+	int ret = KNOT_EOK;
+
+	for (int i = 0; desc->block_types[i] != KNOT_RDATA_WF_END; i++) {
+		int type = desc->block_types[i];
+		size_t to_copy = 0;
+
+		switch (type) {
+		case KNOT_RDATA_WF_COMPRESSIBLE_DNAME:
+		case KNOT_RDATA_WF_DECOMPRESSIBLE_DNAME:
+		case KNOT_RDATA_WF_FIXED_DNAME:
+			ret = dname_callback(src, src_avail, wire, capacity,
+			                     compr, compr_hint, type, flags,
+			                     pkt_wire);
+			break;
+		case KNOT_RDATA_WF_NAPTR_HEADER:
+			ret = naptr_header_size(src, src_avail);
+			to_copy = ret;
+			break;
+		case KNOT_RDATA_WF_REMAINDER:
+			to_copy = *src_avail;
+			break;
+		default:
+			/* Fixed size block */
+			assert(type > 0);
+			to_copy = type;
+		}
+
+		if (to_copy > 0) {
+			ret = write_rdata_fixed(src, src_avail, wire, capacity,
+			                        to_copy);
+		}
+
+		if (ret != KNOT_EOK) {
+			return ret;
+		}
+	}
+
+	return KNOT_EOK;
+}
+
+/*- RRSet to wire ------------------------------------------------------------*/
+
+/*!
+ * \brief Write RR owner to wire.
+ */
+static int write_owner(const knot_rrset_t *rrset,
+                       uint8_t **wire, size_t *capacity,
+                       knot_compr_t *compr, knot_rrset_wire_flags_t flags)
+{
+	assert(rrset);
+	assert(wire && *wire);
+	assert(capacity);
+
+	uint16_t owner_pointer = compr_get_ptr(compr, COMPR_HINT_OWNER);
+
+	/* Check size */
+
+	size_t owner_size = 0;
+	if (owner_pointer > 0) {
+		owner_size = sizeof(uint16_t);
+	} else {
+		owner_size = knot_dname_size(rrset->owner);
+	}
+
+	if (owner_size > *capacity) {
+		return KNOT_ESPACE;
+	}
+
+	/* Write result */
+
+	if (owner_pointer > 0) {
+		knot_wire_put_pointer(*wire, owner_pointer);
+	} else {
+		int written = knot_compr_put_dname(rrset->owner, *wire,
+		                                   dname_max(*capacity), compr);
+		if (written < 0) {
+			return written;
+		}
+
+		if (flags & KNOT_RRSET_WIRE_CANONICAL) {
+			assert(compr == NULL);
+			knot_dname_to_lower(*wire);
+		}
+
+		compr_set_ptr(compr, COMPR_HINT_OWNER, *wire, written);
+		owner_size = written;
+	}
+
+	/* Update buffer */
+
+	*wire += owner_size;
+	*capacity -= owner_size;
+
+	return KNOT_EOK;
+}
+
+/*!
+ * \brief Write RR type, class, and TTL to wire.
+ */
+static int write_fixed_header(const knot_rrset_t *rrset, uint16_t rrset_index,
+                              uint8_t **wire, size_t *capacity)
+{
+	assert(rrset);
+	assert(rrset_index < rrset->rrs.rr_count);
+	assert(wire && *wire);
+	assert(capacity);
+
+	/* Check capacity */
+
+	size_t size = sizeof(uint16_t)  // type
+		    + sizeof(uint16_t)  // class
+		    + sizeof(uint32_t); // ttl
+
+	if (size > *capacity) {
+		return KNOT_ESPACE;
+	}
+
+	/* Write result */
+
+	uint32_t ttl = knot_rdata_ttl(knot_rdataset_at(&rrset->rrs, rrset_index));
+	uint8_t *write = *wire;
+
+	knot_wire_write_u16(write, rrset->type);
+	write += sizeof(uint16_t);
+	knot_wire_write_u16(write, rrset->rclass);
+	write += sizeof(uint16_t);
+	knot_wire_write_u32(write, ttl);
+	write += sizeof(uint32_t);
+	assert(write == *wire + size);
+
+	/* Update buffer */
+
+	*wire = write;
+	*capacity -= size;
+
+	return KNOT_EOK;
+}
+
+/*!
+ * \brief Compresses and stores one RDATA dname from \a src to \a dst.
+ */
+static int compress_dname(const uint8_t **src, size_t *src_avail,
+                          uint8_t **dst, size_t *dst_avail,
+                          knot_compr_t *compr, int compr_hint, int type,
+                          knot_rrset_wire_flags_t flags,
+                          const uint8_t *pkt_wire)
+{
+	assert(src && *src);
+	assert(src_avail);
+	assert(dst && *dst);
+	assert(dst_avail);
+	UNUSED(pkt_wire);
+
+	/* Different policy for compression and decompression (issue #289). */
+	bool compress = (type == KNOT_RDATA_WF_COMPRESSIBLE_DNAME);
+
+	/* Source domain name */
+
+	const knot_dname_t *dname = *src;
+	size_t dname_size = knot_dname_size(dname);
+
+	/* Output domain name */
+
+	int written = knot_compr_put_dname(dname, *dst, dname_max(*dst_avail),
+	                                   compress ? compr : NULL);
+	if (written < 0) {
+		assert(written == KNOT_ESPACE);
+		return written;
+	}
+
+	/* Post-processing */
+
+	if (flags & KNOT_RRSET_WIRE_CANONICAL) {
+		assert(compr == NULL);
+		knot_dname_to_lower(*dst);
+	}
+
+	/* Update compression hints */
+
+	if (compr_get_ptr(compr, compr_hint) == 0) {
+		compr_set_ptr(compr, compr_hint, *dst, written);
+	}
+
+	/* Update buffers */
+
+	*dst += written;
+	*dst_avail -= written;
+
+	*src += dname_size;
+	*src_avail -= dname_size;
+
+	return KNOT_EOK;
+}
+
+/*!
+ * \brief Write RDLENGTH and RDATA fields of a RR in a wire.
+ */
+static int write_rdata(const knot_rrset_t *rrset, uint16_t rrset_index,
+                       uint8_t **wire, size_t *capacity,
+                       knot_compr_t *compr, knot_rrset_wire_flags_t flags)
+{
+	assert(rrset);
+	assert(rrset_index < rrset->rrs.rr_count);
+	assert(wire && *wire);
+	assert(capacity);
+
+	const knot_rdata_t *rdata = knot_rdataset_at(&rrset->rrs, rrset_index);
+
+	/* Reserve space for RDLENGTH */
+
+	size_t rdlength_size = sizeof(uint16_t);
+	if (rdlength_size > *capacity) {
+		return KNOT_ESPACE;
+	}
+
+	uint8_t *wire_rdlength = *wire;
+	*wire += rdlength_size;
+	*capacity -= rdlength_size;
+
+	/* Write RDATA */
+
+	uint8_t *wire_rdata_begin = *wire;
+	int compr_hint = COMPR_HINT_RDATA + rrset_index;
+
+	const uint8_t *src = knot_rdata_data(rdata);
+	size_t src_avail = knot_rdata_rdlen(rdata);
+	if (src_avail > 0) {
+		/* Only write non-empty data. */
+		const rdata_descriptor_t *desc =
+			knot_get_rdata_descriptor(rrset->type);
+		int ret = traverse_rdata(desc, &src, &src_avail, wire,
+		                         capacity, compr, compr_hint, flags,
+		                         NULL, compress_dname);
+		if (ret != KNOT_EOK) {
+			return ret;
+		}
+	}
+
+	if (src_avail > 0) {
+		/* Trailing data in the message. */
+		return KNOT_EMALF;
+	}
+
+	/* Write final RDLENGTH */
+
+	size_t rdlength = *wire - wire_rdata_begin;
+	knot_wire_write_u16(wire_rdlength, rdlength);
+
+	return KNOT_EOK;
+}
+
+/*!
+ * \brief Write one RR from a RR Set to wire.
+ */
+static int write_rr(const knot_rrset_t *rrset, uint16_t rrset_index,
+                    uint8_t **wire, size_t *capacity, knot_compr_t *compr,
+                    knot_rrset_wire_flags_t flags)
+{
+	int ret;
+
+	ret = write_owner(rrset, wire, capacity, compr, flags);
+	if (ret != KNOT_EOK) {
+		return ret;
+	}
+
+	ret = write_fixed_header(rrset, rrset_index, wire, capacity);
+	if (ret != KNOT_EOK) {
+		return ret;
+	}
+
+	ret = write_rdata(rrset, rrset_index, wire, capacity, compr, flags);
+	if (ret != KNOT_EOK) {
+		return ret;
+	}
+
+	return KNOT_EOK;
+}
+
+int knot_rrset_to_wire(const knot_rrset_t *rrset, uint8_t *wire, uint16_t max_size,
+                       knot_compr_t *compr, knot_rrset_wire_flags_t flags)
+{
+	if (!rrset || !wire) {
+		return KNOT_EINVAL;
+	}
+
+	if (flags & KNOT_RRSET_WIRE_CANONICAL) {
+		compr = NULL;
+	}
+
+	uint8_t *write = wire;
+	size_t capacity = max_size;
+
+	for (uint16_t i = 0; i < rrset->rrs.rr_count; i++) {
+		int ret = write_rr(rrset, i, &write, &capacity, compr, flags);
+		if (ret != KNOT_EOK) {
+			return ret;
+		}
+	}
+
+	size_t written = write - wire;
+
+	return written;
+}
+
+/*- RRSet to wire ------------------------------------------------------------*/
+
+static bool allow_zero_rdata(const knot_rrset_t *rr, const rdata_descriptor_t *desc)
+{
+	return rr->rclass != KNOT_CLASS_IN ||  // NONE and ANY for DDNS
+	       rr->type == KNOT_RRTYPE_APL ||  // APLs can have 0 RDLENGTH
+	       desc->type_name == NULL;        // Unknown RR types can have 0 RDLENGTH
+}
+
+/*!
+ * \brief Parses and decompresses one RDATA dname from \a src to \a dst.
+ */
+static int decompress_dname(const uint8_t **src, size_t *src_avail,
+                            uint8_t **dst, size_t *dst_avail,
+                            knot_compr_t *compr, int compr_hint, int type,
+                            knot_rrset_wire_flags_t flags,
+                            const uint8_t *pkt_wire)
+{
+	assert(src && *src);
+	assert(src_avail);
+	assert(dst && *dst);
+	assert(dst_avail);
+	UNUSED(compr);
+	UNUSED(compr_hint);
+
+	/* Different policy for compression and decompression (issue #289). */
+	bool decompress = (type == KNOT_RDATA_WF_COMPRESSIBLE_DNAME
+	                   || type == KNOT_RDATA_WF_DECOMPRESSIBLE_DNAME);
+
+	int ret = knot_dname_wire_check(*src, *src + *src_avail, pkt_wire);
+	if (ret <= 0) {
+		return KNOT_EMALF;
+	}
+
+	size_t dname_size = ret;
+	int written = dname_size;
+
+	if (decompress) {
+		int ret = knot_dname_unpack(*dst, *src, *dst_avail, pkt_wire);
+		if (ret <= 0) {
+			return ret;
+		}
+		written = ret;
+	} else if (dname_size > *dst_avail) {
+		return KNOT_ESPACE;
+	} else {
+		memcpy(*dst, *src, dname_size);
+	}
+
+	/* Post-processing */
+
+	if (flags & KNOT_RRSET_WIRE_CANONICAL) {
+		knot_dname_to_lower(*dst);
+	}
+
+	/* Update buffers */
+
+	*dst += written;
+	*dst_avail -= written;
+
+	*src += dname_size;
+	*src_avail -= dname_size;
+
+	return KNOT_EOK;
+}
+
+/*!
+ * \brief Parse RDATA part of one RR from packet wireformat.
+ */
+static int parse_rdata(const uint8_t *pkt_wire, size_t *pos, size_t pkt_size,
+                       mm_ctx_t *mm, uint32_t ttl, uint16_t rdlength,
+                       knot_rrset_t *rrset)
+{
+	assert(pkt_wire);
+	assert(pos);
+	assert(rrset);
+
+	if (pkt_size - *pos < rdlength) {
+		return KNOT_EMALF;
+	}
+
+	const rdata_descriptor_t *desc = knot_get_rdata_descriptor(rrset->type);
+
+	/* Check for obsolete record. */
+	if (desc->type_name == NULL) {
+		desc = knot_get_obsolete_rdata_descriptor(rrset->type);
+	}
+
+	if (rdlength == 0) {
+		if (allow_zero_rdata(rrset, desc)) {
+			return knot_rrset_add_rdata(rrset, NULL, 0, ttl, mm);
+		} else {
+			return KNOT_EMALF;
+		}
+	}
+
+	size_t dst_avail = rdlength + KNOT_DNAME_MAXLEN;
+	uint8_t rdata_buffer[dst_avail];
+	memset(rdata_buffer, 0, dst_avail);
+
+	const uint8_t *src = pkt_wire + *pos;
+	size_t src_avail = rdlength;
+	uint8_t *dst = rdata_buffer;
+
+	int ret = traverse_rdata(desc, &src, &src_avail, &dst, &dst_avail,
+	                         NULL, 0, KNOT_RRSET_WIRE_NONE, pkt_wire,
+	                         decompress_dname);
+	if (ret != KNOT_EOK) {
+		return ret;
+	}
+
+	assert(src_avail == 0);
+	*pos += rdlength;
+
+	size_t dst_size = dst - rdata_buffer;
+	assert(dst_size == rdlength + KNOT_DNAME_MAXLEN - dst_avail);
+
+	return knot_rrset_add_rdata(rrset, rdata_buffer, dst_size, ttl, mm);
+}
+
+/*!
+ * \brief Parse header of one RR from packet wireformat.
+ */
+static int parse_header(const uint8_t *pkt_wire, size_t *pos,
+                        size_t pkt_size, mm_ctx_t *mm, knot_rrset_t *rrset,
+                        uint32_t *ttl, uint16_t *rdlen)
+{
+	assert(pkt_wire);
+	assert(pos);
+	assert(rrset);
+	assert(ttl);
+	assert(rdlen);
+
+	knot_dname_t *owner = knot_dname_parse(pkt_wire, pos, pkt_size, mm);
+	if (owner == NULL) {
+		return KNOT_EMALF;
+	}
+	knot_dname_to_lower(owner);
+
+	if (pkt_size - *pos < KNOT_RR_HEADER_SIZE) {
+		knot_dname_free(&owner, mm);
+		return KNOT_EMALF;
+	}
+
+	uint16_t type = knot_wire_read_u16(pkt_wire + *pos);
+	uint16_t rclass = knot_wire_read_u16(pkt_wire + *pos + sizeof(uint16_t));
+	*ttl = knot_wire_read_u32(pkt_wire + *pos + 2 * sizeof(uint16_t));
+	*rdlen = knot_wire_read_u16(pkt_wire + *pos + 4 * sizeof(uint16_t));
+
+	*pos += KNOT_RR_HEADER_SIZE;
+
+	if (pkt_size - *pos < *rdlen) {
+		knot_dname_free(&owner, mm);
+		return KNOT_EMALF;
+	}
+
+	knot_rrset_init(rrset, owner, type, rclass);
+
+	return KNOT_EOK;
+}
+
+int knot_rrset_rr_from_wire(const uint8_t *pkt_wire, size_t *pos,
+                            size_t pkt_size, mm_ctx_t *mm, knot_rrset_t *rrset)
+{
+	if (pkt_wire == NULL || pos == NULL || rrset == NULL) {
+		return KNOT_EINVAL;
+	}
+
+	uint32_t ttl = 0;
+	uint16_t rdlen = 0;
+	int ret = parse_header(pkt_wire, pos, pkt_size, mm, rrset, &ttl, &rdlen);
+	if (ret == KNOT_EOK) {
+		ret = parse_rdata(pkt_wire, pos, pkt_size, mm, ttl, rdlen,
+		                  rrset);
+		if (ret != KNOT_EOK) {
+			knot_rrset_clear(rrset, mm);
+		}
+	}
+
+	return ret;
+}
diff --git a/src/libknot/packet/rrset-wire.h b/src/libknot/packet/rrset-wire.h
new file mode 100644
index 0000000000000000000000000000000000000000..e06010f50eeb8a7cfe68c1c2eea4f7be4cb8cacb
--- /dev/null
+++ b/src/libknot/packet/rrset-wire.h
@@ -0,0 +1,78 @@
+/*!
+ * \file rrset.h
+ *
+ * \author Lubos Slovak <lubos.slovak@nic.cz>
+ * \author Jan Vcelak <jan.vcelak@nic.cz>
+ *
+ * \brief RRSet from/to wire conversion functions.
+ *
+ * \addtogroup libknot
+ * @{
+ */
+/*  Copyright (C) 2014 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/>.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "libknot/mempattern.h"
+#include "libknot/dname.h"
+#include "libknot/rrset.h"
+
+struct knot_compr;
+
+/*!
+ * \brief Flags controlling RR set from/to wire conversion.
+ */
+enum knot_rrset_wire_flags {
+	KNOT_RRSET_WIRE_NONE = 0,
+	KNOT_RRSET_WIRE_CANONICAL = 1 << 0,
+};
+
+typedef enum knot_rrset_wire_flags knot_rrset_wire_flags_t;
+
+/*!
+ * \brief Write RR Set content to a wire.
+ *
+ * Function accepts \ref KNOT_RRSET_WIRE_CANONICAL flag, which causes the
+ * output to be written in canonical representation.
+ *
+ * \param rrset     RRSet to be converted.
+ * \param wire      Output wire buffer.
+ * \param max_size  Capacity of wire buffer.
+ * \param compr     Compression context.
+ * \param flags     Flags controlling the output.
+ *
+ * \return Output size, negative number on error (KNOT_E*).
+ */
+int knot_rrset_to_wire(const knot_rrset_t *rrset, uint8_t *wire, uint16_t max_size,
+                       struct knot_compr *compr, knot_rrset_wire_flags_t flags);
+
+/*!
+* \brief Creates one RR from wire, stores it into \a rrset.
+*
+* \param pkt_wire    Source wire (the whole packet).
+* \param pos         Position in \a wire where to start parsing.
+* \param pkt_size    Total size of data in \a wire (size of the packet).
+* \param mm          Memory context.
+* \param rrset       Destination RRSet.
+*
+* \return KNOT_E*
+*/
+int knot_rrset_rr_from_wire(const uint8_t *pkt_wire, size_t *pos,
+                            size_t pkt_size, mm_ctx_t *mm, knot_rrset_t *rrset);
diff --git a/src/libknot/rrset.c b/src/libknot/rrset.c
index fb80d1b852ad7e34daad441cfca99dcf96f3a32e..4b6c1f6a92b86c7e94a403da3eb31c81aa25e29c 100644
--- a/src/libknot/rrset.c
+++ b/src/libknot/rrset.c
@@ -21,10 +21,11 @@
 #include <stdio.h>
 #include <stdlib.h>
 
+#include "libknot/rrset.h"
+
 #include "libknot/consts.h"
 #include "libknot/common.h"
 #include "libknot/mempattern.h"
-#include "libknot/rrset.h"
 #include "libknot/rrset-dump.h"
 #include "libknot/descriptor.h"
 #include "common/debug.h"
@@ -33,475 +34,6 @@
 #include "libknot/packet/pkt.h"
 #include "libknot/dname.h"
 
-/*!
- * \brief Get maximal size of a domain name in a wire with given capacity.
- */
-#define dname_max(wire_capacity) MIN(wire_capacity, KNOT_DNAME_MAXLEN)
-
-/*!
- * \brief Get compression pointer for a given hint.
- */
-static uint16_t compr_get_ptr(knot_compr_t *compr, int hint)
-{
-	if (compr == NULL) {
-		return 0;
-	}
-
-	return compr->rrinfo->compress_ptr[hint];
-}
-
-/*!
- * \brief Set compression pointer for a given hint.
- */
-static void compr_set_ptr(knot_compr_t *compr, int hint,
-                          const uint8_t *written_at, uint16_t written_size)
-{
-	if (compr == NULL) {
-		return;
-	}
-
-	assert(written_at >= compr->wire);
-
-	uint16_t offset = written_at - compr->wire;
-
-	knot_pkt_compr_hint_set(compr->rrinfo, hint, offset, written_size);
-}
-
-/*!
- * \brief Write RR owner to wire.
- */
-static int write_owner(const knot_rrset_t *rrset,
-                       uint8_t **wire, size_t *capacity,
-                       knot_compr_t *compr, knot_rrset_wire_flags_t flags)
-{
-	assert(rrset);
-	assert(wire && *wire);
-	assert(capacity);
-
-	uint16_t owner_pointer = compr_get_ptr(compr, COMPR_HINT_OWNER);
-
-	/* Check size */
-
-	size_t owner_size = 0;
-	if (owner_pointer > 0) {
-		owner_size = sizeof(uint16_t);
-	} else {
-		owner_size = knot_dname_size(rrset->owner);
-	}
-
-	if (owner_size > *capacity) {
-		return KNOT_ESPACE;
-	}
-
-	/* Write result */
-
-	if (owner_pointer > 0) {
-		knot_wire_put_pointer(*wire, owner_pointer);
-	} else {
-		int written = knot_compr_put_dname(rrset->owner, *wire,
-		                                   dname_max(*capacity), compr);
-		if (written < 0) {
-			return written;
-		}
-
-		if (flags & KNOT_RRSET_WIRE_CANONICAL) {
-			assert(compr == NULL);
-			knot_dname_to_lower(*wire);
-		}
-
-		compr_set_ptr(compr, COMPR_HINT_OWNER, *wire, written);
-		owner_size = written;
-	}
-
-	/* Update buffer */
-
-	*wire += owner_size;
-	*capacity -= owner_size;
-
-	return KNOT_EOK;
-}
-
-/*!
- * \brief Write RR type, class, and TTL to wire.
- */
-static int write_fixed_header(const knot_rrset_t *rrset, uint16_t rrset_index,
-                              uint8_t **wire, size_t *capacity)
-{
-	assert(rrset);
-	assert(rrset_index < rrset->rrs.rr_count);
-	assert(wire && *wire);
-	assert(capacity);
-
-	/* Check capacity */
-
-	size_t size = sizeof(uint16_t)  // type
-		    + sizeof(uint16_t)  // class
-		    + sizeof(uint32_t); // ttl
-
-	if (size > *capacity) {
-		return KNOT_ESPACE;
-	}
-
-	/* Write result */
-
-	uint32_t ttl = knot_rdata_ttl(knot_rdataset_at(&rrset->rrs, rrset_index));
-	uint8_t *write = *wire;
-
-	knot_wire_write_u16(write, rrset->type);
-	write += sizeof(uint16_t);
-	knot_wire_write_u16(write, rrset->rclass);
-	write += sizeof(uint16_t);
-	knot_wire_write_u32(write, ttl);
-	write += sizeof(uint32_t);
-	assert(write == *wire + size);
-
-	/* Update buffer */
-
-	*wire = write;
-	*capacity -= size;
-
-	return KNOT_EOK;
-}
-
-/*!
- * \brief Write a fixed block of binary data to wire.
- */
-static int write_rdata_fixed(const uint8_t **src, size_t *src_avail,
-                             uint8_t **wire, size_t *capacity,
-                             size_t size)
-{
-	assert(src && *src);
-	assert(src_avail);
-	assert(wire && *wire);
-	assert(capacity);
-
-	/* Check input/output buffer boundaries */
-
-	if (size > *src_avail) {
-		return KNOT_EMALF;
-	}
-
-	if (size > *capacity) {
-		return KNOT_ESPACE;
-	}
-
-	/* Data binary copy */
-
-	memcpy(*wire, *src, size);
-
-	/* Update buffers */
-
-	*src += size;
-	*src_avail -= size;
-
-	*wire += size;
-	*capacity -= size;
-
-	return KNOT_EOK;
-}
-
-/*!
- * \brief Count size of NAPTR RDATA header.
- */
-static int naptr_header_size(const uint8_t **src, size_t *src_avail)
-{
-	assert(src && *src);
-	assert(src_avail);
-
-	size_t size = 0;
-
-	/* Fixed fields size (order, preference) */
-
-	size += 2 * sizeof(uint16_t);
-
-	/* Variable fields size (flags, services, regexp) */
-
-	for (int i = 0; i < 3; i++) {
-		const uint8_t *len_ptr = *src + size;
-		if (len_ptr >= *src + *src_avail) {
-			return KNOT_EMALF;
-		}
-
-		size += 1 + *len_ptr;
-	}
-
-	return size;
-}
-
-/*!
- * \brief Compresses and stores one RDATA dname from \a src to \a dst.
- */
-static int compress_dname(const uint8_t **src, size_t *src_avail,
-                          uint8_t **dst, size_t *dst_avail,
-                          knot_compr_t *compr, int compr_hint, int type,
-                          knot_rrset_wire_flags_t flags,
-                          const uint8_t *pkt_wire)
-{
-	assert(src && *src);
-	assert(src_avail);
-	assert(dst && *dst);
-	assert(dst_avail);
-	UNUSED(pkt_wire);
-
-	bool compress = (type == KNOT_RDATA_WF_COMPRESSIBLE_DNAME);
-
-	/* Source domain name */
-
-	const knot_dname_t *dname = *src;
-	size_t dname_size = knot_dname_size(dname);
-
-	/* Output domain name */
-
-	int written = knot_compr_put_dname(dname, *dst, dname_max(*dst_avail),
-	                                   compress ? compr : NULL);
-	if (written < 0) {
-		assert(written == KNOT_ESPACE);
-		return written;
-	}
-
-	/* Post-processing */
-
-	if (flags & KNOT_RRSET_WIRE_CANONICAL) {
-		assert(compr == NULL);
-		knot_dname_to_lower(*dst);
-	}
-
-	/* Update compression hints */
-
-	if (compr_get_ptr(compr, compr_hint) == 0) {
-		compr_set_ptr(compr, compr_hint, *dst, written);
-	}
-
-	/* Update buffers */
-
-	*dst += written;
-	*dst_avail -= written;
-
-	*src += dname_size;
-	*src_avail -= dname_size;
-
-	return KNOT_EOK;
-}
-
-/*!
- * \brief Parses and decompresses one RDATA dname from \a src to \a dst.
- */
-static int decompress_dname(const uint8_t **src, size_t *src_avail,
-                            uint8_t **dst, size_t *dst_avail,
-                            knot_compr_t *compr, int compr_hint, int type,
-                            knot_rrset_wire_flags_t flags,
-                            const uint8_t *pkt_wire)
-{
-	assert(src && *src);
-	assert(src_avail);
-	assert(dst && *dst);
-	assert(dst_avail);
-	UNUSED(compr);
-	UNUSED(compr_hint);
-
-	bool decompress = (type == KNOT_RDATA_WF_COMPRESSIBLE_DNAME
-	                   || type == KNOT_RDATA_WF_DECOMPRESSIBLE_DNAME);
-
-	int ret = knot_dname_wire_check(*src, *src + *src_avail, pkt_wire);
-	if (ret <= 0) {
-		return KNOT_EMALF;
-	}
-
-	size_t dname_size = ret;
-	int written = dname_size;
-
-	if (decompress) {
-		int ret = knot_dname_unpack(*dst, *src, *dst_avail, pkt_wire);
-		if (ret <= 0) {
-			return ret;
-		}
-		written = ret;
-	} else if (dname_size > *dst_avail) {
-		return KNOT_ESPACE;
-	} else {
-		memcpy(*dst, *src, dname_size);
-	}
-
-	/* Post-processing */
-
-	if (flags & KNOT_RRSET_WIRE_CANONICAL) {
-		knot_dname_to_lower(*dst);
-	}
-
-	/* Update buffers */
-
-	*dst += written;
-	*dst_avail -= written;
-
-	*src += dname_size;
-	*src_avail -= dname_size;
-
-	return KNOT_EOK;
-}
-
-typedef int (*dname_callback_t)(const uint8_t **, size_t *, uint8_t **,
-                                size_t *, knot_compr_t *, int, int,
-                                knot_rrset_wire_flags_t, const uint8_t *);
-
-/*!
- * \brief Generic function from processing RDATA with de/compression of dnames.
- */
-static int traverse_rdata(const rdata_descriptor_t *desc, const uint8_t **src,
-                          size_t *src_avail, uint8_t **wire, size_t *capacity,
-                          knot_compr_t *compr, int compr_hint,
-                          knot_rrset_wire_flags_t flags, const uint8_t *pkt_wire,
-                          dname_callback_t dname_callback)
-{
-	int ret = KNOT_EOK;
-
-	for (int i = 0; desc->block_types[i] != KNOT_RDATA_WF_END; i++) {
-		int type = desc->block_types[i];
-		size_t to_copy = 0;
-
-		switch (type) {
-		case KNOT_RDATA_WF_COMPRESSIBLE_DNAME:
-		case KNOT_RDATA_WF_DECOMPRESSIBLE_DNAME:
-		case KNOT_RDATA_WF_FIXED_DNAME:
-			ret = dname_callback(src, src_avail, wire, capacity,
-			                     compr, compr_hint, type, flags,
-			                     pkt_wire);
-			break;
-		case KNOT_RDATA_WF_NAPTR_HEADER:
-			ret = naptr_header_size(src, src_avail);
-			to_copy = ret;
-			break;
-		case KNOT_RDATA_WF_REMAINDER:
-			to_copy = *src_avail;
-			break;
-		default:
-			/* Fixed size block */
-			assert(type > 0);
-			to_copy = type;
-		}
-
-		if (to_copy > 0) {
-			ret = write_rdata_fixed(src, src_avail, wire, capacity,
-			                        to_copy);
-		}
-
-		if (ret != KNOT_EOK) {
-			return ret;
-		}
-	}
-
-	return KNOT_EOK;
-}
-
-/*!
- * \brief Write RDLENGTH and RDATA fields of a RR in a wire.
- */
-static int write_rdata(const knot_rrset_t *rrset, uint16_t rrset_index,
-                       uint8_t **wire, size_t *capacity,
-                       knot_compr_t *compr, knot_rrset_wire_flags_t flags)
-{
-	assert(rrset);
-	assert(rrset_index < rrset->rrs.rr_count);
-	assert(wire && *wire);
-	assert(capacity);
-
-	const knot_rdata_t *rdata = knot_rdataset_at(&rrset->rrs, rrset_index);
-
-	/* Reserve space for RDLENGTH */
-
-	size_t rdlength_size = sizeof(uint16_t);
-	if (rdlength_size > *capacity) {
-		return KNOT_ESPACE;
-	}
-
-	uint8_t *wire_rdlength = *wire;
-	*wire += rdlength_size;
-	*capacity -= rdlength_size;
-
-	/* Write RDATA */
-
-	uint8_t *wire_rdata_begin = *wire;
-	int compr_hint = COMPR_HINT_RDATA + rrset_index;
-
-	const uint8_t *src = knot_rdata_data(rdata);
-	size_t src_avail = knot_rdata_rdlen(rdata);
-	if (src_avail > 0) {
-		/* Only write non-empty data. */
-		const rdata_descriptor_t *desc =
-			knot_get_rdata_descriptor(rrset->type);
-		int ret = traverse_rdata(desc, &src, &src_avail, wire,
-		                         capacity, compr, compr_hint, flags,
-		                         NULL, compress_dname);
-		if (ret != KNOT_EOK) {
-			return ret;
-		}
-	}
-
-	if (src_avail > 0) {
-		/* Trailing data in the message. */
-		return KNOT_EMALF;
-	}
-
-	/* Write final RDLENGTH */
-
-	size_t rdlength = *wire - wire_rdata_begin;
-	knot_wire_write_u16(wire_rdlength, rdlength);
-
-	return KNOT_EOK;
-}
-
-/*!
- * \brief Write one RR from a RR Set to wire.
- */
-static int write_rr(const knot_rrset_t *rrset, uint16_t rrset_index,
-                    uint8_t **wire, size_t *capacity, knot_compr_t *compr,
-                    knot_rrset_wire_flags_t flags)
-{
-	int ret;
-
-	ret = write_owner(rrset, wire, capacity, compr, flags);
-	if (ret != KNOT_EOK) {
-		return ret;
-	}
-
-	ret = write_fixed_header(rrset, rrset_index, wire, capacity);
-	if (ret != KNOT_EOK) {
-		return ret;
-	}
-
-	ret = write_rdata(rrset, rrset_index, wire, capacity, compr, flags);
-	if (ret != KNOT_EOK) {
-		return ret;
-	}
-
-	return KNOT_EOK;
-}
-
-int knot_rrset_to_wire(const knot_rrset_t *rrset, uint8_t *wire, uint16_t max_size,
-                       knot_compr_t *compr, knot_rrset_wire_flags_t flags)
-{
-	if (!rrset || !wire) {
-		return KNOT_EINVAL;
-	}
-
-	if (flags & KNOT_RRSET_WIRE_CANONICAL) {
-		compr = NULL;
-	}
-
-	uint8_t *write = wire;
-	size_t capacity = max_size;
-
-	for (uint16_t i = 0; i < rrset->rrs.rr_count; i++) {
-		int ret = write_rr(rrset, i, &write, &capacity, compr, flags);
-		if (ret != KNOT_EOK) {
-			return ret;
-		}
-	}
-
-	size_t written = write - wire;
-
-	return written;
-}
-
 knot_rrset_t *knot_rrset_new(const knot_dname_t *owner, uint16_t type,
                              uint16_t rclass, mm_ctx_t *mm)
 {
@@ -578,129 +110,6 @@ void knot_rrset_clear(knot_rrset_t *rrset, mm_ctx_t *mm)
 	}
 }
 
-static bool allow_zero_rdata(const knot_rrset_t *rr, const rdata_descriptor_t *desc)
-{
-	return rr->rclass != KNOT_CLASS_IN ||  // NONE and ANY for DDNS
-	       rr->type == KNOT_RRTYPE_APL ||  // APLs can have 0 RDLENGTH
-	       desc->type_name == NULL;        // Unknown RR types can have 0 RDLENGTH
-}
-
-/*!
- * \brief Parse RDATA part of one RR from packet wireformat.
- */
-static int parse_rdata(const uint8_t *pkt_wire, size_t *pos, size_t pkt_size,
-                       mm_ctx_t *mm, uint32_t ttl, uint16_t rdlength,
-                       knot_rrset_t *rrset)
-{
-	assert(pkt_wire);
-	assert(pos);
-	assert(rrset);
-
-	if (pkt_size - *pos < rdlength) {
-		return KNOT_EMALF;
-	}
-
-	const rdata_descriptor_t *desc = knot_get_rdata_descriptor(rrset->type);
-
-	/* Check for obsolete record. */
-	if (desc->type_name == NULL) {
-		desc = knot_get_obsolete_rdata_descriptor(rrset->type);
-	}
-
-	if (rdlength == 0) {
-		if (allow_zero_rdata(rrset, desc)) {
-			return knot_rrset_add_rdata(rrset, NULL, 0, ttl, mm);
-		} else {
-			return KNOT_EMALF;
-		}
-	}
-
-	size_t dst_avail = rdlength + KNOT_DNAME_MAXLEN;
-	uint8_t rdata_buffer[dst_avail];
-	memset(rdata_buffer, 0, dst_avail);
-
-	const uint8_t *src = pkt_wire + *pos;
-	size_t src_avail = rdlength;
-	uint8_t *dst = rdata_buffer;
-
-	int ret = traverse_rdata(desc, &src, &src_avail, &dst, &dst_avail,
-	                         NULL, 0, KNOT_RRSET_WIRE_NONE, pkt_wire,
-	                         decompress_dname);
-	if (ret != KNOT_EOK) {
-		return ret;
-	}
-
-	assert(src_avail == 0);
-	*pos += rdlength;
-
-	size_t dst_size = dst - rdata_buffer;
-	assert(dst_size == rdlength + KNOT_DNAME_MAXLEN - dst_avail);
-
-	return knot_rrset_add_rdata(rrset, rdata_buffer, dst_size, ttl, mm);
-}
-
-/*!
- * \brief Parse header of one RR from packet wireformat.
- */
-static int parse_header(const uint8_t *pkt_wire, size_t *pos,
-                        size_t pkt_size, mm_ctx_t *mm, knot_rrset_t *rrset,
-                        uint32_t *ttl, uint16_t *rdlen)
-{
-	assert(pkt_wire);
-	assert(pos);
-	assert(rrset);
-	assert(ttl);
-	assert(rdlen);
-
-	knot_dname_t *owner = knot_dname_parse(pkt_wire, pos, pkt_size, mm);
-	if (owner == NULL) {
-		return KNOT_EMALF;
-	}
-	knot_dname_to_lower(owner);
-
-	if (pkt_size - *pos < KNOT_RR_HEADER_SIZE) {
-		knot_dname_free(&owner, mm);
-		return KNOT_EMALF;
-	}
-
-	uint16_t type = knot_wire_read_u16(pkt_wire + *pos);
-	uint16_t rclass = knot_wire_read_u16(pkt_wire + *pos + sizeof(uint16_t));
-	*ttl = knot_wire_read_u32(pkt_wire + *pos + 2 * sizeof(uint16_t));
-	*rdlen = knot_wire_read_u16(pkt_wire + *pos + 4 * sizeof(uint16_t));
-
-	*pos += KNOT_RR_HEADER_SIZE;
-
-	if (pkt_size - *pos < *rdlen) {
-		knot_dname_free(&owner, mm);
-		return KNOT_EMALF;
-	}
-
-	knot_rrset_init(rrset, owner, type, rclass);
-
-	return KNOT_EOK;
-}
-
-int knot_rrset_rr_from_wire(const uint8_t *pkt_wire, size_t *pos,
-                            size_t pkt_size, mm_ctx_t *mm, knot_rrset_t *rrset)
-{
-	if (pkt_wire == NULL || pos == NULL || rrset == NULL) {
-		return KNOT_EINVAL;
-	}
-
-	uint32_t ttl = 0;
-	uint16_t rdlen = 0;
-	int ret = parse_header(pkt_wire, pos, pkt_size, mm, rrset, &ttl, &rdlen);
-	if (ret == KNOT_EOK) {
-		ret = parse_rdata(pkt_wire, pos, pkt_size, mm, ttl, rdlen,
-		                  rrset);
-		if (ret != KNOT_EOK) {
-			knot_rrset_clear(rrset, mm);
-		}
-	}
-
-	return ret;
-}
-
 int knot_rrset_add_rdata(knot_rrset_t *rrset,
                          const uint8_t *rdata, const uint16_t size,
                          const uint32_t ttl, mm_ctx_t *mm)
diff --git a/src/libknot/rrset.h b/src/libknot/rrset.h
index d90f6a5f92a09b43c3dc2ea9ea79fe42b1a833cc..8025838ac7353e1ea5d2c88a181fffde11bfd6ad 100644
--- a/src/libknot/rrset.h
+++ b/src/libknot/rrset.h
@@ -34,8 +34,6 @@
 #include "libknot/dname.h"
 #include "libknot/rdataset.h"
 
-struct knot_compr;
-
 /*!
  * \brief Structure for representing RRSet.
  *
@@ -123,49 +121,6 @@ void knot_rrset_free(knot_rrset_t **rrset, mm_ctx_t *mm);
  */
 void knot_rrset_clear(knot_rrset_t *rrset, mm_ctx_t *mm);
 
-/* ---------- Wire conversions (legacy, to be done in knot_pkt_t) ----------- */
-
-/*!
- * \brief Flags controlling RR set from/to wire conversion.
- */
-enum knot_rrset_wire_flags {
-	KNOT_RRSET_WIRE_NONE = 0,
-	KNOT_RRSET_WIRE_CANONICAL = 1 << 0,
-};
-
-typedef enum knot_rrset_wire_flags knot_rrset_wire_flags_t;
-
-/*!
- * \brief Write RR Set content to a wire.
- *
- * Function accepts \ref KNOT_RRSET_WIRE_CANONICAL flag, which causes the
- * output to be written in canonical representation.
- *
- * \param rrset     RRSet to be converted.
- * \param wire      Output wire buffer.
- * \param max_size  Capacity of wire buffer.
- * \param compr     Compression context.
- * \param flags     Flags controlling the output.
- *
- * \return Output size, negative number on error (KNOT_E*).
- */
-int knot_rrset_to_wire(const knot_rrset_t *rrset, uint8_t *wire, uint16_t max_size,
-                       struct knot_compr *compr, knot_rrset_wire_flags_t flags);
-
-/*!
-* \brief Creates one RR from wire, stores it into \a rrset.
-*
-* \param pkt_wire    Source wire (the whole packet).
-* \param pos         Position in \a wire where to start parsing.
-* \param pkt_size    Total size of data in \a wire (size of the packet).
-* \param mm          Memory context.
-* \param rrset       Destination RRSet.
-*
-* \return KNOT_E*
-*/
-int knot_rrset_rr_from_wire(const uint8_t *pkt_wire, size_t *pos,
-                            size_t pkt_size, mm_ctx_t *mm, knot_rrset_t *rrset);
-
 /* ---------- RR addition. (legacy, functionality in knot_rdataset_t) ------- */
 
 /*!
diff --git a/src/libknot/tsig-op.c b/src/libknot/tsig-op.c
index 59935a80c3aaed6210fba7f11b36b51bbbd7b9a8..43c6b6c009139dac48714c15aca865ddedbfa589 100644
--- a/src/libknot/tsig-op.c
+++ b/src/libknot/tsig-op.c
@@ -31,6 +31,7 @@
 #include "libknot/packet/wire.h"
 #include "libknot/consts.h"
 #include "libknot/dnssec/key.h"
+#include "libknot/packet/rrset-wire.h"
 
 const int KNOT_TSIG_MAX_DIGEST_SIZE = 64;    // size of HMAC-SHA512 digest
 const uint16_t KNOT_TSIG_FUDGE_DEFAULT = 300;  // default Fudge value