1 /* $NetBSD: ede.c,v 1.3 2026/08/29 14:55:16 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 /*! \file */ 17 18 #include <inttypes.h> 19 20 #include <isc/mem.h> 21 #include <isc/util.h> 22 23 #include <dns/ede.h> 24 25 #define DNS_EDE_MAGIC ISC_MAGIC('E', 'D', 'E', '!') 26 #define DNS_EDE_VALID(v) ISC_MAGIC_VALID(v, DNS_EDE_MAGIC) 27 28 static bool 29 dns__ede_checkandupdateedeused(dns_edectx_t *edectx, uint16_t code) { 30 if (edectx->edeused & (UINT64_C(1) << code)) { 31 return true; 32 } 33 34 edectx->edeused |= UINT64_C(1) << code; 35 return false; 36 } 37 38 void 39 dns_ede_add(dns_edectx_t *edectx, uint16_t code, const char *text) { 40 REQUIRE(DNS_EDE_VALID(edectx)); 41 REQUIRE(code <= DNS_EDE_MAX_CODE); 42 43 uint16_t becode = htobe16(code); 44 dns_ednsopt_t *edns = NULL; 45 size_t textlen = 0; 46 47 if (dns__ede_checkandupdateedeused(edectx, code)) { 48 isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, 49 DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(1), 50 "ignoring duplicate ede %u %s", code, 51 text == NULL ? "(null)" : text); 52 return; 53 } 54 55 if (edectx->nextede >= DNS_EDE_MAX_ERRORS) { 56 isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, 57 DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(1), 58 "too many ede, ignoring %u %s", code, 59 text == NULL ? "(null)" : text); 60 return; 61 } 62 INSIST(edectx->ede[edectx->nextede] == NULL); 63 64 isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, 65 DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(1), 66 "set ede: info-code %u extra-text %s", code, 67 text == NULL ? "(null)" : text); 68 69 if (text != NULL) { 70 textlen = strlen(text); 71 72 if (textlen > DNS_EDE_EXTRATEXT_LEN) { 73 isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, 74 DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(1), 75 "truncate EDE code %hu text: %s", code, 76 text); 77 textlen = DNS_EDE_EXTRATEXT_LEN; 78 } 79 } 80 81 edns = isc_mem_get(edectx->mctx, 82 sizeof(*edns) + sizeof(becode) + textlen); 83 *edns = (dns_ednsopt_t){ 84 .code = DNS_OPT_EDE, 85 .length = sizeof(becode) + textlen, 86 .value = (uint8_t *)edns + sizeof(*edns), 87 }; 88 89 memmove(edns->value, &becode, sizeof(becode)); 90 if (textlen > 0) { 91 memmove(edns->value + sizeof(becode), text, textlen); 92 } 93 94 edectx->ede[edectx->nextede] = edns; 95 edectx->nextede++; 96 } 97 98 void 99 dns_ede_init(isc_mem_t *mctx, dns_edectx_t *edectx) { 100 REQUIRE(mctx != NULL); 101 102 /* 103 * Memory context is assigned, not attached here, 104 * thus there's no detach in dns_ede_reset(). 105 */ 106 *edectx = (dns_edectx_t){ 107 .magic = DNS_EDE_MAGIC, 108 .mctx = mctx, 109 }; 110 } 111 112 void 113 dns_ede_reset(dns_edectx_t *edectx) { 114 REQUIRE(DNS_EDE_VALID(edectx)); 115 116 for (size_t i = 0; i < DNS_EDE_MAX_ERRORS; i++) { 117 dns_ednsopt_t *edns = edectx->ede[i]; 118 if (edns == NULL) { 119 break; 120 } 121 122 isc_mem_put(edectx->mctx, edns, sizeof(*edns) + edns->length); 123 edectx->ede[i] = NULL; 124 } 125 126 dns_ede_init(edectx->mctx, edectx); 127 } 128 129 void 130 dns_ede_invalidate(dns_edectx_t *edectx) { 131 REQUIRE(DNS_EDE_VALID(edectx)); 132 133 dns_ede_reset(edectx); 134 135 edectx->magic = 0; 136 edectx->mctx = NULL; 137 } 138 139 void 140 dns_ede_copy(dns_edectx_t *edectx_to, const dns_edectx_t *edectx_from) { 141 REQUIRE(DNS_EDE_VALID(edectx_to)); 142 REQUIRE(DNS_EDE_VALID(edectx_from)); 143 144 if (edectx_to == edectx_from) { 145 return; 146 } 147 148 for (size_t pos = 0; pos < DNS_EDE_MAX_ERRORS; pos++) { 149 uint16_t fromcode; 150 151 if (edectx_from->ede[pos] == NULL) { 152 break; 153 } 154 155 fromcode = ISC_U8TO16_BE(edectx_from->ede[pos]->value); 156 if (dns__ede_checkandupdateedeused(edectx_to, fromcode)) { 157 continue; 158 } 159 160 if (edectx_to->nextede >= DNS_EDE_MAX_ERRORS) { 161 isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, 162 DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(1), 163 "too many ede from subfetch"); 164 break; 165 } 166 167 INSIST(edectx_to->ede[edectx_to->nextede] == NULL); 168 169 dns_ednsopt_t *edns = isc_mem_get( 170 edectx_to->mctx, 171 sizeof(*edns) + edectx_from->ede[pos]->length); 172 *edns = (dns_ednsopt_t){ 173 .code = DNS_OPT_EDE, 174 .length = edectx_from->ede[pos]->length, 175 .value = (uint8_t *)edns + sizeof(*edns), 176 }; 177 memmove(edns->value, edectx_from->ede[pos]->value, 178 edectx_from->ede[pos]->length); 179 180 edectx_to->ede[edectx_to->nextede] = edns; 181 edectx_to->nextede++; 182 } 183 } 184