/src/ndpi/fuzz/fuzz_dns_parse.c
Line | Count | Source |
1 | | /* |
2 | | * fuzz_dns_parse |
3 | | * |
4 | | * What it tests: |
5 | | * DNS query / answer RR walking in src/lib/protocols/dns.c. Calls |
6 | | * ndpi_search_dns() directly with a synthesised packet_struct so the |
7 | | * dissector is reached without depending on ndpi_detection_process_packet() |
8 | | * and the full flow state machine. Exercises attacker-controlled uint16 |
9 | | * counts (num_queries, num_answers, authority_rrs, additional_rrs) and the |
10 | | * name-compression pointer loops. |
11 | | * |
12 | | * Expected input format: |
13 | | * Raw DNS payload (starts with the 12-byte ndpi_dns_packet_header prefix). |
14 | | * The last byte is consumed as a selector: |
15 | | * bit 0 -> TCP vs UDP framing |
16 | | * bit 1 -> MDNS port (5353) vs DNS port (53) |
17 | | */ |
18 | | |
19 | | #include "ndpi_api.h" |
20 | | #include "ndpi_private.h" |
21 | | #include "fuzz_common_code.h" |
22 | | |
23 | | #include <arpa/inet.h> |
24 | | #include <stdint.h> |
25 | | #include <stdio.h> |
26 | | #include <string.h> |
27 | | |
28 | | static struct ndpi_detection_module_struct *ndpi_struct = NULL; |
29 | | static struct ndpi_flow_struct *ndpi_flow = NULL; |
30 | | static struct ndpi_iphdr iph; |
31 | | static struct ndpi_udphdr udph; |
32 | | static struct ndpi_tcphdr tcph; |
33 | | |
34 | | static char *path = NULL; |
35 | | |
36 | 42 | int LLVMFuzzerInitialize(int *argc, char ***argv) { |
37 | 42 | (void)argc; |
38 | 42 | path = dirname(strdup(*argv[0])); /* No errors; no free! */ |
39 | 42 | return 0; |
40 | 42 | } |
41 | | |
42 | 3.34k | int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { |
43 | 3.34k | struct ndpi_packet_struct *packet; |
44 | 3.34k | uint8_t selector; |
45 | 3.34k | int is_tcp, is_mdns; |
46 | 3.34k | uint16_t port; |
47 | | |
48 | 3.34k | if (ndpi_struct == NULL) { |
49 | 1 | fuzz_init_detection_module(&ndpi_struct, NULL, path); |
50 | 1 | ndpi_flow = ndpi_calloc(1, sizeof(struct ndpi_flow_struct)); |
51 | | |
52 | 1 | memset(&iph, 0, sizeof(iph)); |
53 | 1 | iph.version = 4; |
54 | 1 | iph.ihl = 5; |
55 | 1 | iph.saddr = htonl(0x0A000001); |
56 | 1 | iph.daddr = htonl(0x0A000002); |
57 | 1 | } |
58 | | |
59 | 3.34k | if (size < 1) |
60 | 0 | return 0; |
61 | | |
62 | 3.34k | fuzz_set_alloc_callbacks_and_seed(size); |
63 | | |
64 | 3.34k | selector = data[size - 1]; |
65 | 3.34k | is_tcp = selector & 0x01; |
66 | 3.34k | is_mdns = (selector & 0x02) ? 1 : 0; |
67 | 3.34k | port = is_mdns ? 5353 : 53; |
68 | | |
69 | 3.34k | packet = &ndpi_struct->packet; |
70 | 3.34k | packet->payload = data; |
71 | 3.34k | packet->payload_packet_len = (u_int16_t)size; |
72 | 3.34k | packet->iph = &iph; |
73 | 3.34k | packet->iphv6 = NULL; |
74 | | |
75 | 3.34k | if (is_tcp) { |
76 | 923 | memset(&tcph, 0, sizeof(tcph)); |
77 | 923 | tcph.source = htons(port); |
78 | 923 | tcph.dest = htons(port); |
79 | 923 | packet->tcp = &tcph; |
80 | 923 | packet->udp = NULL; |
81 | 923 | iph.protocol = 6; |
82 | 2.42k | } else { |
83 | 2.42k | memset(&udph, 0, sizeof(udph)); |
84 | 2.42k | udph.source = htons(port); |
85 | 2.42k | udph.dest = htons(port); |
86 | 2.42k | packet->udp = &udph; |
87 | 2.42k | packet->tcp = NULL; |
88 | 2.42k | iph.protocol = 17; |
89 | 2.42k | } |
90 | | |
91 | 3.34k | memset(ndpi_flow, 0, sizeof(struct ndpi_flow_struct)); |
92 | 3.34k | ndpi_flow->l4_proto = is_tcp ? IPPROTO_TCP : IPPROTO_UDP; |
93 | | |
94 | 3.34k | ndpi_search_dns(ndpi_struct, ndpi_flow); |
95 | 3.34k | ndpi_free_flow_data(ndpi_flow); |
96 | | |
97 | 3.34k | return 0; |
98 | 3.34k | } |