Coverage Report

Created: 2025-07-12 06:29

/src/unbound/iterator/iter_fwd.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * iterator/iter_fwd.c - iterative resolver module forward zones.
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 assist the iterator module.
40
 * Keep track of forward zones and config settings.
41
 */
42
#include "config.h"
43
#include "iterator/iter_fwd.h"
44
#include "iterator/iter_delegpt.h"
45
#include "util/log.h"
46
#include "util/config_file.h"
47
#include "util/net_help.h"
48
#include "util/data/dname.h"
49
#include "sldns/rrdef.h"
50
#include "sldns/str2wire.h"
51
52
int
53
fwd_cmp(const void* k1, const void* k2)
54
0
{
55
0
  int m;
56
0
  struct iter_forward_zone* n1 = (struct iter_forward_zone*)k1;
57
0
  struct iter_forward_zone* n2 = (struct iter_forward_zone*)k2;
58
0
  if(n1->dclass != n2->dclass) {
59
0
    if(n1->dclass < n2->dclass)
60
0
      return -1;
61
0
    return 1;
62
0
  }
63
0
  return dname_lab_cmp(n1->name, n1->namelabs, n2->name, n2->namelabs, 
64
0
    &m);
65
0
}
66
67
struct iter_forwards* 
68
forwards_create(void)
69
0
{
70
0
  struct iter_forwards* fwd = (struct iter_forwards*)calloc(1,
71
0
    sizeof(struct iter_forwards));
72
0
  if(!fwd)
73
0
    return NULL;
74
0
  lock_rw_init(&fwd->lock);
75
0
  return fwd;
76
0
}
77
78
static void fwd_zone_free(struct iter_forward_zone* n)
79
0
{
80
0
  if(!n) return;
81
0
  delegpt_free_mlc(n->dp);
82
0
  free(n->name);
83
0
  free(n);
84
0
}
85
86
static void delfwdnode(rbnode_type* n, void* ATTR_UNUSED(arg))
87
0
{
88
0
  struct iter_forward_zone* node = (struct iter_forward_zone*)n;
89
0
  fwd_zone_free(node);
90
0
}
91
92
static void fwd_del_tree(struct iter_forwards* fwd)
93
0
{
94
0
  if(fwd->tree)
95
0
    traverse_postorder(fwd->tree, &delfwdnode, NULL);
96
0
  free(fwd->tree);
97
0
}
98
99
void 
100
forwards_delete(struct iter_forwards* fwd)
101
0
{
102
0
  if(!fwd) 
103
0
    return;
104
0
  lock_rw_destroy(&fwd->lock);
105
0
  fwd_del_tree(fwd);
106
0
  free(fwd);
107
0
}
108
109
/** insert info into forward structure */
110
static int
111
forwards_insert_data(struct iter_forwards* fwd, uint16_t c, uint8_t* nm, 
112
  size_t nmlen, int nmlabs, struct delegpt* dp)
