From: Marek Vavruša Date: Sat, 2 May 2015 14:32:30 +0000 (+0200) Subject: lib: revert to rfc1035 basic dns query on bad reply X-Git-Tag: v1.0.0-beta1~221^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=53cb90dc051597b416cf8bf474f44c1102f358e1;p=thirdparty%2Fknot-resolver.git lib: revert to rfc1035 basic dns query on bad reply if the server doesn’t understand edns0, replies with notimpl, formerr or sends bad badly formed response, we try basic dns query (ns0.rbsov.bbc.co.uk) --- diff --git a/lib/layer/iterate.c b/lib/layer/iterate.c index 2d49d98c5..b3f722aa1 100644 --- a/lib/layer/iterate.c +++ b/lib/layer/iterate.c @@ -345,6 +345,24 @@ static int begin(knot_layer_t *ctx, void *module_param) return reset(ctx); } +static int prepare_additionals(knot_pkt_t *pkt) +{ + knot_rrset_t opt_rr; + int ret = knot_edns_init(&opt_rr, KR_EDNS_PAYLOAD, 0, KR_EDNS_VERSION, &pkt->mm); + if (ret != KNOT_EOK) { + return ret; + } + + knot_pkt_begin(pkt, KNOT_ADDITIONAL); + ret = knot_pkt_put(pkt, KNOT_COMPR_HINT_NONE, &opt_rr, KNOT_PF_FREE); + if (ret != KNOT_EOK) { + knot_rrset_clear(&opt_rr, &pkt->mm); + return ret; + } + + return kr_ok(); +} + static int prepare_query(knot_layer_t *ctx, knot_pkt_t *pkt) { assert(pkt && ctx); @@ -370,23 +388,28 @@ static int prepare_query(knot_layer_t *ctx, knot_pkt_t *pkt) knot_wire_set_id(pkt->wire, query->id); /* Declare EDNS0 support. */ - knot_rrset_t opt_rr; - ret = knot_edns_init(&opt_rr, KR_EDNS_PAYLOAD, 0, KR_EDNS_VERSION, &pkt->mm); - if (ret != KNOT_EOK) { - return KNOT_STATE_FAIL; - } - - knot_pkt_begin(pkt, KNOT_ADDITIONAL); - ret = knot_pkt_put(pkt, KNOT_COMPR_HINT_NONE, &opt_rr, KNOT_PF_FREE); - if (ret != KNOT_EOK) { - knot_rrset_clear(&opt_rr, &pkt->mm); - return KNOT_STATE_FAIL; + if (!(query->flags & QUERY_SAFEMODE)) { + ret = prepare_additionals(pkt); + if (ret != 0) { + return KNOT_STATE_FAIL; + } } /* Query built, expect answer. */ return KNOT_STATE_CONSUME; } +static int resolve_badmsg(knot_pkt_t *pkt, struct kr_request *req, struct kr_query *query) +{ + /* Work around broken auths/load balancers */ + if (query->flags & QUERY_SAFEMODE) { + return resolve_error(pkt, req); + } else { + query->flags |= QUERY_SAFEMODE; + return KNOT_STATE_DONE; + } +} + /** Resolve input query or continue resolution with followups. * * This roughly corresponds to RFC1034, 5.3.3 4a-d. @@ -403,7 +426,7 @@ static int resolve(knot_layer_t *ctx, knot_pkt_t *pkt) /* Check for packet processing errors first. */ if (pkt->parsed < pkt->size) { DEBUG_MSG("<= malformed response\n"); - return resolve_error(pkt, req); + return resolve_badmsg(pkt, req, query); } else if (!is_paired_to_query(pkt, query)) { DEBUG_MSG("<= ignoring mismatching response\n"); return KNOT_STATE_CONSUME; @@ -428,6 +451,10 @@ static int resolve(knot_layer_t *ctx, knot_pkt_t *pkt) case KNOT_RCODE_NOERROR: case KNOT_RCODE_NXDOMAIN: break; /* OK */ + case KNOT_RCODE_FORMERR: + case KNOT_RCODE_NOTIMPL: + DEBUG_MSG("<= rcode: %s\n", rcode ? rcode->name : "??"); + return resolve_badmsg(pkt, req, query); default: DEBUG_MSG("<= rcode: %s\n", rcode ? rcode->name : "??"); return resolve_error(pkt, req); diff --git a/lib/resolve.c b/lib/resolve.c index ce03d43ac..4ac474df1 100644 --- a/lib/resolve.c +++ b/lib/resolve.c @@ -100,6 +100,7 @@ static int sendrecv(struct sockaddr *addr, int proto, const knot_pkt_t *query, k { struct timeval timeout = { KR_CONN_RTT_MAX / 1000, 0 }; auto_close int fd = connected(addr, proto, &timeout); + resp->size = 0; if (fd < 0) { return fd; } @@ -127,11 +128,7 @@ static int sendrecv(struct sockaddr *addr, int proto, const knot_pkt_t *query, k /* Parse and return */ resp->size = ret; - if (knot_pkt_parse(resp, 0) != 0) { - return kr_error(EBADMSG); - } - - return kr_ok(); + return knot_pkt_parse(resp, 0); } int kr_resolve(struct kr_context* ctx, knot_pkt_t *answer, @@ -178,7 +175,6 @@ int kr_resolve(struct kr_context* ctx, knot_pkt_t *answer, int ret = sendrecv(addr, proto, query, resp); if (ret != 0) { DEBUG_MSG("sendrecv: %s\n", kr_strerror(ret)); - resp->size = 0; } state = kr_resolve_consume(&request, resp); knot_pkt_clear(resp); diff --git a/lib/rplan.h b/lib/rplan.h index ef5786c31..c21d75d29 100644 --- a/lib/rplan.h +++ b/lib/rplan.h @@ -31,7 +31,8 @@ enum kr_query_flag { QUERY_NO_MINIMIZE = 1 << 0, /**< Don't minimize QNAME. */ QUERY_TCP = 1 << 1, /**< Use TCP for this query. */ QUERY_RESOLVED = 1 << 2, /**< Query is resolved. */ - QUERY_AWAIT_ADDR = 1 << 3 /**< Query is waiting for NS address. */ + QUERY_AWAIT_ADDR = 1 << 3, /**< Query is waiting for NS address. */ + QUERY_SAFEMODE = 1 << 4 /**< Don't use fancy stuff (EDNS...) */ }; /** diff --git a/tests/testdata/iter_formerr.rpl b/tests/testdata/iter_formerr.rpl new file mode 100644 index 000000000..c541f83b9 --- /dev/null +++ b/tests/testdata/iter_formerr.rpl @@ -0,0 +1,86 @@ +; config options +server: + harden-referral-path: no + target-fetch-policy: "0 0 0 0 0" + +stub-zone: + name: "." + stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET. +CONFIG_END + +SCENARIO_BEGIN Disable EDNS0 and fancy stuff when the server replies with FORMERR. + +STEP 10 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +cz. IN A +ENTRY_END + +; root prime +STEP 30 REPLY +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +. IN NS +SECTION ANSWER +. IN NS K.ROOT-SERVERS.NET. +SECTION ADDITIONAL +K.ROOT-SERVERS.NET. IN A 193.0.14.129 +ENTRY_END + +; query sent to root server +STEP 50 REPLY +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +cz. IN A +SECTION AUTHORITY +cz. IN NS ns1.cz. +SECTION ADDITIONAL +ns1.cz. IN A 168.192.2.2 +ENTRY_END + +; this is the formerr answer +STEP 60 REPLY +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA FORMERR +SECTION QUESTION +cz. IN A +SECTION ANSWER +ENTRY_END + +; this is the correct answer +STEP 60 REPLY +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +cz. IN A +SECTION ANSWER +cz. IN A 10.20.30.40 +SECTION AUTHORITY +cz. IN NS ns1.cz. +SECTION ADDITIONAL +ns1.cz. IN A 168.192.2.2 +ENTRY_END + +; is the final answer correct? +STEP 100 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA +SECTION QUESTION +cz. IN A +SECTION ANSWER +cz. IN A 10.20.30.40 +ENTRY_END + +SCENARIO_END