]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
lib: revert to rfc1035 basic dns query on bad reply
authorMarek Vavruša <marek.vavrusa@nic.cz>
Sat, 2 May 2015 14:32:30 +0000 (16:32 +0200)
committerMarek Vavruša <marek.vavrusa@nic.cz>
Sat, 2 May 2015 14:32:30 +0000 (16:32 +0200)
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)

lib/layer/iterate.c
lib/resolve.c
lib/rplan.h
tests/testdata/iter_formerr.rpl [new file with mode: 0644]

index 2d49d98c59e2f31b5fbc097cb9c9fc8490982d88..b3f722aa1775fc8fc67eee846370bc1d988c586c 100644 (file)
@@ -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);
index ce03d43ac6aa5368ff79ae84592fd55fdd352945..4ac474df109ed4e37ff32f78fab356d986abaa42 100644 (file)
@@ -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);
index ef5786c31c8a7b387f4458b909f704dfc70d06a2..c21d75d298363db71ee9f1b215f5100b736c944b 100644 (file)
@@ -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 (file)
index 0000000..c541f83
--- /dev/null
@@ -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