Coverage Report

Created: 2025-08-26 06:35

/src/unbound/libunbound/libunbound.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * unbound.c - unbound validating resolver public API implementation
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 functions to resolve DNS queries and 
40
 * validate the answers. Synchronously and asynchronously.
41
 *
42
 */
43
44
/* include the public api first, it should be able to stand alone */
45
#include "libunbound/unbound.h"
46
#include "libunbound/unbound-event.h"
47
#include "config.h"
48
#include <ctype.h>
49
#include "libunbound/context.h"
50
#include "libunbound/libworker.h"
51
#include "util/locks.h"
52
#include "util/config_file.h"
53
#include "util/alloc.h"
54
#include "util/module.h"
55
#include "util/regional.h"
56
#include "util/log.h"
57
#include "util/random.h"
58
#include "util/net_help.h"
59
#include "util/tube.h"
60
#include "util/ub_event.h"
61
#include "util/edns.h"
62
#include "services/modstack.h"
63
#include "services/localzone.h"
64
#include "services/cache/infra.h"
65
#include "services/cache/rrset.h"
66
#include "services/authzone.h"
67
#include "services/listen_dnsport.h"
68
#include "sldns/sbuffer.h"
69
#include "iterator/iter_fwd.h"
70
#include "iterator/iter_hints.h"
71
#ifdef HAVE_PTHREAD
72
#include <signal.h>
73
#endif
74
#ifdef HAVE_SYS_WAIT_H
75
#include <sys/wait.h>
76
#endif
77
#ifdef HAVE_TIME_H
78
#include <time.h>
79
#endif
80
81
#if defined(UB_ON_WINDOWS) && defined (HAVE_WINDOWS_H)
82
#include <windows.h>
83
#include <iphlpapi.h>
84
#endif /* UB_ON_WINDOWS */
85
86
/** store that the logfile has a debug override */
87
int ctx_logfile_overridden = 0;
88
89
/** create context functionality, but no pipes */
90
static struct ub_ctx* ub_ctx_create_nopipe(void)
91
0
{
92
0
  struct ub_ctx* ctx;
93
#ifdef USE_WINSOCK
94
  int r;
95
  WSADATA wsa_data;
96
#endif
97
  
98
0
  checklock_start();
99
0
  if(!ctx_logfile_overridden)
100
0
    log_init(NULL, 0, NULL); /* logs to stderr */
101
0
  log_ident_set("libunbound");
102
#ifdef USE_WINSOCK
103
  if((r = WSAStartup(MAKEWORD(2,2), &wsa_data)) != 0) {
104
    log_err("could not init winsock. WSAStartup: %s",
105
      wsa_strerror(r));
106
    return NULL;
107
  }
108
#endif
109
0
  verbosity = NO_VERBOSE; /* errors only */
110
0
  checklock_start();
111
0
  ctx = (struct ub_ctx*)calloc(1, sizeof(*ctx));
112
0
  if(!ctx) {
113
0
    errno = ENOMEM;
114
0
    return NULL;
115
0
  }
116
0
  alloc_init(&ctx->superalloc, NULL, 0);
117
0
  if(!(ctx->seed_rnd = ub_initstate(NULL))) {
118
0
    ub_randfree(ctx->seed_rnd);
119
0
    free(ctx);
120
0
    errno = ENOMEM;
121
0
    return NULL;
122
0
  }
123
0
  lock_basic_init(&ctx->qqpipe_lock);
124
0
  lock_basic_init(&ctx->rrpipe_lock);
125
0
  lock_basic_init(&ctx->cfglock);
126
0
  ctx->env = (struct module_env*)calloc(1, sizeof(*ctx->env));
127
0
  if(!ctx->env) {
128
0
    ub_randfree(ctx->seed_rnd);
129
0
    free(ctx);
130
0
    errno = ENOMEM;
131
0
    return NULL;
132
0
  }
133
0
  ctx->env->cfg = config_create_forlib();
134
0
  if(!ctx->env->cfg) {
135
0
    free(ctx->env);
136
0
    ub_randfree(ctx->seed_rnd);
137
0
    free(ctx);
138
0
    errno = ENOMEM;
139
0
    return NULL;
140
0
  }
141
  /* init edns_known_options */
142
0
  if(!edns_known_options_init(ctx->env)) {
143
0
    config_delete(ctx->env->cfg);
144
0
    free(ctx->env);
145
0
    ub_randfree(ctx->seed_rnd);
146
0
    free(ctx);
147
0
    errno = ENOMEM;
148
0
    return NULL;
149
0
  }
150
0
  ctx->env->auth_zones = auth_zones_create();
151
0
  if(!ctx->env->auth_zones) {
152
0
    edns_known_options_delete(ctx->env);
153
0
    config_delete(ctx->env->cfg);
154
0
    free(ctx->env);
155
0
    ub_randfree(ctx->seed_rnd);
156
0
    free(ctx);
157
0
    errno = ENOMEM;
158
0
    return NULL;
159
0
  }
160
0
  ctx->env->edns_strings = edns_strings_create();
161
0
  if(!ctx->env->edns_strings) {
162
0
    auth_zones_delete(ctx->env->auth_zones);
163
0
    edns_known_options_delete(ctx->env);
164
0
    config_delete(ctx->env->cfg);
165
0
    free(ctx->env);
166
0
    ub_randfree(ctx->seed_rnd);
167
0
    free(ctx);
168
0
    errno = ENOMEM;
169
0
    return NULL;
170
0
  }
171
172
0
  ctx->env->alloc = &ctx->superalloc;
173
0
  ctx->env->worker = NULL;
174
0
  ctx->env->need_to_validate = 0;
175
0
  modstack_init(&ctx->mods);
176
0
  ctx->env->modstack = &ctx->mods;
177
0
  rbtree_init(&ctx->queries, &context_query_cmp);
178
0
  return ctx;
179
0
}
180
181
struct ub_ctx* 
182
ub_ctx_create(void)
183
0
{
184
0
  struct ub_ctx* ctx = ub_ctx_create_nopipe();
185
0
  if(!ctx)
186
0
    return NULL;
187
0
  if((ctx->qq_pipe = tube_create()) == NULL) {
188
0
    int e = errno;
189
0
    ub_randfree(ctx->seed_rnd);
190
0
    config_delete(ctx->env->cfg);
191
0
    modstack_call_deinit(&ctx->mods, ctx->env);
192
0
    modstack_call_destartup(&ctx->mods, ctx->env);
193
0
    modstack_free(&ctx->mods);
194
0
    listen_desetup_locks();
195
0
    edns_known_options_delete(ctx->env);
196
0
    edns_strings_delete(ctx->env->edns_strings);
197
0
    free(ctx->env);
198
0
    free(ctx);
199
0
    errno = e;
200
0
    return NULL;
201
0
  }
202
0
  if((ctx->rr_pipe = tube_create()) == NULL) {
203
0
    int e = errno;
204
0
    tube_delete(ctx->qq_pipe);
205
0
    ub_randfree(ctx->seed_rnd);
206
0
    config_delete(ctx->env->cfg);
207
0
    modstack_call_deinit(&ctx->mods, ctx->env);
208
0
    modstack_call_destartup(&ctx->mods, ctx->env);
209
0
    modstack_free(&ctx->mods);
210
0
    listen_desetup_locks();
211
0
    edns_known_options_delete(ctx->env);
212
0
    edns_strings_delete(ctx->env->edns_strings);
213
0
    free(ctx->env);
214
0
    free(ctx);
215
0
    errno = e;
216
0
    return NULL;
217
0
  }
218
0
  return ctx;
219
0
}
220
221
struct ub_ctx* 
222
ub_ctx_create_ub_event(struct ub_event_base* ueb)
223
0
{
224
0
  struct ub_ctx* ctx = ub_ctx_create_nopipe();
225
0
  if(!ctx)
226
0
    return NULL;
227
  /* no pipes, but we have the locks to make sure everything works */
228
0
  ctx->created_bg = 0;
229
0
  ctx->dothread = 1; /* the processing is in the same process,
230
    makes ub_cancel and ub_ctx_delete do the right thing */
231
0
  ctx->event_base = ueb;
232
0
  return ctx;
233
0
}
234
235
struct ub_ctx* 
236
ub_ctx_create_event(struct event_base* eb)
237
0
{
238
0
  struct ub_ctx* ctx = ub_ctx_create_nopipe();
239
0
  if(!ctx)
240
0
    return NULL;
241
  /* no pipes, but we have the locks to make sure everything works */
242
0
  ctx->created_bg = 0;
243
0
  ctx->dothread = 1; /* the processing is in the same process,
244
    makes ub_cancel and ub_ctx_delete do the right thing */
245
0
  ctx->event_base = ub_libevent_event_base(eb);
246
0
  if (!ctx->event_base) {
247
0
    ub_ctx_delete(ctx);
248
0
    return NULL;
249
0
  }
250
0
  ctx->event_base_malloced = 1;
251
0
  return ctx;
252
0
}
253
  
