Coverage Report

Created: 2025-08-26 06:35

/src/unbound/util/module.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * util/module.c - module interface
3
 *
4
 * Copyright (c) 2007, NLnet Labs. All rights reserved.
5
 *
6
 * This software is open source.
7
 * 
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 
12
 * Redistributions of source code must retain the above copyright notice,
13
 * this list of conditions and the following disclaimer.
14
 * 
15
 * Redistributions in binary form must reproduce the above copyright notice,
16
 * this list of conditions and the following disclaimer in the documentation
17
 * and/or other materials provided with the distribution.
18
 * 
19
 * Neither the name of the NLNET LABS nor the names of its contributors may
20
 * be used to endorse or promote products derived from this software without
21
 * specific prior written permission.
22
 * 
23
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
 */
35
/**
36
 * \file
37
 * Implementation of module.h.
38
 */
39
40
#include "config.h"
41
#include "util/module.h"
42
#include "sldns/wire2str.h"
43
#include "util/config_file.h"
44
#include "util/regional.h"
45
#include "util/data/dname.h"
46
#include "util/net_help.h"
47
48
const char* 
49
strextstate(enum module_ext_state s)
50
0
{
51
0
  switch(s) {
52
0
  case module_state_initial: return "module_state_initial";
53
0
  case module_wait_reply: return "module_wait_reply";
54
0
  case module_wait_module: return "module_wait_module";
55
0
  case module_restart_next: return "module_restart_next";
56
0
  case module_wait_subquery: return "module_wait_subquery";
57
0
  case module_error: return "module_error";
58
0
  case module_finished: return "module_finished";
59
0
  }
60
0
  return "bad_extstate_value";
61
0
}
62
63
const char* 
64
strmodulevent(enum module_ev e)
65
0
{
66
0
  switch(e) {
67
0
  case module_event_new: return "module_event_new";
68
0
  case module_event_pass: return "module_event_pass";
69
0
  case module_event_reply: return "module_event_reply";
70
0
  case module_event_noreply: return "module_event_noreply";
71
0
  case module_event_capsfail: return "module_event_capsfail";
72
0
  case module_event_moddone: return "module_event_moddone";
73
0
  case module_event_error: return "module_event_error";
74
0
  }
75
0
  return "bad_event_value";
76
0
}
77
78
void errinf(struct module_qstate* qstate, const char* str)
79
0
{
80
0
  errinf_ede(qstate, str, LDNS_EDE_NONE);
81
0
}
82
83
void errinf_ede(struct module_qstate* qstate,
84
  const char* str, sldns_ede_code reason_bogus)
85
488
{
86
488
  struct errinf_strlist* p;
87
488
  if(!str || (qstate->env->cfg->val_log_level < 2 &&
88
488
    !qstate->env->cfg->log_servfail)) {
89
488
    return;
90
488
  }
91
0
  p = (struct errinf_strlist*)regional_alloc(qstate->region, sizeof(*p));
92
0
  if(!p) {
93
0
    log_err("malloc failure in validator-error-info string");
94
0
    return;
95
0
  }
96
0
  p->next = NULL;
97
0
  p->str = regional_strdup(qstate->region, str);
98
0
  p->reason_bogus = reason_bogus;
99
0
  if(!p->str) {
100
0
    log_err("malloc failure in validator-error-info string");
101
0
    return;
102
0
  }
103
  /* add at end */
104
0
  if(qstate->errinf) {
105
0
    struct errinf_strlist* q = qstate->errinf;
106
0
    while(q->next)
107
0
      q = q->next;
108
0
    q->next = p;
109
0
  } else  qstate->errinf = p;
110
0
}
111
112
void errinf_origin(struct module_qstate* qstate, struct sock_list *origin)
113
0
{
114
0
  struct sock_list* p;
115
0
  if(qstate->env->cfg->val_log_level < 2 && !qstate->env->cfg->log_servfail)
116
0
    return;
117
0
  for(p=origin; p; p=p->next) {
118
0
    char buf[256];
119
0
    if(p == origin)
120
0
      snprintf(buf, sizeof(buf), "from ");
121
0
    else  snprintf(buf, sizeof(buf), "and ");
122
0
    if(p->len == 0)
123
0
      snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), 
124
0
        "cache");
