/src/unbound/iterator/iter_delegpt.c
Line | Count | Source (jump to first uncovered line) |
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 "sldns/rrdef.h" |
51 | | #include "sldns/sbuffer.h" |
52 | | |
53 | | struct delegpt* |
54 | | delegpt_create(struct regional* region) |
55 | 0 | { |
56 | 0 | struct delegpt* dp=(struct delegpt*)regional_alloc( |
57 | 0 | region, sizeof(*dp)); |
58 | 0 | if(!dp) |
59 | 0 | return NULL; |
60 | 0 | memset(dp, 0, sizeof(*dp)); |
61 | 0 | return dp; |
62 | 0 | } |
63 | | |
64 | | struct delegpt* delegpt_copy(struct delegpt* dp, struct regional* region) |
65 | 0 | { |
66 | 0 | struct delegpt* copy = delegpt_create(region); |
67 | 0 | struct delegpt_ns* ns; |
68 | 0 | struct delegpt_addr* a; |
69 | 0 | if(!copy) |
70 | 0 | return NULL; |
71 | 0 | if(!delegpt_set_name(copy, region, dp->name)) |
72 | 0 | return NULL; |
73 | 0 | copy->bogus = dp->bogus; |
74 | 0 | copy->has_parent_side_NS = dp->has_parent_side_NS; |
75 | 0 | copy->ssl_upstream = dp->ssl_upstream; |
76 | 0 | copy->tcp_upstream = dp->tcp_upstream; |
77 | 0 | for(ns = dp->nslist; ns; ns = ns->next) { |
78 | 0 | if(!delegpt_add_ns(copy, region, ns->name, ns->lame, |
79 | 0 | ns->tls_auth_name, ns->port)) |
80 | 0 | return NULL; |
81 | 0 | copy->nslist->cache_lookup_count = ns->cache_lookup_count; |
82 | 0 | copy->nslist->resolved = ns->resolved; |
83 | 0 | copy->nslist->got4 = ns->got4; |
84 | 0 | copy->nslist->got6 = ns->got6; |
85 | 0 | copy->nslist->done_pside4 = ns->done_pside4; |
86 | 0 | copy->nslist->done_pside6 = ns->done_pside6; |
87 | 0 | } |
88 | 0 | for(a = dp->target_list; a; a = a->next_target) { |
89 | 0 | if(!delegpt_add_addr(copy, region, &a->addr, a->addrlen, |
90 | 0 | a->bogus, a->lame, a->tls_auth_name, -1, NULL)) |
91 | 0 | return NULL; |
92 | 0 | } |
93 | 0 | return copy; |
94 | 0 | } |
95 | | |
96 | | int |
97 | | delegpt_set_name(struct delegpt* dp, struct regional* region, uint8_t* name) |
98 | 0 | { |
99 | 0 | log_assert(!dp->dp_type_mlc); |
100 | 0 | dp->namelabs = dname_count_size_labels(name, &dp->namelen); |
101 | 0 | dp->name = regional_alloc_init(region, name, dp->namelen); |
102 | 0 | return dp->name != 0; |
103 | 0 | } |
104 | | |
105 | | int |
106 | | delegpt_add_ns(struct delegpt* dp, struct regional* region, uint8_t* name, |
107 | | uint8_t lame, char* tls_auth_name, int port) |
108 | 0 | { |
109 | 0 | struct delegpt_ns* ns; |
110 | 0 | size_t len; |
111 | 0 | (void)dname_count_size_labels(name, &len); |
112 | 0 | log_assert(!dp->dp_type_mlc); |
113 | | /* slow check for duplicates to avoid counting failures when |
114 | | * adding the same server as a dependency twice */ |
115 | 0 | if(delegpt_find_ns(dp, name, len)) |
116 | 0 | return 1; |
117 | 0 | ns = (struct delegpt_ns*)regional_alloc(region, |
118 | 0 | sizeof(struct delegpt_ns)); |
119 | 0 | if(!ns) |
120 | 0 | return 0; |
121 | 0 | ns->next = dp->nslist; |
122 | 0 | ns->namelen = len; |
123 | 0 | dp->nslist = ns; |
124 | 0 | ns->name = regional_alloc_init(region, name, ns->namelen); |
125 | 0 | ns->cache_lookup_count = 0; |
126 | 0 | ns->resolved = 0; |
127 | 0 | ns->got4 = 0; |
128 | 0 | ns->got6 = 0; |
129 | 0 | ns->lame = lame; |
130 | 0 | ns->done_pside4 = 0; |
131 | 0 | ns->done_pside6 = 0; |
132 | 0 | ns->port = port; |
133 | 0 | if(tls_auth_name) { |
134 | 0 | ns->tls_auth_name = regional_strdup(region, tls_auth_name); |
135 | 0 | if(!ns->tls_auth_name) |
136 | 0 | return 0; |
137 | 0 | } else { |
138 | 0 | ns->tls_auth_name = NULL; |
139 | 0 | } |
140 | 0 | return ns->name != 0; |
141 | 0 | } |
142 | | |
143 | | struct delegpt_ns* |
144 | | delegpt_find_ns(struct delegpt* dp, uint8_t* name, size_t namelen) |
145 | 0 | { |
146 | 0 | struct delegpt_ns* p = dp->nslist; |
147 | 0 | while(p) { |
148 | 0 | if(namelen == p->namelen && |
149 | 0 | query_dname_compare(name, p->name) == 0) { |
150 | 0 | return p; |
151 | 0 | } |
152 | 0 | p = p->next; |
153 | 0 | } |
154 | 0 | return NULL; |
155 | 0 | } |
156 | | |
157 | | struct delegpt_addr* |
158 | | delegpt_find_addr(struct delegpt* dp, struct sockaddr_storage* addr, |
159 | | socklen_t addrlen) |
160 | 0 | { |
161 | 0 | struct delegpt_addr* p = dp->target_list; |
162 | 0 | while(p) { |
163 | 0 | if(sockaddr_cmp_addr(addr, addrlen, &p->addr, p->addrlen)==0 |
164 | 0 | && ((struct sockaddr_in*)addr)->sin_port == |
165 | 0 | ((struct sockaddr_in*)&p->addr)->sin_port) { |
166 | 0 | return p; |
167 | 0 | } |
168 | 0 | p = p->next_target; |
169 | 0 | } |
170 | 0 | return NULL; |
171 | 0 | } |
172 | | |
173 | | int |
174 | | delegpt_add_target(struct delegpt* dp, struct regional* region, |
175 | | uint8_t* name, size_t namelen, struct sockaddr_storage* addr, |
176 | | socklen_t addrlen, uint8_t bogus, uint8_t lame, int* additions) |
177 | 0 | { |
178 | 0 | struct delegpt_ns* ns = delegpt_find_ns(dp, name, namelen); |
179 | 0 | log_assert(!dp->dp_type_mlc); |
180 | 0 | if(!ns) { |
181 | | /* ignore it */ |
182 | 0 | return 1; |
183 | 0 | } |
184 | 0 | if(!lame) { |
185 | 0 | if(addr_is_ip6(addr, addrlen)) |
186 | 0 | ns->got6 = 1; |
187 | 0 | else ns->got4 = 1; |
188 | 0 | if(ns->got4 && ns->got6) |
189 | 0 | ns->resolved = 1; |
190 | 0 | } else { |
191 | 0 | if(addr_is_ip6(addr, addrlen)) |
192 | 0 | ns->done_pside6 = 1; |
193 | 0 | else ns->done_pside4 = 1; |
194 | 0 | } |
195 | 0 | log_assert(ns->port>0); |
196 | 0 | return delegpt_add_addr(dp, region, addr, addrlen, bogus, lame, |
197 | 0 | ns->tls_auth_name, ns->port, additions); |
198 | 0 | } |
199 | | |
200 | | int |
201 | | delegpt_add_addr(struct delegpt* dp, struct regional* region, |
202 | | struct sockaddr_storage* addr, socklen_t addrlen, uint8_t bogus, |
203 | | uint8_t lame, char* tls_auth_name, int port, int* additions) |
204 | 0 | { |
205 | 0 | struct delegpt_addr* a; |
206 | 0 | log_assert(!dp->dp_type_mlc); |
207 | 0 | if(port != -1) { |
208 | 0 | log_assert(port>0); |
209 | 0 | sockaddr_store_port(addr, addrlen, port); |
210 | 0 | } |
211 | | /* check for duplicates */ |
212 | 0 | if((a = delegpt_find_addr(dp, addr, addrlen))) { |
213 | 0 | if(bogus) |
214 | 0 | a->bogus = bogus; |
215 | 0 | if(!lame) |
216 | 0 | a->lame = 0; |
217 | 0 | return 1; |
218 | 0 | } |
219 | 0 | if(additions) |
220 | 0 | *additions = 1; |
221 | |
|
222 | 0 | a = (struct delegpt_addr*)regional_alloc(region, |
223 | 0 | sizeof(struct delegpt_addr)); |
224 | 0 | if(!a) |
225 | 0 | return 0; |
226 | 0 | a->next_target = dp->target_list; |
227 | 0 | dp->target_list = a; |
228 | 0 | a->next_result = 0; |
229 | 0 | a->next_usable = dp->usable_list; |
230 | 0 | dp->usable_list = a; |
231 | 0 | memcpy(&a->addr, addr, addrlen); |
232 | 0 | a->addrlen = addrlen; |
233 | 0 | a->attempts = 0; |
234 | 0 | a->bogus = bogus; |
235 | 0 | a->lame = lame; |
236 | 0 | a->dnsseclame = 0; |
237 | 0 | if(tls_auth_name) { |
238 | 0 | a->tls_auth_name = regional_strdup(region, tls_auth_name); |
239 | 0 | if(!a->tls_auth_name) |
240 | 0 | return 0; |
241 | 0 | } else { |
242 | 0 | a->tls_auth_name = NULL; |
243 | 0 | } |
244 | 0 | return 1; |
245 | 0 | } |
246 | | |
247 | | void |
248 | | delegpt_count_ns(struct delegpt* dp, size_t* numns, size_t* missing) |
249 | 0 | { |
250 | 0 | struct delegpt_ns* ns; |
251 | 0 | *numns = 0; |
252 | 0 | *missing = 0; |
253 | 0 | for(ns = dp->nslist; ns; ns = ns->next) { |
254 | 0 | (*numns)++; |
255 | 0 | if(!ns->resolved) |
256 | 0 | (*missing)++; |
257 | 0 | } |
258 | 0 | } |
259 | | |
260 | | void |
261 | | delegpt_count_addr(struct delegpt* dp, size_t* numaddr, size_t* numres, |
262 | | size_t* numavail) |
263 | 0 | { |
264 | 0 | struct delegpt_addr* a; |
265 | 0 | *numaddr = 0; |
266 | 0 | *numres = 0; |
267 | 0 | *numavail = 0; |
268 | 0 | for(a = dp->target_list; a; a = a->next_target) { |
269 | 0 | (*numaddr)++; |
270 | 0 | } |
271 | 0 | for(a = dp->result_list; a; a = a->next_result) { |
272 | 0 | (*numres)++; |
273 | 0 | } |
274 | 0 | for(a = dp->usable_list; a; a = a->next_usable) { |
275 | 0 | (*numavail)++; |
276 | 0 | } |
277 | 0 | } |
278 | | |
279 | | void delegpt_log(enum verbosity_value v, struct delegpt* dp) |
280 | 0 | { |
281 | 0 | char buf[LDNS_MAX_DOMAINLEN]; |
282 | 0 | struct delegpt_ns* ns; |
283 | 0 | struct delegpt_addr* a; |
284 | 0 | size_t missing=0, numns=0, numaddr=0, numres=0, numavail=0; |
285 | 0 | if(verbosity < v) |
286 | 0 | return; |
287 | 0 | dname_str(dp->name, buf); |
288 | 0 | if(dp->nslist == NULL && dp->target_list == NULL) { |
289 | 0 | log_info("DelegationPoint<%s>: empty", buf); |
290 | 0 | return; |
291 | 0 | } |
292 | 0 | delegpt_count_ns(dp, &numns, &missing); |
293 | 0 | delegpt_count_addr(dp, &numaddr, &numres, &numavail); |
294 | 0 | log_info("DelegationPoint<%s>: %u names (%u missing), " |
295 | 0 | "%u addrs (%u result, %u avail)%s", |
296 | 0 | buf, (unsigned)numns, (unsigned)missing, |
297 | 0 | (unsigned)numaddr, (unsigned)numres, (unsigned)numavail, |
298 | 0 | (dp->has_parent_side_NS?" parentNS":" cacheNS")); |
299 | 0 | if(verbosity >= VERB_ALGO) { |
300 | 0 | for(ns = dp->nslist; ns; ns = ns->next) { |
301 | 0 | dname_str(ns->name, buf); |
302 | 0 | log_info(" %s %s%s%s%s%s%s%s", buf, |
303 | 0 | (ns->resolved?"*":""), |
304 | 0 | (ns->got4?" A":""), (ns->got6?" AAAA":""), |
305 | 0 | (dp->bogus?" BOGUS":""), (ns->lame?" PARENTSIDE":""), |
306 | 0 | (ns->done_pside4?" PSIDE_A":""), |
307 | 0 | (ns->done_pside6?" PSIDE_AAAA":"")); |
308 | 0 | } |
309 | 0 | for(a = dp->target_list; a; a = a->next_target) { |
310 | 0 | char s[128]; |
311 | 0 | const char* str = " "; |
312 | 0 | if(a->bogus && a->lame) str = " BOGUS ADDR_LAME "; |
313 | 0 | else if(a->bogus) str = " BOGUS "; |
314 | 0 | else if(a->lame) str = " ADDR_LAME "; |
315 | 0 | if(a->tls_auth_name) |
316 | 0 | snprintf(s, sizeof(s), "%s[%s]", str, |
317 | 0 | a->tls_auth_name); |
318 | 0 | else snprintf(s, sizeof(s), "%s", str); |
319 | 0 | log_addr(VERB_ALGO, s, &a->addr, a->addrlen); |
320 | 0 | } |
321 | 0 | } |
322 | 0 | } |
323 | | |
324 | | int |
325 | | delegpt_addr_on_result_list(struct delegpt* dp, struct delegpt_addr* find) |
326 | 0 | { |
327 | 0 | struct delegpt_addr* a = dp->result_list; |
328 | 0 | while(a) { |
329 | 0 | if(a == find) |
330 | 0 | return 1; |
331 | 0 | a = a->next_result; |
332 | 0 | } |
333 | 0 | return 0; |
334 | 0 | } |
335 | | |
336 | | void |
337 | | delegpt_usable_list_remove_addr(struct delegpt* dp, struct delegpt_addr* del) |
338 | 0 | { |
339 | 0 | struct delegpt_addr* usa = dp->usable_list, *prev = NULL; |
340 | 0 | while(usa) { |
341 | 0 | if(usa == del) { |
342 | | /* snip off the usable list */ |
343 | 0 | if(prev) |
344 | 0 | prev->next_usable = usa->next_usable; |
345 | 0 | else dp->usable_list = usa->next_usable; |
346 | 0 | return; |
347 | 0 | } |
348 | 0 | prev = usa; |
349 | 0 | usa = usa->next_usable; |
350 | 0 | } |
351 | 0 | } |
352 | | |
353 | | void |
354 | | delegpt_add_to_result_list(struct delegpt* dp, struct delegpt_addr* a) |
355 | 0 | { |
356 | 0 | if(delegpt_addr_on_result_list(dp, a)) |
357 | 0 | return; |
358 | 0 | delegpt_usable_list_remove_addr(dp, a); |
359 | 0 | a->next_result = dp->result_list; |
360 | 0 | dp->result_list = a; |
361 | 0 | } |
362 | | |
363 | | void |
364 | | delegpt_add_unused_targets(struct delegpt* dp) |
365 | 0 | { |
366 | 0 | struct delegpt_addr* usa = dp->usable_list; |
367 | 0 | dp->usable_list = NULL; |
368 | 0 | while(usa) { |
369 | 0 | usa->next_result = dp->result_list; |
370 | 0 | dp->result_list = usa; |
371 | 0 | usa = usa->next_usable; |
372 | 0 | } |
373 | 0 | } |
374 | | |
375 | | size_t |
376 | | delegpt_count_targets(struct delegpt* dp) |
377 | 0 | { |
378 | 0 | struct delegpt_addr* a; |
379 | 0 | size_t n = 0; |
380 | 0 | for(a = dp->target_list; a; a = a->next_target) |
381 | 0 | n++; |
382 | 0 | return n; |
383 | 0 | } |
384 | | |
385 | | size_t |
386 | | delegpt_count_missing_targets(struct delegpt* dp, int* alllame) |
387 | 0 | { |
388 | 0 | struct delegpt_ns* ns; |
389 | 0 | size_t n = 0, nlame = 0; |
390 | 0 | for(ns = dp->nslist; ns; ns = ns->next) { |
391 | 0 | if(ns->resolved) continue; |
392 | 0 | n++; |
393 | 0 | if(ns->lame) nlame++; |
394 | 0 | } |
395 | 0 | if(alllame && n == nlame) *alllame = 1; |
396 | 0 | return n; |
397 | 0 | } |
398 | | |
399 | | /** find NS rrset in given list */ |
400 | | static struct ub_packed_rrset_key* |
401 | | find_NS(struct reply_info* rep, size_t from, size_t to) |
402 | 0 | { |
403 | 0 | size_t i; |
404 | 0 | for(i=from; i<to; i++) { |
405 | 0 | if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_NS) |
406 | 0 | return rep->rrsets[i]; |
407 | 0 | } |
408 | 0 | return NULL; |
409 | 0 | } |
410 | | |
411 | | struct delegpt* |
412 | | delegpt_from_message(struct dns_msg* msg, struct regional* region) |
413 | 0 | { |
414 | 0 | struct ub_packed_rrset_key* ns_rrset = NULL; |
415 | 0 | struct delegpt* dp; |
416 | 0 | size_t i; |
417 | | /* look for NS records in the authority section... */ |
418 | 0 | ns_rrset = find_NS(msg->rep, msg->rep->an_numrrsets, |
419 | 0 | msg->rep->an_numrrsets+msg->rep->ns_numrrsets); |
420 | | |
421 | | /* In some cases (even legitimate, perfectly legal cases), the |
422 | | * NS set for the "referral" might be in the answer section. */ |
423 | 0 | if(!ns_rrset) |
424 | 0 | ns_rrset = find_NS(msg->rep, 0, msg->rep->an_numrrsets); |
425 | | |
426 | | /* If there was no NS rrset in the authority section, then this |
427 | | * wasn't a referral message. (It might not actually be a |
428 | | * referral message anyway) */ |
429 | 0 | if(!ns_rrset) |
430 | 0 | return NULL; |
431 | | |
432 | | /* If we found any, then Yay! we have a delegation point. */ |
433 | 0 | dp = delegpt_create(region); |
434 | 0 | if(!dp) |
435 | 0 | return NULL; |
436 | 0 | dp->has_parent_side_NS = 1; /* created from message */ |
437 | 0 | if(!delegpt_set_name(dp, region, ns_rrset->rk.dname)) |
438 | 0 | return NULL; |
439 | 0 | if(!delegpt_rrset_add_ns(dp, region, ns_rrset, 0)) |
440 | 0 | return NULL; |
441 | | |
442 | | /* add glue, A and AAAA in answer and additional section */ |
443 | 0 | for(i=0; i<msg->rep->rrset_count; i++) { |
444 | 0 | struct ub_packed_rrset_key* s = msg->rep->rrsets[i]; |
445 | | /* skip auth section. FIXME really needed?*/ |
446 | 0 | if(msg->rep->an_numrrsets <= i && |
447 | 0 | i < (msg->rep->an_numrrsets+msg->rep->ns_numrrsets)) |
448 | 0 | continue; |
449 | | |
450 | 0 | if(ntohs(s->rk.type) == LDNS_RR_TYPE_A) { |
451 | 0 | if(!delegpt_add_rrset_A(dp, region, s, 0, NULL)) |
452 | 0 | return NULL; |
453 | 0 | } else if(ntohs(s->rk.type) == LDNS_RR_TYPE_AAAA) { |
454 | 0 | if(!delegpt_add_rrset_AAAA(dp, region, s, 0, NULL)) |
455 | 0 | return NULL; |
456 | 0 | } |
457 | 0 | } |
458 | 0 | return dp; |
459 | 0 | } |
460 | | |
461 | | int |
462 | | delegpt_rrset_add_ns(struct delegpt* dp, struct regional* region, |
463 | | struct ub_packed_rrset_key* ns_rrset, uint8_t lame) |
464 | 0 | { |
465 | 0 | struct packed_rrset_data* nsdata = (struct packed_rrset_data*) |
466 | 0 | ns_rrset->entry.data; |
467 | 0 | size_t i; |
468 | 0 | log_assert(!dp->dp_type_mlc); |
469 | 0 | if(nsdata->security == sec_status_bogus) |
470 | 0 | dp->bogus = 1; |
471 | 0 | for(i=0; i<nsdata->count; i++) { |
472 | 0 | if(nsdata->rr_len[i] < 2+1) continue; /* len + root label */ |
473 | 0 | if(dname_valid(nsdata->rr_data[i]+2, nsdata->rr_len[i]-2) != |
474 | 0 | (size_t)sldns_read_uint16(nsdata->rr_data[i])) |
475 | 0 | continue; /* bad format */ |
476 | | /* add rdata of NS (= wirefmt dname), skip rdatalen bytes */ |
477 | 0 | if(!delegpt_add_ns(dp, region, nsdata->rr_data[i]+2, lame, |
478 | 0 | NULL, UNBOUND_DNS_PORT)) |
479 | 0 | return 0; |
480 | 0 | } |
481 | 0 | return 1; |
482 | 0 | } |
483 | | |
484 | | int |
485 | | delegpt_add_rrset_A(struct delegpt* dp, struct regional* region, |
486 | | struct ub_packed_rrset_key* ak, uint8_t lame, int* additions) |
487 | 0 | { |
488 | 0 | struct packed_rrset_data* d=(struct packed_rrset_data*)ak->entry.data; |
489 | 0 | size_t i; |
490 | 0 | struct sockaddr_in sa; |
491 | 0 | socklen_t len = (socklen_t)sizeof(sa); |
492 | 0 | log_assert(!dp->dp_type_mlc); |
493 | 0 | memset(&sa, 0, len); |
494 | 0 | sa.sin_family = AF_INET; |
495 | 0 | for(i=0; i<d->count; i++) { |
496 | 0 | if(d->rr_len[i] != 2 + INET_SIZE) |
497 | 0 | continue; |
498 | 0 | memmove(&sa.sin_addr, d->rr_data[i]+2, INET_SIZE); |
499 | 0 | if(!delegpt_add_target(dp, region, ak->rk.dname, |
500 | 0 | ak->rk.dname_len, (struct sockaddr_storage*)&sa, |
501 | 0 | len, (d->security==sec_status_bogus), lame, additions)) |
502 | 0 | return 0; |
503 | 0 | } |
504 | 0 | return 1; |
505 | 0 | } |
506 | | |
507 | | int |
508 | | delegpt_add_rrset_AAAA(struct delegpt* dp, struct regional* region, |
509 | | struct ub_packed_rrset_key* ak, uint8_t lame, int* additions) |
510 | 0 | { |
511 | 0 | struct packed_rrset_data* d=(struct packed_rrset_data*)ak->entry.data; |
512 | 0 | size_t i; |
513 | 0 | struct sockaddr_in6 sa; |
514 | 0 | socklen_t len = (socklen_t)sizeof(sa); |
515 | 0 | log_assert(!dp->dp_type_mlc); |
516 | 0 | memset(&sa, 0, len); |
517 | 0 | sa.sin6_family = AF_INET6; |
518 | 0 | for(i=0; i<d->count; i++) { |
519 | 0 | if(d->rr_len[i] != 2 + INET6_SIZE) /* rdatalen + len of IP6 */ |
520 | 0 | continue; |
521 | 0 | memmove(&sa.sin6_addr, d->rr_data[i]+2, INET6_SIZE); |
522 | 0 | if(!delegpt_add_target(dp, region, ak->rk.dname, |
523 | 0 | ak->rk.dname_len, (struct sockaddr_storage*)&sa, |
524 | 0 | len, (d->security==sec_status_bogus), lame, additions)) |
525 | 0 | return 0; |
526 | 0 | } |
527 | 0 | return 1; |
528 | 0 | } |
529 | | |
530 | | int |
531 | | delegpt_add_rrset(struct delegpt* dp, struct regional* region, |
532 | | struct ub_packed_rrset_key* rrset, uint8_t lame, int* additions) |
533 | 0 | { |
534 | 0 | if(!rrset) |
535 | 0 | return 1; |
536 | 0 | if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_NS) |
537 | 0 | return delegpt_rrset_add_ns(dp, region, rrset, lame); |
538 | 0 | else if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_A) |
539 | 0 | return delegpt_add_rrset_A(dp, region, rrset, lame, additions); |
540 | 0 | else if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_AAAA) |
541 | 0 | return delegpt_add_rrset_AAAA(dp, region, rrset, lame, |
542 | 0 | additions); |
543 | 0 | log_warn("Unknown rrset type added to delegpt"); |
544 | 0 | return 1; |
545 | 0 | } |
546 | | |
547 | | void delegpt_mark_neg(struct delegpt_ns* ns, uint16_t qtype) |
548 | 0 | { |
549 | 0 | if(ns) { |
550 | 0 | if(qtype == LDNS_RR_TYPE_A) |
551 | 0 | ns->got4 = 2; |
552 | 0 | else if(qtype == LDNS_RR_TYPE_AAAA) |
553 | 0 | ns->got6 = 2; |
554 | 0 | if(ns->got4 && ns->got6) |
555 | 0 | ns->resolved = 1; |
556 | 0 | } |
557 | 0 | } |
558 | | |
559 | | void delegpt_add_neg_msg(struct delegpt* dp, struct msgreply_entry* msg) |
560 | 0 | { |
561 | 0 | struct reply_info* rep = (struct reply_info*)msg->entry.data; |
562 | 0 | if(!rep) return; |
563 | | |
564 | | /* if error or no answers */ |
565 | 0 | if(FLAGS_GET_RCODE(rep->flags) != 0 || rep->an_numrrsets == 0) { |
566 | 0 | struct delegpt_ns* ns = delegpt_find_ns(dp, msg->key.qname, |
567 | 0 | msg->key.qname_len); |
568 | 0 | delegpt_mark_neg(ns, msg->key.qtype); |
569 | 0 | } |
570 | 0 | } |
571 | | |
572 | | void delegpt_no_ipv6(struct delegpt* dp) |
573 | 0 | { |
574 | 0 | struct delegpt_ns* ns; |
575 | 0 | for(ns = dp->nslist; ns; ns = ns->next) { |
576 | | /* no ipv6, so only ipv4 is enough to resolve a nameserver */ |
577 | 0 | if(ns->got4) |
578 | 0 | ns->resolved = 1; |
579 | 0 | } |
580 | 0 | } |
581 | | |
582 | | void delegpt_no_ipv4(struct delegpt* dp) |
583 | 0 | { |
584 | 0 | struct delegpt_ns* ns; |
585 | 0 | for(ns = dp->nslist; ns; ns = ns->next) { |
586 | | /* no ipv4, so only ipv6 is enough to resolve a nameserver */ |
587 | 0 | if(ns->got6) |
588 | 0 | ns->resolved = 1; |
589 | 0 | } |
590 | 0 | } |
591 | | |
592 | | struct delegpt* delegpt_create_mlc(uint8_t* name) |
593 | 0 | { |
594 | 0 | struct delegpt* dp=(struct delegpt*)calloc(1, sizeof(*dp)); |
595 | 0 | if(!dp) |
596 | 0 | return NULL; |
597 | 0 | dp->dp_type_mlc = 1; |
598 | 0 | if(name) { |
599 | 0 | dp->namelabs = dname_count_size_labels(name, &dp->namelen); |
600 | 0 | dp->name = memdup(name, dp->namelen); |
601 | 0 | if(!dp->name) { |
602 | 0 | free(dp); |
603 | 0 | return NULL; |
604 | 0 | } |
605 | 0 | } |
606 | 0 | return dp; |
607 | 0 | } |
608 | | |
609 | | void delegpt_free_mlc(struct delegpt* dp) |
610 | 0 | { |
611 | 0 | struct delegpt_ns* n, *nn; |
612 | 0 | struct delegpt_addr* a, *na; |
613 | 0 | if(!dp) return; |
614 | 0 | log_assert(dp->dp_type_mlc); |
615 | 0 | n = dp->nslist; |
616 | 0 | while(n) { |
617 | 0 | nn = n->next; |
618 | 0 | free(n->name); |
619 | 0 | free(n->tls_auth_name); |
620 | 0 | free(n); |
621 | 0 | n = nn; |
622 | 0 | } |
623 | 0 | a = dp->target_list; |
624 | 0 | while(a) { |
625 | 0 | na = a->next_target; |
626 | 0 | free(a->tls_auth_name); |
627 | 0 | free(a); |
628 | 0 | a = na; |
629 | 0 | } |
630 | 0 | free(dp->name); |
631 | 0 | free(dp); |
632 | 0 | } |
633 | | |
634 | | int delegpt_set_name_mlc(struct delegpt* dp, uint8_t* name) |
635 | 0 | { |
636 | 0 | log_assert(dp->dp_type_mlc); |
637 | 0 | dp->namelabs = dname_count_size_labels(name, &dp->namelen); |
638 | 0 | dp->name = memdup(name, dp->namelen); |
639 | 0 | return (dp->name != NULL); |
640 | 0 | } |
641 | | |
642 | | int delegpt_add_ns_mlc(struct delegpt* dp, uint8_t* name, uint8_t lame, |
643 | | char* tls_auth_name, int port) |
644 | 0 | { |
645 | 0 | struct delegpt_ns* ns; |
646 | 0 | size_t len; |
647 | 0 | (void)dname_count_size_labels(name, &len); |
648 | 0 | log_assert(dp->dp_type_mlc); |
649 | | /* slow check for duplicates to avoid counting failures when |
650 | | * adding the same server as a dependency twice */ |
651 | 0 | if(delegpt_find_ns(dp, name, len)) |
652 | 0 | return 1; |
653 | 0 | ns = (struct delegpt_ns*)malloc(sizeof(struct delegpt_ns)); |
654 | 0 | if(!ns) |
655 | 0 | return 0; |
656 | 0 | ns->namelen = len; |
657 | 0 | ns->name = memdup(name, ns->namelen); |
658 | 0 | if(!ns->name) { |
659 | 0 | free(ns); |
660 | 0 | return 0; |
661 | 0 | } |
662 | 0 | ns->next = dp->nslist; |
663 | 0 | dp->nslist = ns; |
664 | 0 | ns->cache_lookup_count = 0; |
665 | 0 | ns->resolved = 0; |
666 | 0 | ns->got4 = 0; |
667 | 0 | ns->got6 = 0; |
668 | 0 | ns->lame = (uint8_t)lame; |
669 | 0 | ns->done_pside4 = 0; |
670 | 0 | ns->done_pside6 = 0; |
671 | 0 | ns->port = port; |
672 | 0 | if(tls_auth_name) { |
673 | 0 | ns->tls_auth_name = strdup(tls_auth_name); |
674 | 0 | if(!ns->tls_auth_name) { |
675 | 0 | free(ns->name); |
676 | 0 | free(ns); |
677 | 0 | return 0; |
678 | 0 | } |
679 | 0 | } else { |
680 | 0 | ns->tls_auth_name = NULL; |
681 | 0 | } |
682 | 0 | return 1; |
683 | 0 | } |
684 | | |
685 | | int delegpt_add_addr_mlc(struct delegpt* dp, struct sockaddr_storage* addr, |
686 | | socklen_t addrlen, uint8_t bogus, uint8_t lame, char* tls_auth_name, |
687 | | int port) |
688 | 0 | { |
689 | 0 | struct delegpt_addr* a; |
690 | 0 | log_assert(dp->dp_type_mlc); |
691 | 0 | if(port != -1) { |
692 | 0 | log_assert(port>0); |
693 | 0 | sockaddr_store_port(addr, addrlen, port); |
694 | 0 | } |
695 | | /* check for duplicates */ |
696 | 0 | if((a = delegpt_find_addr(dp, addr, addrlen))) { |
697 | 0 | if(bogus) |
698 | 0 | a->bogus = bogus; |
699 | 0 | if(!lame) |
700 | 0 | a->lame = 0; |
701 | 0 | return 1; |
702 | 0 | } |
703 | | |
704 | 0 | a = (struct delegpt_addr*)malloc(sizeof(struct delegpt_addr)); |
705 | 0 | if(!a) |
706 | 0 | return 0; |
707 | 0 | a->next_target = dp->target_list; |
708 | 0 | dp->target_list = a; |
709 | 0 | a->next_result = 0; |
710 | 0 | a->next_usable = dp->usable_list; |
711 | 0 | dp->usable_list = a; |
712 | 0 | memcpy(&a->addr, addr, addrlen); |
713 | 0 | a->addrlen = addrlen; |
714 | 0 | a->attempts = 0; |
715 | 0 | a->bogus = bogus; |
716 | 0 | a->lame = lame; |
717 | 0 | a->dnsseclame = 0; |
718 | 0 | if(tls_auth_name) { |
719 | 0 | a->tls_auth_name = strdup(tls_auth_name); |
720 | 0 | if(!a->tls_auth_name) { |
721 | 0 | free(a); |
722 | 0 | return 0; |
723 | 0 | } |
724 | 0 | } else { |
725 | 0 | a->tls_auth_name = NULL; |
726 | 0 | } |
727 | 0 | return 1; |
728 | 0 | } |
729 | | |
730 | | int delegpt_add_target_mlc(struct delegpt* dp, uint8_t* name, size_t namelen, |
731 | | struct sockaddr_storage* addr, socklen_t addrlen, uint8_t bogus, |
732 | | uint8_t lame) |
733 | 0 | { |
734 | 0 | struct delegpt_ns* ns = delegpt_find_ns(dp, name, namelen); |
735 | 0 | log_assert(dp->dp_type_mlc); |
736 | 0 | if(!ns) { |
737 | | /* ignore it */ |
738 | 0 | return 1; |
739 | 0 | } |
740 | 0 | if(!lame) { |
741 | 0 | if(addr_is_ip6(addr, addrlen)) |
742 | 0 | ns->got6 = 1; |
743 | 0 | else ns->got4 = 1; |
744 | 0 | if(ns->got4 && ns->got6) |
745 | 0 | ns->resolved = 1; |
746 | 0 | } else { |
747 | 0 | if(addr_is_ip6(addr, addrlen)) |
748 | 0 | ns->done_pside6 = 1; |
749 | 0 | else ns->done_pside4 = 1; |
750 | 0 | } |
751 | 0 | log_assert(ns->port>0); |
752 | 0 | return delegpt_add_addr_mlc(dp, addr, addrlen, bogus, lame, |
753 | 0 | ns->tls_auth_name, ns->port); |
754 | 0 | } |
755 | | |
756 | | size_t delegpt_get_mem(struct delegpt* dp) |
757 | 0 | { |
758 | 0 | struct delegpt_ns* ns; |
759 | 0 | size_t s; |
760 | 0 | if(!dp) return 0; |
761 | 0 | s = sizeof(*dp) + dp->namelen + |
762 | 0 | delegpt_count_targets(dp)*sizeof(struct delegpt_addr); |
763 | 0 | for(ns=dp->nslist; ns; ns=ns->next) |
764 | 0 | s += sizeof(*ns)+ns->namelen; |
765 | 0 | return s; |
766 | 0 | } |