254
/** delete q */
255
static void
256
delq(rbnode_type* n, void* ATTR_UNUSED(arg))
257
0
{
258
0
  struct ctx_query* q = (struct ctx_query*)n;
259
0
  context_query_delete(q);
260
0
}
261
262
/** stop the bg thread */
263
static void ub_stop_bg(struct ub_ctx* ctx)
264
0
{
265
  /* stop the bg thread */
266
0
  lock_basic_lock(&ctx->cfglock);
267
0
  if(ctx->created_bg) {
268
0
    uint8_t* msg;
269
0
    uint32_t len;
270
0
    uint32_t cmd = UB_LIBCMD_QUIT;
271
0
    lock_basic_unlock(&ctx->cfglock);
272
0
    lock_basic_lock(&ctx->qqpipe_lock);
273
0
    (void)tube_write_msg(ctx->qq_pipe, (uint8_t*)&cmd, 
274
0
      (uint32_t)sizeof(cmd), 0);
275
0
    lock_basic_unlock(&ctx->qqpipe_lock);
276
0
    lock_basic_lock(&ctx->rrpipe_lock);
277
0
    while(tube_read_msg(ctx->rr_pipe, &msg, &len, 0)) {
278
      /* discard all results except a quit confirm */
279
0
      if(context_serial_getcmd(msg, len) == UB_LIBCMD_QUIT) {
280
0
        free(msg);
281
0
        break;
282
0
      }
283
0
      free(msg);
284
0
    }
285
0
    lock_basic_unlock(&ctx->rrpipe_lock);
286
287
    /* if bg worker is a thread, wait for it to exit, so that all
288
     * resources are really gone. */
289
0
    lock_basic_lock(&ctx->cfglock);
290
0
    if(ctx->dothread) {
291
0
      lock_basic_unlock(&ctx->cfglock);
292
0
      ub_thread_join(ctx->bg_tid);
293
0
    } else {
294
0
      lock_basic_unlock(&ctx->cfglock);
295
0
#ifndef UB_ON_WINDOWS
296
0
      if(waitpid(ctx->bg_pid, NULL, 0) == -1) {
297
0
        if(verbosity > 2)
298
0
          log_err("waitpid: %s", strerror(errno));
299
0
      }
300
0
#endif
301
0
    }
302
0
  }
303
0
  else {
304
0
    lock_basic_unlock(&ctx->cfglock);
305
0
  }
306
0
}
307
308
void 
309
ub_ctx_delete(struct ub_ctx* ctx)
310
0
{
311
0
  struct alloc_cache* a, *na;
312
0
  int do_stop = 1;
313
0
  if(!ctx) return;
314
315
  /* if the delete is called but it has forked, and before the fork
316
   * the context was finalized, then the bg worker is not stopped
317
   * from here. There is one worker, but two contexts that refer to
318
   * it and only one should clean up, the one with getpid == pipe_pid.*/
319
0
  if(ctx->created_bg && ctx->pipe_pid != getpid()) {
320
0
    do_stop = 0;
321
0
#ifndef USE_WINSOCK
322
    /* Stop events from getting deregistered, if the backend is
323
     * epoll, the epoll fd is the same as the other process.
324
     * That process should deregister them. */
325
0
    if(ctx->qq_pipe->listen_com)
326
0
      ctx->qq_pipe->listen_com->event_added = 0;
327
0
    if(ctx->qq_pipe->res_com)
328
0
      ctx->qq_pipe->res_com->event_added = 0;
329
0
    if(ctx->rr_pipe->listen_com)
330
0
      ctx->rr_pipe->listen_com->event_added = 0;
331
0
    if(ctx->rr_pipe->res_com)
332
0
      ctx->rr_pipe->res_com->event_added = 0;
333
0
#endif
334
0
  }
335
  /* see if bg thread is created and if threads have been killed */
336
  /* no locks, because those may be held by terminated threads */
337
  /* for processes the read pipe is closed and we see that on read */
338
0
#ifdef HAVE_PTHREAD
339
0
  if(ctx->created_bg && ctx->dothread && do_stop) {
340
0
    if(pthread_kill(ctx->bg_tid, 0) == ESRCH) {
341
      /* thread has been killed */
342
0
      do_stop = 0;
343
0
    }
344
0
  }
345
0
#endif /* HAVE_PTHREAD */
346
0
  if(do_stop)
347
0
    ub_stop_bg(ctx);
348
0
  if(ctx->created_bg && ctx->pipe_pid != getpid() && ctx->thread_worker) {
349
    /* This delete is happening from a different process. Delete
350
     * the thread worker from this process memory space. The
351
     * thread is not there to do so, so it is freed here. */
352
0
    struct ub_event_base* evbase = comm_base_internal(
353
0
      ctx->thread_worker->base);
354
0
    libworker_delete_event(ctx->thread_worker);
355
0
    ctx->thread_worker = NULL;
356
0
#ifdef USE_MINI_EVENT
357
0
    ub_event_base_free(evbase);
358
#else
359
    /* cannot event_base_free, because the epoll_fd cleanup
360
     * in libevent could stop the original event_base in the
361
     * other process from working. */
362
    free(evbase);
363
#endif
364
0
  }
365
0
  libworker_delete_event(ctx->event_worker);
366
367
0
  modstack_call_deinit(&ctx->mods, ctx->env);
368
0
  modstack_call_destartup(&ctx->mods, ctx->env);
369
0
  modstack_free(&ctx->mods);
370
0
  a = ctx->alloc_list;
371
0
  while(a) {
372
0
    na = a->super;
373
0
    a->super = &ctx->superalloc;
374
0
    alloc_clear(a);
375
0
    free(a);
376
0
    a = na;
377
0
  }
378
0
  local_zones_delete(ctx->local_zones);
379
0
  lock_basic_destroy(&ctx->qqpipe_lock);
380
0
  lock_basic_destroy(&ctx->rrpipe_lock);
381
0
  lock_basic_destroy(&ctx->cfglock);
382
0
  tube_delete(ctx->qq_pipe);
383
0
  tube_delete(ctx->rr_pipe);
384
0
  if(ctx->env) {
385
0
    slabhash_delete(ctx->env->msg_cache);
386
0
    rrset_cache_delete(ctx->env->rrset_cache);
387
0
    infra_delete(ctx->env->infra_cache);
388
0
    config_delete(ctx->env->cfg);
389
0
    edns_known_options_delete(ctx->env);
390
0
    edns_strings_delete(ctx->env->edns_strings);
391
0
    forwards_delete(ctx->env->fwds);
392
0
    hints_delete(ctx->env->hints);
393
0
    auth_zones_delete(ctx->env->auth_zones);
394
0
    free(ctx->env);
395
0
  }
396
0
  ub_randfree(ctx->seed_rnd);
397
0
  alloc_clear(&ctx->superalloc);
398
0
  listen_desetup_locks();
399
0
  traverse_postorder(&ctx->queries, delq, NULL);
400
0
  if(ctx_logfile_overridden) {
401
0
    log_file(NULL);
402
0
    ctx_logfile_overridden = 0;
403
0
  }
404
0
  if(ctx->event_base_malloced)
405
0
    free(ctx->event_base);
406
0
  free(ctx);
407
#ifdef USE_WINSOCK
408
  WSACleanup();
409
#endif
410
0
}
411
412
int 
413
ub_ctx_set_option(struct ub_ctx* ctx, const char* opt, const char* val)
414
0
{
415
0
  lock_basic_lock(&ctx->cfglock);
416
0
  if(ctx->finalized) {
417
0
    lock_basic_unlock(&ctx->cfglock);
418
0
    return UB_AFTERFINAL;
419
0
  }
420
0
  if(!config_set_option(ctx->env->cfg, opt, val)) {
421
0
    lock_basic_unlock(&ctx->cfglock);
422
0
    return UB_SYNTAX;
423
0
  }
424
0
  lock_basic_unlock(&ctx->cfglock);
425
0
  return UB_NOERROR;
426
0
}
427
428
int
429
ub_ctx_get_option(struct ub_ctx* ctx, const char* opt, char** str)
430
0
{
431
0
  int r;
432
0
  lock_basic_lock(&ctx->cfglock);
433
0
  r = config_get_option_collate(ctx->env->cfg, opt, str);
434
0
  lock_basic_unlock(&ctx->cfglock);
435
0
  if(r == 0) r = UB_NOERROR;
436
0
  else if(r == 1) r = UB_SYNTAX;
437
0
  else if(r == 2) r = UB_NOMEM;
438
0
  return r;
439
0
}
440
441
int 
442
ub_ctx_config(struct ub_ctx* ctx, const char* fname)
443
0
{
444
0
  lock_basic_lock(&ctx->cfglock);
445
0
  if(ctx->finalized) {
446
0
    lock_basic_unlock(&ctx->cfglock);
447
0
    return UB_AFTERFINAL;
448
0
  }
449
0
  if(!config_read(ctx->env->cfg, fname, NULL)) {
450
0
    lock_basic_unlock(&ctx->cfglock);
451
0
    return UB_SYNTAX;
452
0
  }
453
0
  lock_basic_unlock(&ctx->cfglock);
454
0
  return UB_NOERROR;
455
0
}
456
457
int 
458
ub_ctx_add_ta(struct ub_ctx* ctx, const char* ta)
459
0
{
460
0
  char* dup = strdup(ta);
461
0
  if(!dup) return UB_NOMEM;
462
0
  lock_basic_lock(&ctx->cfglock);
463
0
  if(ctx->finalized) {
464
0
    lock_basic_unlock(&ctx->cfglock);
465
0
    free(dup);
466
0
    return UB_AFTERFINAL;
467
0
  }
468
0
  if(!cfg_strlist_insert(&ctx->env->cfg->trust_anchor_list, dup)) {
469
0
    lock_basic_unlock(&ctx->cfglock);
470
0
    return UB_NOMEM;
471
0
  }
472
0
  lock_basic_unlock(&ctx->cfglock);
473
0
  return UB_NOERROR;
474
0
}
475
476
int 
477
ub_ctx_add_ta_file(struct ub_ctx* ctx, const char* fname)
478
0
{
479
0
  char* dup = strdup(fname);
480
0
  if(!dup) return UB_NOMEM;
481
0
  lock_basic_lock(&ctx->cfglock);
482
0
  if(ctx->finalized) {
483
0
    lock_basic_unlock(&ctx->cfglock);
484
0
    free(dup);
485
0
    return UB_AFTERFINAL;
486
0
  }
487
0
  if(!cfg_strlist_insert(&ctx->env->cfg->trust_anchor_file_list, dup)) {
488
0
    lock_basic_unlock(&ctx->cfglock);
489
0
    return UB_NOMEM;
490
0
  }
491
0
  lock_basic_unlock(&ctx->cfglock);
492
0
  return UB_NOERROR;
493
0
}
494
495
int ub_ctx_add_ta_autr(struct ub_ctx* ctx, const char* fname)
496
0
{
497
0
  char* dup = strdup(fname);
498
0
  if(!dup) return UB_NOMEM;
499
0
  lock_basic_lock(&ctx->cfglock);
500
0
  if(ctx->finalized) {
501
0
    lock_basic_unlock(&ctx->cfglock);
502
0
    free(dup);
503
0
    return UB_AFTERFINAL;
504
0
  }
505
0
  if(!cfg_strlist_insert(&ctx->env->cfg->auto_trust_anchor_file_list,
506
0
    dup)) {
507
0
    lock_basic_unlock(&ctx->cfglock);
508
0
    return UB_NOMEM;
509
0
  }
510
0
  lock_basic_unlock(&ctx->cfglock);
511
0
  return UB_NOERROR;
512
0
}
513
514
int 
515
ub_ctx_trustedkeys(struct ub_ctx* ctx, const char* fname)
516
0
{
517
0
  char* dup = strdup(fname);
518
0
  if(!dup) return UB_NOMEM;
519
0
  lock_basic_lock(&ctx->cfglock);
520
0
  if(ctx->finalized) {
521
0
    lock_basic_unlock(&ctx->cfglock);
522
0
    free(dup);
523
0
    return UB_AFTERFINAL;
524
0
  }
525
0
  if(!cfg_strlist_insert(&ctx->env->cfg->trusted_keys_file_list, dup)) {
526
0
    lock_basic_unlock(&ctx->cfglock);
527
0
    return UB_NOMEM;
528
0
  }
529
0
  lock_basic_unlock(&ctx->cfglock);
530
0
  return UB_NOERROR;
531
0
}
532
533
int
534
ub_ctx_debuglevel(struct ub_ctx* ctx, int d)
535
0
{
536
0
  lock_basic_lock(&ctx->cfglock);
537
0
  verbosity = d;
538
0
  ctx->env->cfg->verbosity = d;
539
0
  lock_basic_unlock(&ctx->cfglock);
540
0
  return UB_NOERROR;
541
0
}
542
543
int ub_ctx_debugout(struct ub_ctx* ctx, void* out)
544
0
{
545
0
  lock_basic_lock(&ctx->cfglock);
546
0
  log_file((FILE*)out);
547
0
  ctx_logfile_overridden = 1;
548
0
  ctx->logfile_override = 1;
549
0
  ctx->log_out = out;
550
0
  lock_basic_unlock(&ctx->cfglock);
551
0
  return UB_NOERROR;
552
0
}
553
554
int 
555
ub_ctx_async(struct ub_ctx* ctx, int dothread)
556
0
{
557
#ifdef THREADS_DISABLED
558
  if(dothread) /* cannot do threading */
559
    return UB_NOERROR;
560
#endif
561
0
  lock_basic_lock(&ctx->cfglock);
562
0
  if(ctx->finalized) {
563
0
    lock_basic_unlock(&ctx->cfglock);
564
0
    return UB_AFTERFINAL;
565
0
  }
566
0
  ctx->dothread = dothread;
567
0
  lock_basic_unlock(&ctx->cfglock);
568
0
  return UB_NOERROR;
569
0
}
570
571
int 
572
ub_poll(struct ub_ctx* ctx)
573
0
{
574
  /* no need to hold lock while testing for readability. */
575
0
  return tube_poll(ctx->rr_pipe);
576
0
}
577
578
int 
579
ub_fd(struct ub_ctx* ctx)
580
0
{
581
0
  return tube_read_fd(ctx->rr_pipe);
582
0
}
583
584
/** process answer from bg worker */
585
static int
586
process_answer_detail(struct ub_ctx* ctx, uint8_t* msg, uint32_t len,
587
  ub_callback_type* cb, void** cbarg, int* err,
588
  struct ub_result** res)
