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