Coverage Report

Created: 2025-07-12 06:29

/src/unbound/iterator/iter_priv.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * iterator/iter_priv.c - iterative resolver private address and domain store
3
 *
4
 * Copyright (c) 2008, 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 the private addresses and lookup fast.
41
 */
42
43
#include "config.h"
44
#include "iterator/iter_priv.h"
45
#include "util/regional.h"
46
#include "util/log.h"
47
#include "util/config_file.h"
48
#include "util/data/dname.h"
49
#include "util/data/msgparse.h"
50
#include "util/net_help.h"
51
#include "util/storage/dnstree.h"
52
#include "sldns/str2wire.h"
53
#include "sldns/sbuffer.h"
54
55
struct iter_priv* priv_create(void)
56
0
{
57
0
  struct iter_priv* priv = (struct iter_priv*)calloc(1, sizeof(*priv));
58
0
  if(!priv)
59
0
    return NULL;
60
0
  priv->region = regional_create();
61
0
  if(!priv->region) {
62
0
    priv_delete(priv);
63
0
    return NULL;
64
0
  }
65
0
  addr_tree_init(&priv->a);
66
0
  name_tree_init(&priv->n);
67
0
  return priv;
68
0
}
69
70
void priv_delete(struct iter_priv* priv)
71
0
{
72
0
  if(!priv) return;
73
0
  regional_destroy(priv->region);
74
0
  free(priv);
75
0
}
76
77
/** Read private-addr declarations from config */
78
static int read_addrs(struct iter_priv* priv, struct config_file* cfg)
79
0
{
80
  /* parse addresses, report errors, insert into tree */
81
0
  struct config_strlist* p;
82
0
  struct addr_tree_node* n;
83
0
  struct sockaddr_storage addr;
84
0
  int net;
85
0
  socklen_t addrlen;
86
87
0
  for(p = cfg->private_address; p; p = p->next) {
88
0
    log_assert(p->str);
89
0
    if(!netblockstrtoaddr(p->str, UNBOUND_DNS_PORT, &addr, 
90
0
      &addrlen, &net)) {
91
0
      log_err("cannot parse private-address: %s", p->str);
92
0
      return 0;
93
0
    }
94
0
    n = (struct addr_tree_node*)regional_alloc(priv->region,
95
0
      sizeof(*n));
96
0
    if(!n) {
97
0
      log_err("out of memory");
98
0
      return 0;
99
0
    }
100
0
    if(!addr_tree_insert(&priv->a, n, &addr, addrlen, net)) {
101
0
      verbose(VERB_QUERY, "ignoring duplicate "
102
0
        "private-address: %s", p->str);
103
0
    }
104
0
  }
105
0
  return 1;
106
0
}
107
108
/** Read private-domain declarations from config */
109
static int read_names(struct iter_priv* priv, struct config_file* cfg)
110
0
{
111
  /* parse names, report errors, insert into tree */
112
0
  struct config_strlist* p;
113
0
  struct name_tree_node* n;
114
0
  uint8_t* nm, *nmr;
115
0
  size_t nm_len;
116
0
  int nm_labs;
117
118
0
  for(p = cfg->private_domain; p; p = p->next) {
119
0
    log_assert(p->str);
120
0
    nm = sldns_str2wire_dname(p->str, &nm_len);
121
0
    if(!nm) {
122
0
      log_err("cannot parse private-domain: %s", p->str);
123
0
      return 0;
124
0
    }
125
0
    nm_labs = dname_count_size_labels(nm, &nm_len);
126
0
    nmr = (uint8_t*)regional_alloc_init(priv->region, nm, nm_len);
127
0
    free(nm);
128
0
    if(!nmr) {
129
0
      log_err("out of memory");
130
0
      return 0;
131
0
    }
132
0
    n = (struct name_tree_node*)regional_alloc(priv->region,
133
0
      sizeof(*n));
134
0
    if(!n) {
135
0
      log_err("out of memory");
136
0
      return 0;
137
0
    }
138
0
    if(!name_tree_insert(&priv->n, n, nmr, nm_len, nm_labs,
139
0
      LDNS_RR_CLASS_IN)) {
140
0
      verbose(VERB_QUERY, "ignoring duplicate "
141
0
        "private-domain: %s", p->str);
142
0
    }
143
0
  }
144
0
  return 1;
145
0
}
146
147
int priv_apply_cfg(struct iter_priv* priv, struct config_file* cfg)
148
0
{
149
  /* empty the current contents */
150
0
  regional_free_all(priv->region);
151
0
  addr_tree_init(&priv->a);
152
0
  name_tree_init(&priv->n);
153
154
  /* read new contents */
155
0
  if(!read_addrs(priv, cfg))
156
0
    return 0;
157
0
  if(!read_names(priv, cfg))
158
0
    return 0;
159
160
  /* prepare for lookups */
161
0
  addr_tree_init_parents(&priv->a);
162
0
  name_tree_init_parents(&priv->n);
163
0
  return 1;
164
0
}
165
166
/**
167
 * See if an address is blocked.
168
 * @param priv: structure for address storage.
169
 * @param addr: address to check
170
 * @param addrlen: length of addr.
171
 * @return: true if the address must not be queried. false if unlisted.
172
 */
