/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+1]; |
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 | | void |
325 | | delegpt_add_unused_targets(struct delegpt* dp) |
326 | 0 | { |
327 | 0 | struct delegpt_addr* usa = dp->usable_list; |
328 | 0 | dp->usable_list = NULL; |
329 | 0 | while(usa) { |
330 | 0 | usa->next_result = dp->result_list; |
331 | 0 | dp->result_list = usa; |
332 | 0 | usa = usa->next_usable; |
333 | 0 | } |
334 | 0 | } |
335 | | |
336 | | size_t |
337 | | delegpt_count_targets(struct delegpt* dp) |
338 | 0 | { |
339 | 0 | struct delegpt_addr* a; |
340 | 0 | size_t n = 0; |
341 | 0 | for(a = dp->target_list; a; a = a->next_target) |
342 | 0 | n++; |
343 | 0 | return n; |
344 | 0 | } |
345 | | |
346 | | size_t |
347 | | delegpt_count_missing_targets(struct delegpt* dp, int* alllame) |
348 | 0 | { |
349 | 0 | struct delegpt_ns* ns; |
350 | 0 | size_t n = 0, nlame = 0; |
351 | 0 | for(ns = dp->nslist; ns; ns = ns->next) { |
352 | 0 | if(ns->resolved) continue; |
353 | 0 | n++; |
354 | 0 | if(ns->lame) nlame++; |
355 | 0 | } |
356 | 0 | if(alllame && n == nlame) *alllame = 1; |
357 | 0 | return n; |
358 | 0 | } |
359 | | |
360 | | /** find NS rrset in given list */ |
361 | | static struct ub_packed_rrset_key* |
362 | | find_NS(struct reply_info* rep, size_t from, size_t to) |
363 | 0 | { |
364 | 0 | size_t i; |
365 | 0 | for(i=from; i<to; i++) { |
366 | 0 | if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_NS) |
367 | 0 | return rep->rrsets[i]; |
368 | 0 | } |
369 | 0 | return NULL; |
370 | 0 | } |
371 | | |
372 | | struct delegpt* |
373 | | delegpt_from_message(struct dns_msg* msg, struct regional* region) |
374 | 0 | { |
375 | 0 | struct ub_packed_rrset_key* ns_rrset = NULL; |
376 | 0 | struct delegpt* dp; |
377 | 0 | size_t i; |
378 | | /* look for NS records in the authority section... */ |
379 | 0 | ns_rrset = find_NS(msg->rep, msg->rep->an_numrrsets, |
380 | 0 | msg->rep->an_numrrsets+msg->rep->ns_numrrsets); |
381 | | |
382 | | /* In some cases (even legitimate, perfectly legal cases), the |
383 | | * NS set for the "referral" might be in the answer section. */ |
384 | 0 | if(!ns_rrset) |
385 | 0 | ns_rrset = find_NS(msg->rep, 0, msg->rep->an_numrrsets); |
386 | | |
387 | | /* If there was no NS rrset in the authority section, then this |
388 | | * wasn't a referral message. (It might not actually be a |
389 | | * referral message anyway) */ |
390 | 0 | if(!ns_rrset) |
391 | 0 | return NULL; |
392 | | |
393 | | /* If we found any, then Yay! we have a delegation point. */ |
394 | 0 | dp = delegpt_create(region); |
395 | 0 | if(!dp) |
396 | 0 | return NULL; |
397 | 0 | dp->has_parent_side_NS = 1; /* created from message */ |
398 | 0 | if(!delegpt_set_name(dp, region, ns_rrset->rk.dname)) |
399 | 0 | return NULL; |
400 | 0 | if(!delegpt_rrset_add_ns(dp, region, ns_rrset, 0)) |
401 | 0 | return NULL; |
402 | | |
403 | | /* add glue, A and AAAA in answer and additional section */ |
404 | 0 | for(i=0; i<msg->rep->rrset_count; i++) { |
405 | 0 | struct ub_packed_rrset_key* s = msg->rep->rrsets[i]; |
406 | | /* skip auth section. FIXME really needed?*/ |
407 | 0 | if(msg->rep->an_numrrsets <= i && |
408 | 0 | i < (msg->rep->an_numrrsets+msg->rep->ns_numrrsets)) |
409 | 0 | continue; |
410 | | |
411 | 0 | if(ntohs(s->rk.type) == LDNS_RR_TYPE_A) { |
412 | 0 | if(!delegpt_add_rrset_A(dp, region, s, 0, NULL)) |
413 | 0 | return NULL; |
414 | 0 | } else if(ntohs(s->rk.type) == LDNS_RR_TYPE_AAAA) { |
415 | 0 | if(!delegpt_add_rrset_AAAA(dp, region, s, 0, NULL)) |
416 | 0 | return NULL; |
417 | 0 | } |
418 | 0 | } |
419 | 0 | return dp; |
420 | 0 | } |
421 | | |
422 | | int |
423 | | delegpt_rrset_add_ns(struct delegpt* dp, struct regional* region, |
424 | | struct ub_packed_rrset_key* ns_rrset, uint8_t lame) |
425 | 0 | { |
426 | 0 | struct packed_rrset_data* nsdata = (struct packed_rrset_data*) |
427 | 0 | ns_rrset->entry.data; |
428 | 0 | size_t i; |
429 | 0 | log_assert(!dp->dp_type_mlc); |
430 | 0 | if(nsdata->security == sec_status_bogus) |
431 | 0 | dp->bogus = 1; |
432 | 0 | for(i=0; i<nsdata->count; i++) { |
433 | 0 | if(nsdata->rr_len[i] < 2+1) continue; /* len + root label */ |
434 | 0 | if(dname_valid(nsdata->rr_data[i]+2, nsdata->rr_len[i]-2) != |
435 | 0 | (size_t)sldns_read_uint16(nsdata->rr_data[i])) |
436 | 0 | continue; /* bad format */ |
437 | | /* add rdata of NS (= wirefmt dname), skip rdatalen bytes */ |
438 | 0 | if(!delegpt_add_ns(dp, region, nsdata->rr_data[i]+2, lame, |
439 | 0 | NULL, UNBOUND_DNS_PORT)) |
440 | 0 | return 0; |
441 | 0 | } |
442 | 0 | return 1; |
443 | 0 | } |
444 | | |
445 | | int |
446 | | delegpt_add_rrset_A(struct delegpt* dp, struct regional* region, |
447 | | struct ub_packed_rrset_key* ak, uint8_t lame, int* additions) |
448 | 0 | { |
449 | 0 | struct packed_rrset_data* d=(struct packed_rrset_data*)ak->entry.data; |
450 | 0 | size_t i; |
451 | 0 | struct sockaddr_in sa; |
452 | 0 | socklen_t len = (socklen_t)sizeof(sa); |
453 | 0 | log_assert(!dp->dp_type_mlc); |
454 | 0 | memset(&sa, 0, len); |
455 | 0 | sa.sin_family = AF_INET; |
456 | 0 | for(i=0; i<d->count; i++) { |
457 | 0 | if(d->rr_len[i] != 2 + INET_SIZE) |
458 | 0 | continue; |
459 | 0 | memmove(&sa.sin_addr, d->rr_data[i]+2, INET_SIZE); |
460 | 0 | if(!delegpt_add_target(dp, region, ak->rk.dname, |
461 | 0 | ak->rk.dname_len, (struct sockaddr_storage*)&sa, |
462 | 0 | len, (d->security==sec_status_bogus), lame, additions)) |
463 | 0 | return 0; |
464 | 0 | } |
465 | 0 | return 1; |
466 | 0 | } |
467 | | |
468 | | int |
469 | | delegpt_add_rrset_AAAA(struct delegpt* dp, struct regional* region, |
470 | | struct ub_packed_rrset_key* ak, uint8_t lame, int* additions) |
471 | 0 | { |
472 | 0 | struct packed_rrset_data* d=(struct packed_rrset_data*)ak->entry.data; |
473 | 0 | size_t i; |
474 | 0 | struct sockaddr_in6 sa; |
475 | 0 | socklen_t len = (socklen_t)sizeof(sa); |
476 | 0 | log_assert(!dp->dp_type_mlc); |
477 | 0 | memset(&sa, 0, len); |
478 | 0 | sa.sin6_family = AF_INET6; |
479 | 0 | for(i=0; i<d->count; i++) { |
480 | 0 | if(d->rr_len[i] != 2 + INET6_SIZE) /* rdatalen + len of IP6 */ |
481 | 0 | continue; |
482 | 0 | memmove(&sa.sin6_addr, d->rr_data[i]+2, INET6_SIZE); |
483 | 0 | if(!delegpt_add_target(dp, region, ak->rk.dname, |
484 | 0 | ak->rk.dname_len, (struct sockaddr_storage*)&sa, |
485 | 0 | len, (d->security==sec_status_bogus), lame, additions)) |
486 | 0 | return 0; |
487 | 0 | } |
488 | 0 | return 1; |
489 | 0 | } |
490 | | |
491 | | int |
492 | | delegpt_add_rrset(struct delegpt* dp, struct regional* region, |
493 | | struct ub_packed_rrset_key* rrset, uint8_t lame, int* additions) |
494 | 0 | { |
495 | 0 | if(!rrset) |
496 | 0 | return 1; |
497 | 0 | if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_NS) |
498 | 0 | return delegpt_rrset_add_ns(dp, region, rrset, lame); |
499 | 0 | else if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_A) |
500 | 0 | return delegpt_add_rrset_A(dp, region, rrset, lame, additions); |
501 | 0 | else if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_AAAA) |
502 | 0 | return delegpt_add_rrset_AAAA(dp, region, rrset, lame, |
503 | 0 | additions); |
504 | 0 | log_warn("Unknown rrset type added to delegpt"); |
505 | 0 | return 1; |
506 | 0 | } |
507 | | |
508 | | void delegpt_mark_neg(struct delegpt_ns* ns, uint16_t qtype) |
509 | 0 | { |
510 | 0 | if(ns) { |
511 | 0 | if(qtype == LDNS_RR_TYPE_A) |
512 | 0 | ns->got4 = 2; |
513 | 0 | else if(qtype == LDNS_RR_TYPE_AAAA) |
514 | 0 | ns->got6 = 2; |
515 | 0 | if(ns->got4 && ns->got6) |
516 | 0 | ns->resolved = 1; |
517 | 0 | } |
518 | 0 | } |
519 | | |
520 | | void delegpt_add_neg_msg(struct delegpt* dp, struct msgreply_entry* msg) |
521 | 0 | { |
522 | 0 | struct reply_info* rep = (struct reply_info*)msg->entry.data; |
523 | 0 | if(!rep) return; |
524 | | |
525 | | /* if error or no answers */ |
526 | 0 | if(FLAGS_GET_RCODE(rep->flags) != 0 || rep->an_numrrsets == 0) { |
527 | 0 | struct delegpt_ns* ns = delegpt_find_ns(dp, msg->key.qname, |
528 | 0 | msg->key.qname_len); |
529 | 0 | delegpt_mark_neg(ns, msg->key.qtype); |
530 | 0 | } |
531 | 0 | } |
532 | | |
533 | | void delegpt_no_ipv6(struct delegpt* dp) |
534 | 0 | { |
535 | 0 | struct delegpt_ns* ns; |
536 | 0 | for(ns = dp->nslist; ns; ns = ns->next) { |
537 | | /* no ipv6, so only ipv4 is enough to resolve a nameserver */ |
538 | 0 | if(ns->got4) |
539 | 0 | ns->resolved = 1; |
540 | 0 | } |
541 | 0 | } |
542 | | |
543 | | void delegpt_no_ipv4(struct delegpt* dp) |
544 | 0 | { |
545 | 0 | struct delegpt_ns* ns; |
546 | 0 | for(ns = dp->nslist; ns; ns = ns->next) { |
547 | | /* no ipv4, so only ipv6 is enough to resolve a nameserver */ |
548 | 0 | if(ns->got6) |
549 | 0 | ns->resolved = 1; |
550 | 0 | } |
551 | 0 | } |
552 | | |
553 | | struct delegpt* delegpt_create_mlc(uint8_t* name) |
554 | 0 | { |
555 | 0 | struct delegpt* dp=(struct delegpt*)calloc(1, sizeof(*dp)); |
556 | 0 | if(!dp) |
557 | 0 | return NULL; |
558 | 0 | dp->dp_type_mlc = 1; |
559 | 0 | if(name) { |
560 | 0 | dp->namelabs = dname_count_size_labels(name, &dp->namelen); |
561 | 0 | dp->name = memdup(name, dp->namelen); |
562 | 0 | if(!dp->name) { |
563 | 0 | free(dp); |
564 | 0 | return NULL; |
565 | 0 | } |
566 | 0 | } |
567 | 0 | return dp; |
568 | 0 | } |
569 | | |
570 | | void delegpt_free_mlc(struct delegpt* dp) |
571 | 0 | { |
572 | 0 | struct delegpt_ns* n, *nn; |
573 | 0 | struct delegpt_addr* a, *na; |
574 | 0 | if(!dp) return; |
575 | 0 | log_assert(dp->dp_type_mlc); |
576 | 0 | n = dp->nslist; |
577 | 0 | while(n) { |
578 | 0 | nn = n->next; |
579 | 0 | free(n->name); |
580 | 0 | free(n->tls_auth_name); |
581 | 0 | free(n); |
582 | 0 | n = nn; |
583 | 0 | } |
584 | 0 | a = dp->target_list; |
585 | 0 | while(a) { |
586 | 0 | na = a->next_target; |
587 | 0 | free(a->tls_auth_name); |
588 | 0 | free(a); |
589 | 0 | a = na; |
590 | 0 | } |
591 | 0 | free(dp->name); |
592 | 0 | free(dp); |
593 | 0 | } |
594 | | |
595 | | int delegpt_set_name_mlc(struct delegpt* dp, uint8_t* name) |
596 | 0 | { |
597 | 0 | log_assert(dp->dp_type_mlc); |
598 | 0 | dp->namelabs = dname_count_size_labels(name, &dp->namelen); |
599 | 0 | dp->name = memdup(name, dp->namelen); |
600 | 0 | return (dp->name != NULL); |
601 | 0 | } |
602 | | |
603 | | int delegpt_add_ns_mlc(struct delegpt* dp, uint8_t* name, uint8_t lame, |
604 | | char* tls_auth_name, int port) |
605 | 0 | { |
606 | 0 | struct delegpt_ns* ns; |
607 | 0 | size_t len; |
608 | 0 | (void)dname_count_size_labels(name, &len); |
609 | 0 | log_assert(dp->dp_type_mlc); |
610 | | /* slow check for duplicates to avoid counting failures when |
611 | | * adding the same server as a dependency twice */ |
612 | 0 | if(delegpt_find_ns(dp, name, len)) |
613 | 0 | return 1; |
614 | 0 | ns = (struct delegpt_ns*)malloc(sizeof(struct delegpt_ns)); |
615 | 0 | if(!ns) |
616 | 0 | return 0; |
617 | 0 | ns->namelen = len; |
618 | 0 | ns->name = memdup(name, ns->namelen); |
619 | 0 | if(!ns->name) { |
620 | 0 | free(ns); |
621 | 0 | return 0; |
622 | 0 | } |
623 | 0 | ns->next = dp->nslist; |
624 | 0 | dp->nslist = ns; |
625 | 0 | ns->cache_lookup_count = 0; |
626 | 0 | ns->resolved = 0; |
627 | 0 | ns->got4 = 0; |
628 | 0 | ns->got6 = 0; |
629 | 0 | ns->lame = (uint8_t)lame; |
630 | 0 | ns->done_pside4 = 0; |
631 | 0 | ns->done_pside6 = 0; |
632 | 0 | ns->port = port; |
633 | 0 | if(tls_auth_name) { |
634 | 0 | ns->tls_auth_name = strdup(tls_auth_name); |
635 | 0 | if(!ns->tls_auth_name) { |
636 | 0 | free(ns->name); |
637 | 0 | free(ns); |
638 | 0 | return 0; |
639 | 0 | } |
640 | 0 | } else { |
641 | 0 | ns->tls_auth_name = NULL; |
642 | 0 | } |
643 | 0 | return 1; |
644 | 0 | } |
645 | | |
646 | | int delegpt_add_addr_mlc(struct delegpt* dp, struct sockaddr_storage* addr, |
647 | | socklen_t addrlen, uint8_t bogus, uint8_t lame, char* tls_auth_name, |
648 | | int port) |
649 | 0 | { |
650 | 0 | struct delegpt_addr* a; |
651 | 0 | log_assert(dp->dp_type_mlc); |
652 | 0 | if(port != -1) { |
653 | 0 | log_assert(port>0); |
654 | 0 | sockaddr_store_port(addr, addrlen, port); |
655 | 0 | } |
656 | | /* check for duplicates */ |
657 | 0 | if((a = delegpt_find_addr(dp, addr, addrlen))) { |
658 | 0 | if(bogus) |
659 | 0 | a->bogus = bogus; |
660 | 0 | if(!lame) |
661 | 0 | a->lame = 0; |
662 | 0 | return 1; |
663 | 0 | } |
664 | | |
665 | 0 | a = (struct delegpt_addr*)malloc(sizeof(struct delegpt_addr)); |
666 | 0 | if(!a) |
667 | 0 | return 0; |
668 | 0 | a->next_target = dp->target_list; |
669 | 0 | dp->target_list = a; |
670 | 0 | a->next_result = 0; |
671 | 0 | a->next_usable = dp->usable_list; |
672 | 0 | dp->usable_list = a; |
673 | 0 | memcpy(&a->addr, addr, addrlen); |
674 | 0 | a->addrlen = addrlen; |
675 | 0 | a->attempts = 0; |
676 | 0 | a->bogus = bogus; |
677 | 0 | a->lame = lame; |
678 | 0 | a->dnsseclame = 0; |
679 | 0 | if(tls_auth_name) { |
680 | 0 | a->tls_auth_name = strdup(tls_auth_name); |
681 | 0 | if(!a->tls_auth_name) { |
682 | 0 | free(a); |
683 | 0 | return 0; |
684 | 0 | } |
685 | 0 | } else { |
686 | 0 | a->tls_auth_name = NULL; |
687 | 0 | } |
688 | 0 | return 1; |
689 | 0 | } |
690 | | |
691 | | int delegpt_add_target_mlc(struct delegpt* dp, uint8_t* name, size_t namelen, |
692 | | struct sockaddr_storage* addr, socklen_t addrlen, uint8_t bogus, |
693 | | uint8_t lame) |
694 | 0 | { |
695 | 0 | struct delegpt_ns* ns = delegpt_find_ns(dp, name, namelen); |
696 | 0 | log_assert(dp->dp_type_mlc); |
697 | 0 | if(!ns) { |
698 | | /* ignore it */ |
699 | 0 | return 1; |
700 | 0 | } |
701 | 0 | if(!lame) { |
702 | 0 | if(addr_is_ip6(addr, addrlen)) |
703 | 0 | ns->got6 = 1; |
704 | 0 | else ns->got4 = 1; |
705 | 0 | if(ns->got4 && ns->got6) |
706 | 0 | ns->resolved = 1; |
707 | 0 | } else { |
708 | 0 | if(addr_is_ip6(addr, addrlen)) |
709 | 0 | ns->done_pside6 = 1; |
710 | 0 | else ns->done_pside4 = 1; |
711 | 0 | } |
712 | 0 | log_assert(ns->port>0); |
713 | 0 | return delegpt_add_addr_mlc(dp, addr, addrlen, bogus, lame, |
714 | 0 | ns->tls_auth_name, ns->port); |
715 | 0 | } |
716 | | |
717 | | size_t delegpt_get_mem(struct delegpt* dp) |
718 | 0 | { |
719 | 0 | struct delegpt_ns* ns; |
720 | 0 | size_t s; |
721 | 0 | if(!dp) return 0; |
722 | 0 | s = sizeof(*dp) + dp->namelen + |
723 | 0 | delegpt_count_targets(dp)*sizeof(struct delegpt_addr); |
724 | 0 | for(ns=dp->nslist; ns; ns=ns->next) |
725 | 0 | s += sizeof(*ns)+ns->namelen; |
726 | 0 | return s; |
727 | 0 | } |