Coverage Report

Created: 2026-09-14 06:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/bind9/lib/dns/ede.c
Line
Count
Source
1
/*
2
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3
 *
4
 * SPDX-License-Identifier: MPL-2.0
5
 *
6
 * This Source Code Form is subject to the terms of the Mozilla Public
7
 * License, v. 2.0. If a copy of the MPL was not distributed with this
8
 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9
 *
10
 * See the COPYRIGHT file distributed with this work for additional
11
 * information regarding copyright ownership.
12
 */
13
14
/*! \file */
15
16
#include <inttypes.h>
17
18
#include <isc/mem.h>
19
#include <isc/util.h>
20
21
#include <dns/ede.h>
22
23
0
#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
0
dns__ede_checkandupdateedeused(dns_edectx_t *edectx, dns_edecode_t code) {
28
0
  if (edectx->edeused & (UINT64_C(1) << code)) {
29
0
    return true;
30
0
  }
31
32
0
  edectx->edeused |= UINT64_C(1) << code;
33
0
  return false;
34
0
}
35
36
void
37
0
dns_ede_add(dns_edectx_t *edectx, uint16_t code, const char *text) {
38
0
  REQUIRE(DNS_EDE_VALID(edectx));
39
0
  REQUIRE(code < DNS_EDE_MAX_CODE);
40
41
0
  uint16_t becode = htobe16(code);
42
0
  dns_ednsopt_t *edns = NULL;
43
0
  size_t textlen = 0;
44
45
0
  if (dns__ede_checkandupdateedeused(edectx, code)) {
46
0
    isc_log_write(DNS_LOGCATEGORY_RESOLVER, DNS_LOGMODULE_RESOLVER,
47
0
            ISC_LOG_DEBUG(1), "ignoring duplicate ede %u %s",
48
0
            code, text == NULL ? "(null)" : text);
49
0
    return;
50
0
  }
51
52
0
  if (edectx->nextede >= DNS_EDE_MAX_ERRORS) {
53
0
    isc_log_write(DNS_LOGCATEGORY_RESOLVER, DNS_LOGMODULE_RESOLVER,
54
0
            ISC_LOG_DEBUG(1), "too many ede, ignoring %u %s",
55
0
            code, text == NULL ? "(null)" : text);
56
0
    return;
57
0
  }
58
0
  INSIST(edectx->ede[edectx->nextede] == NULL);
59
60
0
  isc_log_write(DNS_LOGCATEGORY_RESOLVER, DNS_LOGMODULE_RESOLVER,
61
0
          ISC_LOG_DEBUG(1), "set ede: info-code %u extra-text %s",
62
0
          code, text == NULL ? "(null)" : text);
63
64
0
  if (text != NULL) {
65
0
    textlen = strlen(text);
66
67
0
    if (textlen > DNS_EDE_EXTRATEXT_LEN) {
68
0
      isc_log_write(DNS_LOGCATEGORY_RESOLVER,
69
0
              DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(1),
70
0
              "truncate EDE code %hu text: %s", code,
71
0
              text);
72
0
      textlen = DNS_EDE_EXTRATEXT_LEN;
73
0
    }
74
0
  }
75
76
0
  edns = isc_mem_get(edectx->mctx,
77
0
         sizeof(*edns) + sizeof(becode) + textlen);
78
0
  *edns = (dns_ednsopt_t){
79
0
    .code = DNS_OPT_EDE,
80
0
    .length = sizeof(becode) + textlen,
81
0
    .value = (uint8_t *)edns + sizeof(*edns),
82
0
  };
83
84
0
  memmove(edns->value, &becode, sizeof(becode));
85
0
  if (textlen > 0) {
86
0
    memmove(edns->value + sizeof(becode), text, textlen);
87
0
  }
88
89
0
  edectx->ede[edectx->nextede] = edns;
90
0
  edectx->nextede++;
91
0
}
92
93
void
94
0
dns_ede_init(isc_mem_t *mctx, dns_edectx_t *edectx) {
95
0
  REQUIRE(mctx != NULL);
96
97
  /*
98
   * Memory context is assigned, not attached here,
99
   * thus there's no detach in dns_ede_reset().
100
   */
101
0
  *edectx = (dns_edectx_t){
102
0
    .magic = DNS_EDE_MAGIC,
103
0
    .mctx = mctx,
104
0
  };
105
0
}
106
107
void
108
0
dns_ede_reset(dns_edectx_t *edectx) {
109
0
  REQUIRE(DNS_EDE_VALID(edectx));
110
111
0
  for (size_t i = 0; i < DNS_EDE_MAX_ERRORS; i++) {
112
0
    dns_ednsopt_t *edns = edectx->ede[i];
113
0
    if (edns == NULL) {
114
0
      break;
115
0
    }
116
117
0
    isc_mem_put(edectx->mctx, edns, sizeof(*edns) + edns->length);
118
0
    edectx->ede[i] = NULL;
119
0
  }
120
121
0
  dns_ede_init(edectx->mctx, edectx);
122
0
}
123
124
void
125
0
dns_ede_invalidate(dns_edectx_t *edectx) {
126
0
  REQUIRE(DNS_EDE_VALID(edectx));
127
128
0
  dns_ede_reset(edectx);
129
130
0
  edectx->magic = 0;
131
0
  edectx->mctx = NULL;
132
0
}
133
134
void
135
0
dns_ede_copy(dns_edectx_t *edectx_to, const dns_edectx_t *edectx_from) {
136
0
  REQUIRE(DNS_EDE_VALID(edectx_to));
137
0
  REQUIRE(DNS_EDE_VALID(edectx_from));
138
139
0
  if (edectx_to == edectx_from) {
140
0
    return;
141
0
  }
142
143
0
  for (size_t pos = 0; pos < DNS_EDE_MAX_ERRORS; pos++) {
144
0
    uint16_t fromcode;
145
146
0
    if (edectx_from->ede[pos] == NULL) {
147
0
      break;
148
0
    }
149
150
0
    fromcode = ISC_U8TO16_BE(edectx_from->ede[pos]->value);
151
0
    if (dns__ede_checkandupdateedeused(edectx_to, fromcode)) {
152
0
      continue;
153
0
    }
154
155
0
    if (edectx_to->nextede >= DNS_EDE_MAX_ERRORS) {
156
0
      isc_log_write(DNS_LOGCATEGORY_RESOLVER,
157
0
              DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(1),
158
0
              "too many ede from subfetch");
159
0
      break;
160
0
    }
161
162
0
    INSIST(edectx_to->ede[edectx_to->nextede] == NULL);
163
164
0
    dns_ednsopt_t *edns = isc_mem_get(
165
0
      edectx_to->mctx,
166
0
      sizeof(*edns) + edectx_from->ede[pos]->length);
167
0
    *edns = (dns_ednsopt_t){
168
0
      .code = DNS_OPT_EDE,
169
0
      .length = edectx_from->ede[pos]->length,
170
0
      .value = (uint8_t *)edns + sizeof(*edns),
171
0
    };
172
0
    memmove(edns->value, edectx_from->ede[pos]->value,
173
0
      edectx_from->ede[pos]->length);
174
175
0
    edectx_to->ede[edectx_to->nextede] = edns;
176
0
    edectx_to->nextede++;
177
0
  }
178
0
}