Coverage Report

Created: 2025-07-11 06:08

/src/unbound/libunbound/context.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * libunbound/context.c - validating context for unbound internal use
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
/**
37
 * \file
38
 *
39
 * This file contains the validator context structure.
40
 */
41
#include "config.h"
42
#include "libunbound/context.h"
43
#include "util/module.h"
44
#include "util/config_file.h"
45
#include "util/net_help.h"
46
#include "services/modstack.h"
47
#include "services/localzone.h"
48
#include "services/cache/rrset.h"
49
#include "services/cache/infra.h"
50
#include "services/authzone.h"
51
#include "services/listen_dnsport.h"
52
#include "util/data/msgreply.h"
53
#include "util/storage/slabhash.h"
54
#include "util/edns.h"
55
#include "sldns/sbuffer.h"
56
#include "iterator/iter_fwd.h"
57
#include "iterator/iter_hints.h"
58
59
int 
60
context_finalize(struct ub_ctx* ctx)
61
0
{
62
0
  int is_rpz = 0;
63
0
  struct config_file* cfg = ctx->env->cfg;
64
0
  verbosity = cfg->verbosity;
65
0
  if(ctx_logfile_overridden && !ctx->logfile_override) {
66
0
    log_file(NULL); /* clear that override */
67
0
    ctx_logfile_overridden = 0;
68
0
  }
69
0
  if(ctx->logfile_override) {
70
0
    ctx_logfile_overridden = 1;
71
0
    log_file(ctx->log_out);
72
0
  } else {
73
0
    log_init(cfg->logfile, cfg->use_syslog, NULL);
74
0
  }
75
0
  ctx->pipe_pid = getpid();
76
0
  cfg_apply_local_port_policy(cfg, 65536);
77
0
  config_apply(cfg);
78
0
  if(!modstack_call_startup(&ctx->mods, cfg->module_conf, ctx->env))
79
0
    return UB_INITFAIL;
80
0
  if(!modstack_call_init(&ctx->mods, cfg->module_conf, ctx->env))
81
0
    return UB_INITFAIL;
82
0
  listen_setup_locks();
83
0
  log_edns_known_options(VERB_ALGO, ctx->env);
84
0
  ctx->local_zones = local_zones_create();
85
0
  if(!ctx->local_zones)
86
0
    return UB_NOMEM;
87
0
  if(!local_zones_apply_cfg(ctx->local_zones, cfg))
88
0
    return UB_INITFAIL;
89
0
  if(!auth_zones_apply_cfg(ctx->env->auth_zones, cfg, 1, &is_rpz,
90
0
    ctx->env, &ctx->mods))
91
0
    return UB_INITFAIL;
92
0
  if(!(ctx->env->fwds = forwards_create()) ||
93
0
    !forwards_apply_cfg(ctx->env->fwds, cfg))
94
0
    return UB_INITFAIL;
95
0
  if(!(ctx->env->hints = hints_create()) ||
96
0
    !hints_apply_cfg(ctx->env->hints, cfg))
97
0
    return UB_INITFAIL;
98
0
  if(!edns_strings_apply_cfg(ctx->env->edns_strings, cfg))
99
0
    return UB_INITFAIL;
100
0
  if(!slabhash_is_size(ctx->env->msg_cache, cfg->msg_cache_size,
101
0
    cfg->msg_cache_slabs)) {
102
0
    slabhash_delete(ctx->env->msg_cache);
103
0
    ctx->env->msg_cache = slabhash_create(cfg->msg_cache_slabs,
104
0
      HASH_DEFAULT_STARTARRAY, cfg->msg_cache_size,
105
0
      msgreply_sizefunc, query_info_compare,
106
0
      query_entry_delete, reply_info_delete, NULL);
107
0
    if(!ctx->env->msg_cache)
108
0
      return UB_NOMEM;
109
0
  }
110
0
  ctx->env->rrset_cache = rrset_cache_adjust(ctx->env->rrset_cache,
111
0
    ctx->env->cfg, ctx->env->alloc);
112
0
  if(!ctx->env->rrset_cache)
113
0
    return UB_NOMEM;
114
0
  ctx->env->infra_cache = infra_adjust(ctx->env->infra_cache, cfg);
115
0
  if(!ctx->env->infra_cache)
116
0
    return UB_NOMEM;
117
0
  ctx->finalized = 1;
118
0
  return UB_NOERROR;
119
0
}
120
121
int context_query_cmp(const void* a, const void* b)
122
0
{
123
0
  if( *(int*)a < *(int*)b )
124
0
    return -1;
125
0
  if( *(int*)a > *(int*)b )
126
0
    return 1;
127
0
  return 0;
128
0
}
129
130
void
131
context_query_delete(struct ctx_query* q) 
132
0
{
133
0
  if(!q) return;
134
0
  ub_resolve_free(q->res);
135
0
  free(q->msg);
136
0
  free(q);
137
0
}
138
139
/** How many times to try to find an unused query-id-number for async */
140
0
#define NUM_ID_TRIES 100000
141
/** find next useful id number of 0 on error */
142
static int
143
find_id(struct ub_ctx* ctx, int* id)
144
0
{
145
0
  size_t tries = 0;
146
0
  ctx->next_querynum++;
147
0
  while(rbtree_search(&ctx->queries, &ctx->next_querynum)) {
148
0
    ctx->next_querynum++; /* numerical wraparound is fine */
149
0
    if(tries++ > NUM_ID_TRIES)
150
0
      return 0;
151
0
  }
152
0
  *id = ctx->next_querynum;
153
0
  return 1;
154
0
}
155
156
struct ctx_query* 
157
context_new(struct ub_ctx* ctx, const char* name, int rrtype, int rrclass, 
158
  ub_callback_type cb, ub_event_callback_type cb_event, void* cbarg)
