1933707f3Ssthen /*
2933707f3Ssthen * iterator/iter_delegpt.c - delegation point with NS and address information.
3933707f3Ssthen *
4933707f3Ssthen * Copyright (c) 2007, 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 implements the Delegation Point. It contains a list of name servers
40933707f3Ssthen * and their addresses if known.
41933707f3Ssthen */
42933707f3Ssthen #include "config.h"
43933707f3Ssthen #include "iterator/iter_delegpt.h"
44933707f3Ssthen #include "services/cache/dns.h"
45933707f3Ssthen #include "util/regional.h"
46933707f3Ssthen #include "util/data/dname.h"
47933707f3Ssthen #include "util/data/packed_rrset.h"
48933707f3Ssthen #include "util/data/msgreply.h"
49933707f3Ssthen #include "util/net_help.h"
50fdfb4ba6Ssthen #include "sldns/rrdef.h"
51fdfb4ba6Ssthen #include "sldns/sbuffer.h"
52933707f3Ssthen
53933707f3Ssthen struct delegpt*
delegpt_create(struct regional * region)54933707f3Ssthen delegpt_create(struct regional* region)
55933707f3Ssthen {
56933707f3Ssthen struct delegpt* dp=(struct delegpt*)regional_alloc(
57933707f3Ssthen region, sizeof(*dp));
58933707f3Ssthen if(!dp)
59933707f3Ssthen return NULL;
60933707f3Ssthen memset(dp, 0, sizeof(*dp));
61933707f3Ssthen return dp;
62933707f3Ssthen }
63933707f3Ssthen
delegpt_copy(struct delegpt * dp,struct regional * region)64933707f3Ssthen struct delegpt* delegpt_copy(struct delegpt* dp, struct regional* region)
65933707f3Ssthen {
66933707f3Ssthen struct delegpt* copy = delegpt_create(region);
67933707f3Ssthen struct delegpt_ns* ns;
68933707f3Ssthen struct delegpt_addr* a;
69933707f3Ssthen if(!copy)
70933707f3Ssthen return NULL;
71933707f3Ssthen if(!delegpt_set_name(copy, region, dp->name))
72933707f3Ssthen return NULL;
73933707f3Ssthen copy->bogus = dp->bogus;
74933707f3Ssthen copy->has_parent_side_NS = dp->has_parent_side_NS;
7577079be7Ssthen copy->ssl_upstream = dp->ssl_upstream;
76e21c60efSsthen copy->tcp_upstream = dp->tcp_upstream;
77933707f3Ssthen for(ns = dp->nslist; ns; ns = ns->next) {
78e21c60efSsthen if(!delegpt_add_ns(copy, region, ns->name, ns->lame,
79e21c60efSsthen ns->tls_auth_name, ns->port))
80933707f3Ssthen return NULL;
817dd170e2Ssthen copy->nslist->cache_lookup_count = ns->cache_lookup_count;
82933707f3Ssthen copy->nslist->resolved = ns->resolved;
83933707f3Ssthen copy->nslist->got4 = ns->got4;
84933707f3Ssthen copy->nslist->got6 = ns->got6;
85933707f3Ssthen copy->nslist->done_pside4 = ns->done_pside4;
86933707f3Ssthen copy->nslist->done_pside6 = ns->done_pside6;
87933707f3Ssthen }
88933707f3Ssthen for(a = dp->target_list; a; a = a->next_target) {
89933707f3Ssthen if(!delegpt_add_addr(copy, region, &a->addr, a->addrlen,
90e21c60efSsthen a->bogus, a->lame, a->tls_auth_name, -1, NULL))
91933707f3Ssthen return NULL;
92933707f3Ssthen }
93933707f3Ssthen return copy;
94933707f3Ssthen }
95933707f3Ssthen
96933707f3Ssthen int
delegpt_set_name(struct delegpt * dp,struct regional * region,uint8_t * name)97933707f3Ssthen delegpt_set_name(struct delegpt* dp, struct regional* region, uint8_t* name)
98933707f3Ssthen {
99d8d14d0cSsthen log_assert(!dp->dp_type_mlc);
100933707f3Ssthen dp->namelabs = dname_count_size_labels(name, &dp->namelen);
101933707f3Ssthen dp->name = regional_alloc_init(region, name, dp->namelen);
102933707f3Ssthen return dp->name != 0;
103933707f3Ssthen }
104933707f3Ssthen
105933707f3Ssthen int
delegpt_add_ns(struct delegpt * dp,struct regional * region,uint8_t * name,uint8_t lame,char * tls_auth_name,int port)106933707f3Ssthen delegpt_add_ns(struct delegpt* dp, struct regional* region, uint8_t* name,
107e21c60efSsthen uint8_t lame, char* tls_auth_name, int port)
108933707f3Ssthen {
109933707f3Ssthen struct delegpt_ns* ns;
110933707f3Ssthen size_t len;
111933707f3Ssthen (void)dname_count_size_labels(name, &len);
112d8d14d0cSsthen log_assert(!dp->dp_type_mlc);
113933707f3Ssthen /* slow check for duplicates to avoid counting failures when
114933707f3Ssthen * adding the same server as a dependency twice */
115933707f3Ssthen if(delegpt_find_ns(dp, name, len))
116933707f3Ssthen return 1;
117933707f3Ssthen ns = (struct delegpt_ns*)regional_alloc(region,
118933707f3Ssthen sizeof(struct delegpt_ns));
119933707f3Ssthen if(!ns)
120933707f3Ssthen return 0;
121933707f3Ssthen ns->next = dp->nslist;
122933707f3Ssthen ns->namelen = len;
123933707f3Ssthen dp->nslist = ns;
124933707f3Ssthen ns->name = regional_alloc_init(region, name, ns->namelen);
1257dd170e2Ssthen ns->cache_lookup_count = 0;
126933707f3Ssthen ns->resolved = 0;
127933707f3Ssthen ns->got4 = 0;
128933707f3Ssthen ns->got6 = 0;
129229e174cSsthen ns->lame = lame;
130933707f3Ssthen ns->done_pside4 = 0;
131933707f3Ssthen ns->done_pside6 = 0;
132e21c60efSsthen ns->port = port;
133e21c60efSsthen if(tls_auth_name) {
134e21c60efSsthen ns->tls_auth_name = regional_strdup(region, tls_auth_name);
135e21c60efSsthen if(!ns->tls_auth_name)
136e21c60efSsthen return 0;
137e21c60efSsthen } else {
138e21c60efSsthen ns->tls_auth_name = NULL;
139e21c60efSsthen }
140d8d14d0cSsthen return ns->name != 0;
141933707f3Ssthen }
142933707f3Ssthen
143933707f3Ssthen struct delegpt_ns*
delegpt_find_ns(struct delegpt * dp,uint8_t * name,size_t namelen)144933707f3Ssthen delegpt_find_ns(struct delegpt* dp, uint8_t* name, size_t namelen)
145933707f3Ssthen {
146933707f3Ssthen struct delegpt_ns* p = dp->nslist;
147933707f3Ssthen while(p) {
148933707f3Ssthen if(namelen == p->namelen &&
149933707f3Ssthen query_dname_compare(name, p->name) == 0) {
150933707f3Ssthen return p;
151933707f3Ssthen }
152933707f3Ssthen p = p->next;
153933707f3Ssthen }
154933707f3Ssthen return NULL;
155933707f3Ssthen }
156933707f3Ssthen
157933707f3Ssthen struct delegpt_addr*
delegpt_find_addr(struct delegpt * dp,struct sockaddr_storage * addr,socklen_t addrlen)158933707f3Ssthen delegpt_find_addr(struct delegpt* dp, struct sockaddr_storage* addr,
159933707f3Ssthen socklen_t addrlen)
160933707f3Ssthen {
161933707f3Ssthen struct delegpt_addr* p = dp->target_list;
162933707f3Ssthen while(p) {
16398f3ca02Sbrad if(sockaddr_cmp_addr(addr, addrlen, &p->addr, p->addrlen)==0
16498f3ca02Sbrad && ((struct sockaddr_in*)addr)->sin_port ==
16598f3ca02Sbrad ((struct sockaddr_in*)&p->addr)->sin_port) {
166933707f3Ssthen return p;
167933707f3Ssthen }
168933707f3Ssthen p = p->next_target;
169933707f3Ssthen }
170933707f3Ssthen return NULL;
171933707f3Ssthen }
172933707f3Ssthen
173933707f3Ssthen int
delegpt_add_target(struct delegpt * dp,struct regional * region,uint8_t * name,size_t namelen,struct sockaddr_storage * addr,socklen_t addrlen,uint8_t bogus,uint8_t lame,int * additions)174933707f3Ssthen delegpt_add_target(struct delegpt* dp, struct regional* region,
175933707f3Ssthen uint8_t* name, size_t namelen, struct sockaddr_storage* addr,
17606a13c09Ssthen socklen_t addrlen, uint8_t bogus, uint8_t lame, int* additions)
177933707f3Ssthen {
178933707f3Ssthen struct delegpt_ns* ns = delegpt_find_ns(dp, name, namelen);
179d8d14d0cSsthen log_assert(!dp->dp_type_mlc);
180933707f3Ssthen if(!ns) {
181933707f3Ssthen /* ignore it */
182933707f3Ssthen return 1;
183933707f3Ssthen }
184933707f3Ssthen if(!lame) {
185933707f3Ssthen if(addr_is_ip6(addr, addrlen))
186933707f3Ssthen ns->got6 = 1;
187933707f3Ssthen else ns->got4 = 1;
188933707f3Ssthen if(ns->got4 && ns->got6)
189933707f3Ssthen ns->resolved = 1;
190d1e2768aSsthen } else {
191d1e2768aSsthen if(addr_is_ip6(addr, addrlen))
192d1e2768aSsthen ns->done_pside6 = 1;
193d1e2768aSsthen else ns->done_pside4 = 1;
194933707f3Ssthen }
195e21c60efSsthen log_assert(ns->port>0);
196e21c60efSsthen return delegpt_add_addr(dp, region, addr, addrlen, bogus, lame,
197e21c60efSsthen ns->tls_auth_name, ns->port, additions);
198933707f3Ssthen }
199933707f3Ssthen
200933707f3Ssthen int
delegpt_add_addr(struct delegpt * dp,struct regional * region,struct sockaddr_storage * addr,socklen_t addrlen,uint8_t bogus,uint8_t lame,char * tls_auth_name,int port,int * additions)201933707f3Ssthen delegpt_add_addr(struct delegpt* dp, struct regional* region,
202229e174cSsthen struct sockaddr_storage* addr, socklen_t addrlen, uint8_t bogus,
203e21c60efSsthen uint8_t lame, char* tls_auth_name, int port, int* additions)
204933707f3Ssthen {
205933707f3Ssthen struct delegpt_addr* a;
206d8d14d0cSsthen log_assert(!dp->dp_type_mlc);
207e21c60efSsthen if(port != -1) {
208e21c60efSsthen log_assert(port>0);
209e21c60efSsthen sockaddr_store_port(addr, addrlen, port);
210e21c60efSsthen }
211933707f3Ssthen /* check for duplicates */
212933707f3Ssthen if((a = delegpt_find_addr(dp, addr, addrlen))) {
213933707f3Ssthen if(bogus)
214933707f3Ssthen a->bogus = bogus;
215933707f3Ssthen if(!lame)
216933707f3Ssthen a->lame = 0;
217933707f3Ssthen return 1;
218933707f3Ssthen }
21906a13c09Ssthen if(additions)
22006a13c09Ssthen *additions = 1;
221933707f3Ssthen
222933707f3Ssthen a = (struct delegpt_addr*)regional_alloc(region,
223933707f3Ssthen sizeof(struct delegpt_addr));
224933707f3Ssthen if(!a)
225933707f3Ssthen return 0;
226933707f3Ssthen a->next_target = dp->target_list;
227933707f3Ssthen dp->target_list = a;
228933707f3Ssthen a->next_result = 0;
229933707f3Ssthen a->next_usable = dp->usable_list;
230933707f3Ssthen dp->usable_list = a;
231933707f3Ssthen memcpy(&a->addr, addr, addrlen);
232933707f3Ssthen a->addrlen = addrlen;
233933707f3Ssthen a->attempts = 0;
234933707f3Ssthen a->bogus = bogus;
235933707f3Ssthen a->lame = lame;
236229e174cSsthen a->dnsseclame = 0;
23720237c55Ssthen if(tls_auth_name) {
23820237c55Ssthen a->tls_auth_name = regional_strdup(region, tls_auth_name);
23920237c55Ssthen if(!a->tls_auth_name)
24020237c55Ssthen return 0;
24120237c55Ssthen } else {
24220237c55Ssthen a->tls_auth_name = NULL;
24320237c55Ssthen }
244933707f3Ssthen return 1;
245933707f3Ssthen }
246933707f3Ssthen
247933707f3Ssthen void
delegpt_count_ns(struct delegpt * dp,size_t * numns,size_t * missing)248933707f3Ssthen delegpt_count_ns(struct delegpt* dp, size_t* numns, size_t* missing)
249933707f3Ssthen {
250933707f3Ssthen struct delegpt_ns* ns;
251933707f3Ssthen *numns = 0;
252933707f3Ssthen *missing = 0;
253933707f3Ssthen for(ns = dp->nslist; ns; ns = ns->next) {
254933707f3Ssthen (*numns)++;
255933707f3Ssthen if(!ns->resolved)
256933707f3Ssthen (*missing)++;
257933707f3Ssthen }
258933707f3Ssthen }
259933707f3Ssthen
260933707f3Ssthen void
delegpt_count_addr(struct delegpt * dp,size_t * numaddr,size_t * numres,size_t * numavail)261933707f3Ssthen delegpt_count_addr(struct delegpt* dp, size_t* numaddr, size_t* numres,
262933707f3Ssthen size_t* numavail)
263933707f3Ssthen {
264933707f3Ssthen struct delegpt_addr* a;
265933707f3Ssthen *numaddr = 0;
266933707f3Ssthen *numres = 0;
267933707f3Ssthen *numavail = 0;
268933707f3Ssthen for(a = dp->target_list; a; a = a->next_target) {
269933707f3Ssthen (*numaddr)++;
270933707f3Ssthen }
271933707f3Ssthen for(a = dp->result_list; a; a = a->next_result) {
272933707f3Ssthen (*numres)++;
273933707f3Ssthen }
274933707f3Ssthen for(a = dp->usable_list; a; a = a->next_usable) {
275933707f3Ssthen (*numavail)++;
276933707f3Ssthen }
277933707f3Ssthen }
278933707f3Ssthen
delegpt_log(enum verbosity_value v,struct delegpt * dp)279933707f3Ssthen void delegpt_log(enum verbosity_value v, struct delegpt* dp)
280933707f3Ssthen {
281933707f3Ssthen char buf[LDNS_MAX_DOMAINLEN+1];
282933707f3Ssthen struct delegpt_ns* ns;
283933707f3Ssthen struct delegpt_addr* a;
284933707f3Ssthen size_t missing=0, numns=0, numaddr=0, numres=0, numavail=0;
285933707f3Ssthen if(verbosity < v)
286933707f3Ssthen return;
287933707f3Ssthen dname_str(dp->name, buf);
288933707f3Ssthen if(dp->nslist == NULL && dp->target_list == NULL) {
289933707f3Ssthen log_info("DelegationPoint<%s>: empty", buf);
290933707f3Ssthen return;
291933707f3Ssthen }
292933707f3Ssthen delegpt_count_ns(dp, &numns, &missing);
293933707f3Ssthen delegpt_count_addr(dp, &numaddr, &numres, &numavail);
294933707f3Ssthen log_info("DelegationPoint<%s>: %u names (%u missing), "
295933707f3Ssthen "%u addrs (%u result, %u avail)%s",
296933707f3Ssthen buf, (unsigned)numns, (unsigned)missing,
297933707f3Ssthen (unsigned)numaddr, (unsigned)numres, (unsigned)numavail,
298933707f3Ssthen (dp->has_parent_side_NS?" parentNS":" cacheNS"));
299933707f3Ssthen if(verbosity >= VERB_ALGO) {
300933707f3Ssthen for(ns = dp->nslist; ns; ns = ns->next) {
301933707f3Ssthen dname_str(ns->name, buf);
302933707f3Ssthen log_info(" %s %s%s%s%s%s%s%s", buf,
303933707f3Ssthen (ns->resolved?"*":""),
304933707f3Ssthen (ns->got4?" A":""), (ns->got6?" AAAA":""),
305933707f3Ssthen (dp->bogus?" BOGUS":""), (ns->lame?" PARENTSIDE":""),
306933707f3Ssthen (ns->done_pside4?" PSIDE_A":""),
307933707f3Ssthen (ns->done_pside6?" PSIDE_AAAA":""));
308933707f3Ssthen }
309933707f3Ssthen for(a = dp->target_list; a; a = a->next_target) {
31020237c55Ssthen char s[128];
311933707f3Ssthen const char* str = " ";
312933707f3Ssthen if(a->bogus && a->lame) str = " BOGUS ADDR_LAME ";
313933707f3Ssthen else if(a->bogus) str = " BOGUS ";
314933707f3Ssthen else if(a->lame) str = " ADDR_LAME ";
31520237c55Ssthen if(a->tls_auth_name)
31620237c55Ssthen snprintf(s, sizeof(s), "%s[%s]", str,
31720237c55Ssthen a->tls_auth_name);
31820237c55Ssthen else snprintf(s, sizeof(s), "%s", str);
31920237c55Ssthen log_addr(VERB_ALGO, s, &a->addr, a->addrlen);
320933707f3Ssthen }
321933707f3Ssthen }
322933707f3Ssthen }
323933707f3Ssthen
324*8b7325afSsthen int
delegpt_addr_on_result_list(struct delegpt * dp,struct delegpt_addr * find)325*8b7325afSsthen delegpt_addr_on_result_list(struct delegpt* dp, struct delegpt_addr* find)
326*8b7325afSsthen {
327*8b7325afSsthen struct delegpt_addr* a = dp->result_list;
328*8b7325afSsthen while(a) {
329*8b7325afSsthen if(a == find)
330*8b7325afSsthen return 1;
331*8b7325afSsthen a = a->next_result;
332*8b7325afSsthen }
333*8b7325afSsthen return 0;
334*8b7325afSsthen }
335*8b7325afSsthen
336*8b7325afSsthen void
delegpt_usable_list_remove_addr(struct delegpt * dp,struct delegpt_addr * del)337*8b7325afSsthen delegpt_usable_list_remove_addr(struct delegpt* dp, struct delegpt_addr* del)
338*8b7325afSsthen {
339*8b7325afSsthen struct delegpt_addr* usa = dp->usable_list, *prev = NULL;
340*8b7325afSsthen while(usa) {
341*8b7325afSsthen if(usa == del) {
342*8b7325afSsthen /* snip off the usable list */
343*8b7325afSsthen if(prev)
344*8b7325afSsthen prev->next_usable = usa->next_usable;
345*8b7325afSsthen else dp->usable_list = usa->next_usable;
346*8b7325afSsthen return;
347*8b7325afSsthen }
348*8b7325afSsthen prev = usa;
349*8b7325afSsthen usa = usa->next_usable;
350*8b7325afSsthen }
351*8b7325afSsthen }
352*8b7325afSsthen
353*8b7325afSsthen void
delegpt_add_to_result_list(struct delegpt * dp,struct delegpt_addr * a)354*8b7325afSsthen delegpt_add_to_result_list(struct delegpt* dp, struct delegpt_addr* a)
355*8b7325afSsthen {
356*8b7325afSsthen if(delegpt_addr_on_result_list(dp, a))
357*8b7325afSsthen return;
358*8b7325afSsthen delegpt_usable_list_remove_addr(dp, a);
359*8b7325afSsthen a->next_result = dp->result_list;
360*8b7325afSsthen dp->result_list = a;
361*8b7325afSsthen }
362*8b7325afSsthen
363933707f3Ssthen void
delegpt_add_unused_targets(struct delegpt * dp)364933707f3Ssthen delegpt_add_unused_targets(struct delegpt* dp)
365933707f3Ssthen {
366933707f3Ssthen struct delegpt_addr* usa = dp->usable_list;
367933707f3Ssthen dp->usable_list = NULL;
368933707f3Ssthen while(usa) {
369933707f3Ssthen usa->next_result = dp->result_list;
370933707f3Ssthen dp->result_list = usa;
371933707f3Ssthen usa = usa->next_usable;
372933707f3Ssthen }
373933707f3Ssthen }
374933707f3Ssthen
375933707f3Ssthen size_t
delegpt_count_targets(struct delegpt * dp)376933707f3Ssthen delegpt_count_targets(struct delegpt* dp)
377933707f3Ssthen {
378933707f3Ssthen struct delegpt_addr* a;
379933707f3Ssthen size_t n = 0;
380933707f3Ssthen for(a = dp->target_list; a; a = a->next_target)
381933707f3Ssthen n++;
382933707f3Ssthen return n;
383933707f3Ssthen }
384933707f3Ssthen
385933707f3Ssthen size_t
delegpt_count_missing_targets(struct delegpt * dp,int * alllame)386d1e2768aSsthen delegpt_count_missing_targets(struct delegpt* dp, int* alllame)
387933707f3Ssthen {
388933707f3Ssthen struct delegpt_ns* ns;
389d1e2768aSsthen size_t n = 0, nlame = 0;
390d1e2768aSsthen for(ns = dp->nslist; ns; ns = ns->next) {
391d1e2768aSsthen if(ns->resolved) continue;
392933707f3Ssthen n++;
393d1e2768aSsthen if(ns->lame) nlame++;
394d1e2768aSsthen }
395d1e2768aSsthen if(alllame && n == nlame) *alllame = 1;
396933707f3Ssthen return n;
397933707f3Ssthen }
398933707f3Ssthen
399933707f3Ssthen /** find NS rrset in given list */
400933707f3Ssthen static struct ub_packed_rrset_key*
find_NS(struct reply_info * rep,size_t from,size_t to)401933707f3Ssthen find_NS(struct reply_info* rep, size_t from, size_t to)
402933707f3Ssthen {
403933707f3Ssthen size_t i;
404933707f3Ssthen for(i=from; i<to; i++) {
405933707f3Ssthen if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_NS)
406933707f3Ssthen return rep->rrsets[i];
407933707f3Ssthen }
408933707f3Ssthen return NULL;
409933707f3Ssthen }
410933707f3Ssthen
411933707f3Ssthen struct delegpt*
delegpt_from_message(struct dns_msg * msg,struct regional * region)412933707f3Ssthen delegpt_from_message(struct dns_msg* msg, struct regional* region)
413933707f3Ssthen {
414933707f3Ssthen struct ub_packed_rrset_key* ns_rrset = NULL;
415933707f3Ssthen struct delegpt* dp;
416933707f3Ssthen size_t i;
417933707f3Ssthen /* look for NS records in the authority section... */
418933707f3Ssthen ns_rrset = find_NS(msg->rep, msg->rep->an_numrrsets,
419933707f3Ssthen msg->rep->an_numrrsets+msg->rep->ns_numrrsets);
420933707f3Ssthen
421933707f3Ssthen /* In some cases (even legitimate, perfectly legal cases), the
422933707f3Ssthen * NS set for the "referral" might be in the answer section. */
423933707f3Ssthen if(!ns_rrset)
424933707f3Ssthen ns_rrset = find_NS(msg->rep, 0, msg->rep->an_numrrsets);
425933707f3Ssthen
426933707f3Ssthen /* If there was no NS rrset in the authority section, then this
427933707f3Ssthen * wasn't a referral message. (It might not actually be a
428933707f3Ssthen * referral message anyway) */
429933707f3Ssthen if(!ns_rrset)
430933707f3Ssthen return NULL;
431933707f3Ssthen
432933707f3Ssthen /* If we found any, then Yay! we have a delegation point. */
433933707f3Ssthen dp = delegpt_create(region);
434933707f3Ssthen if(!dp)
435933707f3Ssthen return NULL;
436933707f3Ssthen dp->has_parent_side_NS = 1; /* created from message */
437933707f3Ssthen if(!delegpt_set_name(dp, region, ns_rrset->rk.dname))
438933707f3Ssthen return NULL;
439933707f3Ssthen if(!delegpt_rrset_add_ns(dp, region, ns_rrset, 0))
440933707f3Ssthen return NULL;
441933707f3Ssthen
442933707f3Ssthen /* add glue, A and AAAA in answer and additional section */
443933707f3Ssthen for(i=0; i<msg->rep->rrset_count; i++) {
444933707f3Ssthen struct ub_packed_rrset_key* s = msg->rep->rrsets[i];
445933707f3Ssthen /* skip auth section. FIXME really needed?*/
446933707f3Ssthen if(msg->rep->an_numrrsets <= i &&
447933707f3Ssthen i < (msg->rep->an_numrrsets+msg->rep->ns_numrrsets))
448933707f3Ssthen continue;
449933707f3Ssthen
450933707f3Ssthen if(ntohs(s->rk.type) == LDNS_RR_TYPE_A) {
45106a13c09Ssthen if(!delegpt_add_rrset_A(dp, region, s, 0, NULL))
452933707f3Ssthen return NULL;
453933707f3Ssthen } else if(ntohs(s->rk.type) == LDNS_RR_TYPE_AAAA) {
45406a13c09Ssthen if(!delegpt_add_rrset_AAAA(dp, region, s, 0, NULL))
455933707f3Ssthen return NULL;
456933707f3Ssthen }
457933707f3Ssthen }
458933707f3Ssthen return dp;
459933707f3Ssthen }
460933707f3Ssthen
461933707f3Ssthen int
delegpt_rrset_add_ns(struct delegpt * dp,struct regional * region,struct ub_packed_rrset_key * ns_rrset,uint8_t lame)462933707f3Ssthen delegpt_rrset_add_ns(struct delegpt* dp, struct regional* region,
463229e174cSsthen struct ub_packed_rrset_key* ns_rrset, uint8_t lame)
464933707f3Ssthen {
465933707f3Ssthen struct packed_rrset_data* nsdata = (struct packed_rrset_data*)
466933707f3Ssthen ns_rrset->entry.data;
467933707f3Ssthen size_t i;
468d8d14d0cSsthen log_assert(!dp->dp_type_mlc);
469933707f3Ssthen if(nsdata->security == sec_status_bogus)
470933707f3Ssthen dp->bogus = 1;
471933707f3Ssthen for(i=0; i<nsdata->count; i++) {
472933707f3Ssthen if(nsdata->rr_len[i] < 2+1) continue; /* len + root label */
473933707f3Ssthen if(dname_valid(nsdata->rr_data[i]+2, nsdata->rr_len[i]-2) !=
4745d76a658Ssthen (size_t)sldns_read_uint16(nsdata->rr_data[i]))
475933707f3Ssthen continue; /* bad format */
476933707f3Ssthen /* add rdata of NS (= wirefmt dname), skip rdatalen bytes */
477e21c60efSsthen if(!delegpt_add_ns(dp, region, nsdata->rr_data[i]+2, lame,
478e21c60efSsthen NULL, UNBOUND_DNS_PORT))
479933707f3Ssthen return 0;
480933707f3Ssthen }
481933707f3Ssthen return 1;
482933707f3Ssthen }
483933707f3Ssthen
484933707f3Ssthen int
delegpt_add_rrset_A(struct delegpt * dp,struct regional * region,struct ub_packed_rrset_key * ak,uint8_t lame,int * additions)485933707f3Ssthen delegpt_add_rrset_A(struct delegpt* dp, struct regional* region,
48606a13c09Ssthen struct ub_packed_rrset_key* ak, uint8_t lame, int* additions)
487933707f3Ssthen {
488933707f3Ssthen struct packed_rrset_data* d=(struct packed_rrset_data*)ak->entry.data;
489933707f3Ssthen size_t i;
490933707f3Ssthen struct sockaddr_in sa;
491933707f3Ssthen socklen_t len = (socklen_t)sizeof(sa);
492d8d14d0cSsthen log_assert(!dp->dp_type_mlc);
493933707f3Ssthen memset(&sa, 0, len);
494933707f3Ssthen sa.sin_family = AF_INET;
495933707f3Ssthen for(i=0; i<d->count; i++) {
496933707f3Ssthen if(d->rr_len[i] != 2 + INET_SIZE)
497933707f3Ssthen continue;
498933707f3Ssthen memmove(&sa.sin_addr, d->rr_data[i]+2, INET_SIZE);
499933707f3Ssthen if(!delegpt_add_target(dp, region, ak->rk.dname,
500933707f3Ssthen ak->rk.dname_len, (struct sockaddr_storage*)&sa,
50106a13c09Ssthen len, (d->security==sec_status_bogus), lame, additions))
502933707f3Ssthen return 0;
503933707f3Ssthen }
504933707f3Ssthen return 1;
505933707f3Ssthen }
506933707f3Ssthen
507933707f3Ssthen int
delegpt_add_rrset_AAAA(struct delegpt * dp,struct regional * region,struct ub_packed_rrset_key * ak,uint8_t lame,int * additions)508933707f3Ssthen delegpt_add_rrset_AAAA(struct delegpt* dp, struct regional* region,
50906a13c09Ssthen struct ub_packed_rrset_key* ak, uint8_t lame, int* additions)
510933707f3Ssthen {
511933707f3Ssthen struct packed_rrset_data* d=(struct packed_rrset_data*)ak->entry.data;
512933707f3Ssthen size_t i;
513933707f3Ssthen struct sockaddr_in6 sa;
514933707f3Ssthen socklen_t len = (socklen_t)sizeof(sa);
515d8d14d0cSsthen log_assert(!dp->dp_type_mlc);
516933707f3Ssthen memset(&sa, 0, len);
517933707f3Ssthen sa.sin6_family = AF_INET6;
518933707f3Ssthen for(i=0; i<d->count; i++) {
519933707f3Ssthen if(d->rr_len[i] != 2 + INET6_SIZE) /* rdatalen + len of IP6 */
520933707f3Ssthen continue;
521933707f3Ssthen memmove(&sa.sin6_addr, d->rr_data[i]+2, INET6_SIZE);
522933707f3Ssthen if(!delegpt_add_target(dp, region, ak->rk.dname,
523933707f3Ssthen ak->rk.dname_len, (struct sockaddr_storage*)&sa,
52406a13c09Ssthen len, (d->security==sec_status_bogus), lame, additions))
525933707f3Ssthen return 0;
526933707f3Ssthen }
527933707f3Ssthen return 1;
528933707f3Ssthen }
529933707f3Ssthen
530933707f3Ssthen int
delegpt_add_rrset(struct delegpt * dp,struct regional * region,struct ub_packed_rrset_key * rrset,uint8_t lame,int * additions)531933707f3Ssthen delegpt_add_rrset(struct delegpt* dp, struct regional* region,
53206a13c09Ssthen struct ub_packed_rrset_key* rrset, uint8_t lame, int* additions)
533933707f3Ssthen {
534933707f3Ssthen if(!rrset)
535933707f3Ssthen return 1;
536933707f3Ssthen if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_NS)
537933707f3Ssthen return delegpt_rrset_add_ns(dp, region, rrset, lame);
538933707f3Ssthen else if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_A)
53906a13c09Ssthen return delegpt_add_rrset_A(dp, region, rrset, lame, additions);
540933707f3Ssthen else if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_AAAA)
54106a13c09Ssthen return delegpt_add_rrset_AAAA(dp, region, rrset, lame,
54206a13c09Ssthen additions);
543933707f3Ssthen log_warn("Unknown rrset type added to delegpt");
544933707f3Ssthen return 1;
545933707f3Ssthen }
546933707f3Ssthen
delegpt_mark_neg(struct delegpt_ns * ns,uint16_t qtype)54706a13c09Ssthen void delegpt_mark_neg(struct delegpt_ns* ns, uint16_t qtype)
54806a13c09Ssthen {
54906a13c09Ssthen if(ns) {
55006a13c09Ssthen if(qtype == LDNS_RR_TYPE_A)
55106a13c09Ssthen ns->got4 = 2;
55206a13c09Ssthen else if(qtype == LDNS_RR_TYPE_AAAA)
55306a13c09Ssthen ns->got6 = 2;
55406a13c09Ssthen if(ns->got4 && ns->got6)
55506a13c09Ssthen ns->resolved = 1;
55606a13c09Ssthen }
55706a13c09Ssthen }
55806a13c09Ssthen
delegpt_add_neg_msg(struct delegpt * dp,struct msgreply_entry * msg)559933707f3Ssthen void delegpt_add_neg_msg(struct delegpt* dp, struct msgreply_entry* msg)
560933707f3Ssthen {
561933707f3Ssthen struct reply_info* rep = (struct reply_info*)msg->entry.data;
562933707f3Ssthen if(!rep) return;
563933707f3Ssthen
564933707f3Ssthen /* if error or no answers */
565933707f3Ssthen if(FLAGS_GET_RCODE(rep->flags) != 0 || rep->an_numrrsets == 0) {
566933707f3Ssthen struct delegpt_ns* ns = delegpt_find_ns(dp, msg->key.qname,
567933707f3Ssthen msg->key.qname_len);
56806a13c09Ssthen delegpt_mark_neg(ns, msg->key.qtype);
569933707f3Ssthen }
570933707f3Ssthen }
571933707f3Ssthen
delegpt_no_ipv6(struct delegpt * dp)572933707f3Ssthen void delegpt_no_ipv6(struct delegpt* dp)
573933707f3Ssthen {
574933707f3Ssthen struct delegpt_ns* ns;
575933707f3Ssthen for(ns = dp->nslist; ns; ns = ns->next) {
576933707f3Ssthen /* no ipv6, so only ipv4 is enough to resolve a nameserver */
577933707f3Ssthen if(ns->got4)
578933707f3Ssthen ns->resolved = 1;
579933707f3Ssthen }
580933707f3Ssthen }
581933707f3Ssthen
delegpt_no_ipv4(struct delegpt * dp)582933707f3Ssthen void delegpt_no_ipv4(struct delegpt* dp)
583933707f3Ssthen {
584933707f3Ssthen struct delegpt_ns* ns;
585933707f3Ssthen for(ns = dp->nslist; ns; ns = ns->next) {
586933707f3Ssthen /* no ipv4, so only ipv6 is enough to resolve a nameserver */
587933707f3Ssthen if(ns->got6)
588933707f3Ssthen ns->resolved = 1;
589933707f3Ssthen }
590933707f3Ssthen }
591d8d14d0cSsthen
delegpt_create_mlc(uint8_t * name)592d8d14d0cSsthen struct delegpt* delegpt_create_mlc(uint8_t* name)
593d8d14d0cSsthen {
594d8d14d0cSsthen struct delegpt* dp=(struct delegpt*)calloc(1, sizeof(*dp));
595d8d14d0cSsthen if(!dp)
596d8d14d0cSsthen return NULL;
597d8d14d0cSsthen dp->dp_type_mlc = 1;
598d8d14d0cSsthen if(name) {
599d8d14d0cSsthen dp->namelabs = dname_count_size_labels(name, &dp->namelen);
600d8d14d0cSsthen dp->name = memdup(name, dp->namelen);
601d8d14d0cSsthen if(!dp->name) {
602d8d14d0cSsthen free(dp);
603d8d14d0cSsthen return NULL;
604d8d14d0cSsthen }
605d8d14d0cSsthen }
606d8d14d0cSsthen return dp;
607d8d14d0cSsthen }
608d8d14d0cSsthen
delegpt_free_mlc(struct delegpt * dp)609d8d14d0cSsthen void delegpt_free_mlc(struct delegpt* dp)
610d8d14d0cSsthen {
611d8d14d0cSsthen struct delegpt_ns* n, *nn;
612d8d14d0cSsthen struct delegpt_addr* a, *na;
613d8d14d0cSsthen if(!dp) return;
614d8d14d0cSsthen log_assert(dp->dp_type_mlc);
615d8d14d0cSsthen n = dp->nslist;
616d8d14d0cSsthen while(n) {
617d8d14d0cSsthen nn = n->next;
618d8d14d0cSsthen free(n->name);
619e21c60efSsthen free(n->tls_auth_name);
620d8d14d0cSsthen free(n);
621d8d14d0cSsthen n = nn;
622d8d14d0cSsthen }
623d8d14d0cSsthen a = dp->target_list;
624d8d14d0cSsthen while(a) {
625d8d14d0cSsthen na = a->next_target;
62620237c55Ssthen free(a->tls_auth_name);
627d8d14d0cSsthen free(a);
628d8d14d0cSsthen a = na;
629d8d14d0cSsthen }
630d8d14d0cSsthen free(dp->name);
631d8d14d0cSsthen free(dp);
632d8d14d0cSsthen }
633d8d14d0cSsthen
delegpt_set_name_mlc(struct delegpt * dp,uint8_t * name)634d8d14d0cSsthen int delegpt_set_name_mlc(struct delegpt* dp, uint8_t* name)
635d8d14d0cSsthen {
636d8d14d0cSsthen log_assert(dp->dp_type_mlc);
637d8d14d0cSsthen dp->namelabs = dname_count_size_labels(name, &dp->namelen);
638d8d14d0cSsthen dp->name = memdup(name, dp->namelen);
639d8d14d0cSsthen return (dp->name != NULL);
640d8d14d0cSsthen }
641d8d14d0cSsthen
delegpt_add_ns_mlc(struct delegpt * dp,uint8_t * name,uint8_t lame,char * tls_auth_name,int port)642e21c60efSsthen int delegpt_add_ns_mlc(struct delegpt* dp, uint8_t* name, uint8_t lame,
643e21c60efSsthen char* tls_auth_name, int port)
644d8d14d0cSsthen {
645d8d14d0cSsthen struct delegpt_ns* ns;
646d8d14d0cSsthen size_t len;
647d8d14d0cSsthen (void)dname_count_size_labels(name, &len);
648d8d14d0cSsthen log_assert(dp->dp_type_mlc);
649d8d14d0cSsthen /* slow check for duplicates to avoid counting failures when
650d8d14d0cSsthen * adding the same server as a dependency twice */
651d8d14d0cSsthen if(delegpt_find_ns(dp, name, len))
652d8d14d0cSsthen return 1;
653d8d14d0cSsthen ns = (struct delegpt_ns*)malloc(sizeof(struct delegpt_ns));
654d8d14d0cSsthen if(!ns)
655d8d14d0cSsthen return 0;
656d8d14d0cSsthen ns->namelen = len;
657d8d14d0cSsthen ns->name = memdup(name, ns->namelen);
658d8d14d0cSsthen if(!ns->name) {
659d8d14d0cSsthen free(ns);
660d8d14d0cSsthen return 0;
661d8d14d0cSsthen }
662d8d14d0cSsthen ns->next = dp->nslist;
663d8d14d0cSsthen dp->nslist = ns;
6647dd170e2Ssthen ns->cache_lookup_count = 0;
665d8d14d0cSsthen ns->resolved = 0;
666d8d14d0cSsthen ns->got4 = 0;
667d8d14d0cSsthen ns->got6 = 0;
668d8d14d0cSsthen ns->lame = (uint8_t)lame;
669d8d14d0cSsthen ns->done_pside4 = 0;
670d8d14d0cSsthen ns->done_pside6 = 0;
671e21c60efSsthen ns->port = port;
672e21c60efSsthen if(tls_auth_name) {
673e21c60efSsthen ns->tls_auth_name = strdup(tls_auth_name);
674e21c60efSsthen if(!ns->tls_auth_name) {
675e21c60efSsthen free(ns->name);
676e21c60efSsthen free(ns);
677e21c60efSsthen return 0;
678e21c60efSsthen }
679e21c60efSsthen } else {
680e21c60efSsthen ns->tls_auth_name = NULL;
681e21c60efSsthen }
682d8d14d0cSsthen return 1;
683d8d14d0cSsthen }
684d8d14d0cSsthen
delegpt_add_addr_mlc(struct delegpt * dp,struct sockaddr_storage * addr,socklen_t addrlen,uint8_t bogus,uint8_t lame,char * tls_auth_name,int port)685d8d14d0cSsthen int delegpt_add_addr_mlc(struct delegpt* dp, struct sockaddr_storage* addr,
686e21c60efSsthen socklen_t addrlen, uint8_t bogus, uint8_t lame, char* tls_auth_name,
687e21c60efSsthen int port)
688d8d14d0cSsthen {
689d8d14d0cSsthen struct delegpt_addr* a;
690d8d14d0cSsthen log_assert(dp->dp_type_mlc);
691e21c60efSsthen if(port != -1) {
692e21c60efSsthen log_assert(port>0);
693e21c60efSsthen sockaddr_store_port(addr, addrlen, port);
694e21c60efSsthen }
695d8d14d0cSsthen /* check for duplicates */
696d8d14d0cSsthen if((a = delegpt_find_addr(dp, addr, addrlen))) {
697d8d14d0cSsthen if(bogus)
698d8d14d0cSsthen a->bogus = bogus;
699d8d14d0cSsthen if(!lame)
700d8d14d0cSsthen a->lame = 0;
701d8d14d0cSsthen return 1;
702d8d14d0cSsthen }
703d8d14d0cSsthen
704d8d14d0cSsthen a = (struct delegpt_addr*)malloc(sizeof(struct delegpt_addr));
705d8d14d0cSsthen if(!a)
706d8d14d0cSsthen return 0;
707d8d14d0cSsthen a->next_target = dp->target_list;
708d8d14d0cSsthen dp->target_list = a;
709d8d14d0cSsthen a->next_result = 0;
710d8d14d0cSsthen a->next_usable = dp->usable_list;
711d8d14d0cSsthen dp->usable_list = a;
712d8d14d0cSsthen memcpy(&a->addr, addr, addrlen);
713d8d14d0cSsthen a->addrlen = addrlen;
714d8d14d0cSsthen a->attempts = 0;
715d8d14d0cSsthen a->bogus = bogus;
716d8d14d0cSsthen a->lame = lame;
717229e174cSsthen a->dnsseclame = 0;
71820237c55Ssthen if(tls_auth_name) {
71920237c55Ssthen a->tls_auth_name = strdup(tls_auth_name);
72020237c55Ssthen if(!a->tls_auth_name) {
72120237c55Ssthen free(a);
72220237c55Ssthen return 0;
72320237c55Ssthen }
72420237c55Ssthen } else {
72520237c55Ssthen a->tls_auth_name = NULL;
72620237c55Ssthen }
727d8d14d0cSsthen return 1;
728d8d14d0cSsthen }
729d8d14d0cSsthen
delegpt_add_target_mlc(struct delegpt * dp,uint8_t * name,size_t namelen,struct sockaddr_storage * addr,socklen_t addrlen,uint8_t bogus,uint8_t lame)730d8d14d0cSsthen int delegpt_add_target_mlc(struct delegpt* dp, uint8_t* name, size_t namelen,
731229e174cSsthen struct sockaddr_storage* addr, socklen_t addrlen, uint8_t bogus,
732229e174cSsthen uint8_t lame)
733d8d14d0cSsthen {
734d8d14d0cSsthen struct delegpt_ns* ns = delegpt_find_ns(dp, name, namelen);
735d8d14d0cSsthen log_assert(dp->dp_type_mlc);
736d8d14d0cSsthen if(!ns) {
737d8d14d0cSsthen /* ignore it */
738d8d14d0cSsthen return 1;
739d8d14d0cSsthen }
740d8d14d0cSsthen if(!lame) {
741d8d14d0cSsthen if(addr_is_ip6(addr, addrlen))
742d8d14d0cSsthen ns->got6 = 1;
743d8d14d0cSsthen else ns->got4 = 1;
744d8d14d0cSsthen if(ns->got4 && ns->got6)
745d8d14d0cSsthen ns->resolved = 1;
746d1e2768aSsthen } else {
747d1e2768aSsthen if(addr_is_ip6(addr, addrlen))
748d1e2768aSsthen ns->done_pside6 = 1;
749d1e2768aSsthen else ns->done_pside4 = 1;
750d8d14d0cSsthen }
751e21c60efSsthen log_assert(ns->port>0);
752e21c60efSsthen return delegpt_add_addr_mlc(dp, addr, addrlen, bogus, lame,
753e21c60efSsthen ns->tls_auth_name, ns->port);
754d8d14d0cSsthen }
755d8d14d0cSsthen
delegpt_get_mem(struct delegpt * dp)756d8d14d0cSsthen size_t delegpt_get_mem(struct delegpt* dp)
757d8d14d0cSsthen {
758d8d14d0cSsthen struct delegpt_ns* ns;
759d8d14d0cSsthen size_t s;
760d8d14d0cSsthen if(!dp) return 0;
761d8d14d0cSsthen s = sizeof(*dp) + dp->namelen +
762d8d14d0cSsthen delegpt_count_targets(dp)*sizeof(struct delegpt_addr);
763d8d14d0cSsthen for(ns=dp->nslist; ns; ns=ns->next)
764d8d14d0cSsthen s += sizeof(*ns)+ns->namelen;
765d8d14d0cSsthen return s;
766d8d14d0cSsthen }
767