173
static int 
174
priv_lookup_addr(struct iter_priv* priv, struct sockaddr_storage* addr,
175
  socklen_t addrlen)
176
0
{
177
0
  return addr_tree_lookup(&priv->a, addr, addrlen) != NULL;
178
0
}
179
180
/**
181
 * See if a name is whitelisted.
182
 * @param priv: structure for address storage.
183
 * @param pkt: the packet (for compression ptrs).
184
 * @param name: name to check.
185
 * @param name_len: uncompressed length of the name to check.
186
 * @param dclass: class to check.
187
 * @return: true if the name is OK. false if unlisted.
188
 */
189
static int 
190
priv_lookup_name(struct iter_priv* priv, sldns_buffer* pkt,
191
  uint8_t* name, size_t name_len, uint16_t dclass)
192
0
{
193
0
  size_t len;
194
0
  uint8_t decomp[256];
195
0
  int labs;
196
0
  if(name_len >= sizeof(decomp))
197
0
    return 0;
198
0
  dname_pkt_copy(pkt, decomp, name);
199
0
  labs = dname_count_size_labels(decomp, &len);
200
0
  log_assert(name_len == len);
201
0
  return name_tree_lookup(&priv->n, decomp, len, labs, dclass) != NULL;
202
0
}
203
204
size_t priv_get_mem(struct iter_priv* priv)
205
0
{
206
0
  if(!priv) return 0;
207
0
  return sizeof(*priv) + regional_get_mem(priv->region);
208
0
}
209
210
int priv_rrset_bad(struct iter_priv* priv, sldns_buffer* pkt,
211
  struct rrset_parse* rrset)
212
9.66k
{
213
9.66k
  if(priv->a.count == 0) 
214
9.66k
    return 0; /* there are no blocked addresses */
215
216
  /* see if it is a private name, that is allowed to have any */
217
0
  if(priv_lookup_name(priv, pkt, rrset->dname, rrset->dname_len,
218
0
    ntohs(rrset->rrset_class))) {
219
0
    return 0;
220
0
  } else {
221
    /* so its a public name, check the address */
222
0
    socklen_t len;
223
0
    struct rr_parse* rr, *prev = NULL;
224
0
    if(rrset->type == LDNS_RR_TYPE_A) {
225
0
      struct sockaddr_storage addr;
226
0
      struct sockaddr_in sa;
227
228
0
      len = (socklen_t)sizeof(sa);
229
0
      memset(&sa, 0, len);
230
0
      sa.sin_family = AF_INET;
231
0
      sa.sin_port = (in_port_t)htons(UNBOUND_DNS_PORT);
232
0
      for(rr = rrset->rr_first; rr; rr = rr->next) {
233
0
        if(sldns_read_uint16(rr->ttl_data+4) 
234
0
          != INET_SIZE) {
235
0
          prev = rr;
236
0
          continue;
237
0
        }
238
0
        memmove(&sa.sin_addr, rr->ttl_data+4+2, 
239
0
          INET_SIZE);
240
0
        memmove(&addr, &sa, len);
241
0
        if(priv_lookup_addr(priv, &addr, len)) {
242
0
          if(msgparse_rrset_remove_rr("sanitize: removing public name with private address", pkt, rrset, prev, rr, &addr, len))
243
0
            return 1;
244
0
          continue;
245
0
        }
246
0
        prev = rr;
247
0
      }
248
0
    } else if(rrset->type == LDNS_RR_TYPE_AAAA) {
249
0
      struct sockaddr_storage addr;
250
0
      struct sockaddr_in6 sa;
251
0
      len = (socklen_t)sizeof(sa);
252
0
      memset(&sa, 0, len);
253
0
      sa.sin6_family = AF_INET6;
254
0
      sa.sin6_port = (in_port_t)htons(UNBOUND_DNS_PORT);
255
0
      for(rr = rrset->rr_first; rr; rr = rr->next) {
256
0
        if(sldns_read_uint16(rr->ttl_data+4) 
257
0
          != INET6_SIZE) {
258
0
          prev = rr;
259
0
          continue;
260
0
        }
261
0
        memmove(&sa.sin6_addr, rr->ttl_data+4+2, 
262
0
          INET6_SIZE);
263
0
        memmove(&addr, &sa, len);
264
0
        if(priv_lookup_addr(priv, &addr, len)) {
265
0
          if(msgparse_rrset_remove_rr("sanitize: removing public name with private address", pkt, rrset, prev, rr, &addr, len))
266
0
            return 1;
267
0
          continue;
268
0
        }
269
0
        prev = rr;
270
0
      }
271
0
    } 
272
0
  }
273
0
  return 0;
274
0
}