159
0
{
160
0
  struct ctx_query* q = (struct ctx_query*)calloc(1, sizeof(*q));
161
0
  if(!q) return NULL;
162
0
  lock_basic_lock(&ctx->cfglock);
163
0
  if(!find_id(ctx, &q->querynum)) {
164
0
    lock_basic_unlock(&ctx->cfglock);
165
0
    free(q);
166
0
    return NULL;
167
0
  }
168
0
  lock_basic_unlock(&ctx->cfglock);
169
0
  q->node.key = &q->querynum;
170
0
  q->async = (cb != NULL || cb_event != NULL);
171
0
  q->cb = cb;
172
0
  q->cb_event = cb_event;
173
0
  q->cb_arg = cbarg;
174
0
  q->res = (struct ub_result*)calloc(1, sizeof(*q->res));
175
0
  if(!q->res) {
176
0
    free(q);
177
0
    return NULL;
178
0
  }
179
0
  q->res->qname = strdup(name);
180
0
  if(!q->res->qname) {
181
0
    free(q->res);
182
0
    free(q);
183
0
    return NULL;
184
0
  }
185
0
  q->res->qtype = rrtype;
186
0
  q->res->qclass = rrclass;
187
188
  /* add to query list */
189
0
  lock_basic_lock(&ctx->cfglock);
190
0
  if(q->async)
191
0
    ctx->num_async ++;
192
0
  (void)rbtree_insert(&ctx->queries, &q->node);
193
0
  lock_basic_unlock(&ctx->cfglock);
194
0
  return q;
195
0
}
196
197
struct alloc_cache* 
198
context_obtain_alloc(struct ub_ctx* ctx, int locking)
199
0
{
200
0
  struct alloc_cache* a;
201
0
  int tnum = 0;
202
0
  if(locking) {
203
0
    lock_basic_lock(&ctx->cfglock);
204
0
  }
205
0
  a = ctx->alloc_list;
206
0
  if(a)
207
0
    ctx->alloc_list = a->super; /* snip off list */
208
0
  else  tnum = ctx->thr_next_num++;
209
0
  if(locking) {
210
0
    lock_basic_unlock(&ctx->cfglock);
211
0
  }
212
0
  if(a) {
213
0
    a->super = &ctx->superalloc;
214
0
    return a;
215
0
  }
216
0
  a = (struct alloc_cache*)calloc(1, sizeof(*a));
217
0
  if(!a)
218
0
    return NULL;
219
0
  alloc_init(a, &ctx->superalloc, tnum);
220
0
  return a;
221
0
}
222
223
void 
224
context_release_alloc(struct ub_ctx* ctx, struct alloc_cache* alloc,
225
  int locking)