125
0
    else 
126
0
      addr_to_str(&p->addr, p->len, buf+strlen(buf),
127
0
        sizeof(buf)-strlen(buf));
128
0
    errinf(qstate, buf);
129
0
  }
130
0
}
131
132
char* errinf_to_str_bogus(struct module_qstate* qstate, struct regional* region)
133
0
{
134
0
  char buf[20480];
135
0
  char* p = buf;
136
0
  size_t left = sizeof(buf);
137
0
  struct errinf_strlist* s;
138
0
  char dname[LDNS_MAX_DOMAINLEN];
139
0
  char t[16], c[16];
140
0
  sldns_wire2str_type_buf(qstate->qinfo.qtype, t, sizeof(t));
141
0
  sldns_wire2str_class_buf(qstate->qinfo.qclass, c, sizeof(c));
142
0
  dname_str(qstate->qinfo.qname, dname);
143
0
  snprintf(p, left, "validation failure <%s %s %s>:", dname, t, c);
144
0
  left -= strlen(p); p += strlen(p);
145
0
  if(!qstate->errinf)
146
0
    snprintf(p, left, " misc failure");
147
0
  else for(s=qstate->errinf; s; s=s->next) {
148
0
    snprintf(p, left, " %s", s->str);
149
0
    left -= strlen(p); p += strlen(p);
150
0
  }
151
0
  if(region)
152
0
    p = regional_strdup(region, buf);
153
0
  else
154
0
    p = strdup(buf);
155
0
  if(!p)
156
0
    log_err("malloc failure in errinf_to_str");
157
0
  return p;
158
0
}
159
160
/* Try to find the latest (most specific) dnssec failure */
161
sldns_ede_code errinf_to_reason_bogus(struct module_qstate* qstate)
162
0
{
163
0
  struct errinf_strlist* s;
164
0
  sldns_ede_code ede = LDNS_EDE_NONE;
165
0
  for(s=qstate->errinf; s; s=s->next) {
166
0
    if(s->reason_bogus == LDNS_EDE_NONE) continue;
167
0
    if(ede != LDNS_EDE_NONE
168
0
      && ede != LDNS_EDE_DNSSEC_BOGUS
169
0
      && s->reason_bogus == LDNS_EDE_DNSSEC_BOGUS) continue;
170
0
    ede = s->reason_bogus;
171
0
  }
172
0
  return ede;
173
0
}
174
175
char* errinf_to_str_servfail(struct module_qstate* qstate)
176
0
{
177
0
  char buf[20480];
178
0
  char* p = buf;
179
0
  size_t left = sizeof(buf);
180
0
  struct errinf_strlist* s;
181
0
  char dname[LDNS_MAX_DOMAINLEN];
182
0
  char t[16], c[16];
183
0
  sldns_wire2str_type_buf(qstate->qinfo.qtype, t, sizeof(t));
184
0
  sldns_wire2str_class_buf(qstate->qinfo.qclass, c, sizeof(c));
185
0
  dname_str(qstate->qinfo.qname, dname);
186
0
  snprintf(p, left, "SERVFAIL <%s %s %s>:", dname, t, c);
187
0
  left -= strlen(p); p += strlen(p);
188
0
  if(!qstate->errinf)
189
0
    snprintf(p, left, " misc failure");
190
0
  else for(s=qstate->errinf; s; s=s->next) {
191
0
    snprintf(p, left, " %s", s->str);
192
0
    left -= strlen(p); p += strlen(p);
193
0
  }
194
0
  p = regional_strdup(qstate->region, buf);
195
0
  if(!p)
196
0
    log_err("malloc failure in errinf_to_str");
197
0
  return p;
198
0
}
199
200
char* errinf_to_str_misc(struct module_qstate* qstate)
201
0
{
202
0
  char buf[20480];
203
0
  char* p = buf;
204
0
  size_t left = sizeof(buf);
205
0
  struct errinf_strlist* s;
206
0
  if(!qstate->errinf)
207
0
    snprintf(p, left, "misc failure");
208
0
  else for(s=qstate->errinf; s; s=s->next) {
209
0
    snprintf(p, left, "%s%s", (s==qstate->errinf?"":" "), s->str);
210
0
    left -= strlen(p); p += strlen(p);
211
0
  }
212
0
  p = regional_strdup(qstate->region, buf);
213
0
  if(!p)
214
0
    log_err("malloc failure in errinf_to_str");
215
0
  return p;
216
0
}
217
218
void errinf_rrset(struct module_qstate* qstate, struct ub_packed_rrset_key *rr)
219
0
{
220
0
  char buf[1024];
221
0
  char dname[LDNS_MAX_DOMAINLEN];
222
0
  char t[16], c[16];
223
0
  if((qstate->env->cfg->val_log_level < 2 && !qstate->env->cfg->log_servfail) || !rr)
224
0
    return;
225
0
  sldns_wire2str_type_buf(ntohs(rr->rk.type), t, sizeof(t));
226
0
  sldns_wire2str_class_buf(ntohs(rr->rk.rrset_class), c, sizeof(c));
227
0
  dname_str(rr->rk.dname, dname);
228
0
  snprintf(buf, sizeof(buf), "for <%s %s %s>", dname, t, c);
229
0
  errinf(qstate, buf);
230
0
}
231
232
void errinf_dname(struct module_qstate* qstate, const char* str, uint8_t* dname)
233
0
{
234
0
  char b[1024];
235
0
  char buf[LDNS_MAX_DOMAINLEN];
236
0
  if((qstate->env->cfg->val_log_level < 2 && !qstate->env->cfg->log_servfail) || !str || !dname)
237
0
    return;
238
0
  dname_str(dname, buf);
239
0
  snprintf(b, sizeof(b), "%s %s", str, buf);
240
0
  errinf(qstate, b);
241
0
}
242
243
int
244
edns_known_options_init(struct module_env* env)
245
0
{
246
0
  env->edns_known_options_num = 0;
247
0
  env->edns_known_options = (struct edns_known_option*)calloc(
248
0
    MAX_KNOWN_EDNS_OPTS, sizeof(struct edns_known_option));
249
0
  if(!env->edns_known_options) return 0;
250
0
  return 1;
251
0
}
252
253
void
254
edns_known_options_delete(struct module_env* env)
255
0
{
256
0
  free(env->edns_known_options);
257
0
  env->edns_known_options = NULL;
258
0
  env->edns_known_options_num = 0;
259
0
}
260
261
int
262
edns_register_option(uint16_t opt_code, int bypass_cache_stage,
263
  int no_aggregation, struct module_env* env)