113
0
{
114
0
  struct iter_forward_zone* node = (struct iter_forward_zone*)malloc(
115
0
    sizeof(struct iter_forward_zone));
116
0
  if(!node) {
117
0
    delegpt_free_mlc(dp);
118
0
    return 0;
119
0
  }
120
0
  node->node.key = node;
121
0
  node->dclass = c;
122
0
  node->name = memdup(nm, nmlen);
123
0
  if(!node->name) {
124
0
    delegpt_free_mlc(dp);
125
0
    free(node);
126
0
    return 0;
127
0
  }
128
0
  node->namelen = nmlen;
129
0
  node->namelabs = nmlabs;
130
0
  node->dp = dp;
131
0
  if(!rbtree_insert(fwd->tree, &node->node)) {
132
0
    char buf[LDNS_MAX_DOMAINLEN];
133
0
    dname_str(nm, buf);
134
0
    log_err("duplicate forward zone %s ignored.", buf);
135
0
    delegpt_free_mlc(dp);
136
0
    free(node->name);
137
0
    free(node);
138
0
  }
139
0
  return 1;
140
0
}
141
142
static struct iter_forward_zone*
143
fwd_zone_find(struct iter_forwards* fwd, uint16_t c, uint8_t* nm)
144
0
{
145
0
  struct iter_forward_zone key;
146
0
  key.node.key = &key;
147
0
  key.dclass = c;
148
0
  key.name = nm;
149
0
  key.namelabs = dname_count_size_labels(nm, &key.namelen);
150
0
  return (struct iter_forward_zone*)rbtree_search(fwd->tree, &key);
151
0
}
152
153
/** insert new info into forward structure given dp */
154
static int
155
forwards_insert(struct iter_forwards* fwd, uint16_t c, struct delegpt* dp)
156
0
{
157
0
  return forwards_insert_data(fwd, c, dp->name, dp->namelen,
158
0
    dp->namelabs, dp);
159
0
}
160
161
/** initialise parent pointers in the tree */
162
static void
163
fwd_init_parents(struct iter_forwards* fwd)
164
0
{
165
0
  struct iter_forward_zone* node, *prev = NULL, *p;
166
0
  int m;
167
0
  RBTREE_FOR(node, struct iter_forward_zone*, fwd->tree) {
168
0
    node->parent = NULL;
169
0
    if(!prev || prev->dclass != node->dclass) {
170
0
      prev = node;
171
0
      continue;
172
0
    }
173
0
    (void)dname_lab_cmp(prev->name, prev->namelabs, node->name,
174
0
      node->namelabs, &m); /* we know prev is smaller */
175
    /* sort order like: . com. bla.com. zwb.com. net. */
176
    /* find the previous, or parent-parent-parent */
177
0
    for(p = prev; p; p = p->parent)
178
      /* looking for name with few labels, a parent */
179
0
      if(p->namelabs <= m) {
180
        /* ==: since prev matched m, this is closest*/
181
        /* <: prev matches more, but is not a parent,
182
         * this one is a (grand)parent */
183
0
        node->parent = p;
184
0
        break;
185
0
      }
186
0
    prev = node;
187
0
  }
188
0
}
189
190
/** set zone name */
191
static struct delegpt* 
192
read_fwds_name(struct config_stub* s)
193
0
{
194
0
  struct delegpt* dp;
195
0
  uint8_t* dname;
196
0
  size_t dname_len;
197
0
  if(!s->name) {
198
0
    log_err("forward zone without a name (use name \".\" to forward everything)");
199
0
    return NULL;
200
0
  }
201
0
  dname = sldns_str2wire_dname(s->name, &dname_len);
202
0
  if(!dname) {
203
0
    log_err("cannot parse forward zone name %s", s->name);
204
0
    return NULL;
205
0
  }
206
0
  if(!(dp=delegpt_create_mlc(dname))) {
207
0
    free(dname);
208
0
    log_err("out of memory");
209
0
    return NULL;
210
0
  }
211
0
  free(dname);
212
0
  return dp;
213
0
}
214
215
/** set fwd host names */
216
static int
217
read_fwds_host(struct config_stub* s, struct delegpt* dp)
218
0
{
219
0
  struct config_strlist* p;
220
0
  uint8_t* dname;
221
0
  char* tls_auth_name;
222
0
  int port;
223
0
  for(p = s->hosts; p; p = p->next) {
224
0
    log_assert(p->str);
225
0
    dname = authextstrtodname(p->str, &port, &tls_auth_name);
226
0
    if(!dname) {
227
0
      log_err("cannot parse forward %s server name: '%s'", 
228
0
        s->name, p->str);
229
0
      return 0;
230
0
    }
231
#if ! defined(HAVE_SSL_SET1_HOST) && ! defined(HAVE_X509_VERIFY_PARAM_SET1_HOST)
232
    if(tls_auth_name)
233
      log_err("no name verification functionality in "
234
        "ssl library, ignored name for %s", p->str);
235
#endif
236
0
    if(!delegpt_add_ns_mlc(dp, dname, 0, tls_auth_name, port)) {
237
0
      free(dname);
238
0
      log_err("out of memory");
239
0
      return 0;
240
0
    }
241
0
    free(dname);
242
0
  }
243
0
  return 1;
244
0
}
245
246
/** set fwd server addresses */
247
static int 
248
read_fwds_addr(struct config_stub* s, struct delegpt* dp)
249
0
{
250
0
  struct config_strlist* p;
251
0
  struct sockaddr_storage addr;
252
0
  socklen_t addrlen;
253
0
  char* tls_auth_name;
254
0
  for(p = s->addrs; p; p = p->next) {
255
0
    log_assert(p->str);
256
0
    if(!authextstrtoaddr(p->str, &addr, &addrlen, &tls_auth_name)) {
257
0
      log_err("cannot parse forward %s ip address: '%s'", 
258
0
        s->name, p->str);
259
0
      return 0;
260
0
    }
261
#if ! defined(HAVE_SSL_SET1_HOST) && ! defined(HAVE_X509_VERIFY_PARAM_SET1_HOST)
262
    if(tls_auth_name)
263
      log_err("no name verification functionality in "
264
        "ssl library, ignored name for %s", p->str);
265
#endif
266
0
    if(!delegpt_add_addr_mlc(dp, &addr, addrlen, 0, 0,
267
0
      tls_auth_name, -1)) {
268
0
      log_err("out of memory");
269
0
      return 0;
270
0
    }
271
0
  }
272
0
  return 1;
273
0
}
274
275
/** read forwards config */
276
static int 
277
read_forwards(struct iter_forwards* fwd, struct config_file* cfg)
278
0
{
279
0
  struct config_stub* s;
280
0
  for(s = cfg->forwards; s; s = s->next) {
281
0
    struct delegpt* dp;
282
0
    if(!(dp=read_fwds_name(s)))
283
0
      return 0;
284
0
    if(!read_fwds_host(s, dp) || !read_fwds_addr(s, dp)) {
285
0
      delegpt_free_mlc(dp);
286
0
      return 0;
287
0
    }
288
    /* set flag that parent side NS information is included.
289
     * Asking a (higher up) server on the internet is not useful */
290
    /* the flag is turned off for 'forward-first' so that the
291
     * last resort will ask for parent-side NS record and thus
292
     * fallback to the internet name servers on a failure */
293
0
    dp->has_parent_side_NS = (uint8_t)!s->isfirst;
294
    /* Do not cache if set. */
295
0
    dp->no_cache = s->no_cache;
296
    /* use SSL for queries to this forwarder */
297
0
    dp->ssl_upstream = (uint8_t)s->ssl_upstream;
298
    /* use TCP for queries to this forwarder */
299
0
    dp->tcp_upstream = (uint8_t)s->tcp_upstream;
300
0
    verbose(VERB_QUERY, "Forward zone server list:");
301
0
    delegpt_log(VERB_QUERY, dp);
302
0
    if(!forwards_insert(fwd, LDNS_RR_CLASS_IN, dp))
303
0
      return 0;
304
0
  }
305
0
  return 1;
306
0
}
307
308
/** insert a stub hole (if necessary) for stub name */
309
static int
310
fwd_add_stub_hole(struct iter_forwards* fwd, uint16_t c, uint8_t* nm)
311
0
{
312
0
  struct iter_forward_zone key;
313
0
  key.node.key = &key;
314
0
  key.dclass = c;
315
0
  key.name = nm;
316
0
  key.namelabs = dname_count_size_labels(key.name, &key.namelen);
317
0
  return forwards_insert_data(fwd, key.dclass, key.name,
318
0
    key.namelen, key.namelabs, NULL);
319
0
}
320
321
/** make NULL entries for stubs */
322
static int
323
make_stub_holes(struct iter_forwards* fwd, struct config_file* cfg)
324
0
{
325
0
  struct config_stub* s;
326
0
  uint8_t* dname;
327
0
  size_t dname_len;
328
0
  for(s = cfg->stubs; s; s = s->next) {
329
0
    if(!s->name) continue;
330
0
    dname = sldns_str2wire_dname(s->name, &dname_len);
331
0
    if(!dname) {
332
0
      log_err("cannot parse stub name '%s'", s->name);
333
0
      return 0;
334
0
    }
335
0
    if(fwd_zone_find(fwd, LDNS_RR_CLASS_IN, dname) != NULL) {
336
      /* Already a forward zone there. */
337
0
      free(dname);
338
0
      continue;
339
0
    }
340
0
    if(!fwd_add_stub_hole(fwd, LDNS_RR_CLASS_IN, dname)) {
341
0
      free(dname);
342
0
      log_err("out of memory");
343
0
      return 0;
344
0
    }
345
0
    free(dname);
346
0
  }
347
0
  return 1;
348
0
}
349
350
/** make NULL entries for auths */
351
static int
352
make_auth_holes(struct iter_forwards* fwd, struct config_file* cfg)
353
0
{
354
0
  struct config_auth* a;
355
0
  uint8_t* dname;
356
0
  size_t dname_len;
357
0
  for(a = cfg->auths; a; a = a->next) {
358
0
    if(!a->name) continue;
359
0
    dname = sldns_str2wire_dname(a->name, &dname_len);
360
0
    if(!dname) {
361
0
      log_err("cannot parse auth name '%s'", a->name);
362
0
      return 0;
363
0
    }
364
0
    if(fwd_zone_find(fwd, LDNS_RR_CLASS_IN, dname) != NULL) {
365
      /* Already a forward zone there. */
366
0
      free(dname);
367
0
      continue;
368
0
    }
369
0
    if(!fwd_add_stub_hole(fwd, LDNS_RR_CLASS_IN, dname)) {
370
0
      free(dname);
371
0
      log_err("out of memory");
372
0
      return 0;
373
0
    }
374
0
    free(dname);
375
0
  }
376
0
  return 1;
377
0
}
378
379
int 
380
forwards_apply_cfg(struct iter_forwards* fwd, struct config_file* cfg)
381
0
{
382
0
  if(fwd->tree) {
383
0
    lock_unprotect(&fwd->lock, fwd->tree);
384
0
  }
385
0
  fwd_del_tree(fwd);
386
0
  fwd->tree = rbtree_create(fwd_cmp);
387
0
  if(!fwd->tree)
388
0
    return 0;
389
0
  lock_protect(&fwd->lock, fwd->tree, sizeof(*fwd->tree));
390
391
0
  lock_rw_wrlock(&fwd->lock);
392
  /* read forward zones */
393
0
  if(!read_forwards(fwd, cfg)) {
394
0
    lock_rw_unlock(&fwd->lock);
395
0
    return 0;
396
0
  }
397
0
  if(!make_stub_holes(fwd, cfg)) {
398
0
    lock_rw_unlock(&fwd->lock);
399
0
    return 0;
400
0
  }
401
  /* TODO: Now we punch holes for auth zones as well so that in
402
   *       iterator:forward_request() we see the configured
403
   *       delegation point, but code flow/naming is hard to follow.
404
   *       Consider having a single tree with configured
405
   *       delegation points for all categories
406
   *       (stubs, forwards, auths). */
407
0
  if(!make_auth_holes(fwd, cfg)) {
408
0
    lock_rw_unlock(&fwd->lock);
409
0
    return 0;
410
0
  }
411
0
  fwd_init_parents(fwd);
412
0
  lock_rw_unlock(&fwd->lock);
413
0
  return 1;
414
0
}
415
416
struct delegpt* 
417
forwards_find(struct iter_forwards* fwd, uint8_t* qname, uint16_t qclass,
418
  int nolock)
