[GH-ISSUE #2815] Handling of non-canonical type bit maps #1069

Closed
opened 2026-03-16 01:30:40 +03:00 by kerem · 0 comments
Owner

Originally created by @divergentdave on GitHub (Feb 28, 2025).
Original GitHub issue: https://github.com/hickory-dns/hickory-dns/issues/2815

The message fuzzer currently ignores CSYNC records. Removing this condition reveals that the type bit map may differ when decoding once, versus doing a decode-encode-decode round trip. This can happen when the type bit map includes window blocks in the wrong order, or multiple window blocks with the same block number. Record types are stored internally in a Vec<RecordType>, and record types are added to the vector in the order they are seen on the wire. When encoding, the types get sorted and deduplicated, so the window blocks are written in the correct order. As a result, the two decoded CSYNC structs are not equal to each other, since the first one's record types may include duplicates or be out of order.

The same thing can happen with NSEC and NSEC3 records, which also contain type bit maps. We should enable a DNSSEC feature in the fuzzer in order to explore these record types further.

While RFC 4034 says "Blocks are present in the NSEC RR RDATA in increasing numerical order", we still need to decide how to handle records that do not conform. One approach would be to store record types in a BTreeSet<RecordType> instead of a Vec<RecordType>, in order to erase ordering and duplicates during decoding, instead of during encoding. This would resolve the fuzzer failures. However, this could potentially invalidate RRSIGs over such weird records, since the to-be-signed data is constructed from the re-encoding of the records.

Avoiding re-encoding by saving a copy of the original RDATA sounds promising, but it has different implications for forwarding servers and for DNSSEC validation. Depending on the record type, DNSSEC may require some amount of canonical re-encoding to get rid of name compression and to use the canonical capitalization of names. For CSYNC, there are no names in the RDATA, but NSEC contains a next domain name as well. Maybe we should take a hybrid approach, where we store the original encoded form of the type bit map in RData-related structs, if available?

Originally created by @divergentdave on GitHub (Feb 28, 2025). Original GitHub issue: https://github.com/hickory-dns/hickory-dns/issues/2815 The `message` fuzzer currently ignores `CSYNC` records. Removing this condition reveals that the type bit map may differ when decoding once, versus doing a decode-encode-decode round trip. This can happen when the type bit map includes window blocks in the wrong order, or multiple window blocks with the same block number. Record types are stored internally in a `Vec<RecordType>`, and record types are added to the vector in the order they are seen on the wire. When encoding, the types get sorted and deduplicated, so the window blocks are written in the correct order. As a result, the two decoded `CSYNC` structs are not equal to each other, since the first one's record types may include duplicates or be out of order. The same thing can happen with NSEC and NSEC3 records, which also contain type bit maps. We should enable a DNSSEC feature in the fuzzer in order to explore these record types further. While RFC 4034 says "Blocks are present in the NSEC RR RDATA in increasing numerical order", we still need to decide how to handle records that do not conform. One approach would be to store record types in a `BTreeSet<RecordType>` instead of a `Vec<RecordType>`, in order to erase ordering and duplicates during decoding, instead of during encoding. This would resolve the fuzzer failures. However, this could potentially invalidate RRSIGs over such weird records, since the to-be-signed data is constructed from the re-encoding of the records. Avoiding re-encoding by saving a copy of the original RDATA sounds promising, but it has different implications for forwarding servers and for DNSSEC validation. Depending on the record type, DNSSEC may require some amount of canonical re-encoding to get rid of name compression and to use the canonical capitalization of names. For CSYNC, there are no names in the RDATA, but NSEC contains a next domain name as well. Maybe we should take a hybrid approach, where we store the original encoded form of the type bit map in RData-related structs, if available?
kerem 2026-03-16 01:30:40 +03:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/hickory-dns#1069
No description provided.