589
0
{
590
0
  struct ctx_query* q;
591
0
  if(context_serial_getcmd(msg, len) != UB_LIBCMD_ANSWER) {
592
0
    log_err("error: bad data from bg worker %d",
593
0
      (int)context_serial_getcmd(msg, len));
594
0
    return 0;
595
0
  }
596
597
0
  lock_basic_lock(&ctx->cfglock);
598
0
  q = context_deserialize_answer(ctx, msg, len, err);
599
0
  if(!q) {
600
0
    lock_basic_unlock(&ctx->cfglock);
601
    /* probably simply the lookup that failed, i.e.
602
     * response returned before cancel was sent out, so noerror */
603
0
    return 1;
604
0
  }
605
0
  log_assert(q->async);
606
607
  /* grab cb while locked */
608
0
  if(q->cancelled) {
609
0
    *cb = NULL;
610
0
    *cbarg = NULL;
611
0
  } else {
612
0
    *cb = q->cb;
613
0
    *cbarg = q->cb_arg;
614
0
  }
615
0
  if(*err) {
616
0
    *res = NULL;
617
0
    ub_resolve_free(q->res);
618
0
  } else {
619
    /* parse the message, extract rcode, fill result */
620
0
    sldns_buffer* buf = sldns_buffer_new(q->msg_len);
621
0
    struct regional* region = regional_create();
622
0
    *res = q->res;
623
0
    (*res)->rcode = LDNS_RCODE_SERVFAIL;
624
0
    if(region && buf) {
625
0
      sldns_buffer_clear(buf);
626
0
      sldns_buffer_write(buf, q->msg, q->msg_len);
627
0
      sldns_buffer_flip(buf);
628
0
      libworker_enter_result(*res, buf, region,
629
0
        q->msg_security);
630
0
    }
631
0
    (*res)->answer_packet = q->msg;
632
0
    (*res)->answer_len = (int)q->msg_len;
633
0
    q->msg = NULL;
634
0
    sldns_buffer_free(buf);
635
0
    regional_destroy(region);
636
0
  }
637
0
  q->res = NULL;
638
  /* delete the q from list */
639
0
  (void)rbtree_delete(&ctx->queries, q->node.key);
640
0
  ctx->num_async--;
641
0
  context_query_delete(q);
642
0
  lock_basic_unlock(&ctx->cfglock);
643
644
0
  if(*cb) return 2;
645
0
  ub_resolve_free(*res);
646
0
  return 1;
647
0
}
648
649
/** process answer from bg worker */
650
static int
651
process_answer(struct ub_ctx* ctx, uint8_t* msg, uint32_t len)
652
0
{
653
0
  int err;
654
0
  ub_callback_type cb;
655
0
  void* cbarg;
656
0
  struct ub_result* res;
657
0
  int r;
658
659
0
  r = process_answer_detail(ctx, msg, len, &cb, &cbarg, &err, &res);
660
661
  /* no locks held while calling callback, so that library is
662
   * re-entrant. */
663
0
  if(r == 2)
664
0
    (*cb)(cbarg, err, res);
665
666
0
  return r;
667
0
}
668
669
int 
670
ub_process(struct ub_ctx* ctx)
671
0
{
672
0
  int r;
673
0
  uint8_t* msg;
674
0
  uint32_t len;
675
0
  while(1) {
676
0
    msg = NULL;
677
0
    lock_basic_lock(&ctx->rrpipe_lock);
678
0
    r = tube_read_msg(ctx->rr_pipe, &msg, &len, 1);
679
0
    lock_basic_unlock(&ctx->rrpipe_lock);
680
0
    if(r == 0)
681
0
      return UB_PIPE;
682
0
    else if(r == -1)
683
0
      break;
684
0
    if(!process_answer(ctx, msg, len)) {
685
0
      free(msg);
686
0
      return UB_PIPE;
687
0
    }
688
0
    free(msg);
689
0
  }
690
0
  return UB_NOERROR;
691
0
}
692
693
int 
694
ub_wait(struct ub_ctx* ctx)
695
0
{
696
0
  int err;
697
0
  ub_callback_type cb;
698
0
  void* cbarg;
699
0
  struct ub_result* res;
700
0
  int r;
701
0
  uint8_t* msg;
702
0
  uint32_t len;
703
  /* this is basically the same loop as _process(), but with changes.
704
   * holds the rrpipe lock and waits with tube_wait */
705
0
  while(1) {
706
0
    lock_basic_lock(&ctx->rrpipe_lock);
707
0
    lock_basic_lock(&ctx->cfglock);
708
0
    if(ctx->num_async == 0) {
709
0
      lock_basic_unlock(&ctx->cfglock);
710
0
      lock_basic_unlock(&ctx->rrpipe_lock);
711
0
      break;
712
0
    }
713
0
    lock_basic_unlock(&ctx->cfglock);
714
715
    /* keep rrpipe locked, while
716
     *  o waiting for pipe readable
717
     *  o parsing message
718
     *  o possibly decrementing num_async
719
     * do callback without lock
720
     */
721
0
    r = tube_wait(ctx->rr_pipe);
722
0
    if(r) {
723
0
      r = tube_read_msg(ctx->rr_pipe, &msg, &len, 1);
724
0
      if(r == 0) {
725
0
        lock_basic_unlock(&ctx->rrpipe_lock);
726
0
        return UB_PIPE;
727
0
      }
728
0
      if(r == -1) {
729
0
        lock_basic_unlock(&ctx->rrpipe_lock);
730
0
        continue;
731
0
      }
732
0
      r = process_answer_detail(ctx, msg, len, 
733
0
        &cb, &cbarg, &err, &res);
734
0
      lock_basic_unlock(&ctx->rrpipe_lock);
735
0
      free(msg);
736
0
      if(r == 0)
737
0
        return UB_PIPE;
738
0
      if(r == 2)
739
0
        (*cb)(cbarg, err, res);
740
0
    } else {
741
0
      lock_basic_unlock(&ctx->rrpipe_lock);
742
0
    }
743
0
  }
744
0
  return UB_NOERROR;
745
0
}
746
747
int 
748
ub_resolve(struct ub_ctx* ctx, const char* name, int rrtype, 
749
  int rrclass, struct ub_result** result)