419
0
{
420
0
  struct iter_forward_zone* res;
421
0
  struct iter_forward_zone key;
422
0
  int has_dp;
423
0
  key.node.key = &key;
424
0
  key.dclass = qclass;
425
0
  key.name = qname;
426
0
  key.namelabs = dname_count_size_labels(qname, &key.namelen);
427
  /* lock_() calls are macros that could be nothing, surround in {} */
428
0
  if(!nolock) { lock_rw_rdlock(&fwd->lock); }
429
0
  res = (struct iter_forward_zone*)rbtree_search(fwd->tree, &key);
430
0
  has_dp = res && res->dp;
431
0
  if(!has_dp && !nolock) { lock_rw_unlock(&fwd->lock); }
432
0
  return has_dp?res->dp:NULL;
433
0
}
434
435
struct delegpt* 
436
forwards_lookup(struct iter_forwards* fwd, uint8_t* qname, uint16_t qclass,
437
  int nolock)
438
0
{
439
  /* lookup the forward zone in the tree */
440
0
  rbnode_type* res = NULL;
441
0
  struct iter_forward_zone *result;
442
0
  struct iter_forward_zone key;
443
0
  int has_dp;
444
0
  key.node.key = &key;
445
0
  key.dclass = qclass;
446
0
  key.name = qname;
447
0
  key.namelabs = dname_count_size_labels(qname, &key.namelen);
448
  /* lock_() calls are macros that could be nothing, surround in {} */
449
0
  if(!nolock) { lock_rw_rdlock(&fwd->lock); }
450
0
  if(rbtree_find_less_equal(fwd->tree, &key, &res)) {
451
    /* exact */
452
0
    result = (struct iter_forward_zone*)res;
453
0
  } else {
454
    /* smaller element (or no element) */
455
0
    int m;
456
0
    result = (struct iter_forward_zone*)res;
457
0
    if(!result || result->dclass != qclass) {
458
0
      if(!nolock) { lock_rw_unlock(&fwd->lock); }
459
0
      return NULL;
460
0
    }
461
    /* count number of labels matched */
462
0
    (void)dname_lab_cmp(result->name, result->namelabs, key.name,
463
0
      key.namelabs, &m);
464
0
    while(result) { /* go up until qname is subdomain of stub */
465
0
      if(result->namelabs <= m)
466
0
        break;
467
0
      result = result->parent;
468
0
    }
469
0
  }
470
0
  has_dp = result && result->dp;
471
0
  if(!has_dp && !nolock) { lock_rw_unlock(&fwd->lock); }
472
0
  return has_dp?result->dp:NULL;
473
0
}
474
475
struct delegpt* 
476
forwards_lookup_root(struct iter_forwards* fwd, uint16_t qclass, int nolock)
477
0
{
478
0
  uint8_t root = 0;
479
0
  return forwards_lookup(fwd, &root, qclass, nolock);
480
0
}
481
482
/* Finds next root item in forwards lookup tree.
483
 * Caller needs to handle locking of the forwards structure. */
