The rdns_request_reply_cmp function modifies req->pos as a side effect
during reply validation. This caused packet truncation on retransmits
because req->pos (which tracks the full packet length) was overwritten
with the end position of the question section.
On timeout/retry, rdns_send_request would use the corrupted req->pos
value, resulting in truncated packets missing the OPT additional section.
This made resolvers like Knot and PowerDNS unable to parse retransmitted
packets.
Fix by saving and restoring req->pos around the reply comparison logic.
* Now we have request and query data is now at the end of header, so compare
* request QR section and reply QR section
*/
+ unsigned int saved_pos = req->pos;
req->pos = sizeof(struct dns_header);
pos = in + sizeof(struct dns_header);
t = r - sizeof(struct dns_header);
for (i = 0; i < (int) qdcount; i++) {
if ((npos = rdns_request_reply_cmp(req, pos, t)) == NULL) {
rdns_info("DNS request with id %d is for different query, ignoring", (int) req->id);
+ req->pos = saved_pos;
return false;
}
t -= npos - pos;
pos = npos;
}
+ req->pos = saved_pos;
/*
* Now pos is in answer section, so we should extract data and form reply
*/