750
0
{
751
0
  struct ctx_query* q;
752
0
  int r;
753
0
  *result = NULL;
754
755
0
  lock_basic_lock(&ctx->cfglock);
756
0
  if(!ctx->finalized) {
757
0
    r = context_finalize(ctx);
758
0
    if(r) {
759
0
      lock_basic_unlock(&ctx->cfglock);
760
0
      return r;
761
0
    }
762
0
  }
763
  /* create new ctx_query and attempt to add to the list */
764
0
  lock_basic_unlock(&ctx->cfglock);
765
0
  q = context_new(ctx, name, rrtype, rrclass, NULL, NULL, NULL);
766
0
  if(!q)
767
0
    return UB_NOMEM;
768
  /* become a resolver thread for a bit */
769
770
0
  r = libworker_fg(ctx, q);
771
0
  if(r) {
772
0
    lock_basic_lock(&ctx->cfglock);
773
0
    (void)rbtree_delete(&ctx->queries, q->node.key);
774
0
    context_query_delete(q);
775
0
    lock_basic_unlock(&ctx->cfglock);
776
0
    return r;
777
0
  }
778
0
  q->res->answer_packet = q->msg;
779
0
  q->res->answer_len = (int)q->msg_len;
780
0
  q->msg = NULL;
781
0
  *result = q->res;
782
0
  q->res = NULL;
783
784
0
  lock_basic_lock(&ctx->cfglock);
785
0
  (void)rbtree_delete(&ctx->queries, q->node.key);
786
0
  context_query_delete(q);
787
0
  lock_basic_unlock(&ctx->cfglock);
788
0
  return UB_NOERROR;
789
0
}
790
791
int 
792
ub_resolve_event(struct ub_ctx* ctx, const char* name, int rrtype, 
793
  int rrclass, void* mydata, ub_event_callback_type callback,
794
  int* async_id)
