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