Rrfz - Resource Record Fuzzing Generator

Rrfz - Resource Record Fuzzing Generator

This module allows users to generate custom resource records (RRs) in the Answer section, based on parameters defined in the query.

Clients can specify the record type, DNS class, declared data length (RDLENGTH), actual data size, and the number of records to include in the response. Additionally, users can specify the byte values used to populate the data section.

This allows crafting of a wide range of custom DNS responses, including highly non-compliant, corrupted, or intentionally malformed records.

It is particularly useful for evaluating the robustness of recursive resolvers and clients in handling (parsing) malformed or non-standard records — for example, discrepancies between declared and actual data sizes, corrupted records, or use of unsupported or obsolete record types.

By default, the module returns an A record with a randomly generated IPv4 address, using the following parameters:

  • Record Type: 1 (A / Host Address)
  • DNS Class: 1 (IN / Internet)
  • Declared Data Length: 4
  • Actual Data Size: 4 (IPv4 address)
  • Data Payload: Random bytes

Category: Fuzzing

RFCs: RFC1035

Format

rrfz.<NUMBER>.t<TYPE>.c<CLASS>.l<RDLEN>.d<DATALEN>.b<BYTE>.yourdomain.com

Where:

  • The NUMBER parameter specifies how many records should be generated in the response.

  • The TYPE parameter defines the RR type to generate. There are 65,535 possible values, as defined by the 2-byte field limit. Common types include A, AAAA, NS, SOA, MX, etc. A complete list of types and their numeric values can be found here.

  • The CLASS parameter defines the DNS class for each record. Like types, there are 65,535 possible values. In practice, only IN (1) and CH (3) are widely used. A list of defined classes is available here.

  • The RDLEN parameter specifies the declared data length in bytes for the record's data section. This value can range up to 65,535, as defined by the 2-byte field limit.

  • The DATALEN parameter specifies the actual data length in bytes of the data payload in the record. The payload is filled with random bytes by default. Optionally, a specific <BYTE> value can be used to fill the payload.

  • The BYTE parameter specifies the byte value to be repeated to fill the payload. It can either be:

    • A hexadecimal number (0x0 — 0xff)
    • A decimal number (0 — 255)
    • Ommited, which results in a random value being used (default)

Examples

As mentioned above, the default behavior of the module is to generate a DNS response containing a single A record with a randomly generated IPv4 address:

# dig rrfz.yourdomain.com @127.0.0.1

; <<>> DiG 9.20.7-1-Debian <<>> rrfz.yourdomain.com @127.0.0.1
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 1187
;; flags: qr aa; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;rrfz.yourdomain.com.		IN	A

;; ANSWER SECTION:
rrfz.yourdomain.com.	60	IN	A	195.164.236.154

;; Query time: 4 msec
;; SERVER: 127.0.0.1#53(127.0.0.1) (UDP)
;; WHEN: Mon Jul 07 09:46:36 +04 2025
;; MSG SIZE  rcvd: 53

Download PCAP File


In the following example, we begin customizing the record by specifying that the data section should be filled with the byte value 1 (0x01). We can see that this produces the IPv4 address 1.1.1.1 instead of a randomly generated one:

# dig rrfz.b1.yourdomain.com @127.0.0.1

; <<>> DiG 9.20.7-1-Debian <<>> rrfz.b1.yourdomain.com @127.0.0.1
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 34456
;; flags: qr aa; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;rrfz.b1.yourdomain.com.		IN	A

;; ANSWER SECTION:
rrfz.b1.yourdomain.com.	60	IN	A	1.1.1.1

;; Query time: 4 msec
;; SERVER: 127.0.0.1#53(127.0.0.1) (UDP)
;; WHEN: Tue Jul 08 14:38:24 +04 2025
;; MSG SIZE  rcvd: 56

Download PCAP File


In this example, we specify that both the declared data length and the actual data size are exactly 3 bytes (.l3.d3.). Since a valid IPv4 address requires 4 bytes, the parser cannot interpret this data as a valid address:

# dig rrfz.l3.d3.yourdomain.com @127.0.0.1

;; Warning: Message parser reports malformed message packet.

; <<>> DiG 9.20.7-1-Debian <<>> rrfz.l3.d3.yourdomain.com @127.0.0.1
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 13895
;; flags: qr aa; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; WARNING: Message has 3 extra bytes at end

;; QUESTION SECTION:
;rrfz.l3.d3.yourdomain.com.	IN	A

