diff --git a/src/libknot/packet/rrset-wire.c b/src/libknot/packet/rrset-wire.c index 56e0cae2b4decddef9eb569e74fc8ec3a0792955..8ebccfc958171398014e74180308810ce8822ed5 100644 --- a/src/libknot/packet/rrset-wire.c +++ b/src/libknot/packet/rrset-wire.c @@ -238,7 +238,7 @@ static int compr_put_dname(const knot_dname_t *dname, uint8_t *dst, uint16_t max if (written + sizeof(uint16_t) > max) { return KNOT_ESPACE; } - knot_wire_put_pointer(dst + written, compr_ptr - compr->wire); + knot_wire_put_pointer_check(dst + written, compr_ptr - compr->wire, compr->wire); written += sizeof(uint16_t); } @@ -280,14 +280,14 @@ static int write_owner(const knot_rrset_t *rrset, uint8_t **dst, size_t *dst_ava // Write result. if (owner_pointer > 0) { WRITE_OWNER_CHECK(sizeof(uint16_t), dst_avail); - knot_wire_put_pointer(*dst, owner_pointer); + knot_wire_put_pointer_check(*dst, owner_pointer, compr->wire); WRITE_OWNER_INCR(dst, dst_avail, sizeof(uint16_t)); // Check for coincidence with previous RR set. } else if (compr != NULL && compr->suffix.pos != 0 && *rrset->owner != '\0' && dname_equal_wire(rrset->owner, compr->wire + compr->suffix.pos, compr->wire)) { WRITE_OWNER_CHECK(sizeof(uint16_t), dst_avail); - knot_wire_put_pointer(*dst, compr->suffix.pos); + knot_wire_put_pointer_check(*dst, compr->suffix.pos, compr->wire); compr_set_ptr(compr, KNOT_COMPR_HINT_OWNER, compr->wire + compr->suffix.pos, knot_dname_size(rrset->owner)); diff --git a/src/libknot/packet/wire.h b/src/libknot/packet/wire.h index 698ac3dbfee98681b5c3b6fe6b995e982f5f9367..042705b35fca09b63c38723c026dc2012882dd71 100644 --- a/src/libknot/packet/wire.h +++ b/src/libknot/packet/wire.h @@ -1017,6 +1017,17 @@ static inline void knot_wire_put_pointer(uint8_t *pos, uint16_t ptr) pos[0] |= KNOT_WIRE_PTR; // Add pointer mark. } +/*! \brief Put pointer, but avoid pointing at other pointer. */ +static inline void knot_wire_put_pointer_check(uint8_t *pos, uint16_t ptr, const uint8_t *wire) +{ + if (knot_wire_is_pointer(wire + ptr)) { + // copy the referenced pointer instead + memcpy(pos, wire + ptr, sizeof(ptr)); + } else { + knot_wire_put_pointer(pos, ptr); + } +} + static inline uint16_t knot_wire_get_pointer(const uint8_t *pos) { assert(knot_wire_is_pointer(pos)); // Check pointer.