264
0
{
265
0
  size_t i;
266
0
  if(env->worker) {
267
0
    log_err("invalid edns registration: "
268
0
      "trying to register option after module init phase");
269
0
    return 0;
270
0
  }
271
272
  /**
273
   * Checking if we are full first is faster but it does not provide
274
   * the option to change the flags when the array is full.
275
   * It only impacts unbound initialization, leave it for now.
276
   */
277
  /* Check if the option is already registered. */
278
0
  for(i=0; i<env->edns_known_options_num; i++)
279
0
    if(env->edns_known_options[i].opt_code == opt_code)
280
0
      break;
281
  /* If it is not yet registered check if we have space to add a new one. */
282
0
  if(i == env->edns_known_options_num) {
283
0
    if(env->edns_known_options_num >= MAX_KNOWN_EDNS_OPTS) {
284
0
      log_err("invalid edns registration: maximum options reached");
285
0
      return 0;
286
0
    }
287
0
    env->edns_known_options_num++;
288
0
  }
289
0
  env->edns_known_options[i].opt_code = opt_code;
290
0
  env->edns_known_options[i].bypass_cache_stage = bypass_cache_stage;
291
0
  env->edns_known_options[i].no_aggregation = no_aggregation;
292
0
  return 1;
293
0
}
294
295
int
296
inplace_cb_register(void* cb, enum inplace_cb_list_type type, void* cbarg,
297
  struct module_env* env, int id)