484
static int
485
next_root_locked(struct iter_forwards* fwd, uint16_t* dclass)
486
0
{
487
0
  struct iter_forward_zone key;
488
0
  rbnode_type* n;
489
0
  struct iter_forward_zone* p;
490
0
  if(*dclass == 0) {
491
    /* first root item is first item in tree */
492
0
    n = rbtree_first(fwd->tree);
493
0
    if(n == RBTREE_NULL)
494
0
      return 0;
495
0
    p = (struct iter_forward_zone*)n;
496
0
    if(dname_is_root(p->name)) {
497
0
      *dclass = p->dclass;
498
0
      return 1;
499
0
    }
500
    /* root not first item? search for higher items */
501
0
    *dclass = p->dclass + 1;
502
0
    return next_root_locked(fwd, dclass);
503
0
  }
504
  /* find class n in tree, we may get a direct hit, or if we don't
505
   * this is the last item of the previous class so rbtree_next() takes
506
   * us to the next root (if any) */
507
0
  key.node.key = &key;
508
0
  key.name = (uint8_t*)"\000";
509
0
  key.namelen = 1;
510
0
  key.namelabs = 0;
511
0
  key.dclass = *dclass;
512
0
  n = NULL;
513
0
  if(rbtree_find_less_equal(fwd->tree, &key, &n)) {
514
    /* exact */
515
0
    return 1;
516
0
  } else {
517
    /* smaller element */
518
0
    if(!n || n == RBTREE_NULL)
519
0
      return 0; /* nothing found */
520
0
    n = rbtree_next(n);
521
0
    if(n == RBTREE_NULL)
522
0
      return 0; /* no higher */
523
0
    p = (struct iter_forward_zone*)n;
524
0
    if(dname_is_root(p->name)) {
525
0
      *dclass = p->dclass;
526
0
      return 1;
527
0
    }
528
    /* not a root node, return next higher item */
529
0
    *dclass = p->dclass+1;
530
0
    return next_root_locked(fwd, dclass);
531
0
  }
532
0
}
533
534
int
535
forwards_next_root(struct iter_forwards* fwd, uint16_t* dclass, int nolock)
536
0
{
537
0
  int ret;
538
  /* lock_() calls are macros that could be nothing, surround in {} */
539
0
  if(!nolock) { lock_rw_rdlock(&fwd->lock); }
540
0
  ret = next_root_locked(fwd, dclass);
541
0
  if(!nolock) { lock_rw_unlock(&fwd->lock); }
542
0
  return ret;
543
0
}
544
545
size_t 
546
forwards_get_mem(struct iter_forwards* fwd)
547
0
{
548
0
  struct iter_forward_zone* p;
549
0
  size_t s;
550
0
  if(!fwd)
551
0
    return 0;
552
0
  lock_rw_rdlock(&fwd->lock);
553
0
  s = sizeof(*fwd) + sizeof(*fwd->tree);
554
0
  RBTREE_FOR(p, struct iter_forward_zone*, fwd->tree) {
555
0
    s += sizeof(*p) + p->namelen + delegpt_get_mem(p->dp);
556
0
  }
557
0
  lock_rw_unlock(&fwd->lock);
558
0
  return s;
559
0
}
560
561
int 
562
forwards_add_zone(struct iter_forwards* fwd, uint16_t c, struct delegpt* dp,
563
  int nolock)
