1933707f3Ssthen /*
2933707f3Ssthen * iterator/iter_priv.c - iterative resolver private address and domain store
3933707f3Ssthen *
4933707f3Ssthen * Copyright (c) 2008, NLnet Labs. All rights reserved.
5933707f3Ssthen *
6933707f3Ssthen * This software is open source.
7933707f3Ssthen *
8933707f3Ssthen * Redistribution and use in source and binary forms, with or without
9933707f3Ssthen * modification, are permitted provided that the following conditions
10933707f3Ssthen * are met:
11933707f3Ssthen *
12933707f3Ssthen * Redistributions of source code must retain the above copyright notice,
13933707f3Ssthen * this list of conditions and the following disclaimer.
14933707f3Ssthen *
15933707f3Ssthen * Redistributions in binary form must reproduce the above copyright notice,
16933707f3Ssthen * this list of conditions and the following disclaimer in the documentation
17933707f3Ssthen * and/or other materials provided with the distribution.
18933707f3Ssthen *
19933707f3Ssthen * Neither the name of the NLNET LABS nor the names of its contributors may
20933707f3Ssthen * be used to endorse or promote products derived from this software without
21933707f3Ssthen * specific prior written permission.
22933707f3Ssthen *
23933707f3Ssthen * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
245d76a658Ssthen * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
255d76a658Ssthen * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
265d76a658Ssthen * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
275d76a658Ssthen * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
285d76a658Ssthen * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
295d76a658Ssthen * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
305d76a658Ssthen * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
315d76a658Ssthen * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
325d76a658Ssthen * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
335d76a658Ssthen * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34933707f3Ssthen */
35933707f3Ssthen
36933707f3Ssthen /**
37933707f3Ssthen * \file
38933707f3Ssthen *
39933707f3Ssthen * This file contains functions to assist the iterator module.
40933707f3Ssthen * Keep track of the private addresses and lookup fast.
41933707f3Ssthen */
42933707f3Ssthen
43933707f3Ssthen #include "config.h"
44933707f3Ssthen #include "iterator/iter_priv.h"
45933707f3Ssthen #include "util/regional.h"
46933707f3Ssthen #include "util/log.h"
47933707f3Ssthen #include "util/config_file.h"
48933707f3Ssthen #include "util/data/dname.h"
49933707f3Ssthen #include "util/data/msgparse.h"
50933707f3Ssthen #include "util/net_help.h"
51933707f3Ssthen #include "util/storage/dnstree.h"
52fdfb4ba6Ssthen #include "sldns/str2wire.h"
53fdfb4ba6Ssthen #include "sldns/sbuffer.h"
54933707f3Ssthen
priv_create(void)55933707f3Ssthen struct iter_priv* priv_create(void)
56933707f3Ssthen {
57933707f3Ssthen struct iter_priv* priv = (struct iter_priv*)calloc(1, sizeof(*priv));
58933707f3Ssthen if(!priv)
59933707f3Ssthen return NULL;
60933707f3Ssthen priv->region = regional_create();
61933707f3Ssthen if(!priv->region) {
62933707f3Ssthen priv_delete(priv);
63933707f3Ssthen return NULL;
64933707f3Ssthen }
65933707f3Ssthen addr_tree_init(&priv->a);
66933707f3Ssthen name_tree_init(&priv->n);
67933707f3Ssthen return priv;
68933707f3Ssthen }
69933707f3Ssthen
priv_delete(struct iter_priv * priv)70933707f3Ssthen void priv_delete(struct iter_priv* priv)
71933707f3Ssthen {
72933707f3Ssthen if(!priv) return;
73933707f3Ssthen regional_destroy(priv->region);
74933707f3Ssthen free(priv);
75933707f3Ssthen }
76933707f3Ssthen
77933707f3Ssthen /** Read private-addr declarations from config */
read_addrs(struct iter_priv * priv,struct config_file * cfg)78933707f3Ssthen static int read_addrs(struct iter_priv* priv, struct config_file* cfg)
79933707f3Ssthen {
80933707f3Ssthen /* parse addresses, report errors, insert into tree */
81933707f3Ssthen struct config_strlist* p;
82933707f3Ssthen struct addr_tree_node* n;
83933707f3Ssthen struct sockaddr_storage addr;
84933707f3Ssthen int net;
85933707f3Ssthen socklen_t addrlen;
86933707f3Ssthen
87933707f3Ssthen for(p = cfg->private_address; p; p = p->next) {
88933707f3Ssthen log_assert(p->str);
89933707f3Ssthen if(!netblockstrtoaddr(p->str, UNBOUND_DNS_PORT, &addr,
90933707f3Ssthen &addrlen, &net)) {
91933707f3Ssthen log_err("cannot parse private-address: %s", p->str);
92933707f3Ssthen return 0;
93933707f3Ssthen }
94933707f3Ssthen n = (struct addr_tree_node*)regional_alloc(priv->region,
95933707f3Ssthen sizeof(*n));
96933707f3Ssthen if(!n) {
97933707f3Ssthen log_err("out of memory");
98933707f3Ssthen return 0;
99933707f3Ssthen }
100933707f3Ssthen if(!addr_tree_insert(&priv->a, n, &addr, addrlen, net)) {
101933707f3Ssthen verbose(VERB_QUERY, "ignoring duplicate "
102933707f3Ssthen "private-address: %s", p->str);
103933707f3Ssthen }
104933707f3Ssthen }
105933707f3Ssthen return 1;
106933707f3Ssthen }
107933707f3Ssthen
108933707f3Ssthen /** Read private-domain declarations from config */
read_names(struct iter_priv * priv,struct config_file * cfg)109933707f3Ssthen static int read_names(struct iter_priv* priv, struct config_file* cfg)
110933707f3Ssthen {
111933707f3Ssthen /* parse names, report errors, insert into tree */
112933707f3Ssthen struct config_strlist* p;
113933707f3Ssthen struct name_tree_node* n;
1145d76a658Ssthen uint8_t* nm, *nmr;
115933707f3Ssthen size_t nm_len;
116933707f3Ssthen int nm_labs;
117933707f3Ssthen
118933707f3Ssthen for(p = cfg->private_domain; p; p = p->next) {
119933707f3Ssthen log_assert(p->str);
1205d76a658Ssthen nm = sldns_str2wire_dname(p->str, &nm_len);
1215d76a658Ssthen if(!nm) {
122933707f3Ssthen log_err("cannot parse private-domain: %s", p->str);
123933707f3Ssthen return 0;
124933707f3Ssthen }
125933707f3Ssthen nm_labs = dname_count_size_labels(nm, &nm_len);
1265d76a658Ssthen nmr = (uint8_t*)regional_alloc_init(priv->region, nm, nm_len);
1275d76a658Ssthen free(nm);
1285d76a658Ssthen if(!nmr) {
129933707f3Ssthen log_err("out of memory");
130933707f3Ssthen return 0;
131933707f3Ssthen }
132933707f3Ssthen n = (struct name_tree_node*)regional_alloc(priv->region,
133933707f3Ssthen sizeof(*n));
134933707f3Ssthen if(!n) {
135933707f3Ssthen log_err("out of memory");
136933707f3Ssthen return 0;
137933707f3Ssthen }
1385d76a658Ssthen if(!name_tree_insert(&priv->n, n, nmr, nm_len, nm_labs,
139933707f3Ssthen LDNS_RR_CLASS_IN)) {
140933707f3Ssthen verbose(VERB_QUERY, "ignoring duplicate "
141933707f3Ssthen "private-domain: %s", p->str);
142933707f3Ssthen }
143933707f3Ssthen }
144933707f3Ssthen return 1;
145933707f3Ssthen }
146933707f3Ssthen
priv_apply_cfg(struct iter_priv * priv,struct config_file * cfg)147933707f3Ssthen int priv_apply_cfg(struct iter_priv* priv, struct config_file* cfg)
148933707f3Ssthen {
149933707f3Ssthen /* empty the current contents */
150933707f3Ssthen regional_free_all(priv->region);
151933707f3Ssthen addr_tree_init(&priv->a);
152933707f3Ssthen name_tree_init(&priv->n);
153933707f3Ssthen
154933707f3Ssthen /* read new contents */
155933707f3Ssthen if(!read_addrs(priv, cfg))
156933707f3Ssthen return 0;
157933707f3Ssthen if(!read_names(priv, cfg))
158933707f3Ssthen return 0;
159933707f3Ssthen
160933707f3Ssthen /* prepare for lookups */
161933707f3Ssthen addr_tree_init_parents(&priv->a);
162933707f3Ssthen name_tree_init_parents(&priv->n);
163933707f3Ssthen return 1;
164933707f3Ssthen }
165933707f3Ssthen
166933707f3Ssthen /**
167933707f3Ssthen * See if an address is blocked.
168933707f3Ssthen * @param priv: structure for address storage.
169933707f3Ssthen * @param addr: address to check
170933707f3Ssthen * @param addrlen: length of addr.
171933707f3Ssthen * @return: true if the address must not be queried. false if unlisted.
172933707f3Ssthen */
173933707f3Ssthen static int
priv_lookup_addr(struct iter_priv * priv,struct sockaddr_storage * addr,socklen_t addrlen)174933707f3Ssthen priv_lookup_addr(struct iter_priv* priv, struct sockaddr_storage* addr,
175933707f3Ssthen socklen_t addrlen)
176933707f3Ssthen {
177933707f3Ssthen return addr_tree_lookup(&priv->a, addr, addrlen) != NULL;
178933707f3Ssthen }
179933707f3Ssthen
180933707f3Ssthen /**
181933707f3Ssthen * See if a name is whitelisted.
182933707f3Ssthen * @param priv: structure for address storage.
183933707f3Ssthen * @param pkt: the packet (for compression ptrs).
184933707f3Ssthen * @param name: name to check.
185933707f3Ssthen * @param name_len: uncompressed length of the name to check.
186933707f3Ssthen * @param dclass: class to check.
187933707f3Ssthen * @return: true if the name is OK. false if unlisted.
188933707f3Ssthen */
189933707f3Ssthen static int
priv_lookup_name(struct iter_priv * priv,sldns_buffer * pkt,uint8_t * name,size_t name_len,uint16_t dclass)1905d76a658Ssthen priv_lookup_name(struct iter_priv* priv, sldns_buffer* pkt,
191933707f3Ssthen uint8_t* name, size_t name_len, uint16_t dclass)
192933707f3Ssthen {
193933707f3Ssthen size_t len;
194933707f3Ssthen uint8_t decomp[256];
195933707f3Ssthen int labs;
196933707f3Ssthen if(name_len >= sizeof(decomp))
197933707f3Ssthen return 0;
198933707f3Ssthen dname_pkt_copy(pkt, decomp, name);
199933707f3Ssthen labs = dname_count_size_labels(decomp, &len);
200933707f3Ssthen log_assert(name_len == len);
201933707f3Ssthen return name_tree_lookup(&priv->n, decomp, len, labs, dclass) != NULL;
202933707f3Ssthen }
203933707f3Ssthen
priv_get_mem(struct iter_priv * priv)204933707f3Ssthen size_t priv_get_mem(struct iter_priv* priv)
205933707f3Ssthen {
206933707f3Ssthen if(!priv) return 0;
207933707f3Ssthen return sizeof(*priv) + regional_get_mem(priv->region);
208933707f3Ssthen }
209933707f3Ssthen
priv_rrset_bad(struct iter_priv * priv,sldns_buffer * pkt,struct rrset_parse * rrset)2105d76a658Ssthen int priv_rrset_bad(struct iter_priv* priv, sldns_buffer* pkt,
211933707f3Ssthen struct rrset_parse* rrset)
212933707f3Ssthen {
213933707f3Ssthen if(priv->a.count == 0)
214933707f3Ssthen return 0; /* there are no blocked addresses */
215933707f3Ssthen
216933707f3Ssthen /* see if it is a private name, that is allowed to have any */
217933707f3Ssthen if(priv_lookup_name(priv, pkt, rrset->dname, rrset->dname_len,
218933707f3Ssthen ntohs(rrset->rrset_class))) {
219933707f3Ssthen return 0;
220933707f3Ssthen } else {
221933707f3Ssthen /* so its a public name, check the address */
222933707f3Ssthen socklen_t len;
223229e174cSsthen struct rr_parse* rr, *prev = NULL;
224933707f3Ssthen if(rrset->type == LDNS_RR_TYPE_A) {
225933707f3Ssthen struct sockaddr_storage addr;
226933707f3Ssthen struct sockaddr_in sa;
227933707f3Ssthen
228933707f3Ssthen len = (socklen_t)sizeof(sa);
229933707f3Ssthen memset(&sa, 0, len);
230933707f3Ssthen sa.sin_family = AF_INET;
231933707f3Ssthen sa.sin_port = (in_port_t)htons(UNBOUND_DNS_PORT);
232933707f3Ssthen for(rr = rrset->rr_first; rr; rr = rr->next) {
2335d76a658Ssthen if(sldns_read_uint16(rr->ttl_data+4)
234229e174cSsthen != INET_SIZE) {
235229e174cSsthen prev = rr;
236933707f3Ssthen continue;
237229e174cSsthen }
238933707f3Ssthen memmove(&sa.sin_addr, rr->ttl_data+4+2,
239933707f3Ssthen INET_SIZE);
240933707f3Ssthen memmove(&addr, &sa, len);
241229e174cSsthen if(priv_lookup_addr(priv, &addr, len)) {
242*9c7f0a49Ssthen if(msgparse_rrset_remove_rr("sanitize: removing public name with private address", pkt, rrset, prev, rr, &addr, len))
243933707f3Ssthen return 1;
244229e174cSsthen continue;
245229e174cSsthen }
246229e174cSsthen prev = rr;
247933707f3Ssthen }
248933707f3Ssthen } else if(rrset->type == LDNS_RR_TYPE_AAAA) {
249933707f3Ssthen struct sockaddr_storage addr;
250933707f3Ssthen struct sockaddr_in6 sa;
251933707f3Ssthen len = (socklen_t)sizeof(sa);
252933707f3Ssthen memset(&sa, 0, len);
253933707f3Ssthen sa.sin6_family = AF_INET6;
254933707f3Ssthen sa.sin6_port = (in_port_t)htons(UNBOUND_DNS_PORT);
255933707f3Ssthen for(rr = rrset->rr_first; rr; rr = rr->next) {
2565d76a658Ssthen if(sldns_read_uint16(rr->ttl_data+4)
257229e174cSsthen != INET6_SIZE) {
258229e174cSsthen prev = rr;
259933707f3Ssthen continue;
260229e174cSsthen }
261933707f3Ssthen memmove(&sa.sin6_addr, rr->ttl_data+4+2,
262933707f3Ssthen INET6_SIZE);
263933707f3Ssthen memmove(&addr, &sa, len);
264229e174cSsthen if(priv_lookup_addr(priv, &addr, len)) {
265*9c7f0a49Ssthen if(msgparse_rrset_remove_rr("sanitize: removing public name with private address", pkt, rrset, prev, rr, &addr, len))
266933707f3Ssthen return 1;
267229e174cSsthen continue;
268229e174cSsthen }
269229e174cSsthen prev = rr;
270933707f3Ssthen }
271933707f3Ssthen }
272933707f3Ssthen }
273933707f3Ssthen return 0;
274933707f3Ssthen }
275