Home | History | Annotate | Line # | Download | only in named
fuzz.c revision 1.3.4.2
      1 /*	$NetBSD: fuzz.c,v 1.3.4.2 2024/02/29 12:28:18 martin 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/app.h>
     31 #include <isc/condition.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_app_shutdown();
    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_app_shutdown();
    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_app_shutdown();
    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_app_shutdown();
    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_app_shutdown();
    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_app_shutdown();
    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