xref: /netbsd-src/external/mpl/bind/dist/bin/named/fuzz.c (revision bcda20f65a8566e103791ec395f7f499ef322704)
1 /*	$NetBSD: fuzz.c,v 1.8 2025/01/26 16:24:33 christos Exp $	*/
2 
3 /*
4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5  *
6  * SPDX-License-Identifier: MPL-2.0
7  *
8  * This Source Code Form is subject to the terms of the Mozilla Public
9  * License, v. 2.0. If a copy of the MPL was not distributed with this
10  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11  *
12  * See the COPYRIGHT file distributed with this work for additional
13  * information regarding copyright ownership.
14  */
15 
16 #include <inttypes.h>
17 #include <stdbool.h>
18 
19 #include <named/fuzz.h>
20 
21 #ifdef ENABLE_AFL
22 #include <arpa/inet.h>
23 #include <errno.h>
24 #include <pthread.h>
25 #include <signal.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 
30 #include <isc/condition.h>
31 #include <isc/loop.h>
32 #include <isc/mutex.h>
33 #include <isc/thread.h>
34 #include <isc/util.h>
35 
36 #include <dns/log.h>
37 
38 #include <named/globals.h>
39 #include <named/log.h>
40 #include <named/server.h>
41 
42 /*
43  * We are using pthreads directly because we might be using it with
44  * unthreaded version of BIND, where all thread functions are
45  * mocks. Since AFL for now only works on Linux it's not a problem.
46  */
47 static pthread_cond_t cond;
48 static pthread_mutex_t mutex;
49 static bool ready;
50 
51 /*
52  * In "client:" mode, this thread reads fuzzed query messages from AFL
53  * from standard input and sends it to named's listening port (DNS) that
54  * is passed in the -A client:<address>:<port> option. It can be used to
55  * test named from the client side.
56  */
57 static void *
58 fuzz_thread_client(void *arg) {
59 	char *host;
60 	char *port;
61 	struct sockaddr_in servaddr;
62 	int sockfd;
63 	void *buf;
64 
65 	UNUSED(arg);
66 
67 	/*
68 	 * Parse named -A argument in the "address:port" syntax. Due to
69 	 * the syntax used, this only supports IPv4 addresses.
70 	 */
71 	host = strdup(named_g_fuzz_addr);
72 	RUNTIME_CHECK(host != NULL);
73 
74 	port = strchr(host, ':');
75 	RUNTIME_CHECK(port != NULL);
76 	*port = 0;
77 	++port;
78 
79 	memset(&servaddr, 0, sizeof(servaddr));
80 	servaddr.sin_family = AF_INET;
81 	RUNTIME_CHECK(inet_pton(AF_INET, host, &servaddr.sin_addr) == 1);
82 	servaddr.sin_port = htons(atoi(port));
83 
84 	free(host);
85 
86 	/*
87 	 * Wait for named to start. This is set in run_server() in the
88 	 * named thread.
89 	 */
90 	while (!named_g_run_done) {
91 		usleep(10000);
92 	}
93 
94 	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
95 	RUNTIME_CHECK(sockfd != -1);
96 
97 	buf = malloc(65536);
98 	RUNTIME_CHECK(buf != NULL);
99 
100 	/*
101 	 * Processing fuzzed packets 100,000 times before shutting down
102 	 * the app.
103 	 */
104 #ifdef __AFL_LOOP
105 	for (int loop = 0; loop < 100000; loop++) {
106 #else  /* ifdef __AFL_LOOP */
107 	{
108 #endif /* ifdef __AFL_LOOP */
109 		ssize_t length;
110 		ssize_t sent;
111 
112 		length = read(0, buf, 65536);
113 		if (length <= 0) {
114 			usleep(1000000);
115 			goto next;
116 		}
117 
118 		/*
119 		 * Ignore packets that are larger than 4096 bytes.
120 		 */
121 		if (length > 4096) {
122 			/*
123 			 * AFL_CMIN doesn't support persistent mode, so
124 			 * shutdown the server.
125 			 */
126 			if (getenv("AFL_CMIN")) {
127 				free(buf);
128 				close(sockfd);
129 				named_server_flushonshutdown(named_g_server,
130 							     false);
131 				isc_loopmgr_shutdown(named_g_loopmgr);
132 				return NULL;
133 			}
134 			raise(SIGSTOP);
135 			goto next;
136 		}
137 
138 		RUNTIME_CHECK(pthread_mutex_lock(&mutex) == 0);
139 
140 		ready = false;
141 
142 		sent = sendto(sockfd, buf, length, 0,
143 			      (struct sockaddr *)&servaddr, sizeof(servaddr));
144 		RUNTIME_CHECK(sent == length);
145 
146 		/*
147 		 * Read the reply message from named to unclog it. Don't
148 		 * bother if there isn't a reply.
149 		 */
150 		(void)recvfrom(sockfd, buf, 65536, MSG_DONTWAIT, NULL, NULL);
151 
152 		while (!ready) {
153 			pthread_cond_wait(&cond, &mutex);
154 		}
155 
156 		RUNTIME_CHECK(pthread_mutex_unlock(&mutex) == 0);
157 	next:;
158 	}
159 
160 	free(buf);
161 	close(sockfd);
162 
163 	named_server_flushonshutdown(named_g_server, false);
164 	isc_loopmgr_shutdown(named_g_loopmgr);
165 
166 	return NULL;
167 }
168 
169 /*
170  * In "resolver:" mode, this thread reads fuzzed reply messages from AFL
171  * from standard input. It also sets up a listener as a remote
172  * authoritative server and sends a driver query to the client side of
173  * named(resolver).  When named(resolver) connects to this authoritative
174  * server, this thread writes the fuzzed reply message from AFL to it.
175  *
176  * -A resolver:<saddress>:<sport>:<raddress>:<rport>
177  *
178  * Here, <saddress>:<sport> is where named(resolver) is listening on.
179  * <raddress>:<rport> is where the thread is supposed to setup the
180  * authoritative server. This address should be configured via the root
181  * zone to be the authoritiative server for aaaaaaaaaa.example.
182  *
183  * named(resolver) when being fuzzed will not cache answers.
184  */
185 static void *
186 fuzz_thread_resolver(void *arg) {
187 	char *sqtype, *shost, *sport, *rhost, *rport;
188 	struct sockaddr_in servaddr, recaddr, recvaddr;
189 	/*
190 	 * Query for aaaaaaaaaa.example./A in wire format with RD=1,
191 	 * EDNS and DO=1. 0x88, 0x0c at the start is the ID field which
192 	 * will be updated for each query.
193 	 */
194 	char respacket[] = { 0x88, 0x0c, 0x01, 0x20, 0x00, 0x01, 0x00, 0x00,
195 			     0x00, 0x00, 0x00, 0x01, 0x0a, 0x61, 0x61, 0x61,
196 			     0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x07,
197 			     0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x00,
198 			     0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x29, 0x10,
199 			     0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00 };
200 	/*
201 	 * Response for example./DNSKEY in wire format. Note that RRSIGs
202 	 * were generated with this DNSKEY that are used as seeds for
203 	 * AFL in the DNSSEC fuzzing job. So the DNSKEY content of this
204 	 * message must not change, or the corresponding RRSIGs will
205 	 * have to be updated. 0x8d, 0xf6 at the start is the ID field
206 	 * which will be made to match the query.
207 	 */
208 	const uint8_t dnskey_wf[] = {
209 		0x8d, 0xf6, 0x84, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00,
210 		0x00, 0x01, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65,
211 		0x00, 0x00, 0x30, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x30, 0x00,
212 		0x01, 0x00, 0x00, 0x01, 0x2c, 0x01, 0x08, 0x01, 0x00, 0x03,
213 		0x08, 0x03, 0x01, 0x00, 0x01, 0xbd, 0x81, 0xdc, 0x7f, 0x16,
214 		0xd4, 0x81, 0x7c, 0x1f, 0x9f, 0x6a, 0x68, 0xdd, 0xd4, 0xda,
215 		0x48, 0xd9, 0x1c, 0xbd, 0xa6, 0x46, 0x1a, 0xf0, 0xb4, 0xb9,
216 		0xec, 0x3d, 0x6c, 0x0b, 0x57, 0xc7, 0xd6, 0x54, 0x66, 0xe6,
217 		0x6c, 0xd5, 0x90, 0x3a, 0x78, 0x7d, 0x7f, 0x78, 0x80, 0xa2,
218 		0x89, 0x61, 0x6d, 0x8a, 0x2b, 0xcd, 0x0a, 0x77, 0x7a, 0xad,
219 		0xc9, 0x61, 0x53, 0x53, 0x8c, 0x99, 0x72, 0x86, 0x14, 0x74,
220 		0x9c, 0x49, 0x2a, 0x47, 0x23, 0xf7, 0x02, 0x07, 0x73, 0x1c,
221 		0x5c, 0x2e, 0xb4, 0x9a, 0xa4, 0xd7, 0x98, 0x42, 0xc3, 0xd2,
222 		0xfe, 0xbf, 0xf3, 0xb3, 0x6a, 0x52, 0x92, 0xd5, 0xfa, 0x47,
223 		0x00, 0xe3, 0xd9, 0x59, 0x31, 0x95, 0x48, 0x40, 0xfc, 0x06,
224 		0x73, 0x90, 0xc6, 0x73, 0x96, 0xba, 0x29, 0x91, 0xe2, 0xac,
225 		0xa3, 0xa5, 0x6d, 0x91, 0x6d, 0x52, 0xb9, 0x34, 0xba, 0x68,
226 		0x4f, 0xad, 0xf0, 0xc3, 0xf3, 0x1d, 0x6d, 0x61, 0x76, 0xe5,
227 		0x3d, 0xa3, 0x9b, 0x2a, 0x0c, 0x92, 0xb3, 0x78, 0x6b, 0xf1,
228 		0x20, 0xd6, 0x90, 0xb7, 0xac, 0xe2, 0xf8, 0x2b, 0x94, 0x10,
229 		0x79, 0xce, 0xa8, 0x60, 0x42, 0xea, 0x6a, 0x18, 0x2f, 0xc0,
230 		0xd8, 0x05, 0x0a, 0x3b, 0x06, 0x0f, 0x02, 0x7e, 0xff, 0x33,
231 		0x46, 0xee, 0xb6, 0x21, 0x25, 0x90, 0x63, 0x4b, 0x3b, 0x5e,
232 		0xb2, 0x72, 0x3a, 0xcb, 0x91, 0x41, 0xf4, 0x20, 0x50, 0x78,
233 		0x1c, 0x93, 0x95, 0xda, 0xfa, 0xae, 0x85, 0xc5, 0xd7, 0x6b,
234 		0x92, 0x0c, 0x70, 0x6b, 0xe4, 0xb7, 0x29, 0x3a, 0x2e, 0x18,
235 		0x88, 0x82, 0x33, 0x7c, 0xa8, 0xea, 0xb8, 0x31, 0x8f, 0xaf,
236 		0x50, 0xc5, 0x9c, 0x08, 0x56, 0x8f, 0x09, 0x76, 0x4e, 0xdf,
237 		0x97, 0x75, 0x9d, 0x00, 0x52, 0x7f, 0xdb, 0xec, 0x30, 0xcb,
238 		0x1c, 0x4c, 0x2a, 0x21, 0x93, 0xc4, 0x6d, 0x85, 0xa9, 0x40,
239 		0x3b, 0xc0, 0x0c, 0x00, 0x2e, 0x00, 0x01, 0x00, 0x00, 0x01,
240 		0x2c, 0x01, 0x1b, 0x00, 0x30, 0x08, 0x01, 0x00, 0x00, 0x01,
241 		0x2c, 0x67, 0x74, 0x85, 0x80, 0x58, 0xb3, 0xc5, 0x17, 0x36,
242 		0x90, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x00,
243 		0x45, 0xac, 0xd3, 0x82, 0x69, 0xf3, 0x10, 0x3a, 0x97, 0x2c,
244 		0x6a, 0xa9, 0x78, 0x99, 0xea, 0xb0, 0xcc, 0xf7, 0xaf, 0x33,
245 		0x51, 0x5b, 0xdf, 0x77, 0x04, 0x18, 0x14, 0x99, 0x61, 0xeb,
246 		0x8d, 0x76, 0x3f, 0xd1, 0x71, 0x14, 0x43, 0x80, 0x53, 0xc2,
247 		0x3b, 0x9f, 0x09, 0x4f, 0xb3, 0x51, 0x04, 0x89, 0x0e, 0xc8,
248 		0x54, 0x12, 0xcd, 0x07, 0x20, 0xbe, 0x94, 0xc2, 0xda, 0x99,
249 		0xdd, 0x1e, 0xf8, 0xb0, 0x84, 0x2e, 0xf9, 0x19, 0x35, 0x36,
250 		0xf5, 0xd0, 0x5d, 0x82, 0x18, 0x74, 0xa0, 0x00, 0xb6, 0x15,
251 		0x57, 0x40, 0x5f, 0x78, 0x2d, 0x27, 0xac, 0xc7, 0x8a, 0x29,
252 		0x55, 0xa9, 0xcd, 0xbc, 0xf7, 0x3e, 0xff, 0xae, 0x1a, 0x5a,
253 		0x1d, 0xac, 0x0d, 0x78, 0x0e, 0x08, 0x33, 0x6c, 0x59, 0x70,
254 		0x40, 0xb9, 0x65, 0xbd, 0x35, 0xbb, 0x9a, 0x70, 0xdc, 0x93,
255 		0x66, 0xb0, 0xef, 0xfe, 0xf0, 0x32, 0xa6, 0xee, 0xb7, 0x03,
256 		0x89, 0xa2, 0x4d, 0xe0, 0xf1, 0x20, 0xdf, 0x39, 0xe8, 0xe3,
257 		0xcc, 0x95, 0xe9, 0x9a, 0xad, 0xbf, 0xbd, 0x7c, 0xf7, 0xd7,
258 		0xde, 0x47, 0x9e, 0xf6, 0x17, 0xbb, 0x84, 0xa9, 0xed, 0xf2,
259 		0x45, 0x61, 0x6d, 0x13, 0x0b, 0x06, 0x29, 0x50, 0xde, 0xfd,
260 		0x42, 0xb0, 0x66, 0x2c, 0x1c, 0x2b, 0x63, 0xcb, 0x4e, 0xb9,
261 		0x31, 0xc4, 0xea, 0xd2, 0x07, 0x3a, 0x08, 0x79, 0x19, 0x4b,
262 		0x4c, 0x50, 0x97, 0x02, 0xd7, 0x26, 0x41, 0x2f, 0xdd, 0x57,
263 		0xaa, 0xb0, 0xa0, 0x21, 0x4e, 0x74, 0xb6, 0x97, 0x4b, 0x8b,
264 		0x09, 0x9c, 0x3d, 0x29, 0xfb, 0x12, 0x27, 0x47, 0x8f, 0xb8,
265 		0xc5, 0x8e, 0x65, 0xcd, 0xca, 0x2f, 0xba, 0xf5, 0x3e, 0xec,
266 		0x56, 0xc3, 0xc9, 0xa1, 0x62, 0x7d, 0xf2, 0x9f, 0x90, 0x16,
267 		0x1d, 0xbf, 0x97, 0x28, 0xe1, 0x92, 0xb1, 0x53, 0xab, 0xc4,
268 		0xe0, 0x99, 0xbb, 0x19, 0x90, 0x7c, 0x00, 0x00, 0x29, 0x10,
269 		0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00
270 	};
271 
272 	int sockfd;
273 	int listenfd;
274 	int loop;
275 	uint16_t qtype;
276 	char *buf, *rbuf;
277 	char *nameptr;
278 	unsigned int i;
279 	uint8_t llen;
280 	uint64_t seed;
281 
282 	UNUSED(arg);
283 
284 	/*
285 	 * Parse named -A argument in the "qtype:saddress:sport:raddress:rport"
286 	 * syntax.  Due to the syntax used, this only supports IPv4 addresses.
287 	 */
288 	sqtype = strdup(named_g_fuzz_addr);
289 	RUNTIME_CHECK(sqtype != NULL);
290 
291 	shost = strchr(sqtype, ':');
292 	RUNTIME_CHECK(shost != NULL);
293 	*shost = 0;
294 	shost++;
295 
296 	sport = strchr(shost, ':');
297 	RUNTIME_CHECK(sport != NULL);
298 	*sport = 0;
299 	sport++;
300 
301 	rhost = strchr(sport, ':');
302 	RUNTIME_CHECK(rhost != NULL);
303 	*rhost = 0;
304 	rhost++;
305 
306 	rport = strchr(rhost, ':');
307 	RUNTIME_CHECK(rport != NULL);
308 	*rport = 0;
309 	rport++;
310 
311 	/*
312 	 * Patch in the qtype into the question section of respacket.
313 	 */
314 	qtype = atoi(sqtype);
315 	respacket[32] = (qtype >> 8) & 0xff;
316 	respacket[33] = qtype & 0xff;
317 
318 	memset(&servaddr, 0, sizeof(servaddr));
319 	servaddr.sin_family = AF_INET;
320 	RUNTIME_CHECK(inet_pton(AF_INET, shost, &servaddr.sin_addr) == 1);
321 	servaddr.sin_port = htons(atoi(sport));
322 
323 	memset(&recaddr, 0, sizeof(recaddr));
324 	recaddr.sin_family = AF_INET;
325 	RUNTIME_CHECK(inet_pton(AF_INET, rhost, &recaddr.sin_addr) == 1);
326 	recaddr.sin_port = htons(atoi(rport));
327 
328 	free(sqtype);
329 
330 	/*
331 	 * Wait for named to start. This is set in run_server() in the
332 	 * named thread.
333 	 */
334 	while (!named_g_run_done) {
335 		usleep(10000);
336 	}
337 
338 	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
339 	RUNTIME_CHECK(sockfd != -1);
340 
341 	listenfd = socket(AF_INET, SOCK_DGRAM, 0);
342 	RUNTIME_CHECK(listenfd != -1);
343 
344 	RUNTIME_CHECK(bind(listenfd, (struct sockaddr *)&recaddr,
345 			   sizeof(struct sockaddr_in)) == 0);
346 
347 	buf = malloc(65536);
348 	rbuf = malloc(65536);
349 	RUNTIME_CHECK(buf != NULL);
350 	RUNTIME_CHECK(rbuf != NULL);
351 
352 	seed = 42;
353 
354 	/*
355 	 * Processing fuzzed packets 100,000 times before shutting down
356 	 * the app.
357 	 */
358 	for (loop = 0; loop < 100000; loop++) {
359 		ssize_t length;
360 		ssize_t sent;
361 		unsigned short id;
362 		socklen_t socklen;
363 
364 		memset(buf, 0, 12);
365 		length = read(0, buf, 65536);
366 		if (length <= 0) {
367 			usleep(1000000);
368 			continue;
369 		}
370 
371 		if (length > 4096) {
372 			if (getenv("AFL_CMIN")) {
373 				free(buf);
374 				free(rbuf);
375 				close(sockfd);
376 				close(listenfd);
377 				named_server_flushonshutdown(named_g_server,
378 							     false);
379 				isc_loopmgr_shutdown(named_g_loopmgr);
380 				return NULL;
381 			}
382 			raise(SIGSTOP);
383 			continue;
384 		}
385 
386 		if (length < 12) {
387 			length = 12;
388 		}
389 
390 		RUNTIME_CHECK(pthread_mutex_lock(&mutex) == 0);
391 
392 		ready = false;
393 
394 		/* Use a unique query ID. */
395 		seed = 1664525 * seed + 1013904223;
396 		id = seed & 0xffff;
397 		respacket[0] = (id >> 8) & 0xff;
398 		respacket[1] = id & 0xff;
399 
400 		/*
401 		 * Flush any pending data on the authoritative server.
402 		 */
403 		socklen = sizeof(recvaddr);
404 		(void)recvfrom(listenfd, rbuf, 65536, MSG_DONTWAIT,
405 			       (struct sockaddr *)&recvaddr, &socklen);
406 
407 		/*
408 		 * Send a fixed client query to named(resolver) of
409 		 * aaaaaaaaaa.example./A. This is the starting query
410 		 * driver.
411 		 */
412 		sent = sendto(sockfd, respacket, sizeof(respacket), 0,
413 			      (struct sockaddr *)&servaddr, sizeof(servaddr));
414 		RUNTIME_CHECK(sent == sizeof(respacket));
415 
416 		/*
417 		 * named(resolver) will process the query above and send
418 		 * an upstream query to the authoritative server. We
419 		 * handle that here as the upstream authoritative server
420 		 * on listenfd.
421 		 */
422 		socklen = sizeof(recvaddr);
423 		sent = recvfrom(listenfd, rbuf, 65536, 0,
424 				(struct sockaddr *)&recvaddr, &socklen);
425 		RUNTIME_CHECK(sent > 0);
426 
427 		/*
428 		 * Copy QID and set QR so that response is always
429 		 * accepted by named(resolver).
430 		 */
431 		buf[0] = rbuf[0];
432 		buf[1] = rbuf[1];
433 		buf[2] |= 0x80;
434 
435 		/*
436 		 * NOTE: We are not copying the QNAME or setting
437 		 * rcode=NOERROR each time. So the resolver may fail the
438 		 * client query (driver) / wander due to this. AA flag
439 		 * may also not be set based on the contents of the AFL
440 		 * fuzzed packet.
441 		 */
442 
443 		/*
444 		 * A hack - set QTYPE to the one from query so that we
445 		 * can easily share packets between instances. If we
446 		 * write over something else we'll get FORMERR anyway.
447 		 */
448 
449 		/* Skip DNS header to get to the name */
450 		nameptr = buf + 12;
451 
452 		/* Skip the name to get to the qtype */
453 		i = 0;
454 		while (((llen = nameptr[i]) != 0) && (i < 255) &&
455 		       (((nameptr + i + 1 + llen) - buf) < length))
456 		{
457 			i += 1 + llen;
458 		}
459 
460 		if (i <= 255) {
461 			nameptr += 1 + i;
462 			/* Patch the qtype */
463 			if ((nameptr - buf) < (length - 2)) {
464 				*nameptr++ = (qtype >> 8) & 0xff;
465 				*nameptr++ = qtype & 0xff;
466 			}
467 			/* Patch the qclass */
468 			if ((nameptr - buf) < (length - 2)) {
469 				*nameptr++ = 0;
470 				*nameptr++ = 1;
471 			}
472 		}
473 
474 		/*
475 		 * Send the reply to named(resolver).
476 		 */
477 		sent = sendto(listenfd, buf, length, 0,
478 			      (struct sockaddr *)&recvaddr, sizeof(recvaddr));
479 		RUNTIME_CHECK(sent == length);
480 
481 		/* We might get additional questions here (e.g. for CNAME). */
482 		for (;;) {
483 			fd_set fds;
484 			struct timeval tv;
485 			int rv;
486 			int max;
487 
488 			FD_ZERO(&fds);
489 			FD_SET(listenfd, &fds);
490 			FD_SET(sockfd, &fds);
491 			tv.tv_sec = 10;
492 			tv.tv_usec = 0;
493 			max = (listenfd > sockfd ? listenfd : sockfd) + 1;
494 
495 			rv = select(max, &fds, NULL, NULL, &tv);
496 			RUNTIME_CHECK(rv > 0);
497 
498 			if (FD_ISSET(sockfd, &fds)) {
499 				/*
500 				 * It's the reply from named(resolver)
501 				 * to the client(query driver), so we're
502 				 * done.
503 				 */
504 				(void)recvfrom(sockfd, buf, 65536, 0, NULL,
505 					       NULL);
506 				break;
507 			}
508 
509 			/*
510 			 * We've got additional question (eg. due to
511 			 * CNAME). Bounce it - setting QR flag and
512 			 * NOERROR rcode and sending it back.
513 			 */
514 			length = recvfrom(listenfd, buf, 65536, 0,
515 					  (struct sockaddr *)&recvaddr,
516 					  &socklen);
517 
518 			/*
519 			 * If this is a DNSKEY query, send the DNSKEY,
520 			 * otherwise, bounce the query.
521 			 */
522 
523 			/* Skip DNS header to get to the name */
524 			nameptr = buf + 12;
525 
526 			/* Skip the name to get to the qtype */
527 			i = 0;
528 			while (((llen = nameptr[i]) != 0) && (i < 255) &&
529 			       (((nameptr + i + 1 + llen) - buf) < length))
530 			{
531 				i += 1 + llen;
532 			}
533 
534 			if (i <= 255) {
535 				nameptr += 1 + i;
536 				/*
537 				 * Patch in the DNSKEY reply without
538 				 * touching the ID field. Note that we
539 				 * don't compare the name in the
540 				 * question section in the query, but we
541 				 * don't expect to receive any query for
542 				 * type DNSKEY but for the name
543 				 * "example."
544 				 */
545 				if ((nameptr - buf) < (length - 2)) {
546 					uint8_t hb, lb;
547 					hb = *nameptr++;
548 					lb = *nameptr++;
549 					qtype = (hb << 8) | lb;
550 
551 					if (qtype == 48) {
552 						memmove(buf + 2, dnskey_wf + 2,
553 							sizeof(dnskey_wf) - 2);
554 						length = sizeof(dnskey_wf);
555 					}
556 				}
557 			}
558 
559 			buf[2] |= 0x80;
560 			buf[3] &= 0xF0;
561 			sent = sendto(listenfd, buf, length, 0,
562 				      (struct sockaddr *)&recvaddr,
563 				      sizeof(recvaddr));
564 			RUNTIME_CHECK(sent == length);
565 		}
566 
567 		while (!ready) {
568 			pthread_cond_wait(&cond, &mutex);
569 		}
570 
571 		RUNTIME_CHECK(pthread_mutex_unlock(&mutex) == 0);
572 	}
573 
574 	free(buf);
575 	free(rbuf);
576 	close(sockfd);
577 	close(listenfd);
578 	named_server_flushonshutdown(named_g_server, false);
579 	isc_loopmgr_shutdown(named_g_loopmgr);
580 
581 #ifdef __AFL_LOOP
582 	/*
583 	 * This is here just for the signature, that's how AFL detects
584 	 * if it's a 'persistent mode' binary. It has to occur somewhere
585 	 * in the file, that's all. < wpk_> AFL checks the binary for
586 	 * this signature ("##SIG_AFL_PERSISTENT##") and runs the binary
587 	 * in persistent mode if it's present.
588 	 */
589 	__AFL_LOOP(0);
590 #endif /* ifdef __AFL_LOOP */
591 
592 	return NULL;
593 }
594 
595 /*
596  * In "tcp:", "http:" and "rndc:" modes, this thread reads fuzzed query
597  * blobs from AFL from standard input and sends it to the corresponding
598  * TCP listening port of named (port 53 DNS, or the HTTP statistics
599  * channels listener or the rndc port) that is passed in the -A
600  * <mode>:<address>:<port> option. It can be used to test named from the
601  * client side.
602  */
603 static void *
604 fuzz_thread_tcp(void *arg) {
605 	char *host;
606 	char *port;
607 	struct sockaddr_in servaddr;
608 	int sockfd;
609 	char *buf;
610 	int loop;
611 
612 	UNUSED(arg);
613 
614 	/*
615 	 * Parse named -A argument in the "address:port" syntax. Due to
616 	 * the syntax used, this only supports IPv4 addresses.
617 	 */
618 	host = strdup(named_g_fuzz_addr);
619 	RUNTIME_CHECK(host != NULL);
620 
621 	port = strchr(host, ':');
622 	RUNTIME_CHECK(port != NULL);
623 	*port = 0;
624 	++port;
625 
626 	memset(&servaddr, 0, sizeof(servaddr));
627 	servaddr.sin_family = AF_INET;
628 	RUNTIME_CHECK(inet_pton(AF_INET, host, &servaddr.sin_addr) == 1);
629 	servaddr.sin_port = htons(atoi(port));
630 
631 	free(host);
632 
633 	/*
634 	 * Wait for named to start. This is set in run_server() in the
635 	 * named thread.
636 	 */
637 	while (!named_g_run_done) {
638 		usleep(10000);
639 	}
640 
641 	buf = malloc(65539);
642 	RUNTIME_CHECK(buf != NULL);
643 
644 	/*
645 	 * Processing fuzzed packets 100,000 times before shutting down
646 	 * the app.
647 	 */
648 	for (loop = 0; loop < 100000; loop++) {
649 		ssize_t length;
650 		ssize_t sent;
651 		int yes;
652 		int r;
653 
654 		if (named_g_fuzz_type == isc_fuzz_tcpclient) {
655 			/*
656 			 * To fuzz DNS TCP client we have to put 16-bit
657 			 * message length preceding the start of packet.
658 			 */
659 			length = read(0, buf + 2, 65535);
660 			buf[0] = (length >> 8) & 0xff;
661 			buf[1] = length & 0xff;
662 			length += 2;
663 		} else {
664 			/*
665 			 * Other types of TCP clients such as HTTP, etc.
666 			 */
667 			length = read(0, buf, 65535);
668 		}
669 		if (length <= 0) {
670 			usleep(1000000);
671 			continue;
672 		}
673 		if (named_g_fuzz_type == isc_fuzz_http) {
674 			/*
675 			 * This guarantees that the request will be
676 			 * processed.
677 			 */
678 			INSIST(length <= 65535);
679 			buf[length++] = '\r';
680 			buf[length++] = '\n';
681 			buf[length++] = '\r';
682 			buf[length++] = '\n';
683 		}
684 
685 		RUNTIME_CHECK(pthread_mutex_lock(&mutex) == 0);
686 
687 		ready = false;
688 		yes = 1;
689 		sockfd = socket(AF_INET, SOCK_STREAM, 0);
690 
691 		RUNTIME_CHECK(sockfd != -1);
692 		RUNTIME_CHECK(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes,
693 					 sizeof(int)) == 0);
694 
695 		do {
696 			r = connect(sockfd, (struct sockaddr *)&servaddr,
697 				    sizeof(servaddr));
698 			if (r != 0) {
699 				usleep(10000);
700 			}
701 		} while (r != 0);
702 
703 		/*
704 		 * Send the fuzzed query blob to the target server.
705 		 */
706 		sent = write(sockfd, buf, length);
707 		RUNTIME_CHECK(sent == length);
708 
709 		close(sockfd);
710 
711 		while (!ready) {
712 			pthread_cond_wait(&cond, &mutex);
713 		}
714 
715 		RUNTIME_CHECK(pthread_mutex_unlock(&mutex) == 0);
716 	}
717 
718 	free(buf);
719 	close(sockfd);
720 	named_server_flushonshutdown(named_g_server, false);
721 	isc_loopmgr_shutdown(named_g_loopmgr);
722 
723 	return NULL;
724 }
725 
726 #endif /* ENABLE_AFL */
727 
728 /*
729  * named has finished processing a message and has sent the
730  * reply. Signal the fuzz thread using the condition variable, to read
731  * and process the next item from AFL.
732  */
733 void
734 named_fuzz_notify(void) {
735 #ifdef ENABLE_AFL
736 	if (getenv("AFL_CMIN")) {
737 		named_server_flushonshutdown(named_g_server, false);
738 		isc_loopmgr_shutdown(named_g_loopmgr);
739 		return;
740 	}
741 
742 	raise(SIGSTOP);
743 
744 	RUNTIME_CHECK(pthread_mutex_lock(&mutex) == 0);
745 
746 	ready = true;
747 
748 	RUNTIME_CHECK(pthread_cond_signal(&cond) == 0);
749 	RUNTIME_CHECK(pthread_mutex_unlock(&mutex) == 0);
750 #endif /* ENABLE_AFL */
751 }
752 
753 void
754 named_fuzz_setup(void) {
755 #ifdef ENABLE_AFL
756 	if (getenv("__AFL_PERSISTENT") || getenv("AFL_CMIN")) {
757 		pthread_t thread;
758 		void *(fn) = NULL;
759 
760 		switch (named_g_fuzz_type) {
761 		case isc_fuzz_client:
762 			fn = fuzz_thread_client;
763 			break;
764 
765 		case isc_fuzz_http:
766 		case isc_fuzz_tcpclient:
767 		case isc_fuzz_rndc:
768 			fn = fuzz_thread_tcp;
769 			break;
770 
771 		case isc_fuzz_resolver:
772 			fn = fuzz_thread_resolver;
773 			break;
774 
775 		default:
776 			RUNTIME_CHECK(fn != NULL);
777 		}
778 
779 		RUNTIME_CHECK(pthread_mutex_init(&mutex, NULL) == 0);
780 		RUNTIME_CHECK(pthread_cond_init(&cond, NULL) == 0);
781 		RUNTIME_CHECK(pthread_create(&thread, NULL, fn, NULL) == 0);
782 	}
783 #endif /* ENABLE_AFL */
784 }
785