From: Willem Toorop Date: Tue, 27 Sep 2022 15:23:20 +0000 (+0200) Subject: Bring cookies branch up-to-date with current master X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=67ef9b1bb8be0cda777234faa47e17d01410646a;p=thirdparty%2Funbound.git Bring cookies branch up-to-date with current master --- diff --git a/daemon/acl_list.c b/daemon/acl_list.c index 3c5e7b514..e6d0470a1 100644 --- a/daemon/acl_list.c +++ b/daemon/acl_list.c @@ -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); diff --git a/daemon/worker.c b/daemon/worker.c index ba4dbf3b1..f2fee1040 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -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) { diff --git a/doc/unbound.conf.5.in b/doc/unbound.conf.5.in index 5161c3714..00172954a 100644 --- a/doc/unbound.conf.5.in +++ b/doc/unbound.conf.5.in @@ -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 diff --git a/libunbound/libworker.c b/libunbound/libworker.c index 11bf5f9db..d5fabe6fb 100644 --- a/libunbound/libworker.c +++ b/libunbound/libworker.c @@ -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); diff --git a/services/authzone.c b/services/authzone.c index 6de1e4319..079a7eaf1 100644 --- a/services/authzone.c +++ b/services/authzone.c @@ -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; diff --git a/testcode/fake_event.c b/testcode/fake_event.c index 03e1c04f3..c93ceaa4c 100644 --- a/testcode/fake_event.c +++ b/testcode/fake_event.c @@ -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; diff --git a/util/data/msgencode.c b/util/data/msgencode.c index 41d366063..7b97a5466 100644 --- a/util/data/msgencode.c +++ b/util/data/msgencode.c @@ -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; diff --git a/util/data/msgparse.c b/util/data/msgparse.c index 5bb69d6ed..3059d555c 100644 --- a/util/data/msgparse.c +++ b/util/data/msgparse.c @@ -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 diff --git a/util/data/msgparse.h b/util/data/msgparse.h index 0c458e6e8..aebeb2a88 100644 --- a/util/data/msgparse.h +++ b/util/data/msgparse.h @@ -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. diff --git a/util/edns.c b/util/edns.c index 1d85332a8..f55dcb97e 100644 --- a/util/edns.c +++ b/util/edns.c @@ -47,12 +47,6 @@ #include "util/regional.h" #include "util/data/msgparse.h" #include "util/data/msgreply.h" -#include "sldns/sbuffer.h" - -#ifdef HAVE_SSL -#include -#include -#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; -} - diff --git a/util/edns.h b/util/edns.h index 8074d3444..d9ded0b84 100644 --- a/util/edns.h +++ b/util/edns.h @@ -44,24 +44,11 @@ #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. */ diff --git a/util/net_help.c b/util/net_help.c index eafbac458..54fad6986 100644 --- a/util/net_help.c +++ b/util/net_help.c @@ -79,10 +79,6 @@ #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; diff --git a/util/net_help.h b/util/net_help.h index d014c1028..f1881b3ed 100644 --- a/util/net_help.h +++ b/util/net_help.h @@ -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 diff --git a/validator/autotrust.c b/validator/autotrust.c index 3cdf9ceae..3011a0ace 100644 --- a/validator/autotrust.c +++ b/validator/autotrust.c @@ -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;