887 lines
32 KiB
Diff
887 lines
32 KiB
Diff
|
|
From 75f3fbdd6563dd87c93964e48a3fb7e6c520d74e Mon Sep 17 00:00:00 2001
|
||
|
|
From: Willem Toorop <willem@nlnetlabs.nl>
|
||
|
|
Date: Wed, 28 Sep 2022 10:28:19 +0200
|
||
|
|
Subject: [PATCH] Downstream DNS Cookies a la RFC7873 and RFC9018
|
||
|
|
|
||
|
|
Create server cookies for clients that send client cookies.
|
||
|
|
Needs to be turned on in the config file with:
|
||
|
|
|
||
|
|
answer-cookie: yes
|
||
|
|
|
||
|
|
A cookie-secret can be configured for anycast setups.
|
||
|
|
Also adds an access control list that will allow queries with
|
||
|
|
either a valid cookie or over a stateful transport.
|
||
|
|
---
|
||
|
|
Makefile.in | 8 +-
|
||
|
|
daemon/acl_list.c | 2 +
|
||
|
|
daemon/acl_list.h | 4 +-
|
||
|
|
daemon/worker.c | 44 ++++++++++-
|
||
|
|
doc/unbound.conf.5.in | 23 +++++-
|
||
|
|
libunbound/libworker.c | 2 +
|
||
|
|
services/authzone.c | 4 +
|
||
|
|
sldns/rrdef.h | 4 +
|
||
|
|
testcode/fake_event.c | 2 +
|
||
|
|
util/config_file.c | 23 ++++++
|
||
|
|
util/config_file.h | 7 ++
|
||
|
|
util/configlexer.lex | 2 +
|
||
|
|
util/configparser.y | 35 ++++++++-
|
||
|
|
util/data/msgparse.c | 151 ++++++++++++++++++++++++++++++++++++-
|
||
|
|
util/data/msgparse.h | 14 +++-
|
||
|
|
util/siphash.c | 165 +++++++++++++++++++++++++++++++++++++++++
|
||
|
|
validator/autotrust.c | 2 +
|
||
|
|
17 files changed, 473 insertions(+), 19 deletions(-)
|
||
|
|
create mode 100644 util/siphash.c
|
||
|
|
|
||
|
|
diff --git a/Makefile.in b/Makefile.in
|
||
|
|
index 3189731ad..718f47f5c 100644
|
||
|
|
--- a/Makefile.in
|
||
|
|
+++ b/Makefile.in
|
||
|
|
@@ -128,7 +128,7 @@ util/config_file.c util/configlexer.c util/configparser.c \
|
||
|
|
util/shm_side/shm_main.c services/authzone.c \
|
||
|
|
util/fptr_wlist.c util/locks.c util/log.c util/mini_event.c util/module.c \
|
||
|
|
util/netevent.c util/net_help.c util/random.c util/rbtree.c util/regional.c \
|
||
|
|
-util/rtt.c util/edns.c util/storage/dnstree.c util/storage/lookup3.c \
|
||
|
|
+util/rtt.c util/siphash.c util/edns.c util/storage/dnstree.c util/storage/lookup3.c \
|
||
|
|
util/storage/lruhash.c util/storage/slabhash.c util/tcp_conn_limit.c \
|
||
|
|
util/timehist.c util/tube.c util/proxy_protocol.c \
|
||
|
|
util/ub_event.c util/ub_event_pluggable.c util/winsock_event.c \
|
||
|
|
@@ -145,7 +145,7 @@ as112.lo msgparse.lo msgreply.lo packed_rrset.lo iterator.lo iter_delegpt.lo \
|
||
|
|
iter_donotq.lo iter_fwd.lo iter_hints.lo iter_priv.lo iter_resptype.lo \
|
||
|
|
iter_scrub.lo iter_utils.lo localzone.lo mesh.lo modstack.lo view.lo \
|
||
|
|
outbound_list.lo alloc.lo config_file.lo configlexer.lo configparser.lo \
|
||
|
|
-fptr_wlist.lo edns.lo locks.lo log.lo mini_event.lo module.lo net_help.lo \
|
||
|
|
+fptr_wlist.lo siphash.lo edns.lo locks.lo log.lo mini_event.lo module.lo net_help.lo \
|
||
|
|
random.lo rbtree.lo regional.lo rtt.lo dnstree.lo lookup3.lo lruhash.lo \
|
||
|
|
slabhash.lo tcp_conn_limit.lo timehist.lo tube.lo winsock_event.lo \
|
||
|
|
autotrust.lo val_anchor.lo rpz.lo proxy_protocol.lo \
|
||
|
|
@@ -915,7 +915,8 @@ config_file.lo config_file.o: $(srcdir)/util/config_file.c config.h $(srcdir)/ut
|
||
|
|
configlexer.lo configlexer.o: util/configlexer.c config.h $(srcdir)/util/configyyrename.h \
|
||
|
|
$(srcdir)/util/config_file.h util/configparser.h
|
||
|
|
configparser.lo configparser.o: util/configparser.c config.h $(srcdir)/util/configyyrename.h \
|
||
|
|
- $(srcdir)/util/config_file.h $(srcdir)/util/net_help.h $(srcdir)/util/log.h
|
||
|
|
+ $(srcdir)/util/config_file.h $(srcdir)/util/net_help.h $(srcdir)/util/log.h $(srcdir)/sldns/str2wire.h \
|
||
|
|
+ $(srcdir)/sldns/rrdef.h
|
||
|
|
shm_main.lo shm_main.o: $(srcdir)/util/shm_side/shm_main.c config.h $(srcdir)/util/shm_side/shm_main.h \
|
||
|
|
$(srcdir)/libunbound/unbound.h $(srcdir)/daemon/daemon.h $(srcdir)/util/locks.h $(srcdir)/util/log.h \
|
||
|
|
$(srcdir)/util/alloc.h $(srcdir)/services/modstack.h \
|
||
|
|
@@ -1004,6 +1005,7 @@ rtt.lo rtt.o: $(srcdir)/util/rtt.c config.h $(srcdir)/util/rtt.h $(srcdir)/itera
|
||
|
|
$(srcdir)/services/outbound_list.h $(srcdir)/util/data/msgreply.h $(srcdir)/util/storage/lruhash.h \
|
||
|
|
$(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/module.h \
|
||
|
|
$(srcdir)/util/data/msgparse.h $(srcdir)/sldns/pkthdr.h $(srcdir)/sldns/rrdef.h
|
||
|
|
+siphash.lo siphash.o: $(srcdir)/util/siphash.c
|
||
|
|
edns.lo edns.o: $(srcdir)/util/edns.c config.h $(srcdir)/util/edns.h $(srcdir)/util/storage/dnstree.h \
|
||
|
|
$(srcdir)/util/rbtree.h $(srcdir)/util/config_file.h $(srcdir)/util/netevent.h $(srcdir)/dnscrypt/dnscrypt.h \
|
||
|
|
$(srcdir)/util/net_help.h $(srcdir)/util/log.h $(srcdir)/util/regional.h \
|
||
|
|
diff --git a/daemon/acl_list.c b/daemon/acl_list.c
|
||
|
|
index 8e8e1fc9b..e6d0470a1 100644
|
||
|
|
--- a/daemon/acl_list.c
|
||
|
|
+++ b/daemon/acl_list.c
|
||
|
|
@@ -109,6 +109,8 @@ 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(str, "allow_cookie") == 0)
|
||
|
|
+ *control = acl_allow_cookie;
|
||
|
|
else {
|
||
|
|
log_err("access control type %s unknown", str);
|
||
|
|
return 0;
|
||
|
|
diff --git a/daemon/acl_list.h b/daemon/acl_list.h
|
||
|
|
index c717179ba..8aece11bf 100644
|
||
|
|
--- a/daemon/acl_list.h
|
||
|
|
+++ b/daemon/acl_list.h
|
||
|
|
@@ -65,7 +65,9 @@ enum acl_access {
|
||
|
|
/** allow full access for all queries, recursion and cache snooping */
|
||
|
|
acl_allow_snoop,
|
||
|
|
/** allow full access for recursion queries and set RD flag regardless of request */
|
||
|
|
- acl_allow_setrd
|
||
|
|
+ acl_allow_setrd,
|
||
|
|
+ /** allow full access if valid cookie present or stateful transport */
|
||
|
|
+ acl_allow_cookie
|
||
|
|
};
|
||
|
|
|
||
|
|
/**
|
||
|
|
diff --git a/daemon/worker.c b/daemon/worker.c
|
||
|
|
index c2a94be79..1abf20a7b 100644
|
||
|
|
--- a/daemon/worker.c
|
||
|
|
+++ b/daemon/worker.c
|
||
|
|
@@ -1432,8 +1432,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->client_addr,
|
||
|
|
@@ -1466,6 +1468,44 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||
|
|
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! */
|
||
|
|
+ extended_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),
|
||
|
|
+ 0, &edns);
|
||
|
|
+ regional_free_all(worker->scratchpad);
|
||
|
|
+ goto send_reply;
|
||
|
|
+ } else {
|
||
|
|
+ /* Cookie requered, but no cookie present on UDP */
|
||
|
|
+ verbose(VERB_ALGO, "worker request: "
|
||
|
|
+ "need cookie or stateful transport");
|
||
|
|
+ log_addr(VERB_ALGO, "from",
|
||
|
|
+ &repinfo->remote_addr, repinfo->remote_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|BIT_TC), &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 > worker->daemon->cfg->max_udp_size &&
|
||
|
|
c->type == comm_udp) {
|
||
|
|
verbose(VERB_QUERY,
|
||
|
|
diff --git a/doc/unbound.conf.5.in b/doc/unbound.conf.5.in
|
||
|
|
index 73575d93a..e187452de 100644
|
||
|
|
--- a/doc/unbound.conf.5.in
|
||
|
|
+++ b/doc/unbound.conf.5.in
|
||
|
|
@@ -673,9 +673,9 @@ This option is experimental at this time.
|
||
|
|
.B access\-control: \fI<IP netblock> <action>
|
||
|
|
The netblock is given as an IP4 or IP6 address with /size appended for a
|
||
|
|
classless network block. The action can be \fIdeny\fR, \fIrefuse\fR,
|
||
|
|
-\fIallow\fR, \fIallow_setrd\fR, \fIallow_snoop\fR, \fIdeny_non_local\fR or
|
||
|
|
-\fIrefuse_non_local\fR.
|
||
|
|
-The most specific netblock match is used, if none match \fIrefuse\fR is used.
|
||
|
|
+\fIallow\fR, \fIallow_setrd\fR, \fIallow_snoop\fR, \fIallow_cookie\fR,
|
||
|
|
+\fIdeny_non_local\fR or \fIrefuse_non_local\fR.
|
||
|
|
+The most specific netblock match is used, if none match \fIdeny\fR is used.
|
||
|
|
The order of the access\-control statements therefore does not matter.
|
||
|
|
.IP
|
||
|
|
The action \fIdeny\fR stops queries from hosts from that netblock.
|
||
|
|
@@ -710,6 +710,14 @@ the cache contents (for malicious acts). However, nonrecursive queries can
|
||
|
|
also be a valuable debugging tool (when you want to examine the cache
|
||
|
|
contents). In that case use \fIallow_snoop\fR for your administration host.
|
||
|
|
.IP
|
||
|
|
+When the \fBanswer\-cookie\fR option is enabled, the \fIallow_cookie\fR action
|
||
|
|
+will allow access to UDP queries that contain a valid Server Cookie as
|
||
|
|
+specified in RFC 7873 and RFC9018. UDP queries containing only a Client Cookie
|
||
|
|
+and no Server Cookie, will receive a BADCOOKIE response including a Server
|
||
|
|
+Cookie, allow clients to retry with that Server Cookie. The \fIallow_cookie\fR
|
||
|
|
+will also accept requests over statefull transports, regardless of the precence
|
||
|
|
+of a Cookie and regardless the \fBanswer\-cookie\fR setting.
|
||
|
|
+.IP
|
||
|
|
By default only localhost is \fIallow\fRed, the rest is \fIrefuse\fRd.
|
||
|
|
The default is \fIrefuse\fRd, because that is protocol\-friendly. The DNS
|
||
|
|
protocol is not designed to handle dropped packets due to policy, and
|
||
|
|
@@ -1824,6 +1832,15 @@ Set the number of servers that should be used for fast server selection. Only
|
||
|
|
use the fastest specified number of servers with the fast\-server\-permil
|
||
|
|
option, that turns this on or off. The default is to use the fastest 3 servers.
|
||
|
|
.TP 5
|
||
|
|
+.B answer\-cookie: \fI<yes or no>
|
||
|
|
+Enable to answer to requests containig DNS Cookies as specified in RFC7873 and
|
||
|
|
+RFC9018. Default is no.
|
||
|
|
+.TP 5
|
||
|
|
+.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.
|
||
|
|
+Default is a 128 bits random secret generated at startup time.
|
||
|
|
.B edns\-client\-string: \fI<IP netblock> <string>
|
||
|
|
Include an EDNS0 option containing configured ascii string in queries with
|
||
|
|
destination address matching the configured IP netblock. This configuration
|
||
|
|
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/sldns/rrdef.h b/sldns/rrdef.h
|
||
|
|
index 999c22307..d5b0585fd 100644
|
||
|
|
--- a/sldns/rrdef.h
|
||
|
|
+++ b/sldns/rrdef.h
|
||
|
|
@@ -433,6 +433,7 @@ enum sldns_enum_edns_option
|
||
|
|
LDNS_EDNS_DHU = 6, /* RFC6975 */
|
||
|
|
LDNS_EDNS_N3U = 7, /* RFC6975 */
|
||
|
|
LDNS_EDNS_CLIENT_SUBNET = 8, /* RFC7871 */
|
||
|
|
+ LDNS_EDNS_COOKIE = 10, /* RFC7873 */
|
||
|
|
LDNS_EDNS_KEEPALIVE = 11, /* draft-ietf-dnsop-edns-tcp-keepalive*/
|
||
|
|
LDNS_EDNS_PADDING = 12, /* RFC7830 */
|
||
|
|
LDNS_EDNS_EDE = 15, /* RFC8914 */
|
||
|
|
@@ -482,6 +483,9 @@ typedef enum sldns_enum_ede_code sldns_ede_code;
|
||
|
|
#define LDNS_TSIG_ERROR_BADNAME 20
|
||
|
|
#define LDNS_TSIG_ERROR_BADALG 21
|
||
|
|
|
||
|
|
+/** DNS Cookie extended rcode */
|
||
|
|
+#define LDNS_EXT_RCODE_BADCOOKIE 23
|
||
|
|
+
|
||
|
|
/**
|
||
|
|
* Contains all information about resource record types.
|
||
|
|
*
|
||
|
|
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/config_file.c b/util/config_file.c
|
||
|
|
index 158169c42..a92342761 100644
|
||
|
|
--- a/util/config_file.c
|
||
|
|
+++ b/util/config_file.c
|
||
|
|
@@ -55,6 +55,7 @@
|
||
|
|
#include "util/regional.h"
|
||
|
|
#include "util/fptr_wlist.h"
|
||
|
|
#include "util/data/dname.h"
|
||
|
|
+#include "util/random.h"
|
||
|
|
#include "util/rtt.h"
|
||
|
|
#include "services/cache/infra.h"
|
||
|
|
#include "sldns/wire2str.h"
|
||
|
|
@@ -87,6 +88,9 @@ struct config_parser_state* cfg_parser = 0;
|
||
|
|
/** init ports possible for use */
|
||
|
|
static void init_outgoing_availports(int* array, int num);
|
||
|
|
|
||
|
|
+/** init cookie with random data */
|
||
|
|
+static void init_cookie_secret(uint8_t* cookie_secret,size_t cookie_secret_len);
|
||
|
|
+
|
||
|
|
struct config_file*
|
||
|
|
config_create(void)
|
||
|
|
{
|
||
|
|
@@ -364,6 +368,10 @@ config_create(void)
|
||
|
|
cfg->ipsecmod_whitelist = NULL;
|
||
|
|
cfg->ipsecmod_strict = 0;
|
||
|
|
#endif
|
||
|
|
+ cfg->do_answer_cookie = 0;
|
||
|
|
+ memset(cfg->cookie_secret, 0, sizeof(cfg->cookie_secret));
|
||
|
|
+ cfg->cookie_secret_len = 16;
|
||
|
|
+ init_cookie_secret(cfg->cookie_secret, cfg->cookie_secret_len);
|
||
|
|
#ifdef USE_CACHEDB
|
||
|
|
if(!(cfg->cachedb_backend = strdup("testframe"))) goto error_exit;
|
||
|
|
if(!(cfg->cachedb_secret = strdup("default"))) goto error_exit;
|
||
|
|
@@ -1660,6 +1668,21 @@ config_delete(struct config_file* cfg)
|
||
|
|
free(cfg);
|
||
|
|
}
|
||
|
|
|
||
|
|
+static void
|
||
|
|
+init_cookie_secret(uint8_t* cookie_secret, size_t cookie_secret_len)
|
||
|
|
+{
|
||
|
|
+ struct ub_randstate *rand = ub_initstate(NULL);
|
||
|
|
+
|
||
|
|
+ if (!rand)
|
||
|
|
+ fatal_exit("could not init random generator");
|
||
|
|
+ while (cookie_secret_len) {
|
||
|
|
+ *cookie_secret++ = (uint8_t)ub_random(rand);
|
||
|
|
+ cookie_secret_len--;
|
||
|
|
+ }
|
||
|
|
+ ub_randfree(rand);
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+
|
||
|
|
static void
|
||
|
|
init_outgoing_availports(int* a, int num)
|
||
|
|
{
|
||
|
|
diff --git a/util/config_file.h b/util/config_file.h
|
||
|
|
index bbc6d4ac1..3db4676b9 100644
|
||
|
|
--- a/util/config_file.h
|
||
|
|
+++ b/util/config_file.h
|
||
|
|
@@ -688,6 +688,13 @@ struct config_file {
|
||
|
|
int redis_expire_records;
|
||
|
|
#endif
|
||
|
|
#endif
|
||
|
|
+ /** Downstream DNS Cookies */
|
||
|
|
+ /** do answer with server cookie when request contained cookie option */
|
||
|
|
+ int do_answer_cookie;
|
||
|
|
+ /** cookie secret */
|
||
|
|
+ uint8_t cookie_secret[40];
|
||
|
|
+ /** cookie secret length */
|
||
|
|
+ size_t cookie_secret_len;
|
||
|
|
|
||
|
|
/* ipset module */
|
||
|
|
#ifdef USE_IPSET
|
||
|
|
diff --git a/util/configlexer.lex b/util/configlexer.lex
|
||
|
|
index fc9aa7266..4fdb2cde0 100644
|
||
|
|
--- a/util/configlexer.lex
|
||
|
|
+++ b/util/configlexer.lex
|
||
|
|
@@ -558,6 +558,8 @@ name-v4{COLON} { YDVAR(1, VAR_IPSET_NAME_V4) }
|
||
|
|
name-v6{COLON} { YDVAR(1, VAR_IPSET_NAME_V6) }
|
||
|
|
udp-upstream-without-downstream{COLON} { YDVAR(1, VAR_UDP_UPSTREAM_WITHOUT_DOWNSTREAM) }
|
||
|
|
tcp-connection-limit{COLON} { YDVAR(2, VAR_TCP_CONNECTION_LIMIT) }
|
||
|
|
+answer-cookie{COLON} { YDVAR(1, VAR_ANSWER_COOKIE ) }
|
||
|
|
+cookie-secret{COLON} { YDVAR(1, VAR_COOKIE_SECRET) }
|
||
|
|
edns-client-string{COLON} { YDVAR(2, VAR_EDNS_CLIENT_STRING) }
|
||
|
|
edns-client-string-opcode{COLON} { YDVAR(1, VAR_EDNS_CLIENT_STRING_OPCODE) }
|
||
|
|
nsid{COLON} { YDVAR(1, VAR_NSID ) }
|
||
|
|
diff --git a/util/configparser.y b/util/configparser.y
|
||
|
|
index 8f3672f5d..980201460 100644
|
||
|
|
--- a/util/configparser.y
|
||
|
|
+++ b/util/configparser.y
|
||
|
|
@@ -42,11 +42,13 @@
|
||
|
|
#include <stdio.h>
|
||
|
|
#include <string.h>
|
||
|
|
#include <stdlib.h>
|
||
|
|
+#include <time.h>
|
||
|
|
#include <assert.h>
|
||
|
|
|
||
|
|
#include "util/configyyrename.h"
|
||
|
|
#include "util/config_file.h"
|
||
|
|
#include "util/net_help.h"
|
||
|
|
+#include "sldns/str2wire.h"
|
||
|
|
|
||
|
|
int ub_c_lex(void);
|
||
|
|
void ub_c_error(const char *message);
|
||
|
|
@@ -181,6 +183,7 @@ extern struct config_parser_state* cfg_parser;
|
||
|
|
%token VAR_FALLBACK_ENABLED VAR_TLS_ADDITIONAL_PORT VAR_LOW_RTT VAR_LOW_RTT_PERMIL
|
||
|
|
%token VAR_FAST_SERVER_PERMIL VAR_FAST_SERVER_NUM
|
||
|
|
%token VAR_ALLOW_NOTIFY VAR_TLS_WIN_CERT VAR_TCP_CONNECTION_LIMIT
|
||
|
|
+%token VAR_ANSWER_COOKIE VAR_COOKIE_SECRET
|
||
|
|
%token VAR_FORWARD_NO_CACHE VAR_STUB_NO_CACHE VAR_LOG_SERVFAIL VAR_DENY_ANY
|
||
|
|
%token VAR_UNKNOWN_SERVER_TIME_LIMIT VAR_LOG_TAG_QUERYREPLY
|
||
|
|
%token VAR_STREAM_WAIT_SIZE VAR_TLS_CIPHERS VAR_TLS_CIPHERSUITES VAR_TLS_USE_SNI
|
||
|
|
@@ -316,6 +319,7 @@ content_server: server_num_threads | server_verbosity | server_port |
|
||
|
|
server_unknown_server_time_limit | server_log_tag_queryreply |
|
||
|
|
server_stream_wait_size | server_tls_ciphers |
|
||
|
|
server_tls_ciphersuites | server_tls_session_ticket_keys |
|
||
|
|
+ server_answer_cookie | server_cookie_secret |
|
||
|
|
server_tls_use_sni | server_edns_client_string |
|
||
|
|
server_edns_client_string_opcode | server_nsid |
|
||
|
|
server_zonemd_permissive_mode | server_max_reuse_tcp_queries |
|
||
|
|
@@ -3695,6 +3699,30 @@ server_tcp_connection_limit: VAR_TCP_CONNECTION_LIMIT STRING_ARG STRING_ARG
|
||
|
|
}
|
||
|
|
}
|
||
|
|
;
|
||
|
|
+server_answer_cookie: VAR_ANSWER_COOKIE STRING_ARG
|
||
|
|
+ {
|
||
|
|
+ OUTYY(("P(server_answer_cookie:%s)\n", $2));
|
||
|
|
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
|
||
|
|
+ yyerror("expected yes or no.");
|
||
|
|
+ else cfg_parser->cfg->do_answer_cookie = (strcmp($2, "yes")==0);
|
||
|
|
+ free($2);
|
||
|
|
+ }
|
||
|
|
+ ;
|
||
|
|
+server_cookie_secret: VAR_COOKIE_SECRET STRING_ARG
|
||
|
|
+ {
|
||
|
|
+ uint8_t secret[32];
|
||
|
|
+ size_t secret_len = sizeof(secret);
|
||
|
|
+
|
||
|
|
+ OUTYY(("P(server_cookie_secret:%s)\n", $2));
|
||
|
|
+ if (sldns_str2wire_hex_buf($2, secret, &secret_len)
|
||
|
|
+ || ( secret_len != 16))
|
||
|
|
+ yyerror("expected 128 bit hex string");
|
||
|
|
+ else {
|
||
|
|
+ cfg_parser->cfg->cookie_secret_len = secret_len;
|
||
|
|
+ memcpy(cfg_parser->cfg->cookie_secret, secret, sizeof(secret));
|
||
|
|
+ }
|
||
|
|
+ free($2);
|
||
|
|
+ }
|
||
|
|
ipsetstart: VAR_IPSET
|
||
|
|
{
|
||
|
|
OUTYY(("\nP(ipset:)\n"));
|
||
|
|
@@ -3764,10 +3792,11 @@ validate_acl_action(const char* action)
|
||
|
|
strcmp(action, "refuse_non_local")!=0 &&
|
||
|
|
strcmp(action, "allow_setrd")!=0 &&
|
||
|
|
strcmp(action, "allow")!=0 &&
|
||
|
|
- strcmp(action, "allow_snoop")!=0)
|
||
|
|
+ strcmp(action, "allow_snoop")!=0 &&
|
||
|
|
+ strcmp(action, "allow_cookie")!=0)
|
||
|
|
{
|
||
|
|
yyerror("expected deny, refuse, deny_non_local, "
|
||
|
|
- "refuse_non_local, allow, allow_setrd or "
|
||
|
|
- "allow_snoop as access control action");
|
||
|
|
+ "refuse_non_local, allow, allow_setrd, "
|
||
|
|
+ "allow_snoop or allow_cookie as access control action");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
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->remote_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->remote_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/siphash.c b/util/siphash.c
|
||
|
|
new file mode 100644
|
||
|
|
index 000000000..d69f4b579
|
||
|
|
--- /dev/null
|
||
|
|
+++ b/util/siphash.c
|
||
|
|
@@ -0,0 +1,165 @@
|
||
|
|
+/*
|
||
|
|
+ SipHash reference C implementation
|
||
|
|
+
|
||
|
|
+ Copyright (c) 2012-2016 Jean-Philippe Aumasson
|
||
|
|
+ <jeanphilippe.aumasson@gmail.com>
|
||
|
|
+ Copyright (c) 2012-2014 Daniel J. Bernstein <djb@cr.yp.to>
|
||
|
|
+
|
||
|
|
+ To the extent possible under law, the author(s) have dedicated all copyright
|
||
|
|
+ and related and neighboring rights to this software to the public domain
|
||
|
|
+ worldwide. This software is distributed without any warranty.
|
||
|
|
+
|
||
|
|
+ You should have received a copy of the CC0 Public Domain Dedication along
|
||
|
|
+ with
|
||
|
|
+ this software. If not, see
|
||
|
|
+ <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||
|
|
+ */
|
||
|
|
+#include <assert.h>
|
||
|
|
+#include <stdint.h>
|
||
|
|
+#include <stdio.h>
|
||
|
|
+#include <string.h>
|
||
|
|
+
|
||
|
|
+/* default: SipHash-2-4 */
|
||
|
|
+#define cROUNDS 2
|
||
|
|
+#define dROUNDS 4
|
||
|
|
+
|
||
|
|
+#define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b))))
|
||
|
|
+
|
||
|
|
+#define U32TO8_LE(p, v) \
|
||
|
|
+ (p)[0] = (uint8_t)((v)); \
|
||
|
|
+ (p)[1] = (uint8_t)((v) >> 8); \
|
||
|
|
+ (p)[2] = (uint8_t)((v) >> 16); \
|
||
|
|
+ (p)[3] = (uint8_t)((v) >> 24);
|
||
|
|
+
|
||
|
|
+#define U64TO8_LE(p, v) \
|
||
|
|
+ U32TO8_LE((p), (uint32_t)((v))); \
|
||
|
|
+ U32TO8_LE((p) + 4, (uint32_t)((v) >> 32));
|
||
|
|
+
|
||
|
|
+#define U8TO64_LE(p) \
|
||
|
|
+ (((uint64_t)((p)[0])) | ((uint64_t)((p)[1]) << 8) | \
|
||
|
|
+ ((uint64_t)((p)[2]) << 16) | ((uint64_t)((p)[3]) << 24) | \
|
||
|
|
+ ((uint64_t)((p)[4]) << 32) | ((uint64_t)((p)[5]) << 40) | \
|
||
|
|
+ ((uint64_t)((p)[6]) << 48) | ((uint64_t)((p)[7]) << 56))
|
||
|
|
+
|
||
|
|
+#define SIPROUND \
|
||
|
|
+ do { \
|
||
|
|
+ v0 += v1; \
|
||
|
|
+ v1 = ROTL(v1, 13); \
|
||
|
|
+ v1 ^= v0; \
|
||
|
|
+ v0 = ROTL(v0, 32); \
|
||
|
|
+ v2 += v3; \
|
||
|
|
+ v3 = ROTL(v3, 16); \
|
||
|
|
+ v3 ^= v2; \
|
||
|
|
+ v0 += v3; \
|
||
|
|
+ v3 = ROTL(v3, 21); \
|
||
|
|
+ v3 ^= v0; \
|
||
|
|
+ v2 += v1; \
|
||
|
|
+ v1 = ROTL(v1, 17); \
|
||
|
|
+ v1 ^= v2; \
|
||
|
|
+ v2 = ROTL(v2, 32); \
|
||
|
|
+ } while (0)
|
||
|
|
+
|
||
|
|
+#ifdef DEBUG
|
||
|
|
+#define TRACE \
|
||
|
|
+ do { \
|
||
|
|
+ printf("(%3d) v0 %08x %08x\n", (int)inlen, (uint32_t)(v0 >> 32), \
|
||
|
|
+ (uint32_t)v0); \
|
||
|
|
+ printf("(%3d) v1 %08x %08x\n", (int)inlen, (uint32_t)(v1 >> 32), \
|
||
|
|
+ (uint32_t)v1); \
|
||
|
|
+ printf("(%3d) v2 %08x %08x\n", (int)inlen, (uint32_t)(v2 >> 32), \
|
||
|
|
+ (uint32_t)v2); \
|
||
|
|
+ printf("(%3d) v3 %08x %08x\n", (int)inlen, (uint32_t)(v3 >> 32), \
|
||
|
|
+ (uint32_t)v3); \
|
||
|
|
+ } while (0)
|
||
|
|
+#else
|
||
|
|
+#define TRACE
|
||
|
|
+#endif
|
||
|
|
+
|
||
|
|
+int siphash(const uint8_t *in, const size_t inlen, const uint8_t *k,
|
||
|
|
+ uint8_t *out, const size_t outlen) {
|
||
|
|
+
|
||
|
|
+ assert((outlen == 8) || (outlen == 16));
|
||
|
|
+ uint64_t v0 = 0x736f6d6570736575ULL;
|
||
|
|
+ uint64_t v1 = 0x646f72616e646f6dULL;
|
||
|
|
+ uint64_t v2 = 0x6c7967656e657261ULL;
|
||
|
|
+ uint64_t v3 = 0x7465646279746573ULL;
|
||
|
|
+ uint64_t k0 = U8TO64_LE(k);
|
||
|
|
+ uint64_t k1 = U8TO64_LE(k + 8);
|
||
|
|
+ uint64_t m;
|
||
|
|
+ int i;
|
||
|
|
+ const uint8_t *end = in + inlen - (inlen % sizeof(uint64_t));
|
||
|
|
+ const int left = inlen & 7;
|
||
|
|
+ uint64_t b = ((uint64_t)inlen) << 56;
|
||
|
|
+ v3 ^= k1;
|
||
|
|
+ v2 ^= k0;
|
||
|
|
+ v1 ^= k1;
|
||
|
|
+ v0 ^= k0;
|
||
|
|
+
|
||
|
|
+ if (outlen == 16)
|
||
|
|
+ v1 ^= 0xee;
|
||
|
|
+
|
||
|
|
+ for (; in != end; in += 8) {
|
||
|
|
+ m = U8TO64_LE(in);
|
||
|
|
+ v3 ^= m;
|
||
|
|
+
|
||
|
|
+ TRACE;
|
||
|
|
+ for (i = 0; i < cROUNDS; ++i)
|
||
|
|
+ SIPROUND;
|
||
|
|
+
|
||
|
|
+ v0 ^= m;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ switch (left) {
|
||
|
|
+ case 7:
|
||
|
|
+ b |= ((uint64_t)in[6]) << 48;
|
||
|
|
+ case 6:
|
||
|
|
+ b |= ((uint64_t)in[5]) << 40;
|
||
|
|
+ case 5:
|
||
|
|
+ b |= ((uint64_t)in[4]) << 32;
|
||
|
|
+ case 4:
|
||
|
|
+ b |= ((uint64_t)in[3]) << 24;
|
||
|
|
+ case 3:
|
||
|
|
+ b |= ((uint64_t)in[2]) << 16;
|
||
|
|
+ case 2:
|
||
|
|
+ b |= ((uint64_t)in[1]) << 8;
|
||
|
|
+ case 1:
|
||
|
|
+ b |= ((uint64_t)in[0]);
|
||
|
|
+ break;
|
||
|
|
+ case 0:
|
||
|
|
+ break;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ v3 ^= b;
|
||
|
|
+
|
||
|
|
+ TRACE;
|
||
|
|
+ for (i = 0; i < cROUNDS; ++i)
|
||
|
|
+ SIPROUND;
|
||
|
|
+
|
||
|
|
+ v0 ^= b;
|
||
|
|
+
|
||
|
|
+ if (outlen == 16)
|
||
|
|
+ v2 ^= 0xee;
|
||
|
|
+ else
|
||
|
|
+ v2 ^= 0xff;
|
||
|
|
+
|
||
|
|
+ TRACE;
|
||
|
|
+ for (i = 0; i < dROUNDS; ++i)
|
||
|
|
+ SIPROUND;
|
||
|
|
+
|
||
|
|
+ b = v0 ^ v1 ^ v2 ^ v3;
|
||
|
|
+ U64TO8_LE(out, b);
|
||
|
|
+
|
||
|
|
+ if (outlen == 8)
|
||
|
|
+ return 0;
|
||
|
|
+
|
||
|
|
+ v1 ^= 0xdd;
|
||
|
|
+
|
||
|
|
+ TRACE;
|
||
|
|
+ for (i = 0; i < dROUNDS; ++i)
|
||
|
|
+ SIPROUND;
|
||
|
|
+
|
||
|
|
+ b = v0 ^ v1 ^ v2 ^ v3;
|
||
|
|
+ U64TO8_LE(out + 8, b);
|
||
|
|
+
|
||
|
|
+ return 0;
|
||
|
|
+}
|
||
|
|
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;
|