226
0
{
227
0
  if(!ctx || !alloc)
228
0
    return;
229
0
  if(locking) {
230
0
    lock_basic_lock(&ctx->cfglock);
231
0
  }
232
0
  alloc->super = ctx->alloc_list;
233
0
  ctx->alloc_list = alloc;
234
0
  if(locking) {
235
0
    lock_basic_unlock(&ctx->cfglock);
236
0
  }
237
0
}
238
239
uint8_t* 
240
context_serialize_new_query(struct ctx_query* q, uint32_t* len)
241
0
{
242
  /* format for new query is
243
   *  o uint32 cmd
244
   *  o uint32 id
245
   *  o uint32 type
246
   *  o uint32 class
247
   *  o rest queryname (string)
248
   */
249
0
  uint8_t* p;
250
0
  size_t slen = strlen(q->res->qname) + 1/*end of string*/;
251
0
  *len = sizeof(uint32_t)*4 + slen;
252
0
  p = (uint8_t*)malloc(*len);
253
0
  if(!p) return NULL;
254
0
  sldns_write_uint32(p, UB_LIBCMD_NEWQUERY);
255
0
  sldns_write_uint32(p+sizeof(uint32_t), (uint32_t)q->querynum);
256
0
  sldns_write_uint32(p+2*sizeof(uint32_t), (uint32_t)q->res->qtype);
257
0
  sldns_write_uint32(p+3*sizeof(uint32_t), (uint32_t)q->res->qclass);
258
0
  memmove(p+4*sizeof(uint32_t), q->res->qname, slen);
259
0
  return p;
260
0
}
261
262
struct ctx_query* 
263
context_deserialize_new_query(struct ub_ctx* ctx, uint8_t* p, uint32_t len)
264
0
{
265
0
  struct ctx_query* q = (struct ctx_query*)calloc(1, sizeof(*q));
266
0
  if(!q) return NULL;
267
0
  if(len < 4*sizeof(uint32_t)+1) {
268
0
    free(q);
269
0
    return NULL;
270
0
  }
271
0
  log_assert( sldns_read_uint32(p) == UB_LIBCMD_NEWQUERY);
272
0
  q->querynum = (int)sldns_read_uint32(p+sizeof(uint32_t));
273
0
  q->node.key = &q->querynum;
274
0
  q->async = 1;
275
0
  q->res = (struct ub_result*)calloc(1, sizeof(*q->res));
276
0
  if(!q->res) {
277
0
    free(q);
278
0
    return NULL;
279
0
  }
280
0
  q->res->qtype = (int)sldns_read_uint32(p+2*sizeof(uint32_t));
281
0
  q->res->qclass = (int)sldns_read_uint32(p+3*sizeof(uint32_t));
282
0
  q->res->qname = strdup((char*)(p+4*sizeof(uint32_t)));
283
0
  if(!q->res->qname) {
284
0
    free(q->res);
285
0
    free(q);
286
0
    return NULL;
287
0
  }
288
289
  /** add to query list */
290
0
  ctx->num_async++;
291
0
  (void)rbtree_insert(&ctx->queries, &q->node);
292
0
  return q;
293
0
}
294
295
struct ctx_query* 
296
context_lookup_new_query(struct ub_ctx* ctx, uint8_t* p, uint32_t len)
297
0
{
298
0
  struct ctx_query* q;
299
0
  int querynum;
300
0
  if(len < 4*sizeof(uint32_t)+1) {
301
0
    return NULL;
302
0
  }
303
0
  log_assert( sldns_read_uint32(p) == UB_LIBCMD_NEWQUERY);
304
0
  querynum = (int)sldns_read_uint32(p+sizeof(uint32_t));
305
0
  q = (struct ctx_query*)rbtree_search(&ctx->queries, &querynum);
306
0
  if(!q) {
307
0
    return NULL;
308
0
  }
309
0
  log_assert(q->async);
310
0
  return q;
311
0
}
312
313
uint8_t* 
314
context_serialize_answer(struct ctx_query* q, int err, sldns_buffer* pkt,
315
  uint32_t* len)
316
0
{
317
  /* answer format
318
   *  o uint32 cmd
319
   *  o uint32 id
320
   *  o uint32 error_code
321
   *  o uint32 msg_security
322
   *  o uint32 was_ratelimited
323
   *  o uint32 length of why_bogus string (+1 for eos); 0 absent.
324
   *  o why_bogus_string
325
   *  o the remainder is the answer msg from resolver lookup.
326
   *    remainder can be length 0.
327
   */
328
0
  size_t size_of_uint32s = 6 * sizeof(uint32_t);
329
0
  size_t pkt_len = pkt?sldns_buffer_remaining(pkt):0;
330
0
  size_t wlen = (pkt&&q->res->why_bogus)?strlen(q->res->why_bogus)+1:0;
331
0
  uint8_t* p;
332
0
  *len = size_of_uint32s + pkt_len + wlen;
333
0
  p = (uint8_t*)malloc(*len);
334
0
  if(!p) return NULL;
335
0
  sldns_write_uint32(p, UB_LIBCMD_ANSWER);
336
0
  sldns_write_uint32(p+sizeof(uint32_t), (uint32_t)q->querynum);
337
0
  sldns_write_uint32(p+2*sizeof(uint32_t), (uint32_t)err);
338
0
  sldns_write_uint32(p+3*sizeof(uint32_t), (uint32_t)q->msg_security);
339
0
  sldns_write_uint32(p+4*sizeof(uint32_t), (uint32_t)q->res->was_ratelimited);
340
0
  sldns_write_uint32(p+5*sizeof(uint32_t), (uint32_t)wlen);
341
0
  if(wlen > 0)
342
0
    memmove(p+size_of_uint32s, q->res->why_bogus, wlen);
343
0
  if(pkt_len > 0)
344
0
    memmove(p+size_of_uint32s+wlen,
345
0
      sldns_buffer_begin(pkt), pkt_len);
346
0
  return p;
347
0
}
348
349
struct ctx_query* 
350
context_deserialize_answer(struct ub_ctx* ctx,
351
        uint8_t* p, uint32_t len, int* err)
