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