Coverage Report

Created: 2026-05-23 07:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dns_fuzzer.cc
Line
Count
Source
1
/* Copyright 2026 Google LLC
2
Licensed under the Apache License, Version 2.0 (the "License");
3
you may not use this file except in compliance with the License.
4
You may obtain a copy of the License at
5
      http://www.apache.org/licenses/LICENSE-2.0
6
Unless required by applicable law or agreed to in writing, software
7
distributed under the License is distributed on an "AS IS" BASIS,
8
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9
See the License for the specific language governing permissions and
10
limitations under the License.
11
*/
12
13
#include <stddef.h>
14
#include <stdint.h>
15
#include <stdlib.h>
16
#include <string.h>
17
#include <sys/socket.h>
18
#include <netinet/in.h>
19
#include <arpa/inet.h>
20
#include <unistd.h>
21
#include <fcntl.h>
22
#include <sys/stat.h>
23
24
#include <fuzzer/FuzzedDataProvider.h>
25
26
extern "C" {
27
#include "event2/event.h"
28
#include "event2/dns.h"
29
#include "event2/util.h"
30
#include "event2/dns_struct.h"
31
}
32
33
0
static void dns_callback(int result, char type, int count, int ttl, void *addresses, void *arg) {
34
0
}
35
36
0
static void dns_server_cb(struct evdns_server_request *req, void *data) {
37
0
    evdns_server_request_respond(req, 0);
38
0
}
39
40
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
41
    if (size < 10) return 0;
42
43
    FuzzedDataProvider data_provider(data, size);
44
    uint8_t mode = data_provider.ConsumeIntegral<uint8_t>();
45
46
    struct event_base *base = event_base_new();
47
    if (!base) return 0;
48
49
    if (mode % 3 == 0) {
50
        /* Config parsing (from dns_config_fuzzer.cc) */
51
        uint32_t flags = data_provider.ConsumeIntegral<uint32_t>();
52
        std::string s1 = data_provider.ConsumeRandomLengthString();
53
        std::string s2 = data_provider.ConsumeRandomLengthString();
54
55
        struct evdns_base *dns = evdns_base_new(base, flags % 65537);
56
        if (dns) {
57
            char resolvFilename[50];
58
            sprintf(resolvFilename, "/tmp/resolv.%d", getpid());
59
            FILE *fp = fopen(resolvFilename, "wb");
60
            if (fp) {
61
                fwrite(s1.c_str(), s1.size(), 1, fp);
62
                fclose(fp);
63
                evdns_base_resolv_conf_parse(dns, flags % 17, resolvFilename);
64
                unlink(resolvFilename);
65
            }
66
67
            char hostsFilename[50];
68
            sprintf(hostsFilename, "/tmp/hosts.%d", getpid());
69
            fp = fopen(hostsFilename, "wb");
70
            if (fp) {
71
                fwrite(s2.c_str(), s2.size(), 1, fp);
72
                fclose(fp);
73
                evdns_base_load_hosts(dns, hostsFilename);
74
                unlink(hostsFilename);
75
            }
76
            evdns_base_search_ndots_set(dns, flags);
77
            evdns_base_search_clear(dns);
78
            evdns_base_clear_host_addresses(dns);
79
            evdns_base_free(dns, 0);
80
        }
81
    } else if (mode % 3 == 1) {
82
        /* Server-side request parsing (from dns_message_fuzzer.cc) */
83
        int fds[2];
84
        if (socketpair(AF_UNIX, SOCK_DGRAM, 0, fds) == 0) {
85
            struct evdns_server_port *port =
86
                evdns_add_server_port_with_base(base, fds[0], 0, dns_server_cb, nullptr);
87
            if (port) {
88
                std::vector<uint8_t> packet = data_provider.ConsumeRemainingBytes<uint8_t>();
89
                if (packet.size() > 0) {
90
                    send(fds[1], packet.data(), packet.size(), 0);
91
                    event_base_loop(base, EVLOOP_NONBLOCK);
92
                }
93
                evdns_close_server_port(port);
94
            }
95
            close(fds[1]);
96
        }
97
    } else {
98
        /* Client-side response parsing (from evdns_client_fuzzer.cc) */
99
        struct evdns_base *dns_base = evdns_base_new(base, 0);
100
        if (dns_base) {
101
            int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
102
            if (sockfd >= 0) {
103
                evutil_make_socket_nonblocking(sockfd);
104
                struct sockaddr_in sin;
105
                memset(&sin, 0, sizeof(sin));
106
                sin.sin_family = AF_INET;
107
                sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
108
                sin.sin_port = 0;
109
                if (bind(sockfd, (struct sockaddr *)&sin, sizeof(sin)) == 0) {
110
                    socklen_t slen = sizeof(sin);
111
                    getsockname(sockfd, (struct sockaddr *)&sin, &slen);
112
                    char addr_port[64];
113
                    snprintf(addr_port, sizeof(addr_port), "127.0.0.1:%d", ntohs(sin.sin_port));
114
                    evdns_base_nameserver_ip_add(dns_base, addr_port);
115
116
                    uint8_t type = data_provider.ConsumeIntegral<uint8_t>() % 4;
117
                    const char *name = "example.com";
118
                    switch (type) {
119
                        case 0: evdns_base_resolve_ipv4(dns_base, name, 0, dns_callback, NULL); break;
120
                        case 1: evdns_base_resolve_ipv6(dns_base, name, 0, dns_callback, NULL); break;
121
                        case 2: {
122
                            struct in_addr addr;
123
                            addr.s_addr = 0x01020304;
124
                            evdns_base_resolve_reverse(dns_base, &addr, 0, dns_callback, NULL);
125
                        } break;
126
                        case 3: evdns_base_resolve_reverse_ipv6(dns_base, (struct in6_addr *)"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1", 0, dns_callback, NULL); break;
127
                    }
128
                    event_base_loop(base, EVLOOP_NONBLOCK);
129
130
                    struct sockaddr_in client_addr;
131
                    slen = sizeof(client_addr);
132
                    char buf[1500];
133
                    int n = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&client_addr, &slen);
134
                    if (n > 0) {
135
                        std::vector<uint8_t> resp = data_provider.ConsumeRemainingBytes<uint8_t>();
136
                        if (resp.size() > 0) {
137
                            sendto(sockfd, resp.data(), resp.size(), 0, (struct sockaddr *)&client_addr, slen);
138
                            event_base_loop(base, EVLOOP_NONBLOCK);
139
                        }
140
                    }
141
                }
142
                close(sockfd);
143
            }
144
            evdns_base_free(dns_base, 0);
145
        }
146
    }
147
148
    event_base_free(base);
149
    return 0;
150
}