]>
Commit | Line | Data |
---|---|---|
89c4ed63 A |
1 | /* |
2 | * iterator/iter_delegpt.c - delegation point with NS and address information. | |
3 | * | |
4 | * Copyright (c) 2007, NLnet Labs. All rights reserved. | |
5 | * | |
6 | * This software is open source. | |
7 | * | |
8 | * Redistribution and use in source and binary forms, with or without | |
9 | * modification, are permitted provided that the following conditions | |
10 | * are met: | |
11 | * | |
12 | * Redistributions of source code must retain the above copyright notice, | |
13 | * this list of conditions and the following disclaimer. | |
14 | * | |
15 | * Redistributions in binary form must reproduce the above copyright notice, | |
16 | * this list of conditions and the following disclaimer in the documentation | |
17 | * and/or other materials provided with the distribution. | |
18 | * | |
19 | * Neither the name of the NLNET LABS nor the names of its contributors may | |
20 | * be used to endorse or promote products derived from this software without | |
21 | * specific prior written permission. | |
22 | * | |
23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
24 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
25 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
26 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
27 | * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
28 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED | |
29 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
30 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
31 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
32 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
33 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
34 | */ | |
35 | ||
36 | /** | |
37 | * \file | |
38 | * | |
39 | * This file implements the Delegation Point. It contains a list of name servers | |
40 | * and their addresses if known. | |
41 | */ | |
42 | #include "config.h" | |
43 | #include "iterator/iter_delegpt.h" | |
44 | #include "services/cache/dns.h" | |
45 | #include "util/regional.h" | |
46 | #include "util/data/dname.h" | |
47 | #include "util/data/packed_rrset.h" | |
48 | #include "util/data/msgreply.h" | |
49 | #include "util/net_help.h" | |
50 | #include "ldns/rrdef.h" | |
51 | #include "ldns/sbuffer.h" | |
52 | ||
53 | struct delegpt* | |
54 | delegpt_create(struct regional* region) | |
55 | { | |
56 | struct delegpt* dp=(struct delegpt*)regional_alloc( | |
57 | region, sizeof(*dp)); | |
58 | if(!dp) | |
59 | return NULL; | |
60 | memset(dp, 0, sizeof(*dp)); | |
61 | return dp; | |
62 | } | |
63 | ||
64 | struct delegpt* delegpt_copy(struct delegpt* dp, struct regional* region) | |
65 | { | |
66 | struct delegpt* copy = delegpt_create(region); | |
67 | struct delegpt_ns* ns; | |
68 | struct delegpt_addr* a; | |
69 | if(!copy) | |
70 | return NULL; | |
71 | if(!delegpt_set_name(copy, region, dp->name)) | |
72 | return NULL; | |
73 | copy->bogus = dp->bogus; | |
74 | copy->has_parent_side_NS = dp->has_parent_side_NS; | |
75 | for(ns = dp->nslist; ns; ns = ns->next) { | |
76 | if(!delegpt_add_ns(copy, region, ns->name, ns->lame)) | |
77 | return NULL; | |
78 | copy->nslist->resolved = ns->resolved; | |
79 | copy->nslist->got4 = ns->got4; | |
80 | copy->nslist->got6 = ns->got6; | |
81 | copy->nslist->done_pside4 = ns->done_pside4; | |
82 | copy->nslist->done_pside6 = ns->done_pside6; | |
83 | } | |
84 | for(a = dp->target_list; a; a = a->next_target) { | |
85 | if(!delegpt_add_addr(copy, region, &a->addr, a->addrlen, | |
86 | a->bogus, a->lame)) | |
87 | return NULL; | |
88 | } | |
89 | return copy; | |
90 | } | |
91 | ||
92 | int | |
93 | delegpt_set_name(struct delegpt* dp, struct regional* region, uint8_t* name) | |
94 | { | |
95 | log_assert(!dp->dp_type_mlc); | |
96 | dp->namelabs = dname_count_size_labels(name, &dp->namelen); | |
97 | dp->name = regional_alloc_init(region, name, dp->namelen); | |
98 | return dp->name != 0; | |
99 | } | |
100 | ||
101 | int | |
102 | delegpt_add_ns(struct delegpt* dp, struct regional* region, uint8_t* name, | |
103 | uint8_t lame) | |
104 | { | |
105 | struct delegpt_ns* ns; | |
106 | size_t len; | |
107 | (void)dname_count_size_labels(name, &len); | |
108 | log_assert(!dp->dp_type_mlc); | |
109 | /* slow check for duplicates to avoid counting failures when | |
110 | * adding the same server as a dependency twice */ | |
111 | if(delegpt_find_ns(dp, name, len)) | |
112 | return 1; | |
113 | ns = (struct delegpt_ns*)regional_alloc(region, | |
114 | sizeof(struct delegpt_ns)); | |
115 | if(!ns) | |
116 | return 0; | |
117 | ns->next = dp->nslist; | |
118 | ns->namelen = len; | |
119 | dp->nslist = ns; | |
120 | ns->name = regional_alloc_init(region, name, ns->namelen); | |
121 | ns->resolved = 0; | |
122 | ns->got4 = 0; | |
123 | ns->got6 = 0; | |
124 | ns->lame = lame; | |
125 | ns->done_pside4 = 0; | |
126 | ns->done_pside6 = 0; | |
127 | return ns->name != 0; | |
128 | } | |
129 | ||
130 | struct delegpt_ns* | |
131 | delegpt_find_ns(struct delegpt* dp, uint8_t* name, size_t namelen) | |
132 | { | |
133 | struct delegpt_ns* p = dp->nslist; | |
134 | while(p) { | |
135 | if(namelen == p->namelen && | |
136 | query_dname_compare(name, p->name) == 0) { | |
137 | return p; | |
138 | } | |
139 | p = p->next; | |
140 | } | |
141 | return NULL; | |
142 | } | |
143 | ||
144 | struct delegpt_addr* | |
145 | delegpt_find_addr(struct delegpt* dp, struct sockaddr_storage* addr, | |
146 | socklen_t addrlen) | |
147 | { | |
148 | struct delegpt_addr* p = dp->target_list; | |
149 | while(p) { | |
150 | if(sockaddr_cmp_addr(addr, addrlen, &p->addr, p->addrlen)==0 | |
151 | && ((struct sockaddr_in*)addr)->sin_port == | |
152 | ((struct sockaddr_in*)&p->addr)->sin_port) { | |
153 | return p; | |
154 | } | |
155 | p = p->next_target; | |
156 | } | |
157 | return NULL; | |
158 | } | |
159 | ||
160 | int | |
161 | delegpt_add_target(struct delegpt* dp, struct regional* region, | |
162 | uint8_t* name, size_t namelen, struct sockaddr_storage* addr, | |
163 | socklen_t addrlen, uint8_t bogus, uint8_t lame) | |
164 | { | |
165 | struct delegpt_ns* ns = delegpt_find_ns(dp, name, namelen); | |
166 | log_assert(!dp->dp_type_mlc); | |
167 | if(!ns) { | |
168 | /* ignore it */ | |
169 | return 1; | |
170 | } | |
171 | if(!lame) { | |
172 | if(addr_is_ip6(addr, addrlen)) | |
173 | ns->got6 = 1; | |
174 | else ns->got4 = 1; | |
175 | if(ns->got4 && ns->got6) | |
176 | ns->resolved = 1; | |
177 | } | |
178 | return delegpt_add_addr(dp, region, addr, addrlen, bogus, lame); | |
179 | } | |
180 | ||
181 | int | |
182 | delegpt_add_addr(struct delegpt* dp, struct regional* region, | |
183 | struct sockaddr_storage* addr, socklen_t addrlen, uint8_t bogus, | |
184 | uint8_t lame) | |
185 | { | |
186 | struct delegpt_addr* a; | |
187 | log_assert(!dp->dp_type_mlc); | |
188 | /* check for duplicates */ | |
189 | if((a = delegpt_find_addr(dp, addr, addrlen))) { | |
190 | if(bogus) | |
191 | a->bogus = bogus; | |
192 | if(!lame) | |
193 | a->lame = 0; | |
194 | return 1; | |
195 | } | |
196 | ||
197 | a = (struct delegpt_addr*)regional_alloc(region, | |
198 | sizeof(struct delegpt_addr)); | |
199 | if(!a) | |
200 | return 0; | |
201 | a->next_target = dp->target_list; | |
202 | dp->target_list = a; | |
203 | a->next_result = 0; | |
204 | a->next_usable = dp->usable_list; | |
205 | dp->usable_list = a; | |
206 | memcpy(&a->addr, addr, addrlen); | |
207 | a->addrlen = addrlen; | |
208 | a->attempts = 0; | |
209 | a->bogus = bogus; | |
210 | a->lame = lame; | |
211 | a->dnsseclame = 0; | |
212 | return 1; | |
213 | } | |
214 | ||
215 | void | |
216 | delegpt_count_ns(struct delegpt* dp, size_t* numns, size_t* missing) | |
217 | { | |
218 | struct delegpt_ns* ns; | |
219 | *numns = 0; | |
220 | *missing = 0; | |
221 | for(ns = dp->nslist; ns; ns = ns->next) { | |
222 | (*numns)++; | |
223 | if(!ns->resolved) | |
224 | (*missing)++; | |
225 | } | |
226 | } | |
227 | ||
228 | void | |
229 | delegpt_count_addr(struct delegpt* dp, size_t* numaddr, size_t* numres, | |
230 | size_t* numavail) | |
231 | { | |
232 | struct delegpt_addr* a; | |
233 | *numaddr = 0; | |
234 | *numres = 0; | |
235 | *numavail = 0; | |
236 | for(a = dp->target_list; a; a = a->next_target) { | |
237 | (*numaddr)++; | |
238 | } | |
239 | for(a = dp->result_list; a; a = a->next_result) { | |
240 | (*numres)++; | |
241 | } | |
242 | for(a = dp->usable_list; a; a = a->next_usable) { | |
243 | (*numavail)++; | |
244 | } | |
245 | } | |
246 | ||
247 | void delegpt_log(enum verbosity_value v, struct delegpt* dp) | |
248 | { | |
249 | char buf[LDNS_MAX_DOMAINLEN+1]; | |
250 | struct delegpt_ns* ns; | |
251 | struct delegpt_addr* a; | |
252 | size_t missing=0, numns=0, numaddr=0, numres=0, numavail=0; | |
253 | if(verbosity < v) | |
254 | return; | |
255 | dname_str(dp->name, buf); | |
256 | if(dp->nslist == NULL && dp->target_list == NULL) { | |
257 | log_info("DelegationPoint<%s>: empty", buf); | |
258 | return; | |
259 | } | |
260 | delegpt_count_ns(dp, &numns, &missing); | |
261 | delegpt_count_addr(dp, &numaddr, &numres, &numavail); | |
262 | log_info("DelegationPoint<%s>: %u names (%u missing), " | |
263 | "%u addrs (%u result, %u avail)%s", | |
264 | buf, (unsigned)numns, (unsigned)missing, | |
265 | (unsigned)numaddr, (unsigned)numres, (unsigned)numavail, | |
266 | (dp->has_parent_side_NS?" parentNS":" cacheNS")); | |
267 | if(verbosity >= VERB_ALGO) { | |
268 | for(ns = dp->nslist; ns; ns = ns->next) { | |
269 | dname_str(ns->name, buf); | |
270 | log_info(" %s %s%s%s%s%s%s%s", buf, | |
271 | (ns->resolved?"*":""), | |
272 | (ns->got4?" A":""), (ns->got6?" AAAA":""), | |
273 | (dp->bogus?" BOGUS":""), (ns->lame?" PARENTSIDE":""), | |
274 | (ns->done_pside4?" PSIDE_A":""), | |
275 | (ns->done_pside6?" PSIDE_AAAA":"")); | |
276 | } | |
277 | for(a = dp->target_list; a; a = a->next_target) { | |
278 | const char* str = " "; | |
279 | if(a->bogus && a->lame) str = " BOGUS ADDR_LAME "; | |
280 | else if(a->bogus) str = " BOGUS "; | |
281 | else if(a->lame) str = " ADDR_LAME "; | |
282 | log_addr(VERB_ALGO, str, &a->addr, a->addrlen); | |
283 | } | |
284 | } | |
285 | } | |
286 | ||
287 | void | |
288 | delegpt_add_unused_targets(struct delegpt* dp) | |
289 | { | |
290 | struct delegpt_addr* usa = dp->usable_list; | |
291 | dp->usable_list = NULL; | |
292 | while(usa) { | |
293 | usa->next_result = dp->result_list; | |
294 | dp->result_list = usa; | |
295 | usa = usa->next_usable; | |
296 | } | |
297 | } | |
298 | ||
299 | size_t | |
300 | delegpt_count_targets(struct delegpt* dp) | |
301 | { | |
302 | struct delegpt_addr* a; | |
303 | size_t n = 0; | |
304 | for(a = dp->target_list; a; a = a->next_target) | |
305 | n++; | |
306 | return n; | |
307 | } | |
308 | ||
309 | size_t | |
310 | delegpt_count_missing_targets(struct delegpt* dp) | |
311 | { | |
312 | struct delegpt_ns* ns; | |
313 | size_t n = 0; | |
314 | for(ns = dp->nslist; ns; ns = ns->next) | |
315 | if(!ns->resolved) | |
316 | n++; | |
317 | return n; | |
318 | } | |
319 | ||
320 | /** find NS rrset in given list */ | |
321 | static struct ub_packed_rrset_key* | |
322 | find_NS(struct reply_info* rep, size_t from, size_t to) | |
323 | { | |
324 | size_t i; | |
325 | for(i=from; i<to; i++) { | |
326 | if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_NS) | |
327 | return rep->rrsets[i]; | |
328 | } | |
329 | return NULL; | |
330 | } | |
331 | ||
332 | struct delegpt* | |
333 | delegpt_from_message(struct dns_msg* msg, struct regional* region) | |
334 | { | |
335 | struct ub_packed_rrset_key* ns_rrset = NULL; | |
336 | struct delegpt* dp; | |
337 | size_t i; | |
338 | /* look for NS records in the authority section... */ | |
339 | ns_rrset = find_NS(msg->rep, msg->rep->an_numrrsets, | |
340 | msg->rep->an_numrrsets+msg->rep->ns_numrrsets); | |
341 | ||
342 | /* In some cases (even legitimate, perfectly legal cases), the | |
343 | * NS set for the "referral" might be in the answer section. */ | |
344 | if(!ns_rrset) | |
345 | ns_rrset = find_NS(msg->rep, 0, msg->rep->an_numrrsets); | |
346 | ||
347 | /* If there was no NS rrset in the authority section, then this | |
348 | * wasn't a referral message. (It might not actually be a | |
349 | * referral message anyway) */ | |
350 | if(!ns_rrset) | |
351 | return NULL; | |
352 | ||
353 | /* If we found any, then Yay! we have a delegation point. */ | |
354 | dp = delegpt_create(region); | |
355 | if(!dp) | |
356 | return NULL; | |
357 | dp->has_parent_side_NS = 1; /* created from message */ | |
358 | if(!delegpt_set_name(dp, region, ns_rrset->rk.dname)) | |
359 | return NULL; | |
360 | if(!delegpt_rrset_add_ns(dp, region, ns_rrset, 0)) | |
361 | return NULL; | |
362 | ||
363 | /* add glue, A and AAAA in answer and additional section */ | |
364 | for(i=0; i<msg->rep->rrset_count; i++) { | |
365 | struct ub_packed_rrset_key* s = msg->rep->rrsets[i]; | |
366 | /* skip auth section. FIXME really needed?*/ | |
367 | if(msg->rep->an_numrrsets <= i && | |
368 | i < (msg->rep->an_numrrsets+msg->rep->ns_numrrsets)) | |
369 | continue; | |
370 | ||
371 | if(ntohs(s->rk.type) == LDNS_RR_TYPE_A) { | |
372 | if(!delegpt_add_rrset_A(dp, region, s, 0)) | |
373 | return NULL; | |
374 | } else if(ntohs(s->rk.type) == LDNS_RR_TYPE_AAAA) { | |
375 | if(!delegpt_add_rrset_AAAA(dp, region, s, 0)) | |
376 | return NULL; | |
377 | } | |
378 | } | |
379 | return dp; | |
380 | } | |
381 | ||
382 | int | |
383 | delegpt_rrset_add_ns(struct delegpt* dp, struct regional* region, | |
384 | struct ub_packed_rrset_key* ns_rrset, uint8_t lame) | |
385 | { | |
386 | struct packed_rrset_data* nsdata = (struct packed_rrset_data*) | |
387 | ns_rrset->entry.data; | |
388 | size_t i; | |
389 | log_assert(!dp->dp_type_mlc); | |
390 | if(nsdata->security == sec_status_bogus) | |
391 | dp->bogus = 1; | |
392 | for(i=0; i<nsdata->count; i++) { | |
393 | if(nsdata->rr_len[i] < 2+1) continue; /* len + root label */ | |
394 | if(dname_valid(nsdata->rr_data[i]+2, nsdata->rr_len[i]-2) != | |
395 | (size_t)sldns_read_uint16(nsdata->rr_data[i])) | |
396 | continue; /* bad format */ | |
397 | /* add rdata of NS (= wirefmt dname), skip rdatalen bytes */ | |
398 | if(!delegpt_add_ns(dp, region, nsdata->rr_data[i]+2, lame)) | |
399 | return 0; | |
400 | } | |
401 | return 1; | |
402 | } | |
403 | ||
404 | int | |
405 | delegpt_add_rrset_A(struct delegpt* dp, struct regional* region, | |
406 | struct ub_packed_rrset_key* ak, uint8_t lame) | |
407 | { | |
408 | struct packed_rrset_data* d=(struct packed_rrset_data*)ak->entry.data; | |
409 | size_t i; | |
410 | struct sockaddr_in sa; | |
411 | socklen_t len = (socklen_t)sizeof(sa); | |
412 | log_assert(!dp->dp_type_mlc); | |
413 | memset(&sa, 0, len); | |
414 | sa.sin_family = AF_INET; | |
415 | sa.sin_port = (in_port_t)htons(UNBOUND_DNS_PORT); | |
416 | for(i=0; i<d->count; i++) { | |
417 | if(d->rr_len[i] != 2 + INET_SIZE) | |
418 | continue; | |
419 | memmove(&sa.sin_addr, d->rr_data[i]+2, INET_SIZE); | |
420 | if(!delegpt_add_target(dp, region, ak->rk.dname, | |
421 | ak->rk.dname_len, (struct sockaddr_storage*)&sa, | |
422 | len, (d->security==sec_status_bogus), lame)) | |
423 | return 0; | |
424 | } | |
425 | return 1; | |
426 | } | |
427 | ||
428 | int | |
429 | delegpt_add_rrset_AAAA(struct delegpt* dp, struct regional* region, | |
430 | struct ub_packed_rrset_key* ak, uint8_t lame) | |
431 | { | |
432 | struct packed_rrset_data* d=(struct packed_rrset_data*)ak->entry.data; | |
433 | size_t i; | |
434 | struct sockaddr_in6 sa; | |
435 | socklen_t len = (socklen_t)sizeof(sa); | |
436 | log_assert(!dp->dp_type_mlc); | |
437 | memset(&sa, 0, len); | |
438 | sa.sin6_family = AF_INET6; | |
439 | sa.sin6_port = (in_port_t)htons(UNBOUND_DNS_PORT); | |
440 | for(i=0; i<d->count; i++) { | |
441 | if(d->rr_len[i] != 2 + INET6_SIZE) /* rdatalen + len of IP6 */ | |
442 | continue; | |
443 | memmove(&sa.sin6_addr, d->rr_data[i]+2, INET6_SIZE); | |
444 | if(!delegpt_add_target(dp, region, ak->rk.dname, | |
445 | ak->rk.dname_len, (struct sockaddr_storage*)&sa, | |
446 | len, (d->security==sec_status_bogus), lame)) | |
447 | return 0; | |
448 | } | |
449 | return 1; | |
450 | } | |
451 | ||
452 | int | |
453 | delegpt_add_rrset(struct delegpt* dp, struct regional* region, | |
454 | struct ub_packed_rrset_key* rrset, uint8_t lame) | |
455 | { | |
456 | if(!rrset) | |
457 | return 1; | |
458 | if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_NS) | |
459 | return delegpt_rrset_add_ns(dp, region, rrset, lame); | |
460 | else if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_A) | |
461 | return delegpt_add_rrset_A(dp, region, rrset, lame); | |
462 | else if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_AAAA) | |
463 | return delegpt_add_rrset_AAAA(dp, region, rrset, lame); | |
464 | log_warn("Unknown rrset type added to delegpt"); | |
465 | return 1; | |
466 | } | |
467 | ||
468 | void delegpt_add_neg_msg(struct delegpt* dp, struct msgreply_entry* msg) | |
469 | { | |
470 | struct reply_info* rep = (struct reply_info*)msg->entry.data; | |
471 | if(!rep) return; | |
472 | ||
473 | /* if error or no answers */ | |
474 | if(FLAGS_GET_RCODE(rep->flags) != 0 || rep->an_numrrsets == 0) { | |
475 | struct delegpt_ns* ns = delegpt_find_ns(dp, msg->key.qname, | |
476 | msg->key.qname_len); | |
477 | if(ns) { | |
478 | if(msg->key.qtype == LDNS_RR_TYPE_A) | |
479 | ns->got4 = 1; | |
480 | else if(msg->key.qtype == LDNS_RR_TYPE_AAAA) | |
481 | ns->got6 = 1; | |
482 | if(ns->got4 && ns->got6) | |
483 | ns->resolved = 1; | |
484 | } | |
485 | } | |
486 | } | |
487 | ||
488 | void delegpt_no_ipv6(struct delegpt* dp) | |
489 | { | |
490 | struct delegpt_ns* ns; | |
491 | for(ns = dp->nslist; ns; ns = ns->next) { | |
492 | /* no ipv6, so only ipv4 is enough to resolve a nameserver */ | |
493 | if(ns->got4) | |
494 | ns->resolved = 1; | |
495 | } | |
496 | } | |
497 | ||
498 | void delegpt_no_ipv4(struct delegpt* dp) | |
499 | { | |
500 | struct delegpt_ns* ns; | |
501 | for(ns = dp->nslist; ns; ns = ns->next) { | |
502 | /* no ipv4, so only ipv6 is enough to resolve a nameserver */ | |
503 | if(ns->got6) | |
504 | ns->resolved = 1; | |
505 | } | |
506 | } | |
507 | ||
508 | struct delegpt* delegpt_create_mlc(uint8_t* name) | |
509 | { | |
510 | struct delegpt* dp=(struct delegpt*)calloc(1, sizeof(*dp)); | |
511 | if(!dp) | |
512 | return NULL; | |
513 | dp->dp_type_mlc = 1; | |
514 | if(name) { | |
515 | dp->namelabs = dname_count_size_labels(name, &dp->namelen); | |
516 | dp->name = memdup(name, dp->namelen); | |
517 | if(!dp->name) { | |
518 | free(dp); | |
519 | return NULL; | |
520 | } | |
521 | } | |
522 | return dp; | |
523 | } | |
524 | ||
525 | void delegpt_free_mlc(struct delegpt* dp) | |
526 | { | |
527 | struct delegpt_ns* n, *nn; | |
528 | struct delegpt_addr* a, *na; | |
529 | if(!dp) return; | |
530 | log_assert(dp->dp_type_mlc); | |
531 | n = dp->nslist; | |
532 | while(n) { | |
533 | nn = n->next; | |
534 | free(n->name); | |
535 | free(n); | |
536 | n = nn; | |
537 | } | |
538 | a = dp->target_list; | |
539 | while(a) { | |
540 | na = a->next_target; | |
541 | free(a); | |
542 | a = na; | |
543 | } | |
544 | free(dp->name); | |
545 | free(dp); | |
546 | } | |
547 | ||
548 | int delegpt_set_name_mlc(struct delegpt* dp, uint8_t* name) | |
549 | { | |
550 | log_assert(dp->dp_type_mlc); | |
551 | dp->namelabs = dname_count_size_labels(name, &dp->namelen); | |
552 | dp->name = memdup(name, dp->namelen); | |
553 | return (dp->name != NULL); | |
554 | } | |
555 | ||
556 | int delegpt_add_ns_mlc(struct delegpt* dp, uint8_t* name, uint8_t lame) | |
557 | { | |
558 | struct delegpt_ns* ns; | |
559 | size_t len; | |
560 | (void)dname_count_size_labels(name, &len); | |
561 | log_assert(dp->dp_type_mlc); | |
562 | /* slow check for duplicates to avoid counting failures when | |
563 | * adding the same server as a dependency twice */ | |
564 | if(delegpt_find_ns(dp, name, len)) | |
565 | return 1; | |
566 | ns = (struct delegpt_ns*)malloc(sizeof(struct delegpt_ns)); | |
567 | if(!ns) | |
568 | return 0; | |
569 | ns->namelen = len; | |
570 | ns->name = memdup(name, ns->namelen); | |
571 | if(!ns->name) { | |
572 | free(ns); | |
573 | return 0; | |
574 | } | |
575 | ns->next = dp->nslist; | |
576 | dp->nslist = ns; | |
577 | ns->resolved = 0; | |
578 | ns->got4 = 0; | |
579 | ns->got6 = 0; | |
580 | ns->lame = (uint8_t)lame; | |
581 | ns->done_pside4 = 0; | |
582 | ns->done_pside6 = 0; | |
583 | return 1; | |
584 | } | |
585 | ||
586 | int delegpt_add_addr_mlc(struct delegpt* dp, struct sockaddr_storage* addr, | |
587 | socklen_t addrlen, uint8_t bogus, uint8_t lame) | |
588 | { | |
589 | struct delegpt_addr* a; | |
590 | log_assert(dp->dp_type_mlc); | |
591 | /* check for duplicates */ | |
592 | if((a = delegpt_find_addr(dp, addr, addrlen))) { | |
593 | if(bogus) | |
594 | a->bogus = bogus; | |
595 | if(!lame) | |
596 | a->lame = 0; | |
597 | return 1; | |
598 | } | |
599 | ||
600 | a = (struct delegpt_addr*)malloc(sizeof(struct delegpt_addr)); | |
601 | if(!a) | |
602 | return 0; | |
603 | a->next_target = dp->target_list; | |
604 | dp->target_list = a; | |
605 | a->next_result = 0; | |
606 | a->next_usable = dp->usable_list; | |
607 | dp->usable_list = a; | |
608 | memcpy(&a->addr, addr, addrlen); | |
609 | a->addrlen = addrlen; | |
610 | a->attempts = 0; | |
611 | a->bogus = bogus; | |
612 | a->lame = lame; | |
613 | a->dnsseclame = 0; | |
614 | return 1; | |
615 | } | |
616 | ||
617 | int delegpt_add_target_mlc(struct delegpt* dp, uint8_t* name, size_t namelen, | |
618 | struct sockaddr_storage* addr, socklen_t addrlen, uint8_t bogus, | |
619 | uint8_t lame) | |
620 | { | |
621 | struct delegpt_ns* ns = delegpt_find_ns(dp, name, namelen); | |
622 | log_assert(dp->dp_type_mlc); | |
623 | if(!ns) { | |
624 | /* ignore it */ | |
625 | return 1; | |
626 | } | |
627 | if(!lame) { | |
628 | if(addr_is_ip6(addr, addrlen)) | |
629 | ns->got6 = 1; | |
630 | else ns->got4 = 1; | |
631 | if(ns->got4 && ns->got6) | |
632 | ns->resolved = 1; | |
633 | } | |
634 | return delegpt_add_addr_mlc(dp, addr, addrlen, bogus, lame); | |
635 | } | |
636 | ||
637 | size_t delegpt_get_mem(struct delegpt* dp) | |
638 | { | |
639 | struct delegpt_ns* ns; | |
640 | size_t s; | |
641 | if(!dp) return 0; | |
642 | s = sizeof(*dp) + dp->namelen + | |
643 | delegpt_count_targets(dp)*sizeof(struct delegpt_addr); | |
644 | for(ns=dp->nslist; ns; ns=ns->next) | |
645 | s += sizeof(*ns)+ns->namelen; | |
646 | return s; | |
647 | } |