352
0
{
353
0
  size_t size_of_uint32s = 6 * sizeof(uint32_t);
354
0
  struct ctx_query* q = NULL ;
355
0
  int id;
356
0
  size_t wlen;
357
0
  if(len < size_of_uint32s) return NULL;
358
0
  log_assert( sldns_read_uint32(p) == UB_LIBCMD_ANSWER);
359
0
  id = (int)sldns_read_uint32(p+sizeof(uint32_t));
360
0
  q = (struct ctx_query*)rbtree_search(&ctx->queries, &id);
361
0
  if(!q) return NULL; 
362
0
  *err = (int)sldns_read_uint32(p+2*sizeof(uint32_t));
363
0
  q->msg_security = sldns_read_uint32(p+3*sizeof(uint32_t));
364
0
  q->res->was_ratelimited = (int)sldns_read_uint32(p+4*sizeof(uint32_t));
365
0
  wlen = (size_t)sldns_read_uint32(p+5*sizeof(uint32_t));
366
0
  if(len > size_of_uint32s && wlen > 0) {
367
0
    if(len >= size_of_uint32s+wlen)
368
0
      q->res->why_bogus = (char*)memdup(
369
0
        p+size_of_uint32s, wlen);
370
0
    if(!q->res->why_bogus) {
371
      /* pass malloc failure to the user callback */
372
0
      q->msg_len = 0;
373
0
      *err = UB_NOMEM;
374
0
      return q;
375
0
    }
376
0
    q->res->why_bogus[wlen-1] = 0; /* zero terminated for sure */
377
0
  }
378
0
  if(len > size_of_uint32s+wlen) {
379
0
    q->msg_len = len - size_of_uint32s - wlen;
380
0
    q->msg = (uint8_t*)memdup(p+size_of_uint32s+wlen,
381
0
      q->msg_len);
382
0
    if(!q->msg) {
383
      /* pass malloc failure to the user callback */
384
0
      q->msg_len = 0;
385
0
      *err = UB_NOMEM;
386
0
      return q;
387
0
    }
388
0
  } 
389
0
  return q;
390
0
}
391
392
uint8_t* 
393
context_serialize_cancel(struct ctx_query* q, uint32_t* len)
394
0
{
395
  /* format of cancel:
396
   *  o uint32 cmd
397
   *  o uint32 async-id */
398
0
  uint8_t* p = (uint8_t*)reallocarray(NULL, 2, sizeof(uint32_t));
399
0
  if(!p) return NULL;
400
0
  *len = 2*sizeof(uint32_t);
401
0
  sldns_write_uint32(p, UB_LIBCMD_CANCEL);
402
0
  sldns_write_uint32(p+sizeof(uint32_t), (uint32_t)q->querynum);
403
0
  return p;
404
0
}
405
406
struct ctx_query* context_deserialize_cancel(struct ub_ctx* ctx,
407
        uint8_t* p, uint32_t len)
408
0
{
409
0
  struct ctx_query* q;
410
0
  int id;
411
0
  if(len != 2*sizeof(uint32_t)) return NULL;
412
0
  log_assert( sldns_read_uint32(p) == UB_LIBCMD_CANCEL);
413
0
  id = (int)sldns_read_uint32(p+sizeof(uint32_t));
414
0
  q = (struct ctx_query*)rbtree_search(&ctx->queries, &id);
415
0
  return q;
416
0
}
417
418
uint8_t* 
419
context_serialize_quit(uint32_t* len)
420
0
{
421
0
  uint32_t* p = (uint32_t*)malloc(sizeof(uint32_t));
422
0
  if(!p)
423
0
    return NULL;
424
0
  *len = sizeof(uint32_t);
425
0
  sldns_write_uint32(p, UB_LIBCMD_QUIT);
426
0
  return (uint8_t*)p;
427
0
}
428
429
enum ub_ctx_cmd context_serial_getcmd(uint8_t* p, uint32_t len)
430
0
{
431
0
  uint32_t v;
432
0
  if((size_t)len < sizeof(v))
433
0
    return UB_LIBCMD_QUIT;
434
0
  v = sldns_read_uint32(p);
435
0
  return v;
436
0
}