Home | History | Annotate | Line # | Download | only in dns
      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