564
0
{
565
0
  struct iter_forward_zone *z;
566
  /* lock_() calls are macros that could be nothing, surround in {} */
567
0
  if(!nolock) { lock_rw_wrlock(&fwd->lock); }
568
0
  if((z=fwd_zone_find(fwd, c, dp->name)) != NULL) {
569
0
    (void)rbtree_delete(fwd->tree, &z->node);
570
0
    fwd_zone_free(z);
571
0
  }
572
0
  if(!forwards_insert(fwd, c, dp)) {
573
0
    if(!nolock) { lock_rw_unlock(&fwd->lock); }
574
0
    return 0;
575
0
  }
576
0
  fwd_init_parents(fwd);
577
0
  if(!nolock) { lock_rw_unlock(&fwd->lock); }
578
0
  return 1;
579
0
}
580
581
void 
582
forwards_delete_zone(struct iter_forwards* fwd, uint16_t c, uint8_t* nm,
583
  int nolock)
584
0
{
585
0
  struct iter_forward_zone *z;
586
  /* lock_() calls are macros that could be nothing, surround in {} */
587
0
  if(!nolock) { lock_rw_wrlock(&fwd->lock); }
588
0
  if(!(z=fwd_zone_find(fwd, c, nm))) {
589
0
    if(!nolock) { lock_rw_unlock(&fwd->lock); }
590
0
    return; /* nothing to do */
591
0
  }
592
0
  (void)rbtree_delete(fwd->tree, &z->node);
593
0
  fwd_zone_free(z);
594
0
  fwd_init_parents(fwd);
595
0
  if(!nolock) { lock_rw_unlock(&fwd->lock); }
596
0
}
597
598
int
599
forwards_add_stub_hole(struct iter_forwards* fwd, uint16_t c, uint8_t* nm,
600
  int nolock)
