xref: /netbsd-src/external/mpl/bind/dist/fuzz/dns_message_parse.c (revision bcda20f65a8566e103791ec395f7f499ef322704)
1 /*	$NetBSD: dns_message_parse.c,v 1.3 2025/01/26 16:25:20 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 #include <stdlib.h>
19 
20 #include <isc/buffer.h>
21 #include <isc/commandline.h>
22 #include <isc/file.h>
23 #include <isc/mem.h>
24 #include <isc/result.h>
25 #include <isc/string.h>
26 #include <isc/util.h>
27 
28 #include <dns/message.h>
29 
30 #include "fuzz.h"
31 
32 bool debug = false;
33 
34 static isc_mem_t *mctx = NULL;
35 static uint8_t *output = NULL;
36 static size_t output_len = 1024;
37 static uint8_t render_buf[64 * 1024 - 1];
38 
39 int
40 LLVMFuzzerInitialize(int *argc ISC_ATTR_UNUSED, char ***argv ISC_ATTR_UNUSED) {
41 	isc_mem_create(&mctx);
42 	output = isc_mem_get(mctx, output_len);
43 
44 	return 0;
45 }
46 
47 static isc_result_t
48 parse_message(isc_buffer_t *input, dns_message_t **messagep) {
49 	isc_result_t result;
50 	dns_message_t *message = NULL;
51 
52 	dns_message_create(mctx, NULL, NULL, DNS_MESSAGE_INTENTPARSE, &message);
53 
54 	result = dns_message_parse(message, input, DNS_MESSAGEPARSE_BESTEFFORT);
55 	if (result == DNS_R_RECOVERABLE) {
56 		result = ISC_R_SUCCESS;
57 	}
58 
59 	if (result == ISC_R_SUCCESS && messagep != NULL) {
60 		*messagep = message;
61 	} else {
62 		dns_message_detach(&message);
63 	}
64 
65 	return result;
66 }
67 
68 static isc_result_t
69 print_message(dns_message_t *message) {
70 	isc_result_t result;
71 	isc_buffer_t buffer;
72 
73 	do {
74 		isc_buffer_init(&buffer, output, output_len);
75 		result = dns_message_totext(message, &dns_master_style_debug, 0,
76 					    &buffer);
77 		if (result == ISC_R_NOSPACE) {
78 			isc_mem_put(mctx, output, output_len);
79 			output_len *= 2;
80 			output = isc_mem_get(mctx, output_len);
81 			continue;
82 		}
83 	} while (result == ISC_R_NOSPACE);
84 
85 	if (debug) {
86 		fprintf(stderr, "%.*s\n", (int)isc_buffer_usedlength(&buffer),
87 			output);
88 	}
89 
90 	return result;
91 }
92 
93 #define CHECKRESULT(r, f)                 \
94 	{                                 \
95 		r = (f);                  \
96 		if (r != ISC_R_SUCCESS) { \
97 			goto cleanup;     \
98 		}                         \
99 	}
100 
101 static isc_result_t
102 render_message(dns_message_t **messagep) {
103 	isc_result_t result;
104 	dns_message_t *message = *messagep;
105 	isc_buffer_t buffer;
106 	dns_compress_t cctx;
107 
108 	isc_buffer_init(&buffer, render_buf, sizeof(render_buf));
109 
110 	message->from_to_wire = DNS_MESSAGE_INTENTRENDER;
111 	for (size_t i = 0; i < DNS_SECTION_MAX; i++) {
112 		message->counts[i] = 0;
113 	}
114 
115 	dns_compress_init(&cctx, mctx, 0);
116 
117 	CHECKRESULT(result, dns_message_renderbegin(message, &cctx, &buffer));
118 
119 	CHECKRESULT(result, dns_message_rendersection(message,
120 						      DNS_SECTION_QUESTION, 0));
121 
122 	CHECKRESULT(result,
123 		    dns_message_rendersection(message, DNS_SECTION_ANSWER, 0));
124 	CHECKRESULT(result, dns_message_rendersection(
125 				    message, DNS_SECTION_AUTHORITY, 0));
126 
127 	CHECKRESULT(result, dns_message_rendersection(
128 				    message, DNS_SECTION_ADDITIONAL, 0));
129 
130 	dns_message_renderend(message);
131 
132 	dns_compress_invalidate(&cctx);
133 
134 	message->from_to_wire = DNS_MESSAGE_INTENTPARSE;
135 
136 	dns_message_detach(messagep);
137 
138 	result = parse_message(&buffer, messagep);
139 
140 	return result;
141 
142 cleanup:
143 	dns_compress_invalidate(&cctx);
144 	return result;
145 }
146 
147 int
148 LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
149 	isc_buffer_t buffer;
150 	isc_result_t result;
151 	dns_message_t *message = NULL;
152 
153 	if (size > 65535) {
154 		return 0;
155 	}
156 
157 	isc_buffer_constinit(&buffer, data, size);
158 	isc_buffer_add(&buffer, size);
159 	isc_buffer_setactive(&buffer, size);
160 
161 	result = parse_message(&buffer, &message);
162 	if (result != ISC_R_SUCCESS) {
163 		goto cleanup;
164 	}
165 
166 	result = print_message(message);
167 	if (result != ISC_R_SUCCESS) {
168 		goto cleanup;
169 	}
170 
171 	result = render_message(&message);
172 	if (result != ISC_R_SUCCESS) {
173 		goto cleanup;
174 	}
175 
176 	result = print_message(message);
177 	if (result != ISC_R_SUCCESS) {
178 		goto cleanup;
179 	}
180 
181 cleanup:
182 	if (message != NULL) {
183 		dns_message_detach(&message);
184 	}
185 
186 	return 0;
187 }
188