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