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