xref: /openbsd-src/usr.sbin/unbound/iterator/iter_delegpt.c (revision 8b7325af55f9372784d083aa385d31c4cebf9890)
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