795
0
{
796
0
  struct ctx_query* q;
797
0
  int r;
798
799
0
  if(async_id)
800
0
    *async_id = 0;
801
0
  lock_basic_lock(&ctx->cfglock);
802
0
  if(!ctx->finalized) {
803
0
    r = context_finalize(ctx);
804
0
    if(r) {
805
0
      lock_basic_unlock(&ctx->cfglock);
806
0
      return r;
807
0
    }
808
0
  }
809
0
  lock_basic_unlock(&ctx->cfglock);
810
0
  if(!ctx->event_worker) {
811
0
    ctx->event_worker = libworker_create_event(ctx,
812
0
      ctx->event_base);
813
0
    if(!ctx->event_worker) {
814
0
      return UB_INITFAIL;
815
0
    }
816
0
  }
817
818
  /* set time in case answer comes from cache */
819
0
  ub_comm_base_now(ctx->event_worker->base);
820
821
  /* create new ctx_query and attempt to add to the list */
822
0
  q = context_new(ctx, name, rrtype, rrclass, NULL, callback, mydata);
823
0
  if(!q)
824
0
    return UB_NOMEM;
825
826
  /* attach to mesh */
827
0
  if((r=libworker_attach_mesh(ctx, q, async_id)) != 0)
828
0
    return r;
829
0
  return UB_NOERROR;
830
0
}
831
832
833
int 
834
ub_resolve_async(struct ub_ctx* ctx, const char* name, int rrtype, 
835
  int rrclass, void* mydata, ub_callback_type callback, int* async_id)
