mirror of
https://github.com/NLnetLabs/unbound.git
synced 2026-01-04 05:49:35 -05:00
Merge pull request #762 from NLnetLabs/features/downstream-cookies
Downstream DNS Server Cookies a la RFC7873 and RFC9018
This commit is contained in:
commit
a1c82ac5fd
52 changed files with 2027 additions and 160 deletions
13
Makefile.in
13
Makefile.in
|
|
@ -122,13 +122,13 @@ iterator/iter_delegpt.c iterator/iter_donotq.c iterator/iter_fwd.c \
|
|||
iterator/iter_hints.c iterator/iter_priv.c iterator/iter_resptype.c \
|
||||
iterator/iter_scrub.c iterator/iter_utils.c services/listen_dnsport.c \
|
||||
services/localzone.c services/mesh.c services/modstack.c services/view.c \
|
||||
services/rpz.c \
|
||||
services/rpz.c util/rfc_1982.c \
|
||||
services/outbound_list.c services/outside_network.c util/alloc.c \
|
||||
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/timeval_func.c \
|
||||
util/ub_event.c util/ub_event_pluggable.c util/winsock_event.c \
|
||||
|
|
@ -145,10 +145,10 @@ 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 \
|
||||
autotrust.lo val_anchor.lo rpz.lo rfc_1982.lo proxy_protocol.lo \
|
||||
validator.lo val_kcache.lo val_kentry.lo val_neg.lo val_nsec3.lo val_nsec.lo \
|
||||
val_secalgo.lo val_sigcrypt.lo val_utils.lo dns64.lo $(CACHEDB_OBJ) authzone.lo \
|
||||
$(SUBNET_OBJ) $(PYTHONMOD_OBJ) $(CHECKLOCK_OBJ) $(DNSTAP_OBJ) $(DNSCRYPT_OBJ) \
|
||||
|
|
@ -917,7 +917,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 \
|
||||
|
|
@ -1008,6 +1009,8 @@ 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
|
||||
rfc_1982.lo rfc_1982.o: $(srcdir)/util/rfc_1982.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 \
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -64,8 +64,12 @@ enum acl_access {
|
|||
acl_allow,
|
||||
/** 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
|
||||
/** allow full access for recursion queries and set RD flag regardless
|
||||
* of request */
|
||||
acl_allow_setrd,
|
||||
/** allow full access for recursion (+RD) queries if valid cookie
|
||||
* present or stateful transport */
|
||||
acl_allow_cookie
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -672,6 +672,12 @@ print_stats(RES* ssl, const char* nm, struct ub_stats_info* s)
|
|||
(unsigned long)s->svr.num_queries)) return 0;
|
||||
if(!ssl_printf(ssl, "%s.num.queries_ip_ratelimited"SQ"%lu\n", nm,
|
||||
(unsigned long)s->svr.num_queries_ip_ratelimited)) return 0;
|
||||
if(!ssl_printf(ssl, "%s.num.queries_cookie_valid"SQ"%lu\n", nm,
|
||||
(unsigned long)s->svr.num_queries_cookie_valid)) return 0;
|
||||
if(!ssl_printf(ssl, "%s.num.queries_cookie_client"SQ"%lu\n", nm,
|
||||
(unsigned long)s->svr.num_queries_cookie_client)) return 0;
|
||||
if(!ssl_printf(ssl, "%s.num.queries_cookie_invalid"SQ"%lu\n", nm,
|
||||
(unsigned long)s->svr.num_queries_cookie_invalid)) return 0;
|
||||
if(!ssl_printf(ssl, "%s.num.cachehits"SQ"%lu\n", nm,
|
||||
(unsigned long)(s->svr.num_queries
|
||||
- s->svr.num_queries_missed_cache))) return 0;
|
||||
|
|
|
|||
|
|
@ -435,6 +435,9 @@ void server_stats_add(struct ub_stats_info* total, struct ub_stats_info* a)
|
|||
{
|
||||
total->svr.num_queries += a->svr.num_queries;
|
||||
total->svr.num_queries_ip_ratelimited += a->svr.num_queries_ip_ratelimited;
|
||||
total->svr.num_queries_cookie_valid += a->svr.num_queries_cookie_valid;
|
||||
total->svr.num_queries_cookie_client += a->svr.num_queries_cookie_client;
|
||||
total->svr.num_queries_cookie_invalid += a->svr.num_queries_cookie_invalid;
|
||||
total->svr.num_queries_missed_cache += a->svr.num_queries_missed_cache;
|
||||
total->svr.num_queries_prefetch += a->svr.num_queries_prefetch;
|
||||
total->svr.num_queries_timed_out += a->svr.num_queries_timed_out;
|
||||
|
|
@ -568,3 +571,16 @@ void server_stats_insrcode(struct ub_server_stats* stats, sldns_buffer* buf)
|
|||
stats->ans_rcode_nodata ++;
|
||||
}
|
||||
}
|
||||
|
||||
void server_stats_downstream_cookie(struct ub_server_stats* stats,
|
||||
struct edns_data* edns)
|
||||
{
|
||||
if(!(edns->edns_present && edns->cookie_present)) return;
|
||||
if(edns->cookie_valid) {
|
||||
stats->num_queries_cookie_valid++;
|
||||
} else if(edns->cookie_client) {
|
||||
stats->num_queries_cookie_client++;
|
||||
} else {
|
||||
stats->num_queries_cookie_invalid++;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -126,4 +126,11 @@ void server_stats_insquery(struct ub_server_stats* stats, struct comm_point* c,
|
|||
*/
|
||||
void server_stats_insrcode(struct ub_server_stats* stats, struct sldns_buffer* buf);
|
||||
|
||||
/**
|
||||
* Add DNS Cookie stats for this query
|
||||
* @param stats: the stats
|
||||
* @param edns: edns record
|
||||
*/
|
||||
void server_stats_downstream_cookie(struct ub_server_stats* stats,
|
||||
struct edns_data* edns);
|
||||
#endif /* DAEMON_STATS_H */
|
||||
|
|
|
|||
139
daemon/worker.c
139
daemon/worker.c
|
|
@ -1319,6 +1319,40 @@ deny_refuse_non_local(struct comm_point* c, enum acl_access acl,
|
|||
worker, repinfo, acladdr, ede, check_result);
|
||||
}
|
||||
|
||||
/* Returns 1 if the ip rate limit check can happen before EDNS parsing,
|
||||
* else 0 */
|
||||
static int
|
||||
pre_edns_ip_ratelimit_check(enum acl_access acl)
|
||||
{
|
||||
if(acl == acl_allow_cookie) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Check if the query is blocked by source IP rate limiting.
|
||||
* Returns 1 if it passes the check, 0 otherwise. */
|
||||
static int
|
||||
check_ip_ratelimit(struct worker* worker, struct sockaddr_storage* addr,
|
||||
socklen_t addrlen, int has_cookie, sldns_buffer* pkt)
|
||||
{
|
||||
if(!infra_ip_ratelimit_inc(worker->env.infra_cache, addr, addrlen,
|
||||
*worker->env.now, has_cookie,
|
||||
worker->env.cfg->ip_ratelimit_backoff, pkt)) {
|
||||
/* See if we can pass through with slip factor */
|
||||
if(!has_cookie && worker->env.cfg->ip_ratelimit_factor != 0 &&
|
||||
ub_random_max(worker->env.rnd,
|
||||
worker->env.cfg->ip_ratelimit_factor) == 0) {
|
||||
char addrbuf[128];
|
||||
addr_to_str(addr, addrlen, addrbuf, sizeof(addrbuf));
|
||||
verbose(VERB_QUERY, "ip_ratelimit allowed through for "
|
||||
"ip address %s because of slip in "
|
||||
"ip_ratelimit_factor", addrbuf);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
struct comm_reply* repinfo)
|
||||
|
|
@ -1332,6 +1366,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
|||
struct edns_option* original_edns_list = NULL;
|
||||
enum acl_access acl;
|
||||
struct acl_addr* acladdr;
|
||||
int pre_edns_ip_ratelimit = 1;
|
||||
int rc = 0;
|
||||
int need_drop = 0;
|
||||
int is_expired_answer = 0;
|
||||
|
|
@ -1456,33 +1491,21 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
|||
}
|
||||
|
||||
worker->stats.num_queries++;
|
||||
pre_edns_ip_ratelimit = pre_edns_ip_ratelimit_check(acl);
|
||||
|
||||
/* check if this query should be dropped based on source ip rate limiting
|
||||
* NOTE: we always check the repinfo->client_address. IP ratelimiting is
|
||||
* implicitly disabled for proxies. */
|
||||
if(!infra_ip_ratelimit_inc(worker->env.infra_cache,
|
||||
&repinfo->client_addr, repinfo->client_addrlen,
|
||||
*worker->env.now,
|
||||
worker->env.cfg->ip_ratelimit_backoff, c->buffer)) {
|
||||
/* See if we are passed through with slip factor */
|
||||
if(worker->env.cfg->ip_ratelimit_factor != 0 &&
|
||||
ub_random_max(worker->env.rnd,
|
||||
worker->env.cfg->ip_ratelimit_factor) == 0) {
|
||||
char addrbuf[128];
|
||||
addr_to_str(&repinfo->client_addr,
|
||||
repinfo->client_addrlen, addrbuf,
|
||||
sizeof(addrbuf));
|
||||
verbose(VERB_QUERY, "ip_ratelimit allowed through for "
|
||||
"ip address %s because of slip in "
|
||||
"ip_ratelimit_factor", addrbuf);
|
||||
} else {
|
||||
/* If the IP rate limiting check needs extra EDNS information (e.g.,
|
||||
* DNS Cookies) postpone the check until after EDNS is parsed. */
|
||||
if(pre_edns_ip_ratelimit) {
|
||||
/* NOTE: we always check the repinfo->client_address.
|
||||
* IP ratelimiting is implicitly disabled for proxies. */
|
||||
if(!check_ip_ratelimit(worker, &repinfo->client_addr,
|
||||
repinfo->client_addrlen, 0, c->buffer)) {
|
||||
worker->stats.num_queries_ip_ratelimited++;
|
||||
comm_point_drop_reply(repinfo);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* see if query is in the cache */
|
||||
if(!query_info_parse(&qinfo, c->buffer)) {
|
||||
verbose(VERB_ALGO, "worker parse request: formerror.");
|
||||
log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
|
||||
|
|
@ -1539,16 +1562,16 @@ 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,
|
||||
repinfo->client_addrlen);
|
||||
memset(&reply_edns, 0, sizeof(reply_edns));
|
||||
reply_edns.edns_present = 1;
|
||||
reply_edns.udp_size = EDNS_ADVERTISED_SIZE;
|
||||
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), ret);
|
||||
error_encode(c->buffer, ret, &qinfo,
|
||||
*(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
|
||||
sldns_buffer_read_u16_at(c->buffer, 2), &reply_edns);
|
||||
|
|
@ -1557,23 +1580,15 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
|||
}
|
||||
if(edns.edns_present) {
|
||||
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->client_addr,
|
||||
repinfo->client_addrlen);
|
||||
error_encode(c->buffer, EDNS_RCODE_BADVERS&0xf, &qinfo,
|
||||
extended_error_encode(c->buffer, EDNS_RCODE_BADVERS, &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);
|
||||
sldns_buffer_read_u16_at(c->buffer, 2), 0, &edns);
|
||||
regional_free_all(worker->scratchpad);
|
||||
goto send_reply;
|
||||
}
|
||||
|
|
@ -1586,6 +1601,62 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
|||
edns.udp_size = NORMAL_UDP_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get stats for cookies */
|
||||
server_stats_downstream_cookie(&worker->stats, &edns);
|
||||
|
||||
/* If the IP rate limiting check was postponed, check now. */
|
||||
if(!pre_edns_ip_ratelimit) {
|
||||
/* NOTE: we always check the repinfo->client_address.
|
||||
* IP ratelimiting is implicitly disabled for proxies. */
|
||||
if(!check_ip_ratelimit(worker, &repinfo->client_addr,
|
||||
repinfo->client_addrlen, edns.cookie_valid,
|
||||
c->buffer)) {
|
||||
worker->stats.num_queries_ip_ratelimited++;
|
||||
comm_point_drop_reply(repinfo);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* "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 required, 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,
|
||||
|
|
|
|||
|
|
@ -369,6 +369,15 @@ number of queries received by thread
|
|||
.I threadX.num.queries_ip_ratelimited
|
||||
number of queries rate limited by thread
|
||||
.TP
|
||||
.I threadX.num.queries_cookie_valid
|
||||
number of queries with a valid DNS Cookie by thread
|
||||
.TP
|
||||
.I threadX.num.queries_cookie_client
|
||||
number of queries with a client part only DNS Cookie by thread
|
||||
.TP
|
||||
.I threadX.num.queries_cookie_invalid
|
||||
number of queries with an invalid DNS Cookie by thread
|
||||
.TP
|
||||
.I threadX.num.cachehits
|
||||
number of queries that were successfully answered using a cache lookup
|
||||
.TP
|
||||
|
|
@ -446,6 +455,18 @@ buffers are full.
|
|||
.I total.num.queries
|
||||
summed over threads.
|
||||
.TP
|
||||
.I total.num.queries_ip_ratelimited
|
||||
summed over threads.
|
||||
.TP
|
||||
.I total.num.queries_cookie_valid
|
||||
summed over threads.
|
||||
.TP
|
||||
.I total.num.queries_cookie_client
|
||||
summed over threads.
|
||||
.TP
|
||||
.I total.num.queries_cookie_invalid
|
||||
summed over threads.
|
||||
.TP
|
||||
.I total.num.cachehits
|
||||
summed over threads.
|
||||
.TP
|
||||
|
|
@ -611,7 +632,7 @@ ratelimiting.
|
|||
.TP
|
||||
.I num.query.dnscrypt.shared_secret.cachemiss
|
||||
The number of dnscrypt queries that did not find a shared secret in the cache.
|
||||
The can be use to compute the shared secret hitrate.
|
||||
This can be used to compute the shared secret hitrate.
|
||||
.TP
|
||||
.I num.query.dnscrypt.replay
|
||||
The number of dnscrypt queries that found a nonce hit in the nonce cache and
|
||||
|
|
|
|||
|
|
@ -701,17 +701,17 @@ 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.
|
||||
\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 \fIrefuse\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.
|
||||
The \fIdeny\fR action stops queries from hosts from that netblock.
|
||||
.IP
|
||||
The action \fIrefuse\fR stops queries too, but sends a DNS rcode REFUSED
|
||||
The \fIrefuse\fR action stops queries too, but sends a DNS rcode REFUSED
|
||||
error message back.
|
||||
.IP
|
||||
The action \fIallow\fR gives access to clients from that netblock.
|
||||
The \fIallow\fR action gives access to clients from that netblock.
|
||||
It gives only access for recursion clients (which is
|
||||
what almost all clients need). Nonrecursive queries are refused.
|
||||
.IP
|
||||
|
|
@ -731,13 +731,27 @@ may be useful if another DNS server must forward requests for specific
|
|||
zones to a resolver DNS server, but only supports stub domains and
|
||||
sends queries to the resolver DNS server with the RD bit cleared.
|
||||
.IP
|
||||
The action \fIallow_snoop\fR gives nonrecursive access too. This give
|
||||
The \fIallow_snoop\fR action gives nonrecursive access too. This give
|
||||
both recursive and non recursive access. The name \fIallow_snoop\fR refers
|
||||
to cache snooping, a technique to use nonrecursive queries to examine
|
||||
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
|
||||
The \fIallow_cookie\fR action allows access to UDP queries that contain a
|
||||
valid DNS Cookie as specified in RFC 7873 and RFC 9018, when the
|
||||
\fBanswer\-cookie\fR option is enabled.
|
||||
UDP queries containing only a DNS Client Cookie and no Server Cookie, or an
|
||||
invalid DNS Cookie, will receive a BADCOOKIE response including a newly
|
||||
generated DNS Cookie, allowing clients to retry with that DNS Cookie.
|
||||
The \fIallow_cookie\fR action will also accept requests over stateful
|
||||
transports, regardless of the presence of an DNS Cookie and regardless of the
|
||||
\fBanswer\-cookie\fR setting.
|
||||
If \fBip\-ratelimit\fR is used, clients with a valid DNS Cookie will bypass the
|
||||
ratelimit.
|
||||
If a ratelimit for such clients is still needed, \fBip\-ratelimit\-cookie\fR
|
||||
can be used instead.
|
||||
.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
|
||||
|
|
@ -1806,11 +1820,27 @@ A value of 0 will disable ratelimiting for domain names that end in this name.
|
|||
.TP 5
|
||||
.B ip\-ratelimit: \fI<number or 0>
|
||||
Enable global ratelimiting of queries accepted per IP address.
|
||||
If 0, the default, it is disabled. This option is experimental at this time.
|
||||
This option is experimental at this time.
|
||||
The ratelimit is in queries per second that are allowed. More queries are
|
||||
completely dropped and will not receive a reply, SERVFAIL or otherwise.
|
||||
IP ratelimiting happens before looking in the cache. This may be useful for
|
||||
mitigating amplification attacks.
|
||||
Default is 0 (disabled).
|
||||
.TP 5
|
||||
.B ip\-ratelimit\-cookie: \fI<number or 0>
|
||||
Enable global ratelimiting of queries accepted per IP address with a valid DNS
|
||||
Cookie.
|
||||
This option is experimental at this time.
|
||||
The ratelimit is in queries per second that are allowed.
|
||||
More queries are completely dropped and will not receive a reply, SERVFAIL or
|
||||
otherwise.
|
||||
IP ratelimiting happens before looking in the cache.
|
||||
This option could be useful in combination with \fIallow_cookie\fR in an
|
||||
attempt to mitigate other amplification attacks than UDP reflections (e.g.,
|
||||
attacks targeting Unbound itself) which are already handled with DNS Cookies.
|
||||
If used, the value is suggested to be higher than \fBip\-ratelimit\fR e.g.,
|
||||
tenfold.
|
||||
Default is 0 (disabled).
|
||||
.TP 5
|
||||
.B ip\-ratelimit\-size: \fI<memory size>
|
||||
Give the size of the data structure in which the current ongoing rates are
|
||||
|
|
@ -1879,6 +1909,18 @@ 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>
|
||||
If enabled, Unbound will answer to requests containing DNS Cookies as
|
||||
specified in RFC 7873 and RFC 9018.
|
||||
Default is no.
|
||||
.TP 5
|
||||
.B cookie\-secret: \fI<128 bit hex string>
|
||||
Server's secret for DNS Cookie generation.
|
||||
Useful to explicitly set for servers in an anycast deployment that need to
|
||||
share the secret in order to verify each other's Server Cookies.
|
||||
An example hex string would be "000102030405060708090a0b0c0d0e0f".
|
||||
Default is a 128 bits random secret generated at startup time.
|
||||
.TP 5
|
||||
.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
|
||||
|
|
|
|||
|
|
@ -603,6 +603,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);
|
||||
|
|
|
|||
|
|
@ -695,6 +695,12 @@ struct ub_server_stats {
|
|||
long long num_queries;
|
||||
/** number of queries that have been dropped/ratelimited by ip. */
|
||||
long long num_queries_ip_ratelimited;
|
||||
/** number of queries with a valid DNS Cookie. */
|
||||
long long num_queries_cookie_valid;
|
||||
/** number of queries with only the client part of the DNS Cookie. */
|
||||
long long num_queries_cookie_client;
|
||||
/** number of queries with invalid DNS Cookie. */
|
||||
long long num_queries_cookie_invalid;
|
||||
/** number of queries that had a cache-miss. */
|
||||
long long num_queries_missed_cache;
|
||||
/** number of prefetch queries - cachehits with prefetch */
|
||||
|
|
|
|||
|
|
@ -5420,6 +5420,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;
|
||||
|
|
@ -6613,6 +6615,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;
|
||||
|
|
|
|||
75
services/cache/infra.c
vendored
75
services/cache/infra.c
vendored
|
|
@ -67,6 +67,11 @@ int infra_dp_ratelimit = 0;
|
|||
* in queries per second. */
|
||||
int infra_ip_ratelimit = 0;
|
||||
|
||||
/** ratelimit value for client ip addresses,
|
||||
* in queries per second.
|
||||
* For clients with a valid DNS Cookie. */
|
||||
int infra_ip_ratelimit_cookie = 0;
|
||||
|
||||
size_t
|
||||
infra_sizefunc(void* k, void* ATTR_UNUSED(d))
|
||||
{
|
||||
|
|
@ -1051,9 +1056,50 @@ infra_get_mem(struct infra_cache* infra)
|
|||
return s;
|
||||
}
|
||||
|
||||
/* Returns 1 if the limit has not been exceeded, 0 otherwise. */
|
||||
static int
|
||||
check_ip_ratelimit(struct sockaddr_storage* addr, socklen_t addrlen,
|
||||
struct sldns_buffer* buffer, int premax, int max, int has_cookie)
|
||||
{
|
||||
int limit;
|
||||
|
||||
if(has_cookie) limit = infra_ip_ratelimit_cookie;
|
||||
else limit = infra_ip_ratelimit;
|
||||
|
||||
/* Disabled */
|
||||
if(limit == 0) return 1;
|
||||
|
||||
if(premax <= limit && max > limit) {
|
||||
char client_ip[128], qnm[LDNS_MAX_DOMAINLEN+1+12+12];
|
||||
addr_to_str(addr, addrlen, client_ip, sizeof(client_ip));
|
||||
qnm[0]=0;
|
||||
if(sldns_buffer_limit(buffer)>LDNS_HEADER_SIZE &&
|
||||
LDNS_QDCOUNT(sldns_buffer_begin(buffer))!=0) {
|
||||
(void)sldns_wire2str_rrquestion_buf(
|
||||
sldns_buffer_at(buffer, LDNS_HEADER_SIZE),
|
||||
sldns_buffer_limit(buffer)-LDNS_HEADER_SIZE,
|
||||
qnm, sizeof(qnm));
|
||||
if(strlen(qnm)>0 && qnm[strlen(qnm)-1]=='\n')
|
||||
qnm[strlen(qnm)-1] = 0; /*remove newline*/
|
||||
if(strchr(qnm, '\t'))
|
||||
*strchr(qnm, '\t') = ' ';
|
||||
if(strchr(qnm, '\t'))
|
||||
*strchr(qnm, '\t') = ' ';
|
||||
verbose(VERB_OPS, "ip_ratelimit exceeded %s %d%s %s",
|
||||
client_ip, limit,
|
||||
has_cookie?"(cookie)":"", qnm);
|
||||
} else {
|
||||
verbose(VERB_OPS, "ip_ratelimit exceeded %s %d%s (no query name)",
|
||||
client_ip, limit,
|
||||
has_cookie?"(cookie)":"");
|
||||
}
|
||||
}
|
||||
return (max <= limit);
|
||||
}
|
||||
|
||||
int infra_ip_ratelimit_inc(struct infra_cache* infra,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen, time_t timenow,
|
||||
int backoff, struct sldns_buffer* buffer)
|
||||
int has_cookie, int backoff, struct sldns_buffer* buffer)
|
||||
{
|
||||
int max;
|
||||
struct lruhash_entry* entry;
|
||||
|
|
@ -1070,31 +1116,8 @@ int infra_ip_ratelimit_inc(struct infra_cache* infra,
|
|||
(*cur)++;
|
||||
max = infra_rate_max(entry->data, timenow, backoff);
|
||||
lock_rw_unlock(&entry->lock);
|
||||
|
||||
if(premax <= infra_ip_ratelimit && max > infra_ip_ratelimit) {
|
||||
char client_ip[128], qnm[LDNS_MAX_DOMAINLEN+1+12+12];
|
||||
addr_to_str(addr, addrlen, client_ip, sizeof(client_ip));
|
||||
qnm[0]=0;
|
||||
if(sldns_buffer_limit(buffer)>LDNS_HEADER_SIZE &&
|
||||
LDNS_QDCOUNT(sldns_buffer_begin(buffer))!=0) {
|
||||
(void)sldns_wire2str_rrquestion_buf(
|
||||
sldns_buffer_at(buffer, LDNS_HEADER_SIZE),
|
||||
sldns_buffer_limit(buffer)-LDNS_HEADER_SIZE,
|
||||
qnm, sizeof(qnm));
|
||||
if(strlen(qnm)>0 && qnm[strlen(qnm)-1]=='\n')
|
||||
qnm[strlen(qnm)-1] = 0; /*remove newline*/
|
||||
if(strchr(qnm, '\t'))
|
||||
*strchr(qnm, '\t') = ' ';
|
||||
if(strchr(qnm, '\t'))
|
||||
*strchr(qnm, '\t') = ' ';
|
||||
verbose(VERB_OPS, "ip_ratelimit exceeded %s %d %s",
|
||||
client_ip, infra_ip_ratelimit, qnm);
|
||||
} else {
|
||||
verbose(VERB_OPS, "ip_ratelimit exceeded %s %d (no query name)",
|
||||
client_ip, infra_ip_ratelimit);
|
||||
}
|
||||
}
|
||||
return (max <= infra_ip_ratelimit);
|
||||
return check_ip_ratelimit(addr, addrlen, buffer, premax, max,
|
||||
has_cookie);
|
||||
}
|
||||
|
||||
/* create */
|
||||
|
|
|
|||
5
services/cache/infra.h
vendored
5
services/cache/infra.h
vendored
|
|
@ -153,6 +153,8 @@ struct rate_key {
|
|||
|
||||
/** ip ratelimit, 0 is off */
|
||||
extern int infra_ip_ratelimit;
|
||||
/** ip ratelimit for DNS Cookie clients, 0 is off */
|
||||
extern int infra_ip_ratelimit_cookie;
|
||||
|
||||
/**
|
||||
* key for ip_ratelimit lookups, a source IP.
|
||||
|
|
@ -419,13 +421,14 @@ int infra_find_ratelimit(struct infra_cache* infra, uint8_t* name,
|
|||
* @param addr: client address
|
||||
* @param addrlen: client address length
|
||||
* @param timenow: what time it is now.
|
||||
* @param has_cookie: if the request came with a DNS Cookie.
|
||||
* @param backoff: if backoff is enabled.
|
||||
* @param buffer: with query for logging.
|
||||
* @return 1 if it could be incremented. 0 if the increment overshot the
|
||||
* ratelimit and the query should be dropped. */
|
||||
int infra_ip_ratelimit_inc(struct infra_cache* infra,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen, time_t timenow,
|
||||
int backoff, struct sldns_buffer* buffer);
|
||||
int has_cookie, int backoff, struct sldns_buffer* buffer);
|
||||
|
||||
/**
|
||||
* Get memory used by the infra cache.
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
@ -483,6 +484,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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -204,6 +204,12 @@ static void pr_stats(const char* nm, struct ub_stats_info* s)
|
|||
PR_UL_NM("num.queries", s->svr.num_queries);
|
||||
PR_UL_NM("num.queries_ip_ratelimited",
|
||||
s->svr.num_queries_ip_ratelimited);
|
||||
PR_UL_NM("num.queries_cookie_valid",
|
||||
s->svr.num_queries_cookie_valid);
|
||||
PR_UL_NM("num.queries_cookie_client",
|
||||
s->svr.num_queries_cookie_client);
|
||||
PR_UL_NM("num.queries_cookie_invalid",
|
||||
s->svr.num_queries_cookie_invalid);
|
||||
PR_UL_NM("num.cachehits",
|
||||
s->svr.num_queries - s->svr.num_queries_missed_cache);
|
||||
PR_UL_NM("num.cachemiss", s->svr.num_queries_missed_cache);
|
||||
|
|
|
|||
|
|
@ -1252,6 +1252,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;
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@
|
|||
*/
|
||||
|
||||
#include "config.h"
|
||||
struct sockaddr_storage;
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <ctype.h>
|
||||
|
|
@ -140,6 +139,10 @@ static void matchline(char* line, struct entry* e)
|
|||
e->match_noedns = 1;
|
||||
} else if(str_keyword(&parse, "ednsdata")) {
|
||||
e->match_ednsdata_raw = 1;
|
||||
} else if(str_keyword(&parse, "client_cookie")) {
|
||||
e->match_client_cookie = 1;
|
||||
} else if(str_keyword(&parse, "server_cookie")) {
|
||||
e->match_server_cookie = 1;
|
||||
} else if(str_keyword(&parse, "UDP")) {
|
||||
e->match_transport = transport_udp;
|
||||
} else if(str_keyword(&parse, "TCP")) {
|
||||
|
|
@ -905,37 +908,64 @@ get_do_flag(uint8_t* pkt, size_t len)
|
|||
return (int)(edns_bits&LDNS_EDNS_MASK_DO_BIT);
|
||||
}
|
||||
|
||||
/** Snips the EDE option out of the OPT record and returns the EDNS EDE
|
||||
* INFO-CODE if found, else -1 */
|
||||
/** Snips the specified EDNS option out of the OPT record and puts it in the
|
||||
* provided buffer. The buffer should be able to hold any opt data ie 65535.
|
||||
* Returns the length of the option written,
|
||||
* or 0 if not found, else -1 on error. */
|
||||
static int
|
||||
extract_ede(uint8_t* pkt, size_t len)
|
||||
pkt_snip_edns_option(uint8_t* pkt, size_t len, sldns_edns_option code,
|
||||
uint8_t* buf)
|
||||
{
|
||||
uint8_t *rdata, *opt_position = pkt;
|
||||
uint16_t rdlen, optlen;
|
||||
size_t remaining = len;
|
||||
int ede_code;
|
||||
if(!pkt_find_edns_opt(&opt_position, &remaining)) return -1;
|
||||
if(!pkt_find_edns_opt(&opt_position, &remaining)) return 0;
|
||||
if(remaining < 8) return -1; /* malformed */
|
||||
rdlen = sldns_read_uint16(opt_position+6);
|
||||
rdata = opt_position + 8;
|
||||
while(rdlen > 0) {
|
||||
if(rdlen < 4) return -1; /* malformed */
|
||||
optlen = sldns_read_uint16(rdata+2);
|
||||
if(sldns_read_uint16(rdata) == LDNS_EDNS_EDE) {
|
||||
if(rdlen < 6) return -1; /* malformed */
|
||||
ede_code = sldns_read_uint16(rdata+4);
|
||||
if(sldns_read_uint16(rdata) == code) {
|
||||
/* save data to buf for caller inspection */
|
||||
memmove(buf, rdata+4, optlen);
|
||||
/* snip option from packet; assumes len is correct */
|
||||
memmove(rdata, rdata+4+optlen,
|
||||
(pkt+len)-(rdata+4+optlen));
|
||||
/* update OPT size */
|
||||
sldns_write_uint16(opt_position+6,
|
||||
sldns_read_uint16(opt_position+6)-(4+optlen));
|
||||
return ede_code;
|
||||
return optlen;
|
||||
}
|
||||
rdlen -= 4 + optlen;
|
||||
rdata += 4 + optlen;
|
||||
}
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Snips the EDE option out of the OPT record and returns the EDNS EDE
|
||||
* INFO-CODE if found, else -1 */
|
||||
static int
|
||||
extract_ede(uint8_t* pkt, size_t len)
|
||||
{
|
||||
uint8_t buf[65535];
|
||||
int buflen = pkt_snip_edns_option(pkt, len, LDNS_EDNS_EDE, buf);
|
||||
if(buflen < 2 /*ede without text at minimum*/) return -1;
|
||||
return sldns_read_uint16(buf);
|
||||
}
|
||||
|
||||
/** Snips the DNS Cookie option out of the OPT record and puts it in the
|
||||
* provided cookie buffer (should be at least 24 octets).
|
||||
* Returns the length of the cookie if found, else -1. */
|
||||
static int
|
||||
extract_cookie(uint8_t* pkt, size_t len, uint8_t* cookie)
|
||||
{
|
||||
uint8_t buf[65535];
|
||||
int buflen = pkt_snip_edns_option(pkt, len, LDNS_EDNS_COOKIE, buf);
|
||||
if(buflen != 8 /*client cookie*/ &&
|
||||
buflen != 8 + 16 /*server cookie*/) return -1;
|
||||
memcpy(cookie, buf, buflen);
|
||||
return buflen;
|
||||
}
|
||||
|
||||
/** zero TTLs in packet */
|
||||
|
|
@ -1530,6 +1560,27 @@ find_match(struct entry* entries, uint8_t* query_pkt, size_t len,
|
|||
continue;
|
||||
}
|
||||
}
|
||||
/* Cookies could also modify the query_pkt; keep them early */
|
||||
if(p->match_client_cookie || p->match_server_cookie) {
|
||||
uint8_t cookie[24];
|
||||
int cookie_len = extract_cookie(query_pkt, len,
|
||||
cookie);
|
||||
if(cookie_len == -1) {
|
||||
verbose(3, "bad DNS Cookie. "
|
||||
"Expected but not found\n");
|
||||
continue;
|
||||
} else if(p->match_client_cookie &&
|
||||
cookie_len != 8) {
|
||||
verbose(3, "bad DNS Cookie. Expected client "
|
||||
"cookie of length 8.");
|
||||
continue;
|
||||
} else if((p->match_server_cookie) &&
|
||||
cookie_len != 24) {
|
||||
verbose(3, "bad DNS Cookie. Expected server "
|
||||
"cookie of length 24.");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if(p->match_opcode && get_opcode(query_pkt, len) !=
|
||||
get_opcode(reply, rlen)) {
|
||||
verbose(3, "bad opcode\n");
|
||||
|
|
|
|||
|
|
@ -64,6 +64,14 @@ struct sldns_file_parse_state;
|
|||
; 'ede=any' makes the query match any EDNS EDE info-code.
|
||||
; It also snips the EDE record out of the packet to facilitate
|
||||
; other matches.
|
||||
; 'client_cookie' makes the query match any DNS Cookie option with
|
||||
; with a length of 8 octets.
|
||||
; It also snips the DNS Cookie record out of the packet to
|
||||
; facilitate other matches.
|
||||
; 'server_cookie' makes the query match any DNS Cookie option with
|
||||
; with a length of 24 octets.
|
||||
; It also snips the DNS Cookie record out of the packet to
|
||||
; facilitate other matches.
|
||||
MATCH [opcode] [qtype] [qname] [serial=<value>] [all] [ttl]
|
||||
MATCH [UDP|TCP] DO
|
||||
MATCH ...
|
||||
|
|
@ -104,11 +112,11 @@ struct sldns_file_parse_state;
|
|||
; be parsed, ADJUST rules for the answer packet
|
||||
; are ignored. Only copy_id is done.
|
||||
HEX_ANSWER_END
|
||||
HEX_EDNS_BEGIN ; follow with hex data.
|
||||
HEX_EDNSDATA_BEGIN ; follow with hex data.
|
||||
; Raw EDNS data to match against. It must be an
|
||||
; exact match (all options are matched) and will be
|
||||
; evaluated only when 'MATCH ednsdata' given.
|
||||
HEX_EDNS_END
|
||||
HEX_EDNSDATA_END
|
||||
ENTRY_END
|
||||
|
||||
|
||||
|
|
@ -214,6 +222,10 @@ struct entry {
|
|||
uint8_t match_noedns;
|
||||
/** match edns data field given in hex */
|
||||
uint8_t match_ednsdata_raw;
|
||||
/** match an DNS cookie of length 8 */
|
||||
uint8_t match_client_cookie;
|
||||
/** match an DNS cookie of length 24 */
|
||||
uint8_t match_server_cookie;
|
||||
/** match query serial with this value. */
|
||||
uint32_t ixfr_soa_serial;
|
||||
/** match on UDP/TCP */
|
||||
|
|
@ -235,7 +247,7 @@ struct entry {
|
|||
/** increment the ECS scope copied from the sourcemask by one */
|
||||
uint8_t increment_ecs_scope;
|
||||
/** in seconds */
|
||||
unsigned int sleeptime;
|
||||
unsigned int sleeptime;
|
||||
|
||||
/** some number that names this entry, line number in file or so */
|
||||
int lineno;
|
||||
|
|
|
|||
|
|
@ -530,6 +530,207 @@ infra_test(void)
|
|||
config_delete(cfg);
|
||||
}
|
||||
|
||||
#include "util/edns.h"
|
||||
/* Complete version-invalid client cookie; needs a new one.
|
||||
* Based on edns_cookie_rfc9018_a2 */
|
||||
static void
|
||||
edns_cookie_invalid_version(void)
|
||||
{
|
||||
uint32_t timestamp = 1559734385;
|
||||
uint8_t client_cookie[] = {
|
||||
0x24, 0x64, 0xc4, 0xab, 0xcf, 0x10, 0xc9, 0x57,
|
||||
0x99, 0x00, 0x00, 0x00,
|
||||
0x5c, 0xf7, 0x9f, 0x11,
|
||||
0x1f, 0x81, 0x30, 0xc3, 0xee, 0xe2, 0x94, 0x80 };
|
||||
uint8_t server_cookie[] = {
|
||||
0x24, 0x64, 0xc4, 0xab, 0xcf, 0x10, 0xc9, 0x57,
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
0x5c, 0xf7, 0xa8, 0x71,
|
||||
0xd4, 0xa5, 0x64, 0xa1, 0x44, 0x2a, 0xca, 0x77 };
|
||||
uint8_t server_secret[] = {
|
||||
0xe5, 0xe9, 0x73, 0xe5, 0xa6, 0xb2, 0xa4, 0x3f,
|
||||
0x48, 0xe7, 0xdc, 0x84, 0x9e, 0x37, 0xbf, 0xcf };
|
||||
uint8_t buf[32];
|
||||
/* copy client cookie|version|reserved|timestamp */
|
||||
memcpy(buf, client_cookie, 8 + 4 + 4);
|
||||
/* copy ip 198.51.100.100 */
|
||||
memcpy(buf + 16, "\306\063\144\144", 4);
|
||||
unit_assert(edns_cookie_server_validate(client_cookie,
|
||||
sizeof(client_cookie), server_secret, sizeof(server_secret), 1,
|
||||
buf, timestamp) == COOKIE_STATUS_INVALID);
|
||||
edns_cookie_server_write(buf, server_secret, 1, timestamp);
|
||||
unit_assert(memcmp(server_cookie, buf, 24) == 0);
|
||||
}
|
||||
|
||||
/* Complete hash-invalid client cookie; needs a new one. */
|
||||
static void
|
||||
edns_cookie_invalid_hash(void)
|
||||
{
|
||||
uint32_t timestamp = 0;
|
||||
uint8_t client_cookie[] = {
|
||||
0xfc, 0x93, 0xfc, 0x62, 0x80, 0x7d, 0xdb, 0x86,
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x32, 0xF2, 0x43, 0xB9, 0xBC, 0xFE, 0xC4, 0x06 };
|
||||
uint8_t server_cookie[] = {
|
||||
0xfc, 0x93, 0xfc, 0x62, 0x80, 0x7d, 0xdb, 0x86,
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0xBA, 0x0D, 0x82, 0x90, 0x8F, 0xAA, 0xEB, 0xBD };
|
||||
uint8_t server_secret[] = {
|
||||
0xe5, 0xe9, 0x73, 0xe5, 0xa6, 0xb2, 0xa4, 0x3f,
|
||||
0x48, 0xe7, 0xdc, 0x84, 0x9e, 0x37, 0xbf, 0xcf };
|
||||
uint8_t buf[32];
|
||||
/* copy client cookie|version|reserved|timestamp */
|
||||
memcpy(buf, client_cookie, 8 + 4 + 4);
|
||||
/* copy ip 203.0.113.203 */
|
||||
memcpy(buf + 16, "\313\000\161\313", 4);
|
||||
unit_assert(edns_cookie_server_validate(client_cookie,
|
||||
sizeof(client_cookie), server_secret, sizeof(server_secret), 1,
|
||||
buf, timestamp) == COOKIE_STATUS_INVALID);
|
||||
edns_cookie_server_write(buf, server_secret, 1, timestamp);
|
||||
unit_assert(memcmp(server_cookie, buf, 24) == 0);
|
||||
}
|
||||
|
||||
/* Complete hash-valid client cookie; more than 30 minutes old; needs a
|
||||
* refreshed server cookie.
|
||||
* A slightly better variation of edns_cookie_rfc9018_a3 for Unbound to check
|
||||
* that RESERVED bits do not influence cookie validation. */
|
||||
static void
|
||||
edns_cookie_rfc9018_a3_better(void)
|
||||
{
|
||||
uint32_t timestamp = 1800 + 1;
|
||||
uint8_t client_cookie[] = {
|
||||
0xfc, 0x93, 0xfc, 0x62, 0x80, 0x7d, 0xdb, 0x86,
|
||||
0x01, 0xab, 0xcd, 0xef,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x32, 0xF2, 0x43, 0xB9, 0xBC, 0xFE, 0xC4, 0x06 };
|
||||
uint8_t server_cookie[] = {
|
||||
0xfc, 0x93, 0xfc, 0x62, 0x80, 0x7d, 0xdb, 0x86,
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x07, 0x09,
|
||||
0x62, 0xD5, 0x93, 0x09, 0x14, 0x5C, 0x23, 0x9D };
|
||||
uint8_t server_secret[] = {
|
||||
0xe5, 0xe9, 0x73, 0xe5, 0xa6, 0xb2, 0xa4, 0x3f,
|
||||
0x48, 0xe7, 0xdc, 0x84, 0x9e, 0x37, 0xbf, 0xcf };
|
||||
uint8_t buf[32];
|
||||
/* copy client cookie|version|reserved|timestamp */
|
||||
memcpy(buf, client_cookie, 8 + 4 + 4);
|
||||
/* copy ip 203.0.113.203 */
|
||||
memcpy(buf + 16, "\313\000\161\313", 4);
|
||||
unit_assert(edns_cookie_server_validate(client_cookie,
|
||||
sizeof(client_cookie), server_secret, sizeof(server_secret), 1,
|
||||
buf, timestamp) == COOKIE_STATUS_VALID_RENEW);
|
||||
edns_cookie_server_write(buf, server_secret, 1, timestamp);
|
||||
unit_assert(memcmp(server_cookie, buf, 24) == 0);
|
||||
}
|
||||
|
||||
/* Complete hash-valid client cookie; more than 60 minutes old (expired);
|
||||
* needs a refreshed server cookie. */
|
||||
static void
|
||||
edns_cookie_rfc9018_a3(void)
|
||||
{
|
||||
uint32_t timestamp = 1559734700;
|
||||
uint8_t client_cookie[] = {
|
||||
0xfc, 0x93, 0xfc, 0x62, 0x80, 0x7d, 0xdb, 0x86,
|
||||
0x01, 0xab, 0xcd, 0xef,
|
||||
0x5c, 0xf7, 0x8f, 0x71,
|
||||
0xa3, 0x14, 0x22, 0x7b, 0x66, 0x79, 0xeb, 0xf5 };
|
||||
uint8_t server_cookie[] = {
|
||||
0xfc, 0x93, 0xfc, 0x62, 0x80, 0x7d, 0xdb, 0x86,
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
0x5c, 0xf7, 0xa9, 0xac,
|
||||
0xf7, 0x3a, 0x78, 0x10, 0xac, 0xa2, 0x38, 0x1e };
|
||||
uint8_t server_secret[] = {
|
||||
0xe5, 0xe9, 0x73, 0xe5, 0xa6, 0xb2, 0xa4, 0x3f,
|
||||
0x48, 0xe7, 0xdc, 0x84, 0x9e, 0x37, 0xbf, 0xcf };
|
||||
uint8_t buf[32];
|
||||
/* copy client cookie|version|reserved|timestamp */
|
||||
memcpy(buf, client_cookie, 8 + 4 + 4);
|
||||
/* copy ip 203.0.113.203 */
|
||||
memcpy(buf + 16, "\313\000\161\313", 4);
|
||||
unit_assert(edns_cookie_server_validate(client_cookie,
|
||||
sizeof(client_cookie), server_secret, sizeof(server_secret), 1,
|
||||
buf, timestamp) == COOKIE_STATUS_EXPIRED);
|
||||
edns_cookie_server_write(buf, server_secret, 1, timestamp);
|
||||
unit_assert(memcmp(server_cookie, buf, 24) == 0);
|
||||
}
|
||||
|
||||
/* Complete hash-valid client cookie; more than 30 minutes old; needs a
|
||||
* refreshed server cookie. */
|
||||
static void
|
||||
edns_cookie_rfc9018_a2(void)
|
||||
{
|
||||
uint32_t timestamp = 1559734385;
|
||||
uint8_t client_cookie[] = {
|
||||
0x24, 0x64, 0xc4, 0xab, 0xcf, 0x10, 0xc9, 0x57,
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
0x5c, 0xf7, 0x9f, 0x11,
|
||||
0x1f, 0x81, 0x30, 0xc3, 0xee, 0xe2, 0x94, 0x80 };
|
||||
uint8_t server_cookie[] = {
|
||||
0x24, 0x64, 0xc4, 0xab, 0xcf, 0x10, 0xc9, 0x57,
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
0x5c, 0xf7, 0xa8, 0x71,
|
||||
0xd4, 0xa5, 0x64, 0xa1, 0x44, 0x2a, 0xca, 0x77 };
|
||||
uint8_t server_secret[] = {
|
||||
0xe5, 0xe9, 0x73, 0xe5, 0xa6, 0xb2, 0xa4, 0x3f,
|
||||
0x48, 0xe7, 0xdc, 0x84, 0x9e, 0x37, 0xbf, 0xcf };
|
||||
uint8_t buf[32];
|
||||
/* copy client cookie|version|reserved|timestamp */
|
||||
memcpy(buf, client_cookie, 8 + 4 + 4);
|
||||
/* copy ip 198.51.100.100 */
|
||||
memcpy(buf + 16, "\306\063\144\144", 4);
|
||||
unit_assert(edns_cookie_server_validate(client_cookie,
|
||||
sizeof(client_cookie), server_secret, sizeof(server_secret), 1,
|
||||
buf, timestamp) == COOKIE_STATUS_VALID_RENEW);
|
||||
edns_cookie_server_write(buf, server_secret, 1, timestamp);
|
||||
unit_assert(memcmp(server_cookie, buf, 24) == 0);
|
||||
}
|
||||
|
||||
/* Only client cookie; needs a complete server cookie. */
|
||||
static void
|
||||
edns_cookie_rfc9018_a1(void)
|
||||
{
|
||||
uint32_t timestamp = 1559731985;
|
||||
uint8_t client_cookie[] = {
|
||||
0x24, 0x64, 0xc4, 0xab, 0xcf, 0x10, 0xc9, 0x57 };
|
||||
uint8_t server_cookie[] = {
|
||||
0x24, 0x64, 0xc4, 0xab, 0xcf, 0x10, 0xc9, 0x57,
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
0x5c, 0xf7, 0x9f, 0x11,
|
||||
0x1f, 0x81, 0x30, 0xc3, 0xee, 0xe2, 0x94, 0x80 };
|
||||
uint8_t server_secret[] = {
|
||||
0xe5, 0xe9, 0x73, 0xe5, 0xa6, 0xb2, 0xa4, 0x3f,
|
||||
0x48, 0xe7, 0xdc, 0x84, 0x9e, 0x37, 0xbf, 0xcf };
|
||||
uint8_t buf[32];
|
||||
/* copy client cookie|version|reserved|timestamp */
|
||||
memcpy(buf, server_cookie, 8 + 4 + 4);
|
||||
/* copy ip 198.51.100.100 */
|
||||
memcpy(buf + 16, "\306\063\144\144", 4);
|
||||
unit_assert(edns_cookie_server_validate(client_cookie,
|
||||
sizeof(client_cookie),
|
||||
/* these will not be used; it will return invalid
|
||||
* because of the size. */
|
||||
NULL, 0, 1, NULL, 0) == COOKIE_STATUS_CLIENT_ONLY);
|
||||
edns_cookie_server_write(buf, server_secret, 1, timestamp);
|
||||
unit_assert(memcmp(server_cookie, buf, 24) == 0);
|
||||
}
|
||||
|
||||
/** test interoperable DNS cookies (RFC9018) */
|
||||
static void
|
||||
edns_cookie_test(void)
|
||||
{
|
||||
unit_show_feature("interoperable dns cookies");
|
||||
/* Check RFC9018 appendix test vectors */
|
||||
edns_cookie_rfc9018_a1();
|
||||
edns_cookie_rfc9018_a2();
|
||||
edns_cookie_rfc9018_a3();
|
||||
/* More tests */
|
||||
edns_cookie_rfc9018_a3_better();
|
||||
edns_cookie_invalid_hash();
|
||||
edns_cookie_invalid_version();
|
||||
}
|
||||
|
||||
#include "util/random.h"
|
||||
/** test randomness */
|
||||
static void
|
||||
|
|
@ -915,8 +1116,8 @@ static void edns_ede_encode_encodedecode(struct query_info* qinfo,
|
|||
(void)query_dname_len(pkt);
|
||||
sldns_buffer_skip(pkt, 2 + 2);
|
||||
/* decode */
|
||||
unit_assert(
|
||||
parse_edns_from_query_pkt(pkt, edns, NULL, NULL, region)==0);
|
||||
unit_assert(parse_edns_from_query_pkt(pkt, edns, NULL, NULL, NULL, 0,
|
||||
region) == 0);
|
||||
}
|
||||
|
||||
static void edns_ede_encode_check(struct edns_data* edns, int* found_ede,
|
||||
|
|
@ -1119,6 +1320,7 @@ main(int argc, char* argv[])
|
|||
slabhash_test();
|
||||
infra_test();
|
||||
ldns_test();
|
||||
edns_cookie_test();
|
||||
zonemd_test();
|
||||
tcpreuse_test();
|
||||
msgparse_test();
|
||||
|
|
|
|||
1
testdata/01-doc.tdir/01-doc.test
vendored
1
testdata/01-doc.tdir/01-doc.test
vendored
|
|
@ -34,6 +34,7 @@ fgrep -v -e "ldns-src/" hlist > ilist; mv ilist hlist
|
|||
fgrep -v -e "libunbound/python/libunbound_wrap.c" hlist > ilist; mv ilist hlist
|
||||
fgrep -v -e "pythonmod/interface.h" hlist > ilist; mv ilist hlist
|
||||
fgrep -v -e "dnstap" hlist > ilist; mv ilist hlist
|
||||
fgrep -v -e "util/siphash.c" hlist > ilist; mv ilist hlist
|
||||
# filter out compat
|
||||
fgrep -v -e "compat/" hlist > ilist; mv ilist hlist
|
||||
for h in `cat hlist`; do
|
||||
|
|
|
|||
235
testdata/edns_downstream_cookies.rpl
vendored
Normal file
235
testdata/edns_downstream_cookies.rpl
vendored
Normal file
|
|
@ -0,0 +1,235 @@
|
|||
; config options
|
||||
server:
|
||||
answer-cookie: yes
|
||||
cookie-secret: "000102030405060708090a0b0c0d0e0f"
|
||||
access-control: 127.0.0.1 allow_cookie
|
||||
access-control: 1.2.3.4 allow
|
||||
local-data: "test. TXT test"
|
||||
|
||||
CONFIG_END
|
||||
|
||||
SCENARIO_BEGIN Test downstream DNS Cookies
|
||||
|
||||
; Note: When a valid hash was required, it was generated by running this test
|
||||
; with an invalid one and checking the output for the valid one.
|
||||
; Actual hash generation is tested with unit tests.
|
||||
|
||||
; Query without a client cookie ...
|
||||
STEP 0 QUERY
|
||||
ENTRY_BEGIN
|
||||
REPLY RD
|
||||
SECTION QUESTION
|
||||
test. IN TXT
|
||||
ENTRY_END
|
||||
; ... get TC and refused
|
||||
STEP 1 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all
|
||||
REPLY QR RD RA TC REFUSED
|
||||
SECTION QUESTION
|
||||
test. IN TXT
|
||||
ENTRY_END
|
||||
|
||||
; Query without a client cookie on TCP ...
|
||||
STEP 10 QUERY
|
||||
ENTRY_BEGIN
|
||||
REPLY RD
|
||||
MATCH TCP
|
||||
SECTION QUESTION
|
||||
test. IN TXT
|
||||
ENTRY_END
|
||||
; ... get an answer
|
||||
STEP 11 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all
|
||||
REPLY QR RD RA AA NOERROR
|
||||
SECTION QUESTION
|
||||
test. IN TXT
|
||||
SECTION ANSWER
|
||||
test. IN TXT "test"
|
||||
ENTRY_END
|
||||
|
||||
; Query with only a client cookie ...
|
||||
STEP 20 QUERY
|
||||
ENTRY_BEGIN
|
||||
REPLY RD
|
||||
SECTION QUESTION
|
||||
test. IN TXT
|
||||
SECTION ADDITIONAL
|
||||
HEX_EDNSDATA_BEGIN
|
||||
00 0a ; Opcode 10
|
||||
00 08 ; Length 8
|
||||
31 32 33 34 35 36 37 38 ; Random bits
|
||||
HEX_EDNSDATA_END
|
||||
ENTRY_END
|
||||
; ... get BADCOOKIE and a new cookie
|
||||
STEP 21 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all server_cookie
|
||||
REPLY QR RD RA DO YXRRSET ; BADCOOKIE is an extended rcode
|
||||
SECTION QUESTION
|
||||
test. IN TXT
|
||||
ENTRY_END
|
||||
|
||||
; Query with an invalid cookie ...
|
||||
STEP 30 QUERY
|
||||
ENTRY_BEGIN
|
||||
REPLY RD
|
||||
SECTION QUESTION
|
||||
test. IN TXT
|
||||
SECTION ADDITIONAL
|
||||
HEX_EDNSDATA_BEGIN
|
||||
00 0a ; Opcode 10
|
||||
00 18 ; Length 24
|
||||
31 32 33 34 35 36 37 38 ; Random bits
|
||||
02 00 00 00 ; wrong version
|
||||
00 00 00 00 ; Timestamp
|
||||
31 32 33 34 35 36 37 38 ; wrong hash
|
||||
HEX_EDNSDATA_END
|
||||
ENTRY_END
|
||||
; ... get BADCOOKIE and a new cookie
|
||||
STEP 31 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all server_cookie
|
||||
REPLY QR RD RA DO YXRRSET ; BADCOOKIE is an extended rcode
|
||||
SECTION QUESTION
|
||||
test. IN TXT
|
||||
ENTRY_END
|
||||
|
||||
; Query with an invalid cookie from a non-cookie protected address ...
|
||||
STEP 40 QUERY ADDRESS 1.2.3.4
|
||||
ENTRY_BEGIN
|
||||
REPLY RD
|
||||
SECTION QUESTION
|
||||
test. IN TXT
|
||||
SECTION ADDITIONAL
|
||||
HEX_EDNSDATA_BEGIN
|
||||
00 0a ; Opcode 10
|
||||
00 18 ; Length 24
|
||||
31 32 33 34 35 36 37 38 ; Random bits
|
||||
02 00 00 00 ; wrong version
|
||||
00 00 00 00 ; Timestamp
|
||||
31 32 33 34 35 36 37 38 ; wrong hash
|
||||
HEX_EDNSDATA_END
|
||||
ENTRY_END
|
||||
; ... get answer and a cookie
|
||||
STEP 41 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all server_cookie
|
||||
REPLY QR RD RA AA DO NOERROR
|
||||
SECTION QUESTION
|
||||
test. IN TXT
|
||||
SECTION ANSWER
|
||||
test. IN TXT "test"
|
||||
ENTRY_END
|
||||
|
||||
; Query with a valid cookie ...
|
||||
STEP 50 QUERY
|
||||
ENTRY_BEGIN
|
||||
REPLY RD
|
||||
SECTION QUESTION
|
||||
test. IN TXT
|
||||
SECTION ADDITIONAL
|
||||
HEX_EDNSDATA_BEGIN
|
||||
00 0a ; Opcode 10
|
||||
00 18 ; Length 24
|
||||
31 32 33 34 35 36 37 38 ; Random bits
|
||||
01 00 00 00 ; Version/Reserved
|
||||
00 00 00 00 ; Timestamp
|
||||
38 52 7b a8 c6 a4 ea 96 ; Hash
|
||||
HEX_EDNSDATA_END
|
||||
ENTRY_END
|
||||
; ... get answer and the cookie
|
||||
STEP 51 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all server_cookie
|
||||
REPLY QR RD RA AA DO NOERROR
|
||||
SECTION QUESTION
|
||||
test. IN TXT
|
||||
SECTION ANSWER
|
||||
test. IN TXT "test"
|
||||
ENTRY_END
|
||||
|
||||
; Query with a valid >30 minutes old cookie ...
|
||||
STEP 59 TIME_PASSES ELAPSE 1801
|
||||
STEP 60 QUERY
|
||||
ENTRY_BEGIN
|
||||
REPLY RD
|
||||
SECTION QUESTION
|
||||
test. IN TXT
|
||||
SECTION ADDITIONAL
|
||||
HEX_EDNSDATA_BEGIN
|
||||
00 0a ; Opcode 10
|
||||
00 18 ; Length 24
|
||||
31 32 33 34 35 36 37 38 ; Random bits
|
||||
01 00 00 00 ; Version/Reserved
|
||||
00 00 00 00 ; Timestamp
|
||||
38 52 7b a8 c6 a4 ea 96 ; Hash
|
||||
HEX_EDNSDATA_END
|
||||
ENTRY_END
|
||||
; ... Get answer and a refreshed cookie
|
||||
; (we don't check the re-freshness here; it has its own unit test)
|
||||
STEP 61 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all server_cookie
|
||||
REPLY QR RD RA AA DO NOERROR
|
||||
SECTION QUESTION
|
||||
test. IN TXT
|
||||
SECTION ANSWER
|
||||
test. IN TXT "test"
|
||||
ENTRY_END
|
||||
|
||||
; Query with a hash-valid >60 minutes old cookie ...
|
||||
STEP 69 TIME_PASSES ELAPSE 3601
|
||||
STEP 70 QUERY
|
||||
ENTRY_BEGIN
|
||||
REPLY RD
|
||||
SECTION QUESTION
|
||||
test. IN TXT
|
||||
SECTION ADDITIONAL
|
||||
HEX_EDNSDATA_BEGIN
|
||||
00 0a ; Opcode 10
|
||||
00 18 ; Length 24
|
||||
31 32 33 34 35 36 37 38 ; Random bits
|
||||
01 00 00 00 ; Version/Reserved
|
||||
00 00 07 09 ; Timestamp (1801)
|
||||
77 81 38 e3 8f aa 72 86 ; Hash
|
||||
HEX_EDNSDATA_END
|
||||
ENTRY_END
|
||||
; ... get BADCOOKIE and a new cookie
|
||||
STEP 71 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all server_cookie
|
||||
REPLY QR RD RA DO YXRRSET ; BADCOOKIE is an extended rcode
|
||||
SECTION QUESTION
|
||||
test. IN TXT
|
||||
ENTRY_END
|
||||
|
||||
; Query with a valid future (<5 minutes) cookie ...
|
||||
STEP 80 QUERY
|
||||
ENTRY_BEGIN
|
||||
REPLY RD
|
||||
SECTION QUESTION
|
||||
test. IN TXT
|
||||
SECTION ADDITIONAL
|
||||
HEX_EDNSDATA_BEGIN
|
||||
00 0a ; Opcode 10
|
||||
00 18 ; Length 24
|
||||
31 32 33 34 35 36 37 38 ; Random bits
|
||||
01 00 00 00 ; Version/Reserved
|
||||
00 00 16 45 ; Timestamp (1801 + 3601 + 299)
|
||||
4a f5 0f df f0 e8 c7 09 ; Hash
|
||||
HEX_EDNSDATA_END
|
||||
ENTRY_END
|
||||
; ... get an answer
|
||||
STEP 81 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all server_cookie
|
||||
REPLY QR RD RA AA DO NOERROR
|
||||
SECTION QUESTION
|
||||
test. IN TXT
|
||||
SECTION ANSWER
|
||||
test. IN TXT "test"
|
||||
ENTRY_END
|
||||
|
||||
SCENARIO_END
|
||||
28
testdata/ip_ratelimit.tdir/ip_ratelimit.conf
vendored
Normal file
28
testdata/ip_ratelimit.tdir/ip_ratelimit.conf
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
server:
|
||||
verbosity: 5
|
||||
# num-threads: 1
|
||||
interface: 127.0.0.1
|
||||
port: @PORT@
|
||||
use-syslog: no
|
||||
directory: .
|
||||
pidfile: "unbound.pid"
|
||||
chroot: ""
|
||||
username: ""
|
||||
local-data: "test. IN TXT localdata"
|
||||
|
||||
ip-ratelimit: 1
|
||||
ip-ratelimit-cookie: 0
|
||||
ip-ratelimit-factor: 0
|
||||
ip-ratelimit-backoff: yes
|
||||
answer-cookie: yes
|
||||
access-control: 127.0.0.0/8 allow_cookie
|
||||
|
||||
remote-control:
|
||||
control-enable: yes
|
||||
control-interface: 127.0.0.1
|
||||
# control-interface: ::1
|
||||
control-port: @CONTROL_PORT@
|
||||
server-key-file: "unbound_server.key"
|
||||
server-cert-file: "unbound_server.pem"
|
||||
control-key-file: "unbound_control.key"
|
||||
control-cert-file: "unbound_control.pem"
|
||||
16
testdata/ip_ratelimit.tdir/ip_ratelimit.dsc
vendored
Normal file
16
testdata/ip_ratelimit.tdir/ip_ratelimit.dsc
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
BaseName: ip_ratelimit
|
||||
Version: 1.0
|
||||
Description: Test IP source ratelimit.
|
||||
CreationDate: Tue Aug 8 00:00:00 CET 2023
|
||||
Maintainer: Yorgos Thessalonikefs
|
||||
Category:
|
||||
Component:
|
||||
CmdDepends:
|
||||
Depends:
|
||||
Help:
|
||||
Pre: ip_ratelimit.pre
|
||||
Post: ip_ratelimit.post
|
||||
Test: ip_ratelimit.test
|
||||
AuxFiles:
|
||||
Passed:
|
||||
Failure:
|
||||
13
testdata/ip_ratelimit.tdir/ip_ratelimit.post
vendored
Normal file
13
testdata/ip_ratelimit.tdir/ip_ratelimit.post
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
# #-- ip_ratelimit.post --#
|
||||
# source the master var file when it's there
|
||||
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
|
||||
# source the test var file when it's there
|
||||
[ -f .tpkg.var.test ] && source .tpkg.var.test
|
||||
#
|
||||
# do your teardown here
|
||||
. ../common.sh
|
||||
kill_pid $UNBOUND_PID
|
||||
if test -f unbound.log; then
|
||||
echo ">>> unbound log"
|
||||
cat unbound.log
|
||||
fi
|
||||
24
testdata/ip_ratelimit.tdir/ip_ratelimit.pre
vendored
Normal file
24
testdata/ip_ratelimit.tdir/ip_ratelimit.pre
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
# #-- ip_ratelimit.pre--#
|
||||
# source the master var file when it's there
|
||||
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
|
||||
# use .tpkg.var.test for in test variable passing
|
||||
[ -f .tpkg.var.test ] && source .tpkg.var.test
|
||||
|
||||
PRE="../.."
|
||||
. ../common.sh
|
||||
get_random_port 2
|
||||
UNBOUND_PORT=$RND_PORT
|
||||
CONTROL_PORT=$(($RND_PORT + 1))
|
||||
echo "UNBOUND_PORT=$UNBOUND_PORT" >> .tpkg.var.test
|
||||
echo "CONTROL_PORT=$CONTROL_PORT" >> .tpkg.var.test
|
||||
|
||||
# make config file
|
||||
sed -e 's/@PORT\@/'$UNBOUND_PORT'/' -e 's/@CONTROL_PORT\@/'$CONTROL_PORT'/' < ip_ratelimit.conf > ub.conf
|
||||
# start unbound in the background
|
||||
$PRE/unbound -d -c ub.conf >unbound.log 2>&1 &
|
||||
UNBOUND_PID=$!
|
||||
echo "UNBOUND_PID=$UNBOUND_PID" >> .tpkg.var.test
|
||||
|
||||
wait_unbound_up unbound.log
|
||||
|
||||
cat .tpkg.var.test
|
||||
159
testdata/ip_ratelimit.tdir/ip_ratelimit.test
vendored
Normal file
159
testdata/ip_ratelimit.tdir/ip_ratelimit.test
vendored
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
# #-- ip_ratelimit.test --#
|
||||
# source the master var file when it's there
|
||||
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
|
||||
# use .tpkg.var.test for in test variable passing
|
||||
[ -f .tpkg.var.test ] && source .tpkg.var.test
|
||||
|
||||
PRE="../.."
|
||||
. ../common.sh
|
||||
|
||||
get_make
|
||||
(cd $PRE; $MAKE streamtcp)
|
||||
|
||||
# These tests rely on second time precision. To combat false negatives the
|
||||
# tests run multiple times and we allow 1/3 of the runs to fail.
|
||||
total_runs=6
|
||||
success_threshold=4 # 2/3*total_runs
|
||||
|
||||
echo "> First get a valid cookie"
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT +ednsopt=10:0102030405060708 +tcp +retry=0 +time=1 test. TXT >outfile 2>&1
|
||||
if test "$?" -ne 0; then
|
||||
echo "exit status not OK"
|
||||
echo "> cat logfiles"
|
||||
cat outfile
|
||||
cat unbound.log
|
||||
echo "Not OK"
|
||||
exit 1
|
||||
fi
|
||||
if test `grep "COOKIE: " outfile | wc -l` -ne 1; then
|
||||
echo "Could not get cookie"
|
||||
echo "> cat logfiles"
|
||||
cat outfile
|
||||
cat unbound.log
|
||||
echo "Not OK"
|
||||
exit 1
|
||||
fi
|
||||
cookie=`grep "COOKIE: " outfile | cut -d ' ' -f 3`
|
||||
|
||||
successes=0
|
||||
echo "> Three parallel queries with backoff and cookie"
|
||||
# For this test we send three parallel queries. The ratelimit should be reached
|
||||
# for that second. We send a query to verify that there is no reply.
|
||||
# Then for the next second we again send three parallel queries and we expect
|
||||
# none of them to be allowed through because of the backoff logic that keeps
|
||||
# rolling the RATE_WINDOW based on demand.
|
||||
# Again we send another query but with a valid cookie and we expect to receive
|
||||
# an answer.
|
||||
for i in $(seq 1 $total_runs); do
|
||||
# Try to hit limit
|
||||
$PRE/streamtcp -nu -f 127.0.0.1@$UNBOUND_PORT test. TXT IN test. TXT IN test. TXT IN >outfile 2>&1
|
||||
if test "$?" -ne 0; then
|
||||
echo "exit status not OK"
|
||||
echo "> cat logfiles"
|
||||
cat outfile
|
||||
cat unbound.log
|
||||
echo "Not OK"
|
||||
exit 1
|
||||
fi
|
||||
# Expect no answer because of limit
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT +retry=0 +time=1 test. TXT >outfile 2>&1
|
||||
if test "$?" -eq 0; then
|
||||
continue
|
||||
fi
|
||||
# Try to keep limit
|
||||
$PRE/streamtcp -nu -f 127.0.0.1@$UNBOUND_PORT test. TXT IN test. TXT IN test. TXT IN >outfile 2>&1
|
||||
if test "$?" -ne 0; then
|
||||
echo "exit status not OK"
|
||||
echo "> cat logfiles"
|
||||
cat outfile
|
||||
cat unbound.log
|
||||
echo "Not OK"
|
||||
exit 1
|
||||
fi
|
||||
# Expect answer because of DNS cookie
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT +ednsopt=10:$cookie +retry=0 +time=1 test. TXT >outfile 2>&1
|
||||
if test "$?" -ne 0; then
|
||||
continue
|
||||
fi
|
||||
((successes++))
|
||||
# We don't have to wait for all the runs to complete if we know
|
||||
# we passed the threshold.
|
||||
if test $successes -ge $success_threshold; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if test $successes -ge $success_threshold; then
|
||||
echo "Three parallel queries with backoff and cookie OK"
|
||||
else
|
||||
echo "Three parallel queries with backoff and cookie NOT OK"
|
||||
echo "> cat logfiles"
|
||||
cat outfile
|
||||
cat unbound.log
|
||||
echo "Three parallel queries with backoff and cookie NOT OK"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "> Activating ip-ratelimit-cookie"
|
||||
echo "$PRE/unbound-control -c ub.conf set_option ip-ratelimit-cookie: 1"
|
||||
$PRE/unbound-control -c ub.conf set_option ip-ratelimit-cookie: 1
|
||||
if test $? -ne 0; then
|
||||
echo "wrong exit value after success"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
successes=0
|
||||
echo "> Three parallel queries with backoff and cookie with ip-ratelimit-cookie"
|
||||
# This is the exact same test as above with the exception that we don't expect
|
||||
# an answer on the last query because ip-ratelimit-cookie is now enabled.
|
||||
for i in $(seq 1 $total_runs); do
|
||||
# Try to hit limit
|
||||
$PRE/streamtcp -nu -f 127.0.0.1@$UNBOUND_PORT test. TXT IN test. TXT IN test. TXT IN >outfile 2>&1
|
||||
if test "$?" -ne 0; then
|
||||
echo "exit status not OK"
|
||||
echo "> cat logfiles"
|
||||
cat outfile
|
||||
cat unbound.log
|
||||
echo "Not OK"
|
||||
exit 1
|
||||
fi
|
||||
# Expect no answer because of limit
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT +retry=0 +time=1 test. TXT >outfile 2>&1
|
||||
if test "$?" -eq 0; then
|
||||
continue
|
||||
fi
|
||||
# Try to keep limit
|
||||
$PRE/streamtcp -nu -f 127.0.0.1@$UNBOUND_PORT test. TXT IN test. TXT IN test. TXT IN >outfile 2>&1
|
||||
if test "$?" -ne 0; then
|
||||
echo "exit status not OK"
|
||||
echo "> cat logfiles"
|
||||
cat outfile
|
||||
cat unbound.log
|
||||
echo "Not OK"
|
||||
exit 1
|
||||
fi
|
||||
# Expect no answer because of ip-ratelimit-cookie
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT +ednsopt=10:$cookie +retry=0 +time=1 test. TXT >outfile 2>&1
|
||||
if test "$?" -eq 0; then
|
||||
continue
|
||||
fi
|
||||
((successes++))
|
||||
# We don't have to wait for all the runs to complete if we know
|
||||
# we passed the threshold.
|
||||
if test $successes -ge $success_threshold; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if test $successes -ge $success_threshold; then
|
||||
echo "Three parallel queries with backoff and cookie with ip-ratelimit-cookie OK"
|
||||
else
|
||||
echo "Three parallel queries with backoff and cookie with ip-ratelimit-cookie NOT OK"
|
||||
echo "> cat logfiles"
|
||||
cat outfile
|
||||
cat unbound.log
|
||||
echo "Three parallel queries with backoff and cookie with ip-ratelimit-cookie NOT OK"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exit 0
|
||||
39
testdata/ip_ratelimit.tdir/unbound_control.key
vendored
Normal file
39
testdata/ip_ratelimit.tdir/unbound_control.key
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
-----BEGIN RSA PRIVATE KEY-----
|
||||
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
|
||||
-----END RSA PRIVATE KEY-----
|
||||
22
testdata/ip_ratelimit.tdir/unbound_control.pem
vendored
Normal file
22
testdata/ip_ratelimit.tdir/unbound_control.pem
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIDszCCAhsCFGD5193whHQ2bVdzbaQfdf1gc4SkMA0GCSqGSIb3DQEBCwUAMBIx
|
||||
EDAOBgNVBAMMB3VuYm91bmQwHhcNMjAwNzA4MTMzMjMwWhcNNDAwMzI1MTMzMjMw
|
||||
WjAaMRgwFgYDVQQDDA91bmJvdW5kLWNvbnRyb2wwggGiMA0GCSqGSIb3DQEBAQUA
|
||||
A4IBjwAwggGKAoIBgQCy0Sn4/KHxcau1nvsDgWFiO9t4Hd0xrtDasZbGhvOUD2mv
|
||||
OEDVoKEC9S0I4C4z6sHo1M0HxhZ9kltAdrDIw2mYLvtyDq9ctgIZRAdnICqJ03Tj
|
||||
1EkXlPuPg3xWeK/XsuJF2vRLqzDLg9G8Scg89XjcRAdmoLmNW8ewqSEh+YEX8OPl
|
||||
NdHKl5rBZX+bmN5Tr/gdFgx/K0Fl07WY9e5YuHSWBtDhIJuCs5RUPeueIyTXJkht
|
||||
A6a+UMdip6SMNv+85bYrFRAsbThpkwnWZZ91vAbQIpCRKMhIQNnWXvq+EzqZMzR/
|
||||
Bdsi/IVn3I88KV7WYXlpKXFLZyYa4ZVJFBrDxcX197dr0AIklOvfcd1KnJpmQpEB
|
||||
TMtwqosKXfbd1oq/c3DABPTdOPiJAzjXoBIyiLJ8Vr/YZZMpBWN127wKtqvu0Zp/
|
||||
nGuWKDgMGasG91gDeePLvb9EPvWEvCaVGgIZTt1G4Ov07ooBJSbVGL3U41n+p2My
|
||||
+i/XmXa+PgZX4pdHTR0CAwEAATANBgkqhkiG9w0BAQsFAAOCAYEAd++Wen6l8Ifj
|
||||
4h3p/y16PhSsWJWuJ4wdNYy3/GM84S26wGjzlEEwiW76HpH6VJzPOiBAeWnFKE83
|
||||
hFyetEIxgJeIPbcs9ZP/Uoh8GZH9tRISBSN9Hgk2Slr9llo4t1H0g/XTgA5HqMQU
|
||||
9YydlBh43G7Vw3FVwh09OM6poNOGQKNc/tq2/QdKeUMtyBbLWpRmjH5XcCT35fbn
|
||||
ZiVOUldqSHD4kKrFO4nJYXZyipRbcXybsLiX9GP0GLemc3IgIvOXyJ2RPp06o/SJ
|
||||
pzlMlkcAfLJaSuEW57xRakhuNK7m051TKKzJzIEX+NFYOVdafFHS8VwGrYsdrFvD
|
||||
72tMfu+Fu55y3awdWWGc6YlaGogZiuMnJkvQphwgn+5qE/7CGEckoKEsH601rqIZ
|
||||
muaIc85+nEcHJeijd/ZlBN9zeltjFoMuqTUENgmv8+tUAdVm/UMY9Vjme6b43ydP
|
||||
uv6DS02+k9z8toxXworLiPr94BGaiGV1NxgwZKLZigYJt/Fi2Qte
|
||||
-----END CERTIFICATE-----
|
||||
39
testdata/ip_ratelimit.tdir/unbound_server.key
vendored
Normal file
39
testdata/ip_ratelimit.tdir/unbound_server.key
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
-----BEGIN RSA PRIVATE KEY-----
|
||||
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
|
||||
-----END RSA PRIVATE KEY-----
|
||||
22
testdata/ip_ratelimit.tdir/unbound_server.pem
vendored
Normal file
22
testdata/ip_ratelimit.tdir/unbound_server.pem
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIDqzCCAhMCFBHWXeQ6ZIa9QcQbXLFfC6tj+KA+MA0GCSqGSIb3DQEBCwUAMBIx
|
||||
EDAOBgNVBAMMB3VuYm91bmQwHhcNMjAwNzA4MTMzMjI5WhcNNDAwMzI1MTMzMjI5
|
||||
WjASMRAwDgYDVQQDDAd1bmJvdW5kMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIB
|
||||
igKCAYEAvjSVSN2QMXudpzukdLCqgg/IOhCX8KYkD0FFFfWcQjgKq5wI0x41iG32
|
||||
a6wbGanre4IX7VxaSPu9kkHfnGgynCk5nwDRedE/FLFhAU78PoT0+NqqGRS7XVQ2
|
||||
4vLmIz9Hqc2Ozx1um1BXBTmIT0UfN2e22I0LWQ6a3seZlEDRj45gnk7Zuh9MDgot
|
||||
aBdm+v1JAbupSf6Zis4VEH3JNdvVGE3O1DHEIeuuz/3BDhpf6WBDH+8KWaBe1ca4
|
||||
TZHr9ThL2gEMEfAQl0wXDwRWRoi3NjNMH+mw0L1rjwThI5GXqNIee7o5FzUReSXZ
|
||||
uTdFMyGe3Owcx+XoYnwi6cplSNoGsDBu4B9bKKglR9YleJVw4L4Xi8xPq6O9UPj4
|
||||
+nypHk/DOoC7DIM3ufN0yxPBsFo5TVowxfhdjZXJbbftd2TZv7AH8+XLA5UoZgRz
|
||||
XgzECelXSCTBFlMTnT48LfA9pMLydyjAz2UdPHs5Iv+TK5nnI+aJoeaP7kFZSngx
|
||||
dy1+A/bNAgMBAAEwDQYJKoZIhvcNAQELBQADggGBABunf93MKaCUHiZgnoOTinsW
|
||||
84/EgInrgtKzAyH+BhnKkJOhhR0kkIAx5d9BpDlaSiRTACFon9moWCgDIIsK/Ar7
|
||||
JE0Kln9cV//wiiNoFU0O4mnzyGUIMvlaEX6QHMJJQYvL05+w/3AAcf5XmMJtR5ca
|
||||
fJ8FqvGC34b2WxX9lTQoyT52sRt+1KnQikiMEnEyAdKktMG+MwKsFDdOwDXyZhZg
|
||||
XZhRrfX3/NVJolqB6EahjWIGXDeKuSSKZVtCyib6LskyeMzN5lcRfvubKDdlqFVF
|
||||
qlD7rHBsKhQUWK/IO64mGf7y/de+CgHtED5vDvr/p2uj/9sABATfbrOQR3W/Of25
|
||||
sLBj4OEfrJ7lX8hQgFaxkMI3x6VFT3W8dTCp7xnQgb6bgROWB5fNEZ9jk/gjSRmD
|
||||
yIU+r0UbKe5kBk/CmZVFXL2TyJ92V5NYEQh8V4DGy19qZ6u/XKYyNJL4ocs35GGe
|
||||
CA8SBuyrmdhx38h1RHErR2Skzadi1S7MwGf1y431fQ==
|
||||
-----END CERTIFICATE-----
|
||||
1
testdata/stat_values.tdir/stat_values.pre
vendored
1
testdata/stat_values.tdir/stat_values.pre
vendored
|
|
@ -37,6 +37,7 @@ echo "FWD_EXPIRED_PID=$FWD_EXPIRED_PID" >> .tpkg.var.test
|
|||
# make config file
|
||||
sed -e 's/@PORT\@/'$UNBOUND_PORT'/' -e 's/@TOPORT\@/'$FWD_PORT'/' -e 's/@EXPIREDPORT\@/'$FWD_EXPIRED_PORT'/' -e 's/@CONTROL_PORT\@/'$CONTROL_PORT'/' < stat_values.conf > ub.conf
|
||||
sed -e 's/@PORT\@/'$UNBOUND_PORT'/' -e 's/@TOPORT\@/'$FWD_PORT'/' -e 's/@EXPIREDPORT\@/'$FWD_EXPIRED_PORT'/' -e 's/@CONTROL_PORT\@/'$CONTROL_PORT'/' < stat_values_cachedb.conf > ub_cachedb.conf
|
||||
sed -e 's/@PORT\@/'$UNBOUND_PORT'/' -e 's/@CONTROL_PORT\@/'$CONTROL_PORT'/' < stat_values_downstream_cookies.conf > ub_downstream_cookies.conf
|
||||
# start unbound in the background
|
||||
$PRE/unbound -d -c ub.conf >unbound.log 2>&1 &
|
||||
UNBOUND_PID=$!
|
||||
|
|
|
|||
91
testdata/stat_values.tdir/stat_values.test
vendored
91
testdata/stat_values.tdir/stat_values.test
vendored
|
|
@ -414,6 +414,97 @@ rrset.cache.count=3
|
|||
infra.cache.count=2"
|
||||
|
||||
|
||||
# Bring the downstream DNS Cookies configured Unbound up
|
||||
kill_pid $UNBOUND_PID # kill current Unbound
|
||||
$PRE/unbound -d -c ub_downstream_cookies.conf >unbound.log 2>&1 &
|
||||
UNBOUND_PID=$!
|
||||
echo "UNBOUND_PID=$UNBOUND_PID" >> .tpkg.var.test
|
||||
wait_unbound_up unbound.log
|
||||
|
||||
echo
|
||||
echo "[ Get a DNS Cookie. ]"
|
||||
echo "> dig www.local.zone +tcp +ednsopt=10:0102030405060708"
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT +tcp +ednsopt=10:0102030405060708 +retry=0 +time=1 www.local.zone. | tee outfile
|
||||
echo "> check answer"
|
||||
if grep "192.0.2.1" outfile; then
|
||||
echo "OK"
|
||||
else
|
||||
end 1
|
||||
fi
|
||||
# Save valid cookie
|
||||
valid_cookie=`grep "COOKIE: " outfile | cut -d ' ' -f 3`
|
||||
invalid_cookie=`echo $valid_cookie | tr '0' '4'`
|
||||
check_stats "\
|
||||
total.num.queries=1
|
||||
total.num.queries_cookie_client=1
|
||||
total.num.cachehits=1
|
||||
num.query.type.A=1
|
||||
num.query.class.IN=1
|
||||
num.query.opcode.QUERY=1
|
||||
num.query.flags.RD=1
|
||||
num.query.flags.AD=1
|
||||
num.query.edns.present=1
|
||||
num.query.tcp=1
|
||||
num.answer.rcode.NOERROR=1"
|
||||
|
||||
echo
|
||||
echo "[ Present the valid DNS Cookie. ]"
|
||||
echo "> dig www.local.zone +ednsopt=10:valid_cookie"
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT +ednsopt=10:$valid_cookie +retry=0 +time=1 www.local.zone. | tee outfile
|
||||
echo "> check answer"
|
||||
if grep "192.0.2.1" outfile; then
|
||||
echo "OK"
|
||||
else
|
||||
end 1
|
||||
fi
|
||||
check_stats "\
|
||||
total.num.queries=1
|
||||
total.num.queries_cookie_valid=1
|
||||
total.num.cachehits=1
|
||||
num.query.type.A=1
|
||||
num.query.class.IN=1
|
||||
num.query.opcode.QUERY=1
|
||||
num.query.flags.RD=1
|
||||
num.query.flags.AD=1
|
||||
num.query.edns.present=1
|
||||
num.answer.rcode.NOERROR=1"
|
||||
|
||||
echo
|
||||
echo "[ Present an invalid DNS Cookie. ]"
|
||||
echo "> dig www.local.zone +ednsopt=10:invalid_cookie"
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT +ednsopt=10:$invalid_cookie +retry=0 +time=1 www.local.zone. | tee outfile
|
||||
echo "> check answer"
|
||||
if grep "192.0.2.1" outfile; then
|
||||
end 1
|
||||
else
|
||||
echo "OK"
|
||||
fi
|
||||
# A lot of stats are missing since BADCOOKIE error response is before
|
||||
# those stat calculations.
|
||||
# BADCOOKIE is an extended error code; we record YXRRSET below.
|
||||
check_stats "\
|
||||
total.num.queries=1
|
||||
total.num.queries_cookie_invalid=1
|
||||
total.num.cachehits=1
|
||||
num.answer.rcode.YXRRSET=1"
|
||||
|
||||
echo
|
||||
echo "[ Present no DNS Cookie. ]"
|
||||
echo "> dig www.local.zone +ignore"
|
||||
dig @127.0.0.1 -p $UNBOUND_PORT +ignore +retry=0 +time=1 www.local.zone. | tee outfile
|
||||
echo "> check answer"
|
||||
if grep "192.0.2.1" outfile; then
|
||||
end 1
|
||||
else
|
||||
echo "OK"
|
||||
fi
|
||||
# A lot of stats are missing since REFUSED error response because of no DNS
|
||||
# Cookie is before those stat calculations.
|
||||
check_stats "\
|
||||
total.num.queries=1
|
||||
total.num.cachehits=1
|
||||
num.answer.rcode.REFUSED=1"
|
||||
|
||||
if test x$USE_CACHEDB = "x1"; then
|
||||
|
||||
# Bring the cachedb configured Unbound up
|
||||
|
|
|
|||
32
testdata/stat_values.tdir/stat_values_downstream_cookies.conf
vendored
Normal file
32
testdata/stat_values.tdir/stat_values_downstream_cookies.conf
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
server:
|
||||
verbosity: 5
|
||||
module-config: "iterator"
|
||||
num-threads: 1
|
||||
interface: 127.0.0.1
|
||||
port: @PORT@
|
||||
use-syslog: no
|
||||
directory: ""
|
||||
pidfile: "unbound.pid"
|
||||
chroot: ""
|
||||
username: ""
|
||||
extended-statistics: yes
|
||||
identity: "stat_values"
|
||||
outbound-msg-retry: 0
|
||||
root-key-sentinel: no
|
||||
trust-anchor-signaling: no
|
||||
|
||||
local-zone: local.zone static
|
||||
local-data: "www.local.zone A 192.0.2.1"
|
||||
|
||||
answer-cookie: yes
|
||||
access-control: 127.0.0.1 allow_cookie
|
||||
|
||||
remote-control:
|
||||
control-enable: yes
|
||||
control-interface: 127.0.0.1
|
||||
# control-interface: ::1
|
||||
control-port: @CONTROL_PORT@
|
||||
server-key-file: "unbound_server.key"
|
||||
server-cert-file: "unbound_server.pem"
|
||||
control-key-file: "unbound_control.key"
|
||||
control-cert-file: "unbound_control.pem"
|
||||
|
|
@ -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)
|
||||
{
|
||||
|
|
@ -326,6 +330,7 @@ config_create(void)
|
|||
cfg->dnstap_bidirectional = 1;
|
||||
cfg->dnstap_tls = 1;
|
||||
cfg->disable_dnssec_lame_check = 0;
|
||||
cfg->ip_ratelimit_cookie = 0;
|
||||
cfg->ip_ratelimit = 0;
|
||||
cfg->ratelimit = 0;
|
||||
cfg->ip_ratelimit_slabs = 4;
|
||||
|
|
@ -369,6 +374,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;
|
||||
|
|
@ -771,6 +780,10 @@ int config_set_option(struct config_file* cfg, const char* opt,
|
|||
else S_POW2("dnscrypt-nonce-cache-slabs:",
|
||||
dnscrypt_nonce_cache_slabs)
|
||||
#endif
|
||||
else if(strcmp(opt, "ip-ratelimit-cookie:") == 0) {
|
||||
IS_NUMBER_OR_ZERO; cfg->ip_ratelimit_cookie = atoi(val);
|
||||
infra_ip_ratelimit_cookie=cfg->ip_ratelimit_cookie;
|
||||
}
|
||||
else if(strcmp(opt, "ip-ratelimit:") == 0) {
|
||||
IS_NUMBER_OR_ZERO; cfg->ip_ratelimit = atoi(val);
|
||||
infra_ip_ratelimit=cfg->ip_ratelimit;
|
||||
|
|
@ -1240,6 +1253,7 @@ config_get_option(struct config_file* cfg, const char* opt,
|
|||
else O_LST(opt, "python-script", python_script)
|
||||
else O_LST(opt, "dynlib-file", dynlib_file)
|
||||
else O_YNO(opt, "disable-dnssec-lame-check", disable_dnssec_lame_check)
|
||||
else O_DEC(opt, "ip-ratelimit-cookie", ip_ratelimit_cookie)
|
||||
else O_DEC(opt, "ip-ratelimit", ip_ratelimit)
|
||||
else O_DEC(opt, "ratelimit", ratelimit)
|
||||
else O_MEM(opt, "ip-ratelimit-size", ip_ratelimit_size)
|
||||
|
|
@ -1685,6 +1699,20 @@ 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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -590,6 +590,9 @@ struct config_file {
|
|||
|
||||
/** ratelimit for ip addresses. 0 is off, otherwise qps (unless overridden) */
|
||||
int ip_ratelimit;
|
||||
/** ratelimit for ip addresses with a valid DNS Cookie. 0 is off,
|
||||
* otherwise qps (unless overridden) */
|
||||
int ip_ratelimit_cookie;
|
||||
/** number of slabs for ip_ratelimit cache */
|
||||
size_t ip_ratelimit_slabs;
|
||||
/** memory size in bytes for ip_ratelimit cache */
|
||||
|
|
@ -711,6 +714,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
|
||||
|
|
|
|||
|
|
@ -507,6 +507,7 @@ dnstap-log-forwarder-response-messages{COLON} {
|
|||
YDVAR(1, VAR_DNSTAP_LOG_FORWARDER_RESPONSE_MESSAGES) }
|
||||
disable-dnssec-lame-check{COLON} { YDVAR(1, VAR_DISABLE_DNSSEC_LAME_CHECK) }
|
||||
ip-ratelimit{COLON} { YDVAR(1, VAR_IP_RATELIMIT) }
|
||||
ip-ratelimit-cookie{COLON} { YDVAR(1, VAR_IP_RATELIMIT_COOKIE) }
|
||||
ratelimit{COLON} { YDVAR(1, VAR_RATELIMIT) }
|
||||
ip-ratelimit-slabs{COLON} { YDVAR(1, VAR_IP_RATELIMIT_SLABS) }
|
||||
ratelimit-slabs{COLON} { YDVAR(1, VAR_RATELIMIT_SLABS) }
|
||||
|
|
@ -567,6 +568,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 ) }
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@
|
|||
#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);
|
||||
|
|
@ -183,6 +184,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 VAR_IP_RATELIMIT_COOKIE
|
||||
%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
|
||||
|
|
@ -323,6 +325,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_ip_ratelimit_cookie |
|
||||
server_tls_use_sni | server_edns_client_string |
|
||||
server_edns_client_string_opcode | server_nsid |
|
||||
server_zonemd_permissive_mode | server_max_reuse_tcp_queries |
|
||||
|
|
@ -1160,7 +1163,7 @@ server_http_nodelay: VAR_HTTP_NODELAY STRING_ARG
|
|||
yyerror("expected yes or no.");
|
||||
else cfg_parser->cfg->http_nodelay = (strcmp($2, "yes")==0);
|
||||
free($2);
|
||||
}
|
||||
};
|
||||
server_http_notls_downstream: VAR_HTTP_NOTLS_DOWNSTREAM STRING_ARG
|
||||
{
|
||||
OUTYY(("P(server_http_notls_downstream:%s)\n", $2));
|
||||
|
|
@ -2207,6 +2210,7 @@ server_permit_small_holddown: VAR_PERMIT_SMALL_HOLDDOWN STRING_ARG
|
|||
(strcmp($2, "yes")==0);
|
||||
free($2);
|
||||
}
|
||||
;
|
||||
server_key_cache_size: VAR_KEY_CACHE_SIZE STRING_ARG
|
||||
{
|
||||
OUTYY(("P(server_key_cache_size:%s)\n", $2));
|
||||
|
|
@ -2564,6 +2568,15 @@ server_ip_ratelimit: VAR_IP_RATELIMIT STRING_ARG
|
|||
free($2);
|
||||
}
|
||||
;
|
||||
server_ip_ratelimit_cookie: VAR_IP_RATELIMIT_COOKIE STRING_ARG
|
||||
{
|
||||
OUTYY(("P(server_ip_ratelimit_cookie:%s)\n", $2));
|
||||
if(atoi($2) == 0 && strcmp($2, "0") != 0)
|
||||
yyerror("number expected");
|
||||
else cfg_parser->cfg->ip_ratelimit_cookie = atoi($2);
|
||||
free($2);
|
||||
}
|
||||
;
|
||||
server_ratelimit: VAR_RATELIMIT STRING_ARG
|
||||
{
|
||||
OUTYY(("P(server_ratelimit:%s)\n", $2));
|
||||
|
|
@ -3517,6 +3530,7 @@ py_script: VAR_PYTHON_SCRIPT STRING_ARG
|
|||
if(!cfg_strlist_append_ex(&cfg_parser->cfg->python_script, $2))
|
||||
yyerror("out of memory");
|
||||
}
|
||||
;
|
||||
dynlibstart: VAR_DYNLIB
|
||||
{
|
||||
OUTYY(("\nP(dynlib:)\n"));
|
||||
|
|
@ -3533,6 +3547,7 @@ dl_file: VAR_DYNLIB_FILE STRING_ARG
|
|||
if(!cfg_strlist_append_ex(&cfg_parser->cfg->dynlib_file, $2))
|
||||
yyerror("out of memory");
|
||||
}
|
||||
;
|
||||
server_disable_dnssec_lame_check: VAR_DISABLE_DNSSEC_LAME_CHECK STRING_ARG
|
||||
{
|
||||
OUTYY(("P(disable_dnssec_lame_check:%s)\n", $2));
|
||||
|
|
@ -3593,7 +3608,6 @@ dnsc_dnscrypt_enable: VAR_DNSCRYPT_ENABLE STRING_ARG
|
|||
free($2);
|
||||
}
|
||||
;
|
||||
|
||||
dnsc_dnscrypt_port: VAR_DNSCRYPT_PORT STRING_ARG
|
||||
{
|
||||
OUTYY(("P(dnsc_dnscrypt_port:%s)\n", $2));
|
||||
|
|
@ -3801,6 +3815,31 @@ 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"));
|
||||
|
|
@ -3870,10 +3909,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");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1062,15 +1062,17 @@ qinfo_query_encode(sldns_buffer* pkt, struct query_info* qinfo)
|
|||
sldns_buffer_flip(pkt);
|
||||
}
|
||||
|
||||
void
|
||||
error_encode(sldns_buffer* buf, int r, struct query_info* qinfo,
|
||||
uint16_t qid, uint16_t qflags, struct edns_data* edns)
|
||||
void
|
||||
extended_error_encode(sldns_buffer* buf, uint16_t rcode,
|
||||
struct query_info* qinfo, uint16_t qid, uint16_t qflags,
|
||||
uint16_t xflags, struct edns_data* edns)
|
||||
{
|
||||
uint16_t flags;
|
||||
|
||||
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 | (rcode & 0xF)); /* QR and retcode*/
|
||||
flags |= xflags;
|
||||
flags |= (qflags & (BIT_RD|BIT_CD)); /* copy RD and CD bit */
|
||||
sldns_buffer_write_u16(buf, flags);
|
||||
if(qinfo) flags = 1;
|
||||
|
|
@ -1097,7 +1099,7 @@ error_encode(sldns_buffer* buf, int r, struct query_info* qinfo,
|
|||
struct edns_data es = *edns;
|
||||
es.edns_version = EDNS_ADVERTISED_VERSION;
|
||||
es.udp_size = EDNS_ADVERTISED_SIZE;
|
||||
es.ext_rcode = 0;
|
||||
es.ext_rcode = (uint8_t)(rcode >> 4);
|
||||
es.bits &= EDNS_DO;
|
||||
if(sldns_buffer_limit(buf) + calc_edns_field_size(&es) >
|
||||
edns->udp_size) {
|
||||
|
|
@ -1111,3 +1113,11 @@ error_encode(sldns_buffer* buf, int r, struct query_info* qinfo,
|
|||
attach_edns_record(buf, &es);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
error_encode(sldns_buffer* buf, int r, struct query_info* qinfo,
|
||||
uint16_t qid, uint16_t qflags, struct edns_data* edns)
|
||||
{
|
||||
extended_error_encode(buf, (r & 0x000F), qinfo, qid, qflags,
|
||||
(r & 0xFFF0), edns);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -137,11 +137,11 @@ uint16_t calc_ede_option_size(struct edns_data* edns, uint16_t* txt_size);
|
|||
*/
|
||||
void attach_edns_record(struct sldns_buffer* pkt, struct edns_data* edns);
|
||||
|
||||
/**
|
||||
/**
|
||||
* Encode an error. With QR and RA set.
|
||||
*
|
||||
* @param pkt: where to store the packet.
|
||||
* @param r: RCODE value to encode.
|
||||
* @param r: RCODE value to encode (may contain extra flags).
|
||||
* @param qinfo: if not NULL, the query is included.
|
||||
* @param qid: query ID to set in packet. network order.
|
||||
* @param qflags: original query flags (to copy RD and CD bits). host order.
|
||||
|
|
@ -151,4 +151,21 @@ void attach_edns_record(struct sldns_buffer* pkt, struct edns_data* edns);
|
|||
void error_encode(struct sldns_buffer* pkt, int r, struct query_info* qinfo,
|
||||
uint16_t qid, uint16_t qflags, struct edns_data* edns);
|
||||
|
||||
/**
|
||||
* Encode an extended error. With QR and RA set.
|
||||
*
|
||||
* @param pkt: where to store the packet.
|
||||
* @param rcode: Extended RCODE value to encode.
|
||||
* @param qinfo: if not NULL, the query is included.
|
||||
* @param qid: query ID to set in packet. network order.
|
||||
* @param qflags: original query flags (to copy RD and CD bits). host order.
|
||||
* @param xflags: extra flags to set (such as for example BIT_AA and/or BIT_TC)
|
||||
* @param edns: if not NULL, this is the query edns info,
|
||||
* and an edns reply is attached. Only attached if EDNS record fits reply.
|
||||
* Without edns extended errors (i.e. > 15) will not be conveyed.
|
||||
*/
|
||||
void extended_error_encode(struct sldns_buffer* pkt, uint16_t rcode,
|
||||
struct query_info* qinfo, uint16_t qid, uint16_t qflags,
|
||||
uint16_t xflags, struct edns_data* edns);
|
||||
|
||||
#endif /* UTIL_DATA_MSGENCODE_H */
|
||||
|
|
|
|||
|
|
@ -45,6 +45,8 @@
|
|||
#include "util/netevent.h"
|
||||
#include "util/storage/lookup3.h"
|
||||
#include "util/regional.h"
|
||||
#include "util/rfc_1982.h"
|
||||
#include "util/edns.h"
|
||||
#include "sldns/rrdef.h"
|
||||
#include "sldns/sbuffer.h"
|
||||
#include "sldns/parseutil.h"
|
||||
|
|
@ -940,22 +942,11 @@ parse_packet(sldns_buffer* pkt, struct msg_parse* msg, struct regional* region)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
edns_opt_list_append_keepalive(struct edns_option** list, int msec,
|
||||
struct regional* region)
|
||||
{
|
||||
uint8_t data[2]; /* For keepalive value */
|
||||
data[0] = (uint8_t)((msec >> 8) & 0xff);
|
||||
data[1] = (uint8_t)(msec & 0xff);
|
||||
return edns_opt_list_append(list, LDNS_EDNS_KEEPALIVE, sizeof(data),
|
||||
data, region);
|
||||
}
|
||||
|
||||
/** 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 +970,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];
|
||||
enum edns_cookie_val_status cookie_val_status;
|
||||
int cookie_is_v4 = 1;
|
||||
|
||||
rdata_ptr += 4;
|
||||
rdata_len -= 4;
|
||||
if(opt_len > rdata_len)
|
||||
|
|
@ -1041,6 +1036,76 @@ 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 || !repinfo)
|
||||
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.
|
||||
*/
|
||||
if(opt_len >= 16) {
|
||||
memmove(server_cookie, rdata_ptr, 16);
|
||||
} else {
|
||||
memset(server_cookie, 0, 16);
|
||||
memmove(server_cookie, rdata_ptr, opt_len);
|
||||
}
|
||||
|
||||
/* Copy client ip for validation and creation
|
||||
* purposes. It will be overwritten if (re)creation
|
||||
* is needed.
|
||||
*/
|
||||
if(repinfo->remote_addr.ss_family == AF_INET) {
|
||||
memcpy(server_cookie + 16,
|
||||
&((struct sockaddr_in*)&repinfo->remote_addr)->sin_addr, 4);
|
||||
} else {
|
||||
cookie_is_v4 = 0;
|
||||
memcpy(server_cookie + 16,
|
||||
&((struct sockaddr_in6*)&repinfo->remote_addr)->sin6_addr, 16);
|
||||
}
|
||||
|
||||
cookie_val_status = edns_cookie_server_validate(
|
||||
rdata_ptr, opt_len, cfg->cookie_secret,
|
||||
cfg->cookie_secret_len, cookie_is_v4,
|
||||
server_cookie, now);
|
||||
switch(cookie_val_status) {
|
||||
case COOKIE_STATUS_VALID:
|
||||
case COOKIE_STATUS_VALID_RENEW:
|
||||
edns->cookie_valid = 1;
|
||||
/* Reuse cookie */
|
||||
if(!edns_opt_list_append(
|
||||
&edns->opt_list_out, LDNS_EDNS_COOKIE,
|
||||
opt_len, rdata_ptr, region)) {
|
||||
log_err("out of memory");
|
||||
return LDNS_RCODE_SERVFAIL;
|
||||
}
|
||||
/* Cookie to be reused added to outgoing
|
||||
* options. Done!
|
||||
*/
|
||||
break;
|
||||
case COOKIE_STATUS_CLIENT_ONLY:
|
||||
edns->cookie_client = 1;
|
||||
/* fallthrough */
|
||||
case COOKIE_STATUS_FUTURE:
|
||||
case COOKIE_STATUS_EXPIRED:
|
||||
case COOKIE_STATUS_INVALID:
|
||||
default:
|
||||
edns_cookie_server_write(server_cookie,
|
||||
cfg->cookie_secret, cookie_is_v4, now);
|
||||
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;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -1115,6 +1180,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 +1237,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 +1274,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 +1284,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
|
||||
|
|
|
|||
|
|
@ -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,15 @@ 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;
|
||||
/** if the cookie holds only the client part */
|
||||
unsigned int cookie_client : 1;
|
||||
};
|
||||
|
||||
/**
|
||||
* EDNS option
|
||||
|
|
@ -310,12 +317,15 @@ int skip_pkt_rrs(struct sldns_buffer* pkt, int num);
|
|||
* initialised.
|
||||
* @param cfg: the configuration (with nsid value etc.)
|
||||
* @param c: commpoint to determine transport (if needed)
|
||||
* @param repinfo: commreply to determine the client address
|
||||
* @param now: current time
|
||||
* @param region: region to alloc results in (edns option contents)
|
||||
* @return: 0 on success, or an RCODE on error.
|
||||
* 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.
|
||||
|
|
|
|||
|
|
@ -1049,6 +1049,16 @@ int edns_opt_list_append_ede(struct edns_option** list, struct regional* region,
|
|||
return 1;
|
||||
}
|
||||
|
||||
int edns_opt_list_append_keepalive(struct edns_option** list, int msec,
|
||||
struct regional* region)
|
||||
{
|
||||
uint8_t data[2]; /* For keepalive value */
|
||||
data[0] = (uint8_t)((msec >> 8) & 0xff);
|
||||
data[1] = (uint8_t)(msec & 0xff);
|
||||
return edns_opt_list_append(list, LDNS_EDNS_KEEPALIVE, sizeof(data),
|
||||
data, region);
|
||||
}
|
||||
|
||||
int edns_opt_list_append(struct edns_option** list, uint16_t code, size_t len,
|
||||
uint8_t* data, struct regional* region)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -577,6 +577,16 @@ int edns_opt_list_append(struct edns_option** list, uint16_t code, size_t len,
|
|||
int edns_opt_list_append_ede(struct edns_option** list, struct regional* region,
|
||||
sldns_ede_code code, const char *txt);
|
||||
|
||||
/**
|
||||
* Append edns keep alive option to edns options list
|
||||
* @param list: the edns option list to append the edns option to.
|
||||
* @param msec: the duration in msecs for the keep alive.
|
||||
* @param region: region to allocate the new edns option.
|
||||
* @return false on failure.
|
||||
*/
|
||||
int edns_opt_list_append_keepalive(struct edns_option** list, int msec,
|
||||
struct regional* region);
|
||||
|
||||
/**
|
||||
* Remove any option found on the edns option list that matches the code.
|
||||
* @param list: the list of edns options.
|
||||
|
|
|
|||
59
util/edns.c
59
util/edns.c
|
|
@ -45,8 +45,11 @@
|
|||
#include "util/netevent.h"
|
||||
#include "util/net_help.h"
|
||||
#include "util/regional.h"
|
||||
#include "util/rfc_1982.h"
|
||||
#include "util/siphash.h"
|
||||
#include "util/data/msgparse.h"
|
||||
#include "util/data/msgreply.h"
|
||||
#include "sldns/sbuffer.h"
|
||||
|
||||
struct edns_strings* edns_strings_create(void)
|
||||
{
|
||||
|
|
@ -128,3 +131,59 @@ edns_string_addr_lookup(rbtree_type* tree, struct sockaddr_storage* addr,
|
|||
return (struct edns_string_addr*)addr_tree_lookup(tree, addr, addrlen);
|
||||
}
|
||||
|
||||
uint8_t*
|
||||
edns_cookie_server_hash(const uint8_t* in, const uint8_t* secret, int v4,
|
||||
uint8_t* hash)
|
||||
{
|
||||
v4?siphash(in, 20, secret, hash, 8):siphash(in, 32, secret, hash, 8);
|
||||
return hash;
|
||||
}
|
||||
|
||||
void
|
||||
edns_cookie_server_write(uint8_t* buf, const uint8_t* secret, int v4,
|
||||
uint32_t timestamp)
|
||||
{
|
||||
uint8_t hash[8];
|
||||
buf[ 8] = 1; /* Version */
|
||||
buf[ 9] = 0; /* Reserved */
|
||||
buf[10] = 0; /* Reserved */
|
||||
buf[11] = 0; /* Reserved */
|
||||
sldns_write_uint32(buf + 12, timestamp);
|
||||
(void)edns_cookie_server_hash(buf, secret, v4, hash);
|
||||
memcpy(buf + 16, hash, 8);
|
||||
}
|
||||
|
||||
enum edns_cookie_val_status
|
||||
edns_cookie_server_validate(const uint8_t* cookie, size_t cookie_len,
|
||||
const uint8_t* secret, size_t secret_len, int v4,
|
||||
const uint8_t* hash_input, uint32_t now)
|
||||
{
|
||||
uint8_t hash[8];
|
||||
uint32_t timestamp;
|
||||
uint32_t subt_1982 = 0; /* Initialize for the compiler; unused value */
|
||||
int comp_1982;
|
||||
if(cookie_len != 24)
|
||||
/* RFC9018 cookies are 24 bytes long */
|
||||
return COOKIE_STATUS_CLIENT_ONLY;
|
||||
if(secret_len != 16 || /* RFC9018 cookies have 16 byte secrets */
|
||||
cookie[8] != 1) /* RFC9018 cookies are cookie version 1 */
|
||||
return COOKIE_STATUS_INVALID;
|
||||
timestamp = sldns_read_uint32(cookie + 12);
|
||||
if((comp_1982 = compare_1982(now, timestamp)) > 0
|
||||
&& (subt_1982 = subtract_1982(timestamp, now)) > 3600)
|
||||
/* Cookie is older than 1 hour (see RFC9018 Section 4.3.) */
|
||||
return COOKIE_STATUS_EXPIRED;
|
||||
if(comp_1982 <= 0 && subtract_1982(now, timestamp) > 300)
|
||||
/* Cookie time is more than 5 minutes in the future.
|
||||
* (see RFC9018 Section 4.3.) */
|
||||
return COOKIE_STATUS_FUTURE;
|
||||
if(memcmp(edns_cookie_server_hash(hash_input, secret, v4, hash),
|
||||
cookie + 16, 8) != 0)
|
||||
/* Hashes do not match */
|
||||
return COOKIE_STATUS_INVALID;
|
||||
if(comp_1982 > 0 && subt_1982 > 1800)
|
||||
/* Valid cookie but older than 30 minutes, so create a new one
|
||||
* anyway */
|
||||
return COOKIE_STATUS_VALID_RENEW;
|
||||
return COOKIE_STATUS_VALID;
|
||||
}
|
||||
|
|
|
|||
59
util/edns.h
59
util/edns.h
|
|
@ -75,6 +75,15 @@ struct edns_string_addr {
|
|||
size_t string_len;
|
||||
};
|
||||
|
||||
enum edns_cookie_val_status {
|
||||
COOKIE_STATUS_CLIENT_ONLY = -3,
|
||||
COOKIE_STATUS_FUTURE = -2,
|
||||
COOKIE_STATUS_EXPIRED = -1,
|
||||
COOKIE_STATUS_INVALID = 0,
|
||||
COOKIE_STATUS_VALID = 1,
|
||||
COOKIE_STATUS_VALID_RENEW = 2,
|
||||
};
|
||||
|
||||
/**
|
||||
* Create structure to hold EDNS strings
|
||||
* @return: newly created edns_strings, NULL on alloc failure.
|
||||
|
|
@ -106,4 +115,54 @@ struct edns_string_addr*
|
|||
edns_string_addr_lookup(rbtree_type* tree, struct sockaddr_storage* addr,
|
||||
socklen_t addrlen);
|
||||
|
||||
/**
|
||||
* Compute the interoperable DNS cookie (RFC9018) hash.
|
||||
* @param in: buffer input for the hash generation. It needs to be:
|
||||
* Client Cookie | Version | Reserved | Timestamp | Client-IP
|
||||
* @param secret: the server secret; implicit length of 16 octets.
|
||||
* @param v4: if the client IP is v4 or v6.
|
||||
* @param hash: buffer to write the hash to.
|
||||
* return a pointer to the hash.
|
||||
*/
|
||||
uint8_t* edns_cookie_server_hash(const uint8_t* in, const uint8_t* secret,
|
||||
int v4, uint8_t* hash);
|
||||
|
||||
/**
|
||||
* Write an interoperable DNS server cookie (RFC9018).
|
||||
* @param buf: buffer to write to. It should have a size of at least 32 octets
|
||||
* as it doubles as the output buffer and the hash input buffer.
|
||||
* The first 8 octets are expected to be the Client Cookie and will be
|
||||
* left untouched.
|
||||
* The next 8 octets will be written with Version | Reserved | Timestamp.
|
||||
* The next 4 or 16 octets are expected to be the IPv4 or the IPv6 address
|
||||
* based on the v4 flag.
|
||||
* Thus the first 20 or 32 octets, based on the v4 flag, will be used as
|
||||
* the hash input.
|
||||
* The server hash (8 octets) will be written after the first 16 octets;
|
||||
* overwriting the address information.
|
||||
* The caller expects a complete, 24 octet long cookie in the buffer.
|
||||
* @param secret: the server secret; implicit length of 16 octets.
|
||||
* @param v4: if the client IP is v4 or v6.
|
||||
* @param timestamp: the timestamp to use.
|
||||
*/
|
||||
void edns_cookie_server_write(uint8_t* buf, const uint8_t* secret, int v4,
|
||||
uint32_t timestamp);
|
||||
|
||||
/**
|
||||
* Validate an interoperable DNS cookie (RFC9018).
|
||||
* @param cookie: pointer to the cookie data.
|
||||
* @param cookie_len: the length of the cookie data.
|
||||
* @param secret: pointer to the server secret.
|
||||
* @param secret_len: the length of the secret.
|
||||
* @param v4: if the client IP is v4 or v6.
|
||||
* @param hash_input: pointer to the hash input for validation. It needs to be:
|
||||
* Client Cookie | Version | Reserved | Timestamp | Client-IP
|
||||
* @param now: the current time.
|
||||
* return edns_cookie_val_status with the cookie validation status i.e.,
|
||||
* <=0 for invalid, else valid.
|
||||
*/
|
||||
enum edns_cookie_val_status edns_cookie_server_validate(const uint8_t* cookie,
|
||||
size_t cookie_len, const uint8_t* secret, size_t secret_len, int v4,
|
||||
const uint8_t* hash_input, uint32_t now);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
74
util/rfc_1982.c
Normal file
74
util/rfc_1982.c
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* util/rfc_1982.c - RFC 1982 Serial Number Arithmetic
|
||||
*
|
||||
* Copyright (c) 2023, NLnet Labs. All rights reserved.
|
||||
*
|
||||
* This software is open source.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of the NLNET LABS nor the names of its contributors may
|
||||
* be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* This file contains functions for RFC 1982 serial number arithmetic.
|
||||
*/
|
||||
#include "config.h"
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
63
util/rfc_1982.h
Normal file
63
util/rfc_1982.h
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* util/rfc_1982.h - RFC 1982 Serial Number Arithmetic
|
||||
*
|
||||
* Copyright (c) 2023, NLnet Labs. All rights reserved.
|
||||
*
|
||||
* This software is open source.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of the NLNET LABS nor the names of its contributors may
|
||||
* be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* This file contains functions for RFC 1982 serial number arithmetic.
|
||||
*/
|
||||
#ifndef RFC_1982_H
|
||||
#define RFC_1982_H
|
||||
|
||||
/**
|
||||
* RFC 1982 comparison, uses unsigned integers, and tries to avoid
|
||||
* compiler optimization (eg. by avoiding a-b<0 comparisons).
|
||||
* @param a: value to compare.
|
||||
* @param b: value to compare.
|
||||
* @return 0 if equal, 1 if a > b, else -1.
|
||||
*/
|
||||
int compare_1982(uint32_t a, uint32_t b);
|
||||
|
||||
/**
|
||||
* RFC 1982 subtraction, uses unsigned integers, and tries to avoid
|
||||
* compiler optimization (eg. by avoiding a-b<0 comparisons).
|
||||
* @param a: value to subtract from.
|
||||
* @param b: value to subtract.
|
||||
* @return the difference between them if we know that b is larger than a,
|
||||
* that is the distance between them in serial number arithmetic.
|
||||
*/
|
||||
uint32_t subtract_1982(uint32_t a, uint32_t b);
|
||||
|
||||
#endif /* RFC_1982_H */
|
||||
187
util/siphash.c
Normal file
187
util/siphash.c
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
/*
|
||||
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/>.
|
||||
*/
|
||||
/**
|
||||
* Edited slightly for integration in Unbound. Edits are noted with 'EDIT'.
|
||||
*/
|
||||
/** EDIT
|
||||
* \#include <assert.h>
|
||||
* \#include <stdint.h>
|
||||
* \#include <stdio.h>
|
||||
* \#include <string.h>
|
||||
* Replaced the above includes with Unbound's config.h
|
||||
*/
|
||||
#include "config.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) {
|
||||
|
||||
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;
|
||||
/** EDIT
|
||||
* The following assert moved here from the top for C90 compliance.
|
||||
*/
|
||||
assert((outlen == 8) || (outlen == 16));
|
||||
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;
|
||||
/** EDIT annotate case statement fallthrough for gcc */
|
||||
/* fallthrough */
|
||||
case 6:
|
||||
b |= ((uint64_t)in[5]) << 40;
|
||||
/** EDIT annotate case statement fallthrough for gcc */
|
||||
/* fallthrough */
|
||||
case 5:
|
||||
b |= ((uint64_t)in[4]) << 32;
|
||||
/** EDIT annotate case statement fallthrough for gcc */
|
||||
/* fallthrough */
|
||||
case 4:
|
||||
b |= ((uint64_t)in[3]) << 24;
|
||||
/** EDIT annotate case statement fallthrough for gcc */
|
||||
/* fallthrough */
|
||||
case 3:
|
||||
b |= ((uint64_t)in[2]) << 16;
|
||||
/** EDIT annotate case statement fallthrough for gcc */
|
||||
/* fallthrough */
|
||||
case 2:
|
||||
b |= ((uint64_t)in[1]) << 8;
|
||||
/** EDIT annotate case statement fallthrough for gcc */
|
||||
/* fallthrough */
|
||||
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;
|
||||
}
|
||||
43
util/siphash.h
Normal file
43
util/siphash.h
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* util/siphash.h - header for SipHash reference C implementation.
|
||||
*
|
||||
* Copyright (c) 2023, NLnet Labs. All rights reserved.
|
||||
*
|
||||
* This software is open source.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of the NLNET LABS nor the names of its contributors may
|
||||
* be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/**
|
||||
* \file
|
||||
* Contains the SipHash reference C implementation.
|
||||
*/
|
||||
#ifndef UTIL_SIPHASH_H
|
||||
#define UTIL_SIPHASH_H
|
||||
int siphash(const uint8_t *in, const size_t inlen, const uint8_t *k,
|
||||
uint8_t *out, const size_t outlen);
|
||||
#endif /* UTIL_SIPHASH_H */
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@
|
|||
#include "util/data/msgparse.h"
|
||||
#include "util/data/dname.h"
|
||||
#include "util/rbtree.h"
|
||||
#include "util/rfc_1982.h"
|
||||
#include "util/module.h"
|
||||
#include "util/net_help.h"
|
||||
#include "util/regional.h"
|
||||
|
|
@ -1378,44 +1379,6 @@ sigdate_error(const char* str, int32_t expi, int32_t incep, int32_t now)
|
|||
(unsigned)incep, (unsigned)now);
|
||||
}
|
||||
|
||||
/** 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;
|
||||
}
|
||||
|
||||
/** check rrsig dates */
|
||||
static int
|
||||
check_dates(struct val_env* ve, uint32_t unow, uint8_t* expi_p,
|
||||
|
|
|
|||
Loading…
Reference in a new issue