]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
Bring cookies branch up-to-date with current master
authorWillem Toorop <willem@nlnetlabs.nl>
Tue, 27 Sep 2022 15:23:20 +0000 (17:23 +0200)
committerWillem Toorop <willem@nlnetlabs.nl>
Tue, 27 Sep 2022 15:23:20 +0000 (17:23 +0200)
14 files changed:
daemon/acl_list.c
daemon/worker.c
doc/unbound.conf.5.in
libunbound/libworker.c
services/authzone.c
testcode/fake_event.c
util/data/msgencode.c
util/data/msgparse.c
util/data/msgparse.h
util/edns.c
util/edns.h
util/net_help.c
util/net_help.h
validator/autotrust.c

index 3c5e7b51407daa387bff059adc3380062bdf1060..e6d0470a1940a3cd22a770953170a7d2e8001431 100644 (file)
@@ -109,7 +109,7 @@ parse_acl_access(const char* str, enum acl_access* control)
                *control = acl_allow_snoop;
        else if(strcmp(str, "allow_setrd") == 0)
                *control = acl_allow_setrd;
-       else if (strcmp(s2, "allow_cookie") == 0)
+       else if (strcmp(str, "allow_cookie") == 0)
                *control = acl_allow_cookie;
        else {
                log_err("access control type %s unknown", str);
index ba4dbf3b1bf59f6f55b5aaa71673bdf11e43d009..f2fee104055fbff8ee43b25de637202c2c645638 100644 (file)
@@ -1267,8 +1267,9 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
        struct query_info* lookup_qinfo = &qinfo;
        struct query_info qinfo_tmp; /* placeholder for lookup_qinfo */
        struct respip_client_info* cinfo = NULL, cinfo_tmp;
-       int valid_cookie = 0;
        memset(&qinfo, 0, sizeof(qinfo));
+       memset(&edns, 0, sizeof(edns));
+       edns.udp_size = 512;
 
        if((error != NETEVENT_NOERROR && error != NETEVENT_DONE)|| !repinfo) {
                /* some bad tcp query DNS formats give these error calls */
@@ -1433,8 +1434,10 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
                }
                goto send_reply;
        }