601
0
{
602
  /* lock_() calls are macros that could be nothing, surround in {} */
603
0
  if(!nolock) { lock_rw_wrlock(&fwd->lock); }
604
0
  if(fwd_zone_find(fwd, c, nm) != NULL) {
605
0
    if(!nolock) { lock_rw_unlock(&fwd->lock); }
606
0
    return 1; /* already a stub zone there */
607
0
  }
608
0
  if(!fwd_add_stub_hole(fwd, c, nm)) {
609
0
    if(!nolock) { lock_rw_unlock(&fwd->lock); }
610
0
    return 0;
611
0
  }
612
0
  fwd_init_parents(fwd);
613
0
  if(!nolock) { lock_rw_unlock(&fwd->lock); }
614
0
  return 1;
615
0
}
616
617
void
618
forwards_delete_stub_hole(struct iter_forwards* fwd, uint16_t c,
619
  uint8_t* nm, int nolock)
620
0
{
621
0
  struct iter_forward_zone *z;
622
  /* lock_() calls are macros that could be nothing, surround in {} */
623
0
  if(!nolock) { lock_rw_wrlock(&fwd->lock); }
624
0
  if(!(z=fwd_zone_find(fwd, c, nm))) {
625
0
    if(!nolock) { lock_rw_unlock(&fwd->lock); }
626
0
    return; /* nothing to do */
627
0
  }
628
0
  if(z->dp != NULL) {
629
0
    if(!nolock) { lock_rw_unlock(&fwd->lock); }
630
0
    return; /* not a stub hole */
631
0
  }
632
0
  (void)rbtree_delete(fwd->tree, &z->node);
633
0
  fwd_zone_free(z);
634
0
  fwd_init_parents(fwd);
635
0
  if(!nolock) { lock_rw_unlock(&fwd->lock); }
636
0
}
637
638
void
639
forwards_swap_tree(struct iter_forwards* fwd, struct iter_forwards* data)
640
0
{
641
0
  rbtree_type* oldtree = fwd->tree;
642
0
  if(oldtree) {
643
0
    lock_unprotect(&fwd->lock, oldtree);
644
0
  }
645
0
  if(data->tree) {
646
0
    lock_unprotect(&data->lock, data->tree);
647
0
  }
648
0
  fwd->tree = data->tree;
649
0
  data->tree = oldtree;
650
0
  lock_protect(&fwd->lock, fwd->tree, sizeof(*fwd->tree));
651
0
  lock_protect(&data->lock, data->tree, sizeof(*data->tree));
652
0
}