836
0
{
837
0
  struct ctx_query* q;
838
0
  uint8_t* msg = NULL;
839
0
  uint32_t len = 0;
840
841
0
  if(async_id)
842
0
    *async_id = 0;
843
0
  lock_basic_lock(&ctx->cfglock);
844
0
  if(!ctx->finalized) {
845
0
    int r = context_finalize(ctx);
846
0
    if(r) {
847
0
      lock_basic_unlock(&ctx->cfglock);
848
0
      return r;
849
0
    }
850
0
  }
851
0
  if(!ctx->created_bg) {
852
0
    int r;
853
0
    ctx->created_bg = 1;
854
0
    lock_basic_unlock(&ctx->cfglock);
855
0
    r = libworker_bg(ctx);
856
0
    if(r) {
857
0
      lock_basic_lock(&ctx->cfglock);
858
0
      ctx->created_bg = 0;
859
0
      lock_basic_unlock(&ctx->cfglock);
860
0
      return r;
861
0
    }
862
0
  } else {
863
0
    lock_basic_unlock(&ctx->cfglock);
864
0
  }
865
866
  /* create new ctx_query and attempt to add to the list */
867
0
  q = context_new(ctx, name, rrtype, rrclass, callback, NULL, mydata);
868
0
  if(!q)
869
0
    return UB_NOMEM;
870
871
  /* write over pipe to background worker */
872
0
  lock_basic_lock(&ctx->cfglock);
873
0
  msg = context_serialize_new_query(q, &len);
874
0
  if(!msg) {
875
0
    (void)rbtree_delete(&ctx->queries, q->node.key);
876
0
    ctx->num_async--;
877
0
    context_query_delete(q);
878
0
    lock_basic_unlock(&ctx->cfglock);
879
0
    return UB_NOMEM;
880
0
  }
881
0
  if(async_id)
882
0
    *async_id = q->querynum;
883
0
  lock_basic_unlock(&ctx->cfglock);
884
  
885
0
  lock_basic_lock(&ctx->qqpipe_lock);
886
0
  if(!tube_write_msg(ctx->qq_pipe, msg, len, 0)) {
887
0
    lock_basic_unlock(&ctx->qqpipe_lock);
888
0
    free(msg);
889
0
    return UB_PIPE;
890
0
  }
891
0
  lock_basic_unlock(&ctx->qqpipe_lock);
892
0
  free(msg);
893
0
  return UB_NOERROR;
894
0
}
895
896
int 
897
ub_cancel(struct ub_ctx* ctx, int async_id)
898
0
{
899
0
  struct ctx_query* q;
900
0
  uint8_t* msg = NULL;
901
0
  uint32_t len = 0;
902
0
  lock_basic_lock(&ctx->cfglock);
903
0
  q = (struct ctx_query*)rbtree_search(&ctx->queries, &async_id);
904
0
  if(!q || !q->async) {
905
    /* it is not there, so nothing to do */
906
0
    lock_basic_unlock(&ctx->cfglock);
907
0
    return UB_NOID;
908
0
  }
909
0
  log_assert(q->async);
910
0
  q->cancelled = 1;
911
  
912
  /* delete it */
913
0
  if(!ctx->dothread) { /* if forked */
914
0
    (void)rbtree_delete(&ctx->queries, q->node.key);
915
0
    ctx->num_async--;
916
0
    msg = context_serialize_cancel(q, &len);
917
0
    context_query_delete(q);
918
0
    lock_basic_unlock(&ctx->cfglock);
919
0
    if(!msg) {
920
0
      return UB_NOMEM;
921
0
    }
922
    /* send cancel to background worker */
923
0
    lock_basic_lock(&ctx->qqpipe_lock);
924
0
    if(!tube_write_msg(ctx->qq_pipe, msg, len, 0)) {
925
0
      lock_basic_unlock(&ctx->qqpipe_lock);
926
0
      free(msg);
927
0
      return UB_PIPE;
928
0
    }
929
0
    lock_basic_unlock(&ctx->qqpipe_lock);
930
0
    free(msg);
931
0
  } else {
932
0
    lock_basic_unlock(&ctx->cfglock);
933
0
  }
934
0
  return UB_NOERROR;
935
0
}
936
937
void 
938
ub_resolve_free(struct ub_result* result)
939
0
{
940
0
  char** p;
941
0
  if(!result) return;
942
0
  free(result->qname);
943
0
  if(result->canonname != result->qname)
944
0
    free(result->canonname);
945
0
  if(result->data)
946
0
    for(p = result->data; *p; p++)
947
0
      free(*p);
948
0
  free(result->data);
949
0
  free(result->len);
950
0
  free(result->answer_packet);
951
0
  free(result->why_bogus);
952
0
  free(result);
953
0
}
954
955
const char* 
956
ub_strerror(int err)
957
0
{
958
0
  switch(err) {
959
0
    case UB_NOERROR: return "no error";
960
0
    case UB_SOCKET: return "socket io error";
961
0
    case UB_NOMEM: return "out of memory";
962
0
    case UB_SYNTAX: return "syntax error";
963
0
    case UB_SERVFAIL: return "server failure";
964
0
    case UB_FORKFAIL: return "could not fork";
965
0
    case UB_INITFAIL: return "initialization failure";
966
0
    case UB_AFTERFINAL: return "setting change after finalize";
967
0
    case UB_PIPE: return "error in pipe communication with async";
968
0
    case UB_READFILE: return "error reading file";
969
0
    case UB_NOID: return "error async_id does not exist";
970
0
    default: return "unknown error";
971
0
  }
972
0
}
973
974
int 
975
ub_ctx_set_fwd(struct ub_ctx* ctx, const char* addr)
976
0
{
977
0
  struct sockaddr_storage storage;
978
0
  socklen_t stlen;
979
0
  struct config_stub* s;
980
0
  char* dupl;
981
0
  lock_basic_lock(&ctx->cfglock);
982
0
  if(ctx->finalized) {
983
0
    lock_basic_unlock(&ctx->cfglock);
984
0
    errno=EINVAL;
985
0
    return UB_AFTERFINAL;
986
0
  }
987
0
  if(!addr) {
988
    /* disable fwd mode - the root stub should be first. */
989
0
    if(ctx->env->cfg->forwards &&
990
0
      (ctx->env->cfg->forwards->name &&
991
0
      strcmp(ctx->env->cfg->forwards->name, ".") == 0)) {
992
0
      s = ctx->env->cfg->forwards;
993
0
      ctx->env->cfg->forwards = s->next;
994
0
      s->next = NULL;
995
0
      config_delstubs(s);
996
0
    }
997
0
    lock_basic_unlock(&ctx->cfglock);
998
0
    return UB_NOERROR;
999
0
  }
1000
0
  lock_basic_unlock(&ctx->cfglock);
1001
1002
  /* check syntax for addr */
1003
0
  if(!extstrtoaddr(addr, &storage, &stlen, UNBOUND_DNS_PORT)) {
1004
0
    errno=EINVAL;
1005
0
    return UB_SYNTAX;
1006
0
  }
1007
  
1008
  /* it parses, add root stub in front of list */
1009
0
  lock_basic_lock(&ctx->cfglock);
1010
0
  if(!ctx->env->cfg->forwards ||
1011
0
    (ctx->env->cfg->forwards->name &&
1012
0
    strcmp(ctx->env->cfg->forwards->name, ".") != 0)) {
1013
0
    s = calloc(1, sizeof(*s));
1014
0
    if(!s) {
1015
0
      lock_basic_unlock(&ctx->cfglock);
1016
0
      errno=ENOMEM;
1017
0
      return UB_NOMEM;
1018
0
    }
1019
0
    s->name = strdup(".");
1020
0
    if(!s->name) {
1021
0
      free(s);
1022
0
      lock_basic_unlock(&ctx->cfglock);
1023
0
      errno=ENOMEM;
1024
0
      return UB_NOMEM;
1025
0
    }
1026
0
    s->next = ctx->env->cfg->forwards;
1027
0
    ctx->env->cfg->forwards = s;
1028
0
  } else {
1029
0
    log_assert(ctx->env->cfg->forwards);
1030
0
    log_assert(ctx->env->cfg->forwards->name);
1031
0
    s = ctx->env->cfg->forwards;
1032
0
  }
1033
0
  dupl = strdup(addr);
1034
0
  if(!dupl) {
1035
0
    lock_basic_unlock(&ctx->cfglock);
1036
0
    errno=ENOMEM;
1037
0
    return UB_NOMEM;
1038
0
  }
1039
0
  if(!cfg_strlist_insert(&s->addrs, dupl)) {
1040
0
    lock_basic_unlock(&ctx->cfglock);
1041
0
    errno=ENOMEM;
1042
0
    return UB_NOMEM;
1043
0
  }
1044
0
  lock_basic_unlock(&ctx->cfglock);
1045
0
  return UB_NOERROR;
1046
0
}
1047
1048
int ub_ctx_set_tls(struct ub_ctx* ctx, int tls)
1049
0
{
1050
0
  lock_basic_lock(&ctx->cfglock);
1051
0
  if(ctx->finalized) {
1052
0
    lock_basic_unlock(&ctx->cfglock);
1053
0
    errno=EINVAL;
1054
0
    return UB_AFTERFINAL;
1055
0
  }
1056
0
  ctx->env->cfg->ssl_upstream = tls;
1057
0
  lock_basic_unlock(&ctx->cfglock);
1058
0
  return UB_NOERROR;
1059
0
}
1060
1061
int ub_ctx_set_stub(struct ub_ctx* ctx, const char* zone, const char* addr,
1062
  int isprime)