-       if((ret=parse_edns_from_query_pkt(c->buffer, &edns, worker->env.cfg, c,
-                                       worker->scratchpad)) != 0) {
+       if((ret=parse_edns_from_query_pkt(
+                       c->buffer, &edns, worker->env.cfg, c, repinfo,
+                       (worker->env.now ? *worker->env.now : time(NULL)),
+                       worker->scratchpad)) != 0) {
                struct edns_data reply_edns;
                verbose(VERB_ALGO, "worker parse edns: formerror.");
                log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
@@ -1448,163 +1451,66 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
                regional_free_all(worker->scratchpad);
                goto send_reply;
        }
-       if(!edns.edns_present) {
-               if(c->type == comm_udp && acl == acl_allow_cookie) {
-                       verbose(VERB_ALGO, "worker request: "
-                               "need cookie or stateful transport");
-                       log_addr(VERB_ALGO, "from",
-                               &repinfo->addr, repinfo->addrlen);
-                       LDNS_QR_SET(sldns_buffer_begin(c->buffer));
-                       LDNS_TC_SET(sldns_buffer_begin(c->buffer));
-                       LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), 
-                               LDNS_RCODE_REFUSED);
-                       sldns_buffer_set_position(c->buffer,
-                                       LDNS_HEADER_SIZE);
-                       sldns_buffer_write_at(c->buffer, 4, 
-                               (uint8_t*)"\0\0\0\0\0\0\0\0", 8);
-                       sldns_buffer_flip(c->buffer);
-                       regional_free_all(worker->scratchpad);
-                       goto send_reply;
-               }
+       if(edns.edns_present && edns.edns_version != 0) {
+               edns.opt_list_in = NULL;
+               edns.opt_list_out = NULL;
+               edns.opt_list_inplace_cb_out = NULL;
+               edns.padding_block_size = 0;
+               edns.cookie_present = 0;
+               edns.cookie_valid = 0;
+               verbose(VERB_ALGO, "query with bad edns version.");
+               log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
+               error_encode(c->buffer, EDNS_RCODE_BADVERS, &qinfo,
+                       *(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
+                       sldns_buffer_read_u16_at(c->buffer, 2), &edns);
+               regional_free_all(worker->scratchpad);
+               goto send_reply;
+       }
+       if(edns.udp_size < NORMAL_UDP_SIZE &&
+          worker->daemon->cfg->harden_short_bufsize) {
+               verbose(VERB_QUERY, "worker request: EDNS bufsize %d ignored",
+                       (int)edns.udp_size);
+               log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
+               edns.udp_size = NORMAL_UDP_SIZE;
+       }
+       /* "if, else if" sequence below deals with downstream DNS Cookies */
+       if (acl != acl_allow_cookie)
+               ; /* pass; No cookie downstream processing whatsoever */
+
+       else if (edns.cookie_valid)
+               ; /* pass; Valid cookie is good! */
+
+       else if (c->type != comm_udp)
+               ; /* pass; Stateful transport */
+
+       else if (edns.cookie_present) {
+               /* Cookie present, but not valid: Cookie was bad! */
+               error_encode(c->buffer,
+                       LDNS_EXT_RCODE_BADCOOKIE, &qinfo,
+                       *(uint16_t*)(void *)
+                       sldns_buffer_begin(c->buffer),
+                       sldns_buffer_read_u16_at(c->buffer, 2),
+                       &edns);
+               regional_free_all(worker->scratchpad);
+               goto send_reply;
        } else {
-               struct edns_option* edns_opt;
-
-               if(edns.edns_version != 0) {
-                       edns.ext_rcode = (uint8_t)(EDNS_RCODE_BADVERS>>4);
-                       edns.edns_version = EDNS_ADVERTISED_VERSION;
-                       edns.udp_size = EDNS_ADVERTISED_SIZE;
-                       edns.bits &= EDNS_DO;
-                       edns.opt_list_in = NULL;
-                       edns.opt_list_out = NULL;
-                       edns.opt_list_inplace_cb_out = NULL;
-                       edns.padding_block_size = 0;
-                       verbose(VERB_ALGO, "query with bad edns version.");
-                       log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
-                       error_encode(c->buffer, EDNS_RCODE_BADVERS&0xf, &qinfo,
-                               *(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
-                               sldns_buffer_read_u16_at(c->buffer, 2), NULL);
-                       if(sldns_buffer_capacity(c->buffer) >=
-                          sldns_buffer_limit(c->buffer)+calc_edns_field_size(&edns))
-                               attach_edns_record(c->buffer, &edns);
-                       regional_free_all(worker->scratchpad);
-                       goto send_reply;
-               }
-               if(edns.udp_size < NORMAL_UDP_SIZE &&
-                  worker->daemon->cfg->harden_short_bufsize) {
-                       verbose(VERB_QUERY, "worker request: EDNS bufsize %d ignored",
-                               (int)edns.udp_size);
-                       log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
-                       edns.udp_size = NORMAL_UDP_SIZE;
-               }
-               if(c->type == comm_udp) {
-                       /* Cookies only on UDP */
-
-                       if(!worker->daemon->cfg->do_answer_cookie)
-                               ; /* pass; No cookie processing whatsoever */
-
-                       else if(!(edns_opt = edns_opt_list_find(
-                                       edns.opt_list, LDNS_EDNS_COOKIE))) {
-                               ; /* pass; No cookie option present */
-
-                       } else if(edns_opt->opt_len != 8 &&
-                                       (  edns_opt->opt_len < 16
-                                       || edns_opt->opt_len > 40)) {
-                               edns.ext_rcode = 0;
-                               edns.edns_version = EDNS_ADVERTISED_VERSION;
-                               edns.udp_size = EDNS_ADVERTISED_SIZE;
-                               edns.bits &= EDNS_DO;
-                               edns.opt_list = NULL;
-                               verbose(VERB_ALGO, "worker request: "
-                                               "badly formatted cookie");
-                               log_addr(VERB_CLIENT, "from",
-                                       &repinfo->addr, repinfo->addrlen);
-                               error_encode(c->buffer, LDNS_RCODE_FORMERR,
-                                       &qinfo, *(uint16_t*)(void *)
-                                       sldns_buffer_begin(c->buffer),
-                                       sldns_buffer_read_u16_at(c->buffer, 2),
-                                       NULL);
-                               if(sldns_buffer_capacity(c->buffer) >=
-                                  sldns_buffer_limit(c->buffer)
-                                  + calc_edns_field_size(&edns))
-                                       attach_edns_record(c->buffer, &edns);
-                               regional_free_all(worker->scratchpad);
-                               goto send_reply;
-
-                       } else if (edns_cookie_validate(worker->env.cfg,
-                                       repinfo, edns_opt, *worker->env.now)) {
-                               valid_cookie = 1;
-
-                       } else if (acl == acl_allow_cookie) {
-                               struct edns_data edns_bak = edns;
-                               int rcode;
-
-                               /* With invalid or just client Cookie
-                                * reply with BADCOOKIE + server cookie
-                                */
-                               edns.ext_rcode = 0;
-                               edns.edns_version = EDNS_ADVERTISED_VERSION;
-                               edns.udp_size = EDNS_ADVERTISED_SIZE;
-                               edns.bits &= EDNS_DO;
-                               edns.opt_list = NULL;
-                               if (apply_edns_options(&edns, &edns_bak,
-                                                       worker->env.cfg, c,
-                                                       repinfo,
-                                                       *worker->env.now,
-                                                       worker->scratchpad)) {
-                                       edns.ext_rcode = 1;
-                                       rcode = LDNS_EXT_RCODE_BADCOOKIE & 0xF;
-                               } else
-                                       rcode = LDNS_RCODE_SERVFAIL;
-                               error_encode(c->buffer, rcode, &qinfo,
-                                       *(uint16_t*)(void *)
-                                       sldns_buffer_begin(c->buffer),
-                                       sldns_buffer_read_u16_at(c->buffer, 2),
-                                       NULL);
-                               if(sldns_buffer_capacity(c->buffer) >=
-                                  sldns_buffer_limit(c->buffer)
-                                  + calc_edns_field_size(&edns))
-                                       attach_edns_record(c->buffer, &edns);
-                               regional_free_all(worker->scratchpad);
-                               goto send_reply;
-                       }
-                       if (acl == acl_allow_cookie && !valid_cookie) {
-                               verbose(VERB_ALGO, "worker request: "
-                                       "need cookie or stateful transport");
-                               log_addr(VERB_ALGO, "from",
-                                       &repinfo->addr, repinfo->addrlen);
-                               LDNS_QR_SET(sldns_buffer_begin(c->buffer));
-                               LDNS_TC_SET(sldns_buffer_begin(c->buffer));
-                               LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), 
-                                       LDNS_RCODE_REFUSED);
-                               sldns_buffer_set_position(c->buffer,
-                                               LDNS_HEADER_SIZE);
-                               sldns_buffer_write_at(c->buffer, 4, 
-                                       (uint8_t*)"\0\0\0\0\0\0\0\0", 8);
-                               sldns_buffer_flip(c->buffer);
-                               regional_free_all(worker->scratchpad);
-                               goto send_reply;
-                       }
-
-               } else  { /* if(c->type == comm_udp) */
-                       edns_opt = edns_opt_list_find(edns.opt_list, LDNS_EDNS_KEEPALIVE);
-                       if(edns_opt && edns_opt->opt_len > 0) {
-                               edns.ext_rcode = 0;
-                               edns.edns_version = EDNS_ADVERTISED_VERSION;
-                               edns.udp_size = EDNS_ADVERTISED_SIZE;
-                               edns.bits &= EDNS_DO;
-                               edns.opt_list = NULL;
-                               verbose(VERB_ALGO, "query with bad edns keepalive.");
-                               log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
-                               error_encode(c->buffer, LDNS_RCODE_FORMERR, &qinfo,
-                                       *(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
-                                       sldns_buffer_read_u16_at(c->buffer, 2), NULL);
-                               if(sldns_buffer_capacity(c->buffer) >=
-                                  sldns_buffer_limit(c->buffer)+calc_edns_field_size(&edns))
-                                       attach_edns_record(c->buffer, &edns);
-                               regional_free_all(worker->scratchpad);
-                               goto send_reply;
-                       }
-               }
+               /* Cookie requered, but no cookie present on UDP */
+               verbose(VERB_ALGO, "worker request: "
+                       "need cookie or stateful transport");
+               log_addr(VERB_ALGO, "from",
+                       &repinfo->addr, repinfo->addrlen);
+               EDNS_OPT_LIST_APPEND_EDE(&edns.opt_list_out,
+                       worker->scratchpad, LDNS_EDE_OTHER,
+                       "DNS Cookie needed for UDP replies");
+               error_encode(c->buffer,
+                       LDNS_RCODE_REFUSED, &qinfo,
+                       *(uint16_t*)(void *)
+                       sldns_buffer_begin(c->buffer),
+                       sldns_buffer_read_u16_at(c->buffer, 2),
+                       &edns);
+               LDNS_TC_SET(sldns_buffer_begin(c->buffer));
+               regional_free_all(worker->scratchpad);
+               goto send_reply;
        }
        if(edns.udp_size > worker->daemon->cfg->max_udp_size &&
                c->type == comm_udp) {
index 5161c37145d02d4c011696226290ee0beade33a3..00172954a4e583eb58d15dce4833b75b77da39d0 100644 (file)
@@ -1836,7 +1836,7 @@ option, that turns this on or off. The default is to use the fastest 3 servers.
 Enable to answer to requests containig DNS Cookies as specified in RFC7873.
 Default is yes.
 .TP 5
-.B cookie\-secret: \fI<128, 192 or 256 bit hex string>
+.B cookie\-secret: \fI<128 bit hex string>
 Server's in an Anycast deployment need to be able to verify each other's
 Server Cookies. For this they need to share the secret used to construct
 and verify the Server Cookies.
@@ -2071,9 +2071,8 @@ Default is no.  If enabled, data inside the forward is not cached.  This is
 useful when you want immediate changes to be visible.
 .SS "Authority Zone Options"
 .LP
-Authority zones are configured with \fBauth\-zone:\fR, and each one must have a
-\fBname:\fR.  There can be multiple ones, by listing multiple auth\-zone
-clauses, each with a different name, pertaining to that part of the namespace.
+Authority zones are configured with \fBauth\-zone:\fR, and each one must
+have a \fBname:\fR.  There can be multiple ones, by listing multiple auth\-zone clauses, each with a different name, pertaining to that part of the namespace.
 The authority zone with the name closest to the name looked up is used.
 Authority zones are processed after \fBlocal\-zones\fR and before
 cache (\fBfor\-downstream:\fR \fIyes\fR), and when used in this manner
index 11bf5f9db555d0f9e69c4547fdd6287fcff24394..d5fabe6fb6ee0c1cce47ffb43d7efb28d891533d 100644 (file)
@@ -604,6 +604,8 @@ setup_qinfo_edns(struct libworker* w, struct ctx_query* q,
        edns->opt_list_out = NULL;
        edns->opt_list_inplace_cb_out = NULL;
        edns->padding_block_size = 0;
+       edns->cookie_present = 0;
+       edns->cookie_valid = 0;
        if(sldns_buffer_capacity(w->back->udp_buff) < 65535)
                edns->udp_size = (uint16_t)sldns_buffer_capacity(
                        w->back->udp_buff);
index 6de1e43190955b798c1591d7682889227823fced..079a7eaf14634e3a245cba40a59e63c4ba5d1e8e 100644 (file)
@@ -5419,6 +5419,8 @@ xfr_transfer_lookup_host(struct auth_xfer* xfr, struct module_env* env)
        edns.opt_list_out = NULL;
        edns.opt_list_inplace_cb_out = NULL;
        edns.padding_block_size = 0;
+       edns.cookie_present = 0;
+       edns.cookie_valid = 0;
        if(sldns_buffer_capacity(buf) < 65535)
                edns.udp_size = (uint16_t)sldns_buffer_capacity(buf);
        else    edns.udp_size = 65535;
@@ -6612,6 +6614,8 @@ xfr_probe_lookup_host(struct auth_xfer* xfr, struct module_env* env)
        edns.opt_list_out = NULL;
        edns.opt_list_inplace_cb_out = NULL;
        edns.padding_block_size = 0;
+       edns.cookie_present = 0;
+       edns.cookie_valid = 0;
        if(sldns_buffer_capacity(buf) < 65535)
                edns.udp_size = (uint16_t)sldns_buffer_capacity(buf);
        else    edns.udp_size = 65535;
index 03e1c04f3dc8a4dd60e82655518c2aaf6a1f7ad4..c93ceaa4c0d4145d78728b3a449523d0a0ccfd03 100644 (file)
@@ -1263,6 +1263,8 @@ struct serviced_query* outnet_serviced_query(struct outside_network* outnet,
                if(dnssec)
                        edns.bits = EDNS_DO;
                edns.padding_block_size = 0;
+               edns.cookie_present = 0;
+               edns.cookie_valid = 0;
                edns.opt_list_in = NULL;
                edns.opt_list_out = per_upstream_opt_list;
                edns.opt_list_inplace_cb_out = NULL;
index 41d36606350162f999b17db71a769f7d275cb5ec..7b97a5466f5e441f2a5a854ee6e7720cccdae739 100644 (file)
@@ -966,7 +966,7 @@ error_encode(sldns_buffer* buf, int r, struct query_info* qinfo,
 
        sldns_buffer_clear(buf);
        sldns_buffer_write(buf, &qid, sizeof(uint16_t));
-       flags = (uint16_t)(BIT_QR | BIT_RA | r); /* QR and retcode*/
+       flags = (uint16_t)(BIT_QR | BIT_RA | (r & 0xF)); /* QR and retcode*/
        flags |= (qflags & (BIT_RD|BIT_CD)); /* copy RD and CD bit */
        sldns_buffer_write_u16(buf, flags);
        if(qinfo) flags = 1;
@@ -994,7 +994,7 @@ error_encode(sldns_buffer* buf, int r, struct query_info* qinfo,
                size_t edns_field_size = calc_edns_field_size(&es);
                es.edns_version = EDNS_ADVERTISED_VERSION;
                es.udp_size = EDNS_ADVERTISED_SIZE;
-               es.ext_rcode = 0;
+               es.ext_rcode = r >= 0x10 ? 1 : 0;
                es.bits &= EDNS_DO;
                if(sldns_buffer_limit(buf) + edns_field_size > edns->udp_size)
                        return;
index 5bb69d6ed06fc2fff257bddb591def269c94236c..3059d555c70589aa36f545845f006e177a78034d 100644 (file)
@@ -951,11 +951,67 @@ edns_opt_list_append_keepalive(struct edns_option** list, int msec,
                        data, region);
 }
 
+int siphash(const uint8_t *in, const size_t inlen,
+               const uint8_t *k, uint8_t *out, const size_t outlen);
+
+/** RFC 1982 comparison, uses unsigned integers, and tries to avoid
+ * compiler optimization (eg. by avoiding a-b<0 comparisons),
+ * this routine matches compare_serial(), for SOA serial number checks */
+static int
+compare_1982(uint32_t a, uint32_t b)
+{
+       /* for 32 bit values */
+       const uint32_t cutoff = ((uint32_t) 1 << (32 - 1));
+
+       if (a == b) {
+               return 0;
+       } else if ((a < b && b - a < cutoff) || (a > b && a - b > cutoff)) {
+               return -1;
+       } else {
+               return 1;
+       }
+}
+
+/** if we know that b is larger than a, return the difference between them,
+ * that is the distance between them. in RFC1982 arith */
+static uint32_t
+subtract_1982(uint32_t a, uint32_t b)
+{
+       /* for 32 bit values */
+       const uint32_t cutoff = ((uint32_t) 1 << (32 - 1));
+
+       if(a == b)
+               return 0;
+       if(a < b && b - a < cutoff) {
+               return b-a;
+       }
+       if(a > b && a - b > cutoff) {
+               return ((uint32_t)0xffffffff) - (a-b-1);
+       }
+       /* wrong case, b smaller than a */
+       return 0;
+}
+
+
+static uint8_t *
+cookie_hash(uint8_t *hash, uint8_t *buf,
+               struct sockaddr_storage *addr, uint8_t *secret)
+{
+       if (addr->ss_family == AF_INET6) {
+               memcpy(buf+16, &((struct sockaddr_in6 *)addr)->sin6_addr, 16);
+               siphash(buf, 32, secret, hash, 8);
+       } else {
+               memcpy(buf+16, &((struct sockaddr_in *)addr)->sin_addr, 4);
+               siphash(buf, 20, secret, hash, 8);
+       }
+       return hash;
+}
+
 /** parse EDNS options from EDNS wireformat rdata */
 static int
 parse_edns_options_from_query(uint8_t* rdata_ptr, size_t rdata_len,
        struct edns_data* edns, struct config_file* cfg, struct comm_point* c,
-       struct regional* region)
+       struct comm_reply* repinfo, uint32_t now, struct regional* region)
 {
        /* To respond with a Keepalive option, the client connection must have
         * received one message with a TCP Keepalive EDNS option, and that
@@ -979,6 +1035,10 @@ parse_edns_options_from_query(uint8_t* rdata_ptr, size_t rdata_len,
        while(rdata_len >= 4) {
                uint16_t opt_code = sldns_read_uint16(rdata_ptr);
                uint16_t opt_len = sldns_read_uint16(rdata_ptr+2);
+               uint8_t server_cookie[40], hash[8];
+               uint32_t cookie_time, subt_1982;
+               int comp_1982;
+
                rdata_ptr += 4;
                rdata_len -= 4;
                if(opt_len > rdata_len)
@@ -1041,6 +1101,86 @@ parse_edns_options_from_query(uint8_t* rdata_ptr, size_t rdata_len,
                        edns->padding_block_size = cfg->pad_responses_block_size;
                        break;
 
+               case LDNS_EDNS_COOKIE:
+                       if(!cfg || !cfg->do_answer_cookie)
+                               break;
+                       if(opt_len != 8 && (opt_len < 16 || opt_len > 40)) {
+                               verbose(VERB_ALGO, "worker request: "
+                                               "badly formatted cookie");
+                               return LDNS_RCODE_FORMERR;
+                       }
+                       edns->cookie_present = 1;
+
+                       /* Copy client cookie, version and timestamp for
+                        * validation and creation purposes.
+                        */
+                       memcpy(server_cookie, rdata_ptr, 16);
+
+                       /* In the "if, if else" block below, we validate a
+                        * RFC9018 cookie. If it doesn't match the recipe, or
+                        * if it doesn't validate, or if the cookie is too old
+                        * (< 30 min), a new cookie is generated.
+                        */
+                       if (opt_len != 24)
+                               ; /* RFC9018 cookies are 24 bytes long */
+
+                       else if (cfg->cookie_secret_len != 16)
+                               ; /* RFC9018 cookies have 16 byte secrets */
+
+                       else if (rdata_ptr[8] != 1)
+                               ; /* RFC9018 cookies are cookie version 1 */
+
+                       else if ((comp_1982 = compare_1982(now,
+                                       (cookie_time = sldns_read_uint32(rdata_ptr + 12)))) > 0
+                            &&  (subt_1982 = subtract_1982(cookie_time, now)) > 3600)
+                               ; /* Cookie is older than 1 hour
+                                  * (see RFC9018 Section 4.3.)
+                                  */
+
+                       else if (comp_1982 <= 0
+                            &&  subtract_1982(now, cookie_time) > 300)
+                               ; /* Cookie time is more than 5 minutes in the
+                                  * future. (see RFC9018 Section 4.3.)
+                                  */
+
+                       else if (memcmp( cookie_hash( hash, server_cookie
+                                                   , &repinfo->addr
+                                                   , cfg->cookie_secret)
+                                      , rdata_ptr + 16 , 8 ) == 0) {
+
+                               /* Cookie is valid! */
+                               edns->cookie_valid = 1;
+                               if (comp_1982 > 0 && subt_1982 > 1800)
+                                       ; /* But older than 30 minutes,
+                                          * so create a new one anyway */
+
+                               else if (!edns_opt_list_append( /* Reuse cookie */
+                                   &edns->opt_list_out, LDNS_EDNS_COOKIE, opt_len,
+                                   rdata_ptr, region)) {
+                                       log_err("out of memory");
+                                       return LDNS_RCODE_SERVFAIL;
+                               } else
+                                       /* Cookie to be reused added to
+                                        * outgoing options. Done!
+                                        */
+                                       break;
+                       }
+                       /* Add a new server cookie to outgoing cookies */
+                       server_cookie[ 8] = 1;   /* Version */
+                       server_cookie[ 9] = 0;   /* Reserved */
+                       server_cookie[10] = 0;   /* Reserved */
+                       server_cookie[11] = 0;   /* Reserved */
+                       sldns_write_uint32(server_cookie + 12, now);
+                       cookie_hash( hash, server_cookie
+                                  , &repinfo->addr, cfg->cookie_secret);
+                       memcpy(server_cookie + 16, hash, 8);
+                       if (!edns_opt_list_append( &edns->opt_list_out
+                                                , LDNS_EDNS_COOKIE
+                                                , 24, server_cookie, region)) {
+                               log_err("out of memory");
+                               return LDNS_RCODE_SERVFAIL;
+                       }
+                       break;
                default:
                        break;
                }
@@ -1115,6 +1255,8 @@ parse_extract_edns_from_response_msg(struct msg_parse* msg,
        edns->opt_list_out = NULL;
        edns->opt_list_inplace_cb_out = NULL;
        edns->padding_block_size = 0;
+       edns->cookie_present = 0;
+       edns->cookie_valid = 0;
 
        /* take the options */
        rdata_len = found->rr_first->size-2;
@@ -1170,7 +1312,8 @@ skip_pkt_rrs(sldns_buffer* pkt, int num)
 
 int 
 parse_edns_from_query_pkt(sldns_buffer* pkt, struct edns_data* edns,
-       struct config_file* cfg, struct comm_point* c, struct regional* region)
+       struct config_file* cfg, struct comm_point* c,
+       struct comm_reply* repinfo, time_t now, struct regional* region)
 {
        size_t rdata_len;
        uint8_t* rdata_ptr;
@@ -1206,6 +1349,8 @@ parse_edns_from_query_pkt(sldns_buffer* pkt, struct edns_data* edns,
        edns->opt_list_out = NULL;
        edns->opt_list_inplace_cb_out = NULL;
        edns->padding_block_size = 0;
+       edns->cookie_present = 0;
+       edns->cookie_valid = 0;
 
        /* take the options */
        rdata_len = sldns_buffer_read_u16(pkt);
@@ -1214,7 +1359,7 @@ parse_edns_from_query_pkt(sldns_buffer* pkt, struct edns_data* edns,
        rdata_ptr = sldns_buffer_current(pkt);
        /* ignore rrsigs */
        return parse_edns_options_from_query(rdata_ptr, rdata_len, edns, cfg,
-                       c, region);
+                       c, repinfo, now, region);
 }
 
 void
index 0c458e6e8e251e2a9200af44bfaf6fac3166dfff..aebeb2a88b48335f9f1d6114c2b688ddc77b768a 100644 (file)
@@ -72,6 +72,7 @@ struct regional;
 struct edns_option;
 struct config_file;
 struct comm_point;
+struct comm_reply;
 
 /** number of buckets in parse rrset hash table. Must be power of 2. */
 #define PARSE_TABLE_SIZE 32
@@ -217,8 +218,6 @@ struct rr_parse {
  * region.
  */
 struct edns_data {
-       /** if EDNS OPT record was present */
-       int edns_present;
        /** Extended RCODE */
        uint8_t ext_rcode;
        /** The EDNS version number */
@@ -238,7 +237,13 @@ struct edns_data {
        struct edns_option* opt_list_inplace_cb_out;
        /** block size to pad */
        uint16_t padding_block_size;
-};
+       /** if EDNS OPT record was present */
+       unsigned int edns_present   : 1;
+       /** if a cookie was present */
+       unsigned int cookie_present : 1;
+       /** if the cookie validated */
+       unsigned int cookie_valid   : 1;
+};     
 
 /**
  * EDNS option
@@ -315,7 +320,8 @@ int skip_pkt_rrs(struct sldns_buffer* pkt, int num);
  *     RCODE formerr if OPT is badly formatted and so on.
  */
 int parse_edns_from_query_pkt(struct sldns_buffer* pkt, struct edns_data* edns,
-       struct config_file* cfg, struct comm_point* c, struct regional* region);
+       struct config_file* cfg, struct comm_point* c,
+       struct comm_reply* repinfo, time_t now, struct regional* region);
 
 /**
  * Calculate hash value for rrset in packet.
index 1d85332a8f403e6ab5f21ebd1b7ce7ddcd66376d..f55dcb97e755ad56a4a28578dd9d9cdef2e0f0a9 100644 (file)
 #include "util/regional.h"
 #include "util/data/msgparse.h"
 #include "util/data/msgreply.h"
-#include "sldns/sbuffer.h"
-
-#ifdef HAVE_SSL
-#include <openssl/opensslv.h>
-#include <openssl/evp.h>
-#endif
 
 struct edns_strings* edns_strings_create(void)
 {
@@ -134,128 +128,3 @@ edns_string_addr_lookup(rbtree_type* tree, struct sockaddr_storage* addr,
        return (struct edns_string_addr*)addr_tree_lookup(tree, addr, addrlen);
 }
 
-int siphash(const uint8_t *in, const size_t inlen,
-               const uint8_t *k, uint8_t *out, const size_t outlen);
-
-/** RFC 1982 comparison, uses unsigned integers, and tries to avoid
- * compiler optimization (eg. by avoiding a-b<0 comparisons),
- * this routine matches compare_serial(), for SOA serial number checks */
-static int
-compare_1982(uint32_t a, uint32_t b)
-{
-       /* for 32 bit values */
-       const uint32_t cutoff = ((uint32_t) 1 << (32 - 1));
-
-       if (a == b) {
-               return 0;
-       } else if ((a < b && b - a < cutoff) || (a > b && a - b > cutoff)) {
-               return -1;
-       } else {
-               return 1;
-       }
-}
-
-/** if we know that b is larger than a, return the difference between them,
- * that is the distance between them. in RFC1982 arith */
-static uint32_t
-subtract_1982(uint32_t a, uint32_t b)
-{
-       /* for 32 bit values */
-       const uint32_t cutoff = ((uint32_t) 1 << (32 - 1));
-
-       if(a == b)
-               return 0;
-       if(a < b && b - a < cutoff) {
-               return b-a;
-       }
-       if(a > b && a - b > cutoff) {
-               return ((uint32_t)0xffffffff) - (a-b-1);
-       }
-       /* wrong case, b smaller than a */
-       return 0;
-}
-
-
-int edns_cookie_validate(struct config_file* cfg, struct comm_reply* repinfo,
-               struct edns_option* cookie_opt, time_t now)
-{
-       uint8_t hash[8], data2hash[40];
-       uint32_t cookie_time, now_uint32 = now;
-
-       /* We support only draft-sury-toorop-dns-cookies-algorithms
-        * sized cookies
-        */
-       if(cookie_opt->opt_len != 24)
-               return 0;
-
-       if(cookie_opt->opt_data[8] != 1)
-               return 0;
-
-       cookie_time = sldns_read_uint32(cookie_opt->opt_data + 12);
-
-       if(compare_1982(now_uint32, cookie_time) > 0) {
-               if (subtract_1982(cookie_time, now_uint32) > 3600)
-                       return 0; /* Not older than 1 hour */
-
-       } else if (subtract_1982(now_uint32, cookie_time) > 300)
-               /* ignore cookies > 5 minutes in future */
-               return 0;
-
-       if (cfg->cookie_secret_len != 16)
-               return 0;
-
-       memcpy(data2hash, cookie_opt->opt_data, 16);
-       if (repinfo->addr.ss_family == AF_INET6) {
-               memcpy( data2hash + 16, &((struct sockaddr_in6 *)
-                                       &repinfo->addr)->sin6_addr, 16);
-               siphash(data2hash, 32, cfg->cookie_secret, hash, 8);
-       } else {
-               memcpy( data2hash + 16, &((struct sockaddr_in *)
-                                       &repinfo->addr)->sin_addr, 4);
-               siphash(data2hash, 20, cfg->cookie_secret, hash, 8);
-       }
-       return memcmp(cookie_opt->opt_data + 16, hash, 8) == 0;
-}
-
-static int edns_cookie(struct edns_data* edns_out, struct edns_data* edns_in,
-       struct config_file* cfg, struct comm_point* c,
-       struct comm_reply *repinfo, time_t now,
-       struct regional* region)
-{
-       struct edns_option *opt;
-
-       if(c->type != comm_udp)
-               return 1;
-
-       if(!cfg->do_answer_cookie)
-               return 1;
-
-       opt = edns_opt_list_find(edns_in->opt_list, LDNS_EDNS_COOKIE);
-       if (opt && opt->opt_len >= 8) {
-               uint8_t data_out[40], hash[8];
-
-               log_assert(cfg->cookie_secret_len >= 16);
-
-               (void)memcpy(data_out, opt->opt_data, 8);
-               data_out[ 8] = 1;   /* Version */
-               data_out[ 9] = 0;   /* Reserved */
-               data_out[10] = 0;   /* Reserved */
-               data_out[11] = 0;   /* Reserved */
-               sldns_write_uint32(data_out + 12, time(NULL));
-               if (repinfo->addr.ss_family == AF_INET6) {
-                       memcpy( data_out + 16, &((struct sockaddr_in6 *)
-                                              &repinfo->addr)->sin6_addr, 16);
-                       siphash(data_out, 32, cfg->cookie_secret, hash, 8);
-               } else {
-                       memcpy( data_out + 16, &((struct sockaddr_in *)
-                                              &repinfo->addr)->sin_addr, 4);
-                       siphash(data_out, 20, cfg->cookie_secret, hash, 8);
-               }
-               memcpy(data_out + 16, hash, 8);
-               if(!edns_opt_list_append(&edns_out->opt_list, LDNS_EDNS_COOKIE,
-                               24, data_out, region))
-                       return 0;
-       }
-       return 1;
-}
-
index 8074d34449dc2df8d0af8de1f4c17e56e98b1033..d9ded0b84dc4534c3af51c1f85a887dd82402416 100644 (file)
 
 #include "util/storage/dnstree.h"
 
-struct edns_option;
 struct edns_data;
 struct config_file;
 struct comm_point;
 struct regional;
-struct comm_reply;
 
-/**
- * Validate the EDNS Server cookie.
- *
- * @param cfg: configuration.
- * @param repinfo: struct containing the address of the querier.
- * @param cookie_opt: comm channel.
- * @param now: current time.
- * @return 1 on a valid server cookie, otherwise 0.
- */
-int edns_cookie_validate(struct config_file* cfg, struct comm_reply* repinfo,
-                struct edns_option* cookie_opt, time_t now) ;
 /**
  * Structure containing all EDNS strings.
  */
index eafbac458c1ec91af24e69db3e267e858bce3b95..54fad6986f3c6b2213761f91163abd6f15d5db29 100644 (file)
 #define MAX_ADDR_STRLEN 128 /* characters */
 /** default value for EDNS ADVERTISED size */
 uint16_t EDNS_ADVERTISED_SIZE = 4096;
-/** default value of padding block size with encrypted queries (RFC8467) */
-uint16_t EDNS_PADDING_QUERY_BLOCK_SIZE = 128;
-/** default value of padding block size with encrypted responses (RFC8467) */
-uint16_t EDNS_PADDING_RESPONSE_BLOCK_SIZE = 468;
 
 /** minimal responses when positive answer: default is no */
 int MINIMAL_RESPONSES = 0;
index d014c1028a1621caa932c075d7d0913c80a9cdab..f1881b3ed0ca7e007dc432dcded76eb1aab06250 100644 (file)
@@ -87,10 +87,6 @@ extern uint16_t EDNS_ADVERTISED_SIZE;
 #define INET_SIZE 4
 /** byte size of ip6 address */
 #define INET6_SIZE 16
-/** block size with which to pad encrypted queries */
-extern uint16_t EDNS_PADDING_QUERY_BLOCK_SIZE;
-/** block size with which to pad encrypted responses */
-extern uint16_t EDNS_PADDING_RESPONSE_BLOCK_SIZE;
 
 /** DNSKEY zone sign key flag */
 #define DNSKEY_BIT_ZSK 0x0100
index 3cdf9ceae851d2199f84ab0bc9e6f0bd9bcf0abf..3011a0ace7a2c2aee77d4efe76eddd83c1b8ac4c 100644 (file)
@@ -2376,6 +2376,8 @@ probe_anchor(struct module_env* env, struct trust_anchor* tp)
        edns.opt_list_out = NULL;
        edns.opt_list_inplace_cb_out = NULL;
        edns.padding_block_size = 0;
+       edns.cookie_present = 0;
+       edns.cookie_valid = 0;
        if(sldns_buffer_capacity(buf) < 65535)
                edns.udp_size = (uint16_t)sldns_buffer_capacity(buf);
        else    edns.udp_size = 65535;