;; Query time: 0 msec
;; SERVER: 127.0.0.1#53(127.0.0.1) (UDP)
;; WHEN: Mon Jul 07 09:46:37 +04 2025
;; MSG SIZE  rcvd: 58

Download PCAP File

Instead, the client (dig) displays no answer, even though the header indicates that one is present (ANSWER: 1). It only reports the presence of 3 unexpected bytes at the end of the packet.


In this example, we specify the declared data length of exactly 4 bytes (.l4.) — the correct size for an IPv4 address — while also setting the actual data size to 5 bytes (.d5.). As a result, the parser detects one extra byte beyond the expected IPv4 address length:

# dig rrfz.l4.d5.yourdomain.com @127.0.0.1

; <<>> DiG 9.20.7-1-Debian <<>> rrfz.l4.d5.yourdomain.com @127.0.0.1
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 52046
;; flags: qr aa; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; WARNING: Message has 1 extra bytes at end

;; QUESTION SECTION:
;rrfz.l4.d5.yourdomain.com.	IN	A

;; ANSWER SECTION:
rrfz.l4.d5.yourdomain.com. 60	IN	A	55.148.82.125

;; Query time: 4 msec
;; SERVER: 127.0.0.1#53(127.0.0.1) (UDP)
;; WHEN: Mon Jul 07 15:29:08 +04 2025
;; MSG SIZE  rcvd: 60

Download PCAP File


Now, we generate a response containing two records (.2.) identical to the previous example — each record with one extra byte beyond the expected size. The response should include two answers, however we can see that the parser is unable to process it:

# dig rrfz.2.l4.d5.yourdomain.com @127.0.0.1

;; Got bad packet: bad compression pointer
79 bytes
5c 61 84 00 00 01 00 02 00 00 00 00 04 72 72 66          \a...........rrf
7a 01 32 02 6c 34 02 64 35 0a 79 6f 75 72 64 6f          z.2.l4.d5.yourdo
6d 61 69 6e 03 63 6f 6d 00 00 01 00 01 c0 0c 00          main.com........
01 00 01 00 00 00 3c 00 04 67 c9 fd e6 ee c0 0c          ......<..g......
00 01 00 01 00 00 00 3c 00 04 45 21 da e9 60             .......<..E!..`

Download PCAP File

This is caused by the unexpected trailing byte in the first record, which disrupts the parsing logic.


Here, we can see that without the extra byte, the response would be parsed correctly:

# dig rrfz.2.l4.d4.yourdomain.com @127.0.0.1

; <<>> DiG 9.20.7-1-Debian <<>> rrfz.2.l4.d4.yourdomain.com @127.0.0.1
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 62544
;; flags: qr aa; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;rrfz.2.l4.d4.yourdomain.com.	IN	A

;; ANSWER SECTION:
rrfz.2.l4.d4.yourdomain.com. 60	IN	A	63.60.182.137
rrfz.2.l4.d4.yourdomain.com. 60	IN	A	23.161.129.75

;; Query time: 4 msec
;; SERVER: 127.0.0.1#53(127.0.0.1) (UDP)
;; WHEN: Tue Jul 08 11:49:32 +04 2025
;; MSG SIZE  rcvd: 77

Download PCAP File


In this example, we request a response containing a record with the RR type set to 65535, DNS class set to 65535, both the declared and actual data lengths set to 20 bytes, and the data section filled with the byte value 255 (0xFF). This results in the following unusual-looking response:

# dig rrfz.t65535.c65535.l20.d20.b255.yourdomain.com @127.0.0.1

;; Warning: Message parser reports malformed message packet.

; <<>> DiG 9.20.7-1-Debian <<>> rrfz.t65535.c65535.l20.d20.b255.yourdomain.com @127.0.0.1
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 20942
;; flags: qr aa; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;rrfz.t65535.c65535.l20.d20.b255.yourdomain.com.	IN A

;; ANSWER SECTION:
rrfz.t65535.c65535.l20.d20.b255.yourdomain.com.	60 CLASS65535 TYPE65535	\# 20 FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF

;; Query time: 8 msec
;; SERVER: 127.0.0.1#53(127.0.0.1) (UDP)
;; WHEN: Tue Jul 08 11:31:41 +04 2025
;; MSG SIZE  rcvd: 96

Download PCAP File

We can see that the client (dig) struggles to parse this unusual response, reporting it as malformed. However, when inspected in Wireshark, the response does not appear to be explicitly malformed — the record type and class are simply unknown or unrecognized.


From the same category


Go back to catalogue.