1063
0
{
1064
0
  char* a;
1065
0
  struct config_stub **prev, *elem;
1066
1067
  /* check syntax for zone name */
1068
0
  if(zone) {
1069
0
    uint8_t* nm;
1070
0
    int nmlabs;
1071
0
    size_t nmlen;
1072
0
    if(!parse_dname(zone, &nm, &nmlen, &nmlabs)) {
1073
0
      errno=EINVAL;
1074
0
      return UB_SYNTAX;
1075
0
    }
1076
0
    free(nm);
1077
0
  } else {
1078
0
    zone = ".";
1079
0
  }
1080
1081
  /* check syntax for addr (if not NULL) */
1082
0
  if(addr) {
1083
0
    struct sockaddr_storage storage;
1084
0
    socklen_t stlen;
1085
0
    if(!extstrtoaddr(addr, &storage, &stlen, UNBOUND_DNS_PORT)) {
1086
0
      errno=EINVAL;
1087
0
      return UB_SYNTAX;
1088
0
    }
1089
0
  }
1090
1091
0
  lock_basic_lock(&ctx->cfglock);
1092
0
  if(ctx->finalized) {
1093
0
    lock_basic_unlock(&ctx->cfglock);
1094
0
    errno=EINVAL;
1095
0
    return UB_AFTERFINAL;
1096
0
  }
1097
1098
  /* arguments all right, now find or add the stub */
1099
0
  prev = &ctx->env->cfg->stubs;
1100
0
  elem = cfg_stub_find(&prev, zone);
1101
0
  if(!elem && !addr) {
1102
    /* not found and we want to delete, nothing to do */
1103
0
    lock_basic_unlock(&ctx->cfglock);
1104
0
    return UB_NOERROR;
1105
0
  } else if(elem && !addr) {
1106
    /* found, and we want to delete */
1107
0
    *prev = elem->next;
1108
0
    config_delstub(elem);
1109
0
    lock_basic_unlock(&ctx->cfglock);
1110
0
    return UB_NOERROR;
1111
0
  } else if(!elem) {
1112
    /* not found, create the stub entry */
1113
0
    elem=(struct config_stub*)calloc(1, sizeof(struct config_stub));
1114
0
    if(elem) elem->name = strdup(zone);
1115
0
    if(!elem || !elem->name) {
1116
0
      free(elem);
1117
0
      lock_basic_unlock(&ctx->cfglock);
1118
0
      errno = ENOMEM;
1119
0
      return UB_NOMEM;
1120
0
    }
1121
0
    elem->next = ctx->env->cfg->stubs;
1122
0
    ctx->env->cfg->stubs = elem;
1123
0
  }
1124
1125
  /* add the address to the list and set settings */
1126
0
  elem->isprime = isprime;
1127
0
  a = strdup(addr);
1128
0
  if(!a) {
1129
0
    lock_basic_unlock(&ctx->cfglock);
1130
0
    errno = ENOMEM;
1131
0
    return UB_NOMEM;
1132
0
  }
1133
0
  if(!cfg_strlist_insert(&elem->addrs, a)) {
1134
0
    lock_basic_unlock(&ctx->cfglock);
1135
0
    errno = ENOMEM;
1136
0
    return UB_NOMEM;
1137
0
  }
1138
0
  lock_basic_unlock(&ctx->cfglock);
1139
0
  return UB_NOERROR;
1140
0
}
1141
1142
int 
1143
ub_ctx_resolvconf(struct ub_ctx* ctx, const char* fname)
1144
0
{
1145
0
  FILE* in;
1146
0
  int numserv = 0;
1147
0
  char buf[1024];
1148
0
  char* parse, *addr;
1149
0
  int r;
1150
1151
0
  if(fname == NULL) {
1152
0
#if !defined(UB_ON_WINDOWS) || !defined(HAVE_WINDOWS_H)
1153
0
    fname = "/etc/resolv.conf";
1154
#else
1155
    FIXED_INFO *info;
1156
    ULONG buflen = sizeof(*info);
1157
    IP_ADDR_STRING *ptr;
1158
1159
    info = (FIXED_INFO *) malloc(sizeof (FIXED_INFO));
1160
    if (info == NULL) 
1161
      return UB_READFILE;
1162
1163
    if (GetNetworkParams(info, &buflen) == ERROR_BUFFER_OVERFLOW) {
1164
      free(info);
1165
      info = (FIXED_INFO *) malloc(buflen);
1166
      if (info == NULL)
1167
        return UB_READFILE;
1168
    }
1169
1170
    if (GetNetworkParams(info, &buflen) == NO_ERROR) {
1171
      int retval=0;
1172
      ptr = &(info->DnsServerList);
1173
      while (ptr) {
1174
        numserv++;
1175
        if((retval=ub_ctx_set_fwd(ctx, 
1176
          ptr->IpAddress.String))!=0) {
1177
          free(info);
1178
          return retval;
1179
        }
1180
        ptr = ptr->Next;
1181
      }
1182
      free(info);
1183
      if (numserv==0)
1184
        return UB_READFILE;
1185
      return UB_NOERROR;
1186
    }
1187
    free(info);
1188
    return UB_READFILE;
1189
#endif /* WINDOWS */
1190
0
  }
1191
0
  in = fopen(fname, "r");
1192
0
  if(!in) {
1193
    /* error in errno! perror(fname) */
1194
0
    return UB_READFILE;
1195
0
  }
1196
0
  while(fgets(buf, (int)sizeof(buf), in)) {
1197
0
    buf[sizeof(buf)-1] = 0;
1198
0
    parse=buf;
1199
0
    while(*parse == ' ' || *parse == '\t')
1200
0
      parse++;
1201
0
    if(strncmp(parse, "nameserver", 10) == 0) {
1202
0
      numserv++;
1203
0
      parse += 10; /* skip 'nameserver' */
1204
      /* skip whitespace */
1205
0
      while(*parse == ' ' || *parse == '\t')
1206
0
        parse++;
1207
0
      addr = parse;
1208
      /* skip [0-9a-fA-F.:]*, i.e. IP4 and IP6 address */
1209
0
      while(isxdigit((unsigned char)*parse) || *parse=='.' || *parse==':')
1210
0
        parse++;
1211
      /* terminate after the address, remove newline */
1212
0
      *parse = 0;
1213
      
1214
0
      if((r = ub_ctx_set_fwd(ctx, addr)) != UB_NOERROR) {
1215
0
        fclose(in);
1216
0
        return r;
1217
0
      }
1218
0
    }
1219
0
  }
1220
0
  fclose(in);
1221
0
  if(numserv == 0) {
1222
    /* from resolv.conf(5) if none given, use localhost */
1223
0
    return ub_ctx_set_fwd(ctx, "127.0.0.1");
1224
0
  }
1225
0
  return UB_NOERROR;
1226
0
}
1227
1228
int
1229
ub_ctx_hosts(struct ub_ctx* ctx, const char* fname)
1230
0
{
1231
0
  FILE* in;
1232
0
  char buf[1024], ldata[2048];
1233
0
  char* parse, *addr, *name, *ins;
1234
0
  lock_basic_lock(&ctx->cfglock);
1235
0
  if(ctx->finalized) {
1236
0
    lock_basic_unlock(&ctx->cfglock);
1237
0
    errno=EINVAL;
1238
0
    return UB_AFTERFINAL;
1239
0
  }
1240
0
  lock_basic_unlock(&ctx->cfglock);
1241
0
  if(fname == NULL) {
1242
#if defined(UB_ON_WINDOWS) && defined(HAVE_WINDOWS_H)
1243
    /*
1244
     * If this is Windows NT/XP/2K it's in
1245
     * %WINDIR%\system32\drivers\etc\hosts.
1246
     * If this is Windows 95/98/Me it's in %WINDIR%\hosts.
1247
     */
1248
    name = getenv("WINDIR");
1249
    if (name != NULL) {
1250
      int retval=0;
1251
      snprintf(buf, sizeof(buf), "%s%s", name, 
1252
        "\\system32\\drivers\\etc\\hosts");
1253
      if((retval=ub_ctx_hosts(ctx, buf)) !=0 ) {
1254
        snprintf(buf, sizeof(buf), "%s%s", name, 
1255
          "\\hosts");
1256
        retval=ub_ctx_hosts(ctx, buf);
1257
      }
1258
      return retval;
1259
    }
1260
    return UB_READFILE;
1261
#else
1262
0
    fname = "/etc/hosts";
1263
0
#endif /* WIN32 */
1264
0
  }
1265
0
  in = fopen(fname, "r");
1266
0
  if(!in) {
1267
    /* error in errno! perror(fname) */
1268
0
    return UB_READFILE;
1269
0
  }
1270
0
  while(fgets(buf, (int)sizeof(buf), in)) {
1271
0
    buf[sizeof(buf)-1] = 0;
1272
0
    parse=buf;
1273
0
    while(*parse == ' ' || *parse == '\t')
1274
0
      parse++;
1275
0
    if(*parse == '#')
1276
0
      continue; /* skip comment */
1277
    /* format: <addr> spaces <name> spaces <name> ... */
1278
0
    addr = parse;
1279
    /* skip addr */
1280
0
    while(isxdigit((unsigned char)*parse) || *parse == '.' || *parse == ':')
1281
0
      parse++;
1282
0
    if(*parse == '\r')
1283
0
      parse++;
1284
0
    if(*parse == '\n' || *parse == 0)
1285
0
      continue;
1286
0
    if(*parse == '%') 
1287
0
      continue; /* ignore macOSX fe80::1%lo0 localhost */
1288
0
    if(*parse != ' ' && *parse != '\t') {
1289
      /* must have whitespace after address */
1290
0
      fclose(in);
1291
0
      errno=EINVAL;
1292
0
      return UB_SYNTAX;
1293
0
    }
1294
0
    *parse++ = 0; /* end delimiter for addr ... */
1295
    /* go to names and add them */
1296
0
    while(*parse) {
1297
0
      while(*parse == ' ' || *parse == '\t' || *parse=='\n'
1298
0
        || *parse=='\r')
1299
0
        parse++;
1300
0
      if(*parse == 0 || *parse == '#')
1301
0
        break;
1302
      /* skip name, allows (too) many printable characters */
1303
0
      name = parse;
1304
0
      while('!' <= *parse && *parse <= '~')
1305
0
        parse++;
1306
0
      if(*parse)
1307
0
        *parse++ = 0; /* end delimiter for name */
1308
0
      snprintf(ldata, sizeof(ldata), "%s %s %s",
1309
0
        name, str_is_ip6(addr)?"AAAA":"A", addr);
1310
0
      ins = strdup(ldata);
1311
0
      if(!ins) {
1312
        /* out of memory */
1313
0
        fclose(in);
1314
0
        errno=ENOMEM;
1315
0
        return UB_NOMEM;
1316
0
      }
1317
0
      lock_basic_lock(&ctx->cfglock);
1318
0
      if(!cfg_strlist_insert(&ctx->env->cfg->local_data, 
1319
0
        ins)) {
1320
0
        lock_basic_unlock(&ctx->cfglock);
1321
0
        fclose(in);
1322
0
        errno=ENOMEM;
1323
0
        return UB_NOMEM;
1324
0
      }
1325
0
      lock_basic_unlock(&ctx->cfglock);
1326
0
    }
1327
0
  }
1328
0
  fclose(in);
1329
0
  return UB_NOERROR;
1330
0
}
1331
1332
/** finalize the context, if not already finalized */
1333
static int ub_ctx_finalize(struct ub_ctx* ctx)
1334
0
{
1335
0
  int res = 0;
1336
0
  lock_basic_lock(&ctx->cfglock);
1337
0
  if (!ctx->finalized) {
1338
0
    res = context_finalize(ctx);
1339
0
  }
1340
0
  lock_basic_unlock(&ctx->cfglock);
1341
0
  return res;
1342
0
}
1343
1344
/* Print local zones and RR data */
1345
int ub_ctx_print_local_zones(struct ub_ctx* ctx)
1346
0
{   
1347
0
  int res = ub_ctx_finalize(ctx);
1348
0
  if (res) return res;
1349
1350
0
  local_zones_print(ctx->local_zones);
1351
1352
0
  return UB_NOERROR;
1353
0
}
1354
1355
/* Add a new zone */
1356
int ub_ctx_zone_add(struct ub_ctx* ctx, const char *zone_name, 
1357
  const char *zone_type)