298
0
{
299
0
  struct inplace_cb* callback;
300
0
  struct inplace_cb** prevp;
301
0
  if(env->worker) {
302
0
    log_err("invalid edns callback registration: "
303
0
      "trying to register callback after module init phase");
304
0
    return 0;
305
0
  }
306
307
0
  callback = (struct inplace_cb*)calloc(1, sizeof(*callback));
308
0
  if(callback == NULL) {
309
0
    log_err("out of memory during edns callback registration.");
310
0
    return 0;
311
0
  }
312
0
  callback->id = id;
313
0
  callback->next = NULL;
314
0
  callback->cb = cb;
315
0
  callback->cb_arg = cbarg;
316
  
317
0
  prevp = (struct inplace_cb**) &env->inplace_cb_lists[type];
318
  /* append at end of list */
319
0
  while(*prevp != NULL)
320
0
    prevp = &((*prevp)->next);
321
0
  *prevp = callback;
322
0
  return 1;
323
0
}
324
325
void
326
inplace_cb_delete(struct module_env* env, enum inplace_cb_list_type type,
327
  int id)
328
0
{
329
0
  struct inplace_cb* temp = env->inplace_cb_lists[type];
330
0
  struct inplace_cb* prev = NULL;
331
332
0
  while(temp) {
333
0
    if(temp->id == id) {
334
0
      if(!prev) {
335
0
        env->inplace_cb_lists[type] = temp->next;
336
0
        free(temp);
337
0
        temp = env->inplace_cb_lists[type];
338
0
      }
339
0
      else {
340
0
        prev->next = temp->next;
341
0
        free(temp);
342
0
        temp = prev->next;
343
0
      }
344
0
    }
345
0
    else {
346
0
      prev = temp;
347
0
      temp = temp->next;
348
0
    }
349
0
  }
350
0
}
351
352
struct edns_known_option*
353
edns_option_is_known(uint16_t opt_code, struct module_env* env)
354
0
{
355
0
  size_t i;
356
0
  for(i=0; i<env->edns_known_options_num; i++)
357
0
    if(env->edns_known_options[i].opt_code == opt_code)
358
0
      return env->edns_known_options + i;
359
0
  return NULL;
360
0
}
361
362
int
363
edns_bypass_cache_stage(struct edns_option* list, struct module_env* env)
364
0
{
365
0
  size_t i;
366
0
  for(; list; list=list->next)
367
0
    for(i=0; i<env->edns_known_options_num; i++)
368
0
      if(env->edns_known_options[i].opt_code == list->opt_code &&
369
0
        env->edns_known_options[i].bypass_cache_stage == 1)
370
0
          return 1;
371
0
  return 0;
372
0
}
373
374
int
375
unique_mesh_state(struct edns_option* list, struct module_env* env)
376
0
{
377
0
  size_t i;
378
0
  if(env->unique_mesh)
379
0
    return 1;
380
0
  for(; list; list=list->next)
381
0
    for(i=0; i<env->edns_known_options_num; i++)
382
0
      if(env->edns_known_options[i].opt_code == list->opt_code &&
383
0
        env->edns_known_options[i].no_aggregation == 1)
384
0
          return 1;
385
0
  return 0;
386
0
}
387
388
void
389
log_edns_known_options(enum verbosity_value level, struct module_env* env)
390
0
{
391
0
  size_t i;
392
0
  char str[32], *s;
393
0
  size_t slen;
394
0
  if(env->edns_known_options_num > 0 && verbosity >= level) {
395
0
    verbose(level, "EDNS known options:");
396
0
    verbose(level, "  Code:    Bypass_cache_stage: Aggregate_mesh:");
397
0
    for(i=0; i<env->edns_known_options_num; i++) {
398
0
      s = str;
399
0
      slen = sizeof(str);
400
0
      (void)sldns_wire2str_edns_option_code_print(&s, &slen,
401
0
        env->edns_known_options[i].opt_code);
402
0
      verbose(level, "  %-8.8s %-19s %-15s", str,
403
0
        env->edns_known_options[i].bypass_cache_stage?"YES":"NO",
404
0
        env->edns_known_options[i].no_aggregation?"NO":"YES");
405
0
    }
406
0
  }
407
0
}
408
409
void
410
copy_state_to_super(struct module_qstate* qstate, int ATTR_UNUSED(id),
411
  struct module_qstate* super)
412
0
{
413
  /* Overwrite super's was_ratelimited only when it was not set */
414
0
  if(!super->was_ratelimited) {
415
0
    super->was_ratelimited = qstate->was_ratelimited;
416
0
  }
417
0
}