Attachment 'resolve.c'
Download 1 /* Copyright (C) 2014 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
2
3 This program is free software: you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation, either version 3 of the License, or
6 (at your option) any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17 #include <ctype.h>
18 #include <stdio.h>
19 #include <fcntl.h>
20 #include <libknot/rrtype/rdname.h>
21 #include <libknot/descriptor.h>
22 #include <ucw/mempool.h>
23 #include "lib/resolve.h"
24 #include "lib/layer.h"
25 #include "lib/rplan.h"
26 #include "lib/layer/iterate.h"
27 #include "lib/dnssec/ta.h"
28
29 #define DEBUG_MSG(qry, fmt...) QRDEBUG((qry), "resl", fmt)
30
31 /** @internal Macro for iterating module layers. */
32 #define ITERATE_LAYERS(req, qry, func, ...) \
33 (req)->current_query = (qry); \
34 for (unsigned i = 0; i < (req)->ctx->modules->len; ++i) { \
35 struct kr_module *mod = (req)->ctx->modules->at[i]; \
36 if (mod->layer) { \
37 struct knot_layer layer = {.state = (req)->state, .api = mod->layer(mod), .data = (req)}; \
38 if (layer.api && layer.api->func) { \
39 (req)->state = layer.api->func(&layer, ##__VA_ARGS__); \
40 if ((req)->state == KNOT_STATE_YIELD) \
41 break; \
42 } \
43 } \
44 } /* Invalidate current query. */ \
45 (req)->current_query = NULL
46
47 /* Randomize QNAME letter case.
48 * This adds 32 bits of randomness at maximum, but that's more than an average domain name length.
49 * https://tools.ietf.org/html/draft-vixie-dnsext-dns0x20-00
50 */
51 static void randomized_qname_case(knot_dname_t *qname, uint32_t secret)
52 {
53 unsigned k = 0;
54 while (*qname != '\0') {
55 for (unsigned i = *qname; i--;) {
56 int chr = qname[i + 1];
57 if (isalpha(chr)) {
58 if (secret & (1 << k)) {
59 qname[i + 1] ^= 0x20;
60 }
61 k = (k + 1) % (sizeof(secret) * CHAR_BIT);
62 }
63 }
64 qname = (uint8_t *)knot_wire_next_label(qname, NULL);
65 }
66 }
67
68 /** Invalidate current NS/addr pair. */
69 static int invalidate_ns(struct kr_rplan *rplan, struct kr_query *qry)
70 {
71 if (qry->ns.addr[0].ip.sa_family != AF_UNSPEC) {
72 uint8_t *addr = kr_nsrep_inaddr(qry->ns.addr[0]);
73 size_t addr_len = kr_nsrep_inaddr_len(qry->ns.addr[0]);
74 knot_rdata_t rdata[knot_rdata_array_size(addr_len)];
75 knot_rdata_init(rdata, addr_len, addr, 0);
76 return kr_zonecut_del(&qry->zone_cut, qry->ns.name, rdata);
77 } else {
78 return kr_zonecut_del(&qry->zone_cut, qry->ns.name, NULL);
79 }
80 }
81
82 static int ns_fetch_cut(struct kr_query *qry, struct kr_request *req, bool secured)
83 {
84 int ret = 0;
85
86 /* Find closest zone cut from cache */
87 struct kr_cache_txn txn;
88 if (kr_cache_txn_begin(&req->ctx->cache, &txn, NAMEDB_RDONLY) == 0) {
89 /* If at/subdomain of parent zone cut, start from its encloser.
90 * This is for case when we get to a dead end (and need glue from parent), or DS refetch. */
91 struct kr_query *parent = qry->parent;
92 if (parent && qry->sname[0] != '\0' && knot_dname_in(parent->zone_cut.name, qry->sname)) {
93 const knot_dname_t *encloser = knot_wire_next_label(parent->zone_cut.name, NULL);
94 ret = kr_zonecut_find_cached(req->ctx, &qry->zone_cut, encloser, &txn, qry->timestamp.tv_sec, secured);
95 } else {
96 ret = kr_zonecut_find_cached(req->ctx, &qry->zone_cut, qry->sname, &txn, qry->timestamp.tv_sec, secured);
97 }
98 kr_cache_txn_abort(&txn);
99 } else {
100 ret = kr_error(ENOENT);
101 }
102 return ret;
103 }
104
105 static int ns_resolve_addr(struct kr_query *qry, struct kr_request *param)
106 {
107 struct kr_rplan *rplan = ¶m->rplan;
108 struct kr_context *ctx = param->ctx;
109
110
111 /* Start NS queries from root, to avoid certain cases
112 * where a NS drops out of cache and the rest is unavailable,
113 * this would lead to dependency loop in current zone cut.
114 * Prefer IPv6 and continue with IPv4 if not available.
115 */
116 uint16_t next_type = 0;
117 if (!(qry->flags & QUERY_AWAIT_IPV6)) {
118 next_type = KNOT_RRTYPE_AAAA;
119 qry->flags |= QUERY_AWAIT_IPV6;
120 } else if (!(qry->flags & QUERY_AWAIT_IPV4)) {
121 next_type = KNOT_RRTYPE_A;
122 qry->flags |= QUERY_AWAIT_IPV4;
123 /* Hmm, no useable IPv6 then. */
124 qry->ns.reputation |= KR_NS_NOIP6;
125 kr_nsrep_update_rep(&qry->ns, qry->ns.reputation, ctx->cache_rep);
126 }
127 /* Bail out if the query is already pending or dependency loop. */
128 if (!next_type || kr_rplan_satisfies(qry->parent, qry->ns.name, KNOT_CLASS_IN, next_type)) {
129 /* Fall back to SBELT if root server query fails. */
130 if (!next_type && qry->zone_cut.name[0] == '\0') {
131 DEBUG_MSG(qry, "=> fallback to root hints\n");
132 kr_zonecut_set_sbelt(ctx, &qry->zone_cut);
133 qry->flags |= QUERY_NO_THROTTLE; /* Pick even bad SBELT servers */
134 return kr_error(EAGAIN);
135 }
136 /* No IPv4 nor IPv6, flag server as unuseable. */
137 DEBUG_MSG(qry, "=> unresolvable NS address, bailing out\n");
138 qry->ns.reputation |= KR_NS_NOIP4 | KR_NS_NOIP6;
139 kr_nsrep_update_rep(&qry->ns, qry->ns.reputation, ctx->cache_rep);
140 invalidate_ns(rplan, qry);
141 return kr_error(EHOSTUNREACH);
142 }
143 /* Push new query to the resolution plan */
144 struct kr_query *next = kr_rplan_push(rplan, qry, qry->ns.name, KNOT_CLASS_IN, next_type);
145 if (!next) {
146 return kr_error(ENOMEM);
147 }
148 /* At the root level with no NS addresses, add SBELT subrequest. */
149 int ret = 0;
150 if (qry->zone_cut.name[0] == '\0') {
151 ret = kr_zonecut_set_sbelt(ctx, &next->zone_cut);
152 if (ret == 0) { /* Copy TA and key since it's the same cut to avoid lookup. */
153 kr_zonecut_copy_trust(&next->zone_cut, &qry->zone_cut);
154 kr_zonecut_set_sbelt(ctx, &qry->zone_cut); /* Add SBELT to parent in case query fails. */
155 qry->flags |= QUERY_NO_THROTTLE; /* Pick even bad SBELT servers */
156 }
157 } else {
158 next->flags |= QUERY_AWAIT_CUT;
159 }
160 return ret;
161 }
162
163 static int edns_put(knot_pkt_t *pkt)
164 {
165 if (!pkt->opt_rr) {
166 return kr_ok();
167 }
168 /* Reclaim reserved size. */
169 int ret = knot_pkt_reclaim(pkt, knot_edns_wire_size(pkt->opt_rr));
170 if (ret != 0) {
171 return ret;
172 }
173 /* Write to packet. */
174 assert(pkt->current == KNOT_ADDITIONAL);
175 return knot_pkt_put(pkt, KNOT_COMPR_HINT_NONE, pkt->opt_rr, KNOT_PF_FREE);
176 }
177
178 static int edns_create(knot_pkt_t *pkt, knot_pkt_t *template, struct kr_request *req)
179 {
180 pkt->opt_rr = knot_rrset_copy(req->ctx->opt_rr, &pkt->mm);
181 return knot_pkt_reserve(pkt, knot_edns_wire_size(pkt->opt_rr));
182 }
183
184 static int answer_prepare(knot_pkt_t *answer, knot_pkt_t *query, struct kr_request *req)
185 {
186 if (knot_pkt_init_response(answer, query) != 0) {
187 return kr_error(ENOMEM); /* Failed to initialize answer */
188 }
189 /* Handle EDNS in the query */
190 if (knot_pkt_has_edns(query)) {
191 int ret = edns_create(answer, query, req);
192 if (ret != 0){
193 return ret;
194 }
195 /* Set DO bit if set (DNSSEC requested). */
196 if (knot_pkt_has_dnssec(query)) {
197 knot_edns_set_do(answer->opt_rr);
198 }
199 }
200 return kr_ok();
201 }
202
203 static int answer_finalize(struct kr_request *request, int state)
204 {
205 /* Write EDNS information */
206 knot_pkt_t *answer = request->answer;
207 knot_pkt_begin(answer, KNOT_ADDITIONAL);
208 if (answer->opt_rr) {
209 int ret = edns_put(answer);
210 if (ret != 0) {
211 return ret;
212 }
213 }
214 /* Set AD=1 if succeeded and requested secured answer. */
215 struct kr_rplan *rplan = &request->rplan;
216 if (state == KNOT_STATE_DONE && !EMPTY_LIST(rplan->resolved)) {
217 struct kr_query *last = TAIL(rplan->resolved);
218 /* Do not set AD for RRSIG query, as we can't validate it. */
219 if ((last->flags & QUERY_DNSSEC_WANT) && knot_pkt_has_dnssec(answer) &&
220 knot_pkt_qtype(answer) != KNOT_RRTYPE_RRSIG) {
221 knot_wire_set_ad(answer->wire);
222 }
223 }
224 return kr_ok();
225 }
226
227 static int query_finalize(struct kr_request *request, struct kr_query *qry, knot_pkt_t *pkt)
228 {
229 /* Randomize query case (if not in safemode) */
230 qry->secret = (qry->flags & QUERY_SAFEMODE) ? 0 : kr_rand_uint(UINT32_MAX);
231 knot_dname_t *qname_raw = (knot_dname_t *)knot_pkt_qname(pkt);
232 randomized_qname_case(qname_raw, qry->secret);
233
234 int ret = 0;
235 knot_pkt_begin(pkt, KNOT_ADDITIONAL);
236 if (!(qry->flags & QUERY_SAFEMODE)) {
237 ret = edns_create(pkt, request->answer, request);
238 if (ret == 0) { /* Enable DNSSEC for query. */
239 if (qry->flags & QUERY_DNSSEC_WANT) {
240 knot_edns_set_do(pkt->opt_rr);
241 knot_wire_set_cd(pkt->wire);
242 }
243 ret = edns_put(pkt);
244 }
245 }
246 return ret;
247 }
248
249 int kr_resolve_begin(struct kr_request *request, struct kr_context *ctx, knot_pkt_t *answer)
250 {
251 /* Initialize request */
252 request->ctx = ctx;
253 request->answer = answer;
254 request->options = ctx->options;
255 request->state = KNOT_STATE_CONSUME;
256 request->current_query = NULL;
257
258 /* Expect first query */
259 kr_rplan_init(&request->rplan, request, &request->pool);
260 return KNOT_STATE_CONSUME;
261 }
262
263 static int resolve_query(struct kr_request *request, const knot_pkt_t *packet)
264 {
265 struct kr_rplan *rplan = &request->rplan;
266 const knot_dname_t *qname = knot_pkt_qname(packet);
267 uint16_t qclass = knot_pkt_qclass(packet);
268 uint16_t qtype = knot_pkt_qtype(packet);
269 struct kr_query *qry = kr_rplan_push(rplan, NULL, qname, qclass, qtype);
270 if (!qry) {
271 return KNOT_STATE_FAIL;
272 }
273
274 /* Deferred zone cut lookup for this query. */
275 qry->flags |= QUERY_AWAIT_CUT;
276 /* Want DNSSEC if it's posible to secure this name (e.g. is covered by any TA) */
277 map_t *negative_anchors = &request->ctx->negative_anchors;
278 map_t *trust_anchors = &request->ctx->trust_anchors;
279 if (knot_pkt_has_dnssec(packet) &&
280 kr_ta_covers(trust_anchors, qname) && !kr_ta_covers(negative_anchors, qname)) {
281 qry->flags |= QUERY_DNSSEC_WANT;
282 }
283
284 /* Initialize answer packet */
285 knot_pkt_t *answer = request->answer;
286 knot_wire_set_qr(answer->wire);
287 knot_wire_clear_aa(answer->wire);
288 knot_wire_set_ra(answer->wire);
289 knot_wire_set_rcode(answer->wire, KNOT_RCODE_NOERROR);
290
291 /* Expect answer, pop if satisfied immediately */
292 ITERATE_LAYERS(request, qry, begin, request);
293 if (request->state == KNOT_STATE_DONE) {
294 kr_rplan_pop(rplan, qry);
295 }
296 return request->state;
297 }
298
299 int kr_resolve_consume(struct kr_request *request, const struct sockaddr *src, knot_pkt_t *packet)
300 {
301 struct kr_rplan *rplan = &request->rplan;
302 struct kr_context *ctx = request->ctx;
303
304 /* Empty resolution plan, push packet as the new query */
305 if (packet && kr_rplan_empty(rplan)) {
306 if (answer_prepare(request->answer, packet, request) != 0) {
307 return KNOT_STATE_FAIL;
308 }
309 return resolve_query(request, packet);
310 }
311
312 /* Different processing for network error */
313 struct kr_query *qry = TAIL(rplan->pending);
314 bool tried_tcp = (qry->flags & QUERY_TCP);
315 if (!packet || packet->size == 0) {
316 /* Network error, retry over TCP. */
317 if (!tried_tcp) {
318 DEBUG_MSG(qry, "=> NS unreachable, retrying over TCP\n");
319 qry->flags |= QUERY_TCP;
320 return KNOT_STATE_PRODUCE;
321 }
322 request->state = KNOT_STATE_FAIL;
323 } else {
324 /* Packet cleared, derandomize QNAME. */
325 knot_dname_t *qname_raw = (knot_dname_t *)knot_pkt_qname(packet);
326 if (qname_raw && qry->secret != 0) {
327 randomized_qname_case(qname_raw, qry->secret);
328 }
329 request->state = KNOT_STATE_CONSUME;
330 ITERATE_LAYERS(request, qry, consume, packet);
331 }
332
333 /* Resolution failed, invalidate current NS. */
334 if (request->state == KNOT_STATE_FAIL) {
335 kr_nsrep_update_rtt(&qry->ns, src, KR_NS_TIMEOUT, ctx->cache_rtt);
336 invalidate_ns(rplan, qry);
337 qry->flags &= ~QUERY_RESOLVED;
338 /* Track RTT for iterative answers */
339 } else if (!(qry->flags & QUERY_CACHED)) {
340 struct timeval now;
341 gettimeofday(&now, NULL);
342 kr_nsrep_update_rtt(&qry->ns, src, time_diff(&qry->timestamp, &now), ctx->cache_rtt);
343 /* Sucessful answer, lift any address resolution requests. */
344 qry->flags &= ~(QUERY_AWAIT_IPV6|QUERY_AWAIT_IPV4);
345 }
346
347 /* Pop query if resolved. */
348 if (qry->flags & QUERY_RESOLVED) {
349 kr_rplan_pop(rplan, qry);
350 } else if (!tried_tcp && (qry->flags & QUERY_TCP)) {
351 return KNOT_STATE_PRODUCE; /* Requery over TCP */
352 } else { /* Clear query flags for next attempt */
353 qry->flags &= ~(QUERY_CACHED|QUERY_TCP);
354 }
355
356 ITERATE_LAYERS(request, qry, reset);
357
358 /* Do not finish with bogus answer. */
359 if (qry->flags & QUERY_DNSSEC_BOGUS) {
360 return KNOT_STATE_FAIL;
361 }
362
363 return kr_rplan_empty(&request->rplan) ? KNOT_STATE_DONE : KNOT_STATE_PRODUCE;
364 }
365
366 /** @internal Spawn subrequest in current zone cut (no minimization or lookup). */
367 static struct kr_query *zone_cut_subreq(struct kr_rplan *rplan, struct kr_query *parent,
368 const knot_dname_t *qname, uint16_t qtype)
369 {
370 struct kr_query *next = kr_rplan_push(rplan, parent, qname, parent->sclass, qtype);
371 if (!next) {
372 return NULL;
373 }
374 kr_zonecut_set(&next->zone_cut, parent->zone_cut.name);
375 if (kr_zonecut_copy(&next->zone_cut, &parent->zone_cut) != 0 ||
376 kr_zonecut_copy_trust(&next->zone_cut, &parent->zone_cut) != 0) {
377 return NULL;
378 }
379 next->flags |= QUERY_NO_MINIMIZE;
380 if (parent->flags & QUERY_DNSSEC_WANT) {
381 next->flags |= QUERY_DNSSEC_WANT;
382 }
383 return next;
384 }
385
386 /** @internal Check current zone cut status and credibility, spawn subrequests if needed. */
387 static int zone_cut_check(struct kr_request *request, struct kr_query *qry, knot_pkt_t *packet)
388 {
389 struct kr_rplan *rplan = &request->rplan;
390 map_t *trust_anchors = &request->ctx->trust_anchors;
391 map_t *negative_anchors = &request->ctx->negative_anchors;
392
393 /* The query wasn't resolved from cache,
394 * now it's the time to look up closest zone cut from cache. */
395 if (qry->flags & QUERY_AWAIT_CUT) {
396 /* Want DNSSEC if it's posible to secure this name (e.g. is covered by any TA) */
397 if (!kr_ta_covers(negative_anchors, qry->zone_cut.name) &&
398 kr_ta_covers(trust_anchors, qry->zone_cut.name)) {
399 qry->flags |= QUERY_DNSSEC_WANT;
400 } else {
401 qry->flags &= ~QUERY_DNSSEC_WANT;
402 }
403 int ret = ns_fetch_cut(qry, request, (qry->flags & QUERY_DNSSEC_WANT));
404 if (ret != 0) {
405 /* No cached cut found, start from SBELT and issue priming query. */
406 if (ret == kr_error(ENOENT)) {
407 ret = kr_zonecut_set_sbelt(request->ctx, &qry->zone_cut);
408 if (ret != 0) {
409 return KNOT_STATE_FAIL;
410 }
411 if (qry->sname[0] != '\0') {
412 DEBUG_MSG(qry, "=> root priming query\n");
413 zone_cut_subreq(rplan, qry, qry->zone_cut.name, KNOT_RRTYPE_NS);
414 } else {
415 DEBUG_MSG(qry, "=> using root hints\n");
416 }
417 qry->flags &= ~QUERY_AWAIT_CUT;
418 return KNOT_STATE_DONE;
419 } else {
420 return KNOT_STATE_FAIL;
421 }
422 }
423 /* Update minimized QNAME if zone cut changed */
424 if (qry->zone_cut.name[0] != '\0' && !(qry->flags & QUERY_NO_MINIMIZE)) {
425 if (kr_make_query(qry, packet) != 0) {
426 return KNOT_STATE_FAIL;
427 }
428 }
429 qry->flags &= ~QUERY_AWAIT_CUT;
430 }
431 /* Disable DNSSEC if it enters NTA. */
432 if (kr_ta_get(negative_anchors, qry->zone_cut.name)){
433 DEBUG_MSG(qry, ">< negative TA, going insecure\n");
434 qry->flags &= ~QUERY_DNSSEC_WANT;
435 }
436 /* Enable DNSSEC if enters a new island of trust. */
437 bool want_secured = (qry->flags & QUERY_DNSSEC_WANT);
438 if (!want_secured && kr_ta_get(trust_anchors, qry->zone_cut.name)) {
439 qry->flags |= QUERY_DNSSEC_WANT;
440 want_secured = true;
441 WITH_DEBUG {
442 char qname_str[KNOT_DNAME_MAXLEN];
443 knot_dname_to_str(qname_str, qry->zone_cut.name, sizeof(qname_str));
444 DEBUG_MSG(qry, ">< TA: '%s'\n", qname_str);
445 }
446 }
447 if (want_secured && !qry->zone_cut.trust_anchor) {
448 knot_rrset_t *ta_rr = kr_ta_get(trust_anchors, qry->zone_cut.name);
449 qry->zone_cut.trust_anchor = knot_rrset_copy(ta_rr, qry->zone_cut.pool);
450 }
451 /* Try to fetch missing DS (from above the cut). */
452 const bool has_ta = (qry->zone_cut.trust_anchor != NULL);
453 const knot_dname_t *ta_name = (has_ta ? qry->zone_cut.trust_anchor->owner : NULL);
454 const bool refetch_ta = !has_ta || !knot_dname_is_equal(qry->zone_cut.name, ta_name);
455 if (want_secured && refetch_ta) {
456 /* @todo we could fetch the information from the parent cut, but we don't remember that now */
457 struct kr_query *next = kr_rplan_push(rplan, qry, qry->zone_cut.name, qry->sclass, KNOT_RRTYPE_DS);
458 if (!next) {
459 return KNOT_STATE_FAIL;
460 }
461 next->flags |= QUERY_AWAIT_CUT|QUERY_DNSSEC_WANT;
462 return KNOT_STATE_DONE;
463 }
464 /* Try to fetch missing DNSKEY (either missing or above current cut).
465 * Do not fetch if this is a DNSKEY subrequest to avoid circular dependency. */
466 const bool is_dnskey_subreq = kr_rplan_satisfies(qry, ta_name, KNOT_CLASS_IN, KNOT_RRTYPE_DNSKEY);
467 const bool refetch_key = has_ta && (!qry->zone_cut.key || !knot_dname_is_equal(ta_name, qry->zone_cut.key->owner));
468 if (want_secured && refetch_key && !is_dnskey_subreq) {
469 struct kr_query *next = zone_cut_subreq(rplan, qry, ta_name, KNOT_RRTYPE_DNSKEY);
470 if (!next) {
471 return KNOT_STATE_FAIL;
472 }
473 return KNOT_STATE_DONE;
474 }
475
476 return KNOT_STATE_PRODUCE;
477 }
478
479 int kr_resolve_produce(struct kr_request *request, struct sockaddr **dst, int *type, knot_pkt_t *packet)
480 {
481 struct kr_rplan *rplan = &request->rplan;
482 unsigned ns_election_iter = 0;
483
484 /* No query left for resolution */
485 if (kr_rplan_empty(rplan)) {
486 return KNOT_STATE_FAIL;
487 }
488
489 /* Resolve current query and produce dependent or finish */
490 struct kr_query *qry = TAIL(rplan->pending);
491 request->state = KNOT_STATE_PRODUCE;
492 ITERATE_LAYERS(request, qry, produce, packet);
493 if (request->state != KNOT_STATE_FAIL && knot_wire_get_qr(packet->wire)) {
494 /* Produced an answer, consume it. */
495 qry->secret = 0;
496 request->state = KNOT_STATE_CONSUME;
497 ITERATE_LAYERS(request, qry, consume, packet);
498 }
499 switch(request->state) {
500 case KNOT_STATE_FAIL: return request->state;
501 case KNOT_STATE_CONSUME: break;
502 case KNOT_STATE_DONE:
503 default: /* Current query is done */
504 if (qry->flags & QUERY_RESOLVED) {
505 kr_rplan_pop(rplan, qry);
506 }
507 ITERATE_LAYERS(request, qry, reset);
508 return kr_rplan_empty(rplan) ? KNOT_STATE_DONE : KNOT_STATE_PRODUCE;
509 }
510
511 /* This query has RD=0 or is ANY, stop here. */
512 if (qry->stype == KNOT_RRTYPE_ANY || !knot_wire_get_rd(request->answer->wire)) {
513 DEBUG_MSG(qry, "=> qtype is ANY or RD=0, bail out\n");
514 return KNOT_STATE_FAIL;
515 }
516
517 /* Update zone cut, spawn new subrequests. */
518 int state = zone_cut_check(request, qry, packet);
519 switch(state) {
520 case KNOT_STATE_FAIL: return KNOT_STATE_FAIL;
521 case KNOT_STATE_DONE: return KNOT_STATE_PRODUCE;
522 default: break;
523 }
524
525 ns_election:
526
527 /* If the query has already selected a NS and is waiting for IPv4/IPv6 record,
528 * elect best address only, otherwise elect a completely new NS.
529 */
530 if(++ns_election_iter >= KR_ITER_LIMIT) {
531 DEBUG_MSG(qry, "=> couldn't converge NS selection, bail out\n");
532 return KNOT_STATE_FAIL;
533 }
534 if (qry->flags & (QUERY_AWAIT_IPV4|QUERY_AWAIT_IPV6)) {
535 kr_nsrep_elect_addr(qry, request->ctx);
536 } else if (!qry->ns.name || !(qry->flags & QUERY_TCP)) { /* Keep address when TCP retransmit. */
537 /* Root DNSKEY must be fetched from the hints to avoid chicken and egg problem. */
538 if (qry->sname[0] == '\0' && qry->stype == KNOT_RRTYPE_DNSKEY) {
539 DEBUG_MSG(qry, "=> priming root DNSKEY\n");
540 kr_zonecut_set_sbelt(request->ctx, &qry->zone_cut);
541 qry->flags |= QUERY_NO_THROTTLE; /* Pick even bad SBELT servers */
542 }
543 kr_nsrep_elect(qry, request->ctx);
544 if (qry->ns.score > KR_NS_MAX_SCORE) {
545 DEBUG_MSG(qry, "=> no valid NS left\n");
546 ITERATE_LAYERS(request, qry, reset);
547 kr_rplan_pop(rplan, qry);
548 return KNOT_STATE_PRODUCE;
549 }
550 }
551
552 /* Resolve address records */
553 if (qry->ns.addr[0].ip.sa_family == AF_UNSPEC) {
554 int ret = ns_resolve_addr(qry, request);
555 if (ret != 0) {
556 qry->flags &= ~(QUERY_AWAIT_IPV6|QUERY_AWAIT_IPV4|QUERY_TCP);
557 goto ns_election; /* Must try different NS */
558 }
559 ITERATE_LAYERS(request, qry, reset);
560 return KNOT_STATE_PRODUCE;
561 }
562
563 /* Prepare additional query */
564 int ret = query_finalize(request, qry, packet);
565 if (ret != 0) {
566 return KNOT_STATE_FAIL;
567 }
568
569 WITH_DEBUG {
570 char qname_str[KNOT_DNAME_MAXLEN], zonecut_str[KNOT_DNAME_MAXLEN], ns_str[SOCKADDR_STRLEN], type_str[16];
571 knot_dname_to_str(qname_str, knot_pkt_qname(packet), sizeof(qname_str));
572 knot_dname_to_str(zonecut_str, qry->zone_cut.name, sizeof(zonecut_str));
573 knot_rrtype_to_string(knot_pkt_qtype(packet), type_str, sizeof(type_str));
574 for (size_t i = 0; i < KR_NSREP_MAXADDR; ++i) {
575 struct sockaddr *addr = &qry->ns.addr[i].ip;
576 if (addr->sa_family == AF_UNSPEC) {
577 break;
578 }
579 inet_ntop(addr->sa_family, kr_nsrep_inaddr(qry->ns.addr[i]), ns_str, sizeof(ns_str));
580 DEBUG_MSG(qry, "%s: '%s' score: %u zone cut: '%s' m12n: '%s' type: '%s'\n",
581 i == 0 ? "=> querying" : " optional",
582 ns_str, qry->ns.score, zonecut_str, qname_str, type_str);
583 }
584 }
585
586 gettimeofday(&qry->timestamp, NULL);
587 *dst = &qry->ns.addr[0].ip;
588 *type = (qry->flags & QUERY_TCP) ? SOCK_STREAM : SOCK_DGRAM;
589 return request->state;
590 }
591
592 int kr_resolve_finish(struct kr_request *request, int state)
593 {
594 #ifndef NDEBUG
595 struct kr_rplan *rplan = &request->rplan;
596 #endif
597 /* Finalize answer */
598 if (answer_finalize(request, state) != 0) {
599 state = KNOT_STATE_FAIL;
600 }
601 /* Error during procesing, internal failure */
602 if (state != KNOT_STATE_DONE) {
603 knot_pkt_t *answer = request->answer;
604 if (knot_wire_get_rcode(answer->wire) == KNOT_RCODE_NOERROR) {
605 knot_wire_set_rcode(answer->wire, KNOT_RCODE_SERVFAIL);
606 }
607 }
608
609 ITERATE_LAYERS(request, NULL, finish);
610 DEBUG_MSG(NULL, "finished: %d, queries: %zu, mempool: %zu B\n",
611 state, list_size(&rplan->resolved), (size_t) mp_total_size(request->pool.ctx));
612 return KNOT_STATE_DONE;
613 }
614
615 struct kr_rplan *kr_resolve_plan(struct kr_request *request)
616 {
617 if (request) {
618 return &request->rplan;
619 }
620 return NULL;
621 }
Attached Files
To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.You are not allowed to attach a file to this page.