1358
0
{
1359
0
  enum localzone_type t;
1360
0
  struct local_zone* z;
1361
0
  uint8_t* nm;
1362
0
  int nmlabs;
1363
0
  size_t nmlen;
1364
1365
0
  int res = ub_ctx_finalize(ctx);
1366
0
  if (res) return res;
1367
1368
0
  if(!local_zone_str2type(zone_type, &t)) {
1369
0
    return UB_SYNTAX;
1370
0
  }
1371
1372
0
  if(!parse_dname(zone_name, &nm, &nmlen, &nmlabs)) {
1373
0
    return UB_SYNTAX;
1374
0
  }
1375
1376
0
  lock_rw_wrlock(&ctx->local_zones->lock);
1377
0
  if((z=local_zones_find(ctx->local_zones, nm, nmlen, nmlabs, 
1378
0
    LDNS_RR_CLASS_IN))) {
1379
    /* already present in tree */
1380
0
    lock_rw_wrlock(&z->lock);
1381
0
    z->type = t; /* update type anyway */
1382
0
    lock_rw_unlock(&z->lock);
1383
0
    lock_rw_unlock(&ctx->local_zones->lock);
1384
0
    free(nm);
1385
0
    return UB_NOERROR;
1386
0
  }
1387
0
  if(!local_zones_add_zone(ctx->local_zones, nm, nmlen, nmlabs, 
1388
0
    LDNS_RR_CLASS_IN, t)) {
1389
0
    lock_rw_unlock(&ctx->local_zones->lock);
1390
0
    return UB_NOMEM;
1391
0
  }
1392
0
  lock_rw_unlock(&ctx->local_zones->lock);
1393
0
  return UB_NOERROR;
1394
0
}
1395
1396
/* Remove zone */
1397
int ub_ctx_zone_remove(struct ub_ctx* ctx, const char *zone_name)
1398
0
{   
1399
0
  struct local_zone* z;
1400
0
  uint8_t* nm;
1401
0
  int nmlabs;
1402
0
  size_t nmlen;
1403
1404
0
  int res = ub_ctx_finalize(ctx);
1405
0
  if (res) return res;
1406
1407
0
  if(!parse_dname(zone_name, &nm, &nmlen, &nmlabs)) {
1408
0
    return UB_SYNTAX;
1409
0
  }
1410
1411
0
  lock_rw_wrlock(&ctx->local_zones->lock);
1412
0
  if((z=local_zones_find(ctx->local_zones, nm, nmlen, nmlabs, 
1413
0
    LDNS_RR_CLASS_IN))) {
1414
    /* present in tree */
1415
0
    local_zones_del_zone(ctx->local_zones, z);
1416
0
  }
1417
0
  lock_rw_unlock(&ctx->local_zones->lock);
1418
0
  free(nm);
1419
0
  return UB_NOERROR;
1420
0
}
1421
1422
/* Add new RR data */
1423
int ub_ctx_data_add(struct ub_ctx* ctx, const char *data)
1424
0
{
1425
0
  int res = ub_ctx_finalize(ctx);
1426
0
  if (res) return res;
1427
1428
0
  res = local_zones_add_RR(ctx->local_zones, data);
1429
0
  return (!res) ? UB_NOMEM : UB_NOERROR;
1430
0
}
1431
1432
/* Remove RR data */
1433
int ub_ctx_data_remove(struct ub_ctx* ctx, const char *data)
1434
0
{
1435
0
  uint8_t* nm;
1436
0
  int nmlabs;
1437
0
  size_t nmlen;
1438
0
  int res = ub_ctx_finalize(ctx);
1439
0
  if (res) return res;
1440
1441
0
  if(!parse_dname(data, &nm, &nmlen, &nmlabs)) 
1442
0
    return UB_SYNTAX;
1443
1444
0
  local_zones_del_data(ctx->local_zones, nm, nmlen, nmlabs, 
1445
0
    LDNS_RR_CLASS_IN);
1446
1447
0
  free(nm);
1448
0
  return UB_NOERROR;
1449
0
}
1450
1451
const char* ub_version(void)
1452
0
{
1453
0
  return PACKAGE_VERSION;
1454
0
}
1455
1456
int 
1457
0
ub_ctx_set_event(struct ub_ctx* ctx, struct event_base* base) {
1458
0
  struct ub_event_base* new_base;
1459
1460
0
  if (!ctx || !ctx->event_base || !base) {
1461
0
    return UB_INITFAIL;
1462
0
  }
1463
0
  if (ub_libevent_get_event_base(ctx->event_base) == base) {
1464
    /* already set */
1465
0
    return UB_NOERROR;
1466
0
  }
1467
  
1468
0
  lock_basic_lock(&ctx->cfglock);
1469
  /* destroy the current worker - safe to pass in NULL */
1470
0
  libworker_delete_event(ctx->event_worker);
1471
0
  ctx->event_worker = NULL;
1472
0
  new_base = ub_libevent_event_base(base);
1473
0
  if (new_base)
1474
0
    ctx->event_base = new_base; 
1475
0
  ctx->created_bg = 0;
1476
0
  ctx->dothread = 1;
1477
0
  lock_basic_unlock(&ctx->cfglock);
1478
0
  return new_base ? UB_NOERROR : UB_INITFAIL;
1479
0
}