Compare commits

...
Author SHA1 Message Date
TCY16 8c96e26074 modify tdir to ignore localzone tests 2022-01-13 14:50:43 +01:00
Willem Toorop 9ae988cea6 Merge branch 'master' into review-rfc8914-ede 2022-01-11 09:26:49 +01:00
TCY16 80957b6da3 remove debug line 2022-01-10 16:28:54 +01:00
TCY16 69e188b5cf fix missing disable in remote-control local_zone do_ede and typos 2021-12-22 15:47:50 +01:00
TCY16 49f2960089 add remote control options for local-zone and RPZ do_ede 2021-12-22 14:39:06 +01:00
TCY16 94f04a77d9 remove superfluous linebreaks 2021-12-21 13:17:57 +01:00
TCY16 fe8ef6e53d add logic for per zone EDE for RPZ and configurable rpz-do-ede 2021-12-21 13:17:07 +01:00
TCY16 79024484a7 Document how the log-val-level: config options influences the returned EDE option text 2021-12-16 11:45:18 +01:00
TCY16 05e06fdcf5 fix rpl tests 2021-12-15 14:59:45 +01:00
tcarpayandGitHub df229db074 Merge branch 'master' into features/rfc8914-ede 2021-12-15 13:07:01 +01:00
TCY16 4f37d6489e fix DNSSEC nsec-failure test 2021-12-15 12:49:54 +01:00
TCY16 ea1a5f35e4 add todo for tests and fix EDE codes for DNSKEY missing 2021-12-15 12:29:11 +01:00
Tom Carpay dc38aacefc expand ede.tdir to do validator test for DNSKEY, RRSIG and NSEC missing 2021-12-15 11:05:45 +00:00
TCY16 63e6604b2a add config options to test conf, fix local-zone EDE printing logic, and fix typo in the unbound.conf 2021-12-07 13:25:32 +01:00
TCY16 65ee2f2c39 finish up adding validator EDEs and other TODOs and fix tests with more specific EDE codes 2021-12-06 14:19:28 +01:00
TCY16 db98a8b825 add ede-local-zones in the manpage and update the iana_ports.inc for some reason 2021-11-30 12:12:57 +01:00
TCY16 3ccb4c6c26 change local-zone-default-ede keywords to '-', add missing {}, and add manpage entry for local-zone-do-ede, local-zone-default-ede, and ede-local-zones 2021-11-30 11:32:01 +01:00
TCY16 ff356b940b add error in case of incorrect string for local-zone-default-ede 2021-11-26 15:35:53 +01:00
TCY16 7926874669 add config option for global EDE flag, local-zone specific EDE flag and default EDE code for a zone 2021-11-26 15:12:56 +01:00
TCY16 575a6865be add forgotten autogenerated files 2021-11-19 11:55:13 +01:00
TCY16 0572870592 change do_ede to be local-zone specific and add places for more EDE codes 2021-11-19 11:27:13 +01:00
Tom Carpay 0747d016e4 add missing parsing 2021-11-16 13:21:03 +00:00
TCY16 4a43aee99e setup for configurable EDEs for local-zone 2021-11-16 11:25:58 +01:00
Tom Carpay a3171a1d48 remove superfluous EDE left over from merge 2021-11-16 08:25:53 +00:00
Tom Carpay f22e42f554 Fix merge bugs 2021-11-15 15:00:35 +00:00
Tom Carpay 787d7a5952 Merge branch 'master' into features/rfc8914-ede 2021-11-15 14:48:35 +00:00
TCY16 0eba781ed3 make local_data ede inclusion configurable, rewrite local_error_encode to include this logic, and remove superfluous msgparse_check_edns_in_packet function 2021-11-10 16:58:54 +01:00
TCY16 df984d9c6f add dnssec ede tests 2021-10-18 16:45:42 +02:00
George Thessalonikefs fed0fb42dd - Fix testcode, 0 is a valid EDE INFO-CODE. 2021-10-14 14:01:39 +02:00
TCY16 abd948f3d7 change unittests to match just the ede code 2021-10-13 15:28:10 +02:00
George Thessalonikefs f7bb7f2a94 Merge branch 'features/rfc8914-ede' of github.com:NLnetLabs/unbound into features/rfc8914-ede 2021-10-13 12:02:29 +02:00
George Thessalonikefs 9bff0b94dd - Introduce 'ede=<info-code>' and 'all_noedns' as options in the MATCH line for
replay test packets.
2021-10-13 12:01:36 +02:00
TCY16 d2a719f606 add test setup for DNSSEC EDEs 2021-10-13 11:17:42 +02:00
TCY16 b825bb668d add more tests 2021-10-08 15:55:40 +02:00
TCY16 8a6b3f088b add DNSKEY EDE code 2021-10-08 15:54:10 +02:00
TCY16 86e8050352 add EDE responses to unittests 2021-10-01 14:46:29 +02:00
TCY16 c42c2cbbff add EDE response to autotrust_init_failsig test 2021-09-30 16:56:50 +02:00
TCY16 7df2df0fc9 add EDE response to autotrust_init_fail test 2021-09-30 16:39:40 +02:00
TCY16 320aa64d18 add QDCOUNT=0 to CHAOS query in ACL 2021-09-29 12:54:41 +02:00
TCY16 3ba8ea321a fix CH class response 2021-09-28 16:35:50 +02:00
TCY16 42ba5ae4a2 process @wcawijngaards' comments v2 2021-09-28 13:48:36 +02:00
TCY16 732ad94729 process @wcawijngaards' comments 2021-09-28 13:28:25 +02:00
TCY16 84da2409b3 change strncpy to memmove at @wcawijngaards' suggestion 2021-09-28 10:05:47 +02:00
Tom Carpay 0b376cc42f add routine to add EDE to ACL:refused at correct location 2021-09-27 14:17:21 +00:00
Tom Carpay b606c8273d Merge branch 'features/rfc8914-ede' of github.com:NLnetLabs/unbound into features/rfc8914-ede 2021-09-20 09:42:47 +00:00
TCY16 4df2965459 add forgotten compile error fixes from previous commit 2021-09-20 11:42:39 +02:00
Tom Carpay 65852bcbc4 Merge branch 'features/rfc8914-ede' of github.com:NLnetLabs/unbound into features/rfc8914-ede 2021-09-20 09:35:30 +00:00
TCY16 4d15603a8c add routine to do EDE on ACL blocked messages 2021-09-20 11:35:00 +02:00
Tom Carpay 5617de6867 Answer LDNS_EDE_RRSIGS_MISSING for normal answers with missing signatures 2021-09-15 10:15:35 +00:00
TCY16 3576033b62 add possible EDE spots 2021-09-15 11:17:04 +02:00
Tom Carpay a664e8cec4 First step towards specific EDE DNSSEC errors 2021-09-14 07:45:51 +00:00
TCY16 2360120562 add mesh bogus test, possible locations for more EDE and remove superfluous todo comments 2021-09-13 13:25:17 +02:00
TCY16 9df75a842b add DNSSEC indeterminate EDE and DNAME expansion test 2021-09-08 16:38:33 +02:00
Tom Carpay 7079f0b5aa add ede to always_refuse and always_null 2021-09-06 13:13:49 +00:00
tcarpay 33445be8df add setup of RPZ and full tests of earlier implemented EDEs 2021-08-31 15:22:44 +02:00
tcarpay fba1c302ac add localzones test 2021-08-23 14:26:32 +02:00
tcarpay ec4cf69eb7 set up for tpkg test 2021-08-23 14:00:04 +02:00
tcarpay d9a947f267 Merge branch 'master' into features/rfc8914-ede 2021-08-20 16:28:27 +02:00
Tom Carpay a98659791e EDE Blocked with local-zone refused answers 2021-08-19 14:31:03 +00:00
Tom Carpay 5fff0f7e30 Fix dont echo edns0 option list ...
when refusing to answer authoritatively.
Also remove TODO comments that were already done
2021-08-19 14:28:26 +00:00
Tom Carpay 935634dcae Revert "add local anwser blocked"
This reverts commit b3f60db184.
2021-08-19 14:21:10 +00:00
tcarpay b3f60db184 add local anwser blocked 2021-08-19 14:01:14 +02:00
Tom Carpay a9e6f6bc23 add variable bogus reason 2021-08-17 14:10:48 +00:00
Tom Carpay 6b5f314a3a Show reason when returning EDE_DNSSEC_BOGUS 2021-08-16 13:36:45 +00:00
Tom Carpay eac4eb3a9e Return EDE_DNSSEC_BOGUS when returning bogus answers 2021-08-16 12:46:24 +00:00
Tom Carpay 0703a38243 Fix: use EDE codes with EDNS_OPT_APPEND_EDE
+ complete EDE codes
2021-08-16 09:59:13 +00:00
tcarpay 4049885da2 add locations for EDE errors 2021-08-13 12:01:28 +02:00
Willem Toorop a8d78b2083 Simple EDE example 2021-06-24 12:55:46 +02:00
Willem Toorop 285f93ff82 Add EDE EDNS0 Option code 2021-06-24 11:20:58 +02:00
68 changed files with 6804 additions and 5641 deletions
+120
View File
@@ -1285,6 +1285,62 @@ do_zone_remove(RES* ssl, struct local_zones* zones, char* arg)
send_ok(ssl);
}
/** Enable or disable EDE (RFC 8914) responses in this local-zone */
static int
do_zone_enable_disable_ede(RES* ssl, struct local_zones* zones, char* arg,
int enable)
{
uint8_t* name;
int namelabels;
size_t namelen;
struct local_zone* z;
if(!parse_arg_name(ssl, arg, &name, &namelen, &namelabels)) {
free(name);
return 0;
}
lock_rw_wrlock(&zones->lock);
if(!(z=local_zones_find(zones, name, namelen,
namelabels, LDNS_RR_CLASS_IN))) {
ssl_printf(ssl, "local-zone: %s not found\n", arg);
free(name);
lock_rw_unlock(&zones->lock);
return 0;
}
/* found local-zone in tree */
lock_rw_wrlock(&z->lock);
if (enable) {
z->do_ede = 1;
}
else
z->do_ede = 0;
lock_rw_unlock(&z->lock);
free(name);
lock_rw_unlock(&zones->lock);
return 1;
}
/** Perform the do_zone_enable_ede command */
static void
do_zone_enable_ede(RES* ssl, struct local_zones* zones, char* arg)
{
if(!(do_zone_enable_disable_ede(ssl, zones, arg, 1)))
return;
send_ok(ssl);
}
/** Perform the do_zone_disable_ede command */
static void
do_zone_disable_ede(RES* ssl, struct local_zones* zones, char* arg)
{
if(!(do_zone_enable_disable_ede(ssl, zones, arg, 0)))
return;
send_ok(ssl);
}
/** Do the local_zones_remove command */
static void
do_zones_remove(RES* ssl, struct local_zones* zones)
@@ -2992,6 +3048,60 @@ do_rpz_disable(RES* ssl, struct worker* worker, char* arg)
do_rpz_enable_disable(ssl, worker, arg, 0);
}
/** enable/disable EDE (RFC 8914) responses this zone */
static void
do_rpz_do_ede_enable_disable(RES* ssl, struct worker* worker, char* arg, int enable) {
size_t namelen;
int namelabels;
uint8_t *name = NULL;
struct auth_zones *az = worker->env.auth_zones;
struct auth_zone *z = NULL;
if (!parse_arg_name(ssl, arg, &name, &namelen, &namelabels))
return;
(void)ssl_printf(ssl, "NAME: %s", name);
if (az) {
lock_rw_rdlock(&az->lock);
z = auth_zone_find(az, name, namelen, LDNS_RR_CLASS_IN);
if (z) {
lock_rw_wrlock(&z->lock);
}
lock_rw_unlock(&az->lock);
}
free(name);
if (!z) {
(void) ssl_printf(ssl, "error no auth-zone %s\n", arg);
return;
}
if (!z->rpz) {
(void) ssl_printf(ssl, "error auth-zone %s not RPZ\n", arg);
lock_rw_unlock(&z->lock);
return;
}
if (enable) {
rpz_do_ede_enable(z->rpz);
} else {
rpz_do_ede_disable(z->rpz);
}
lock_rw_unlock(&z->lock);
send_ok(ssl);
}
/** do the rpz_enable command */
static void
do_rpz_do_ede_enable(RES* ssl, struct worker* worker, char* arg)
{
do_rpz_enable_disable(ssl, worker, arg, 1);
}
/** do the rpz_disable command */
static void
do_rpz_do_ede_disable(RES* ssl, struct worker* worker, char* arg)
{
do_rpz_do_ede_enable_disable(ssl, worker, arg, 0);
}
/** tell other processes to execute the command */
static void
distribute_cmd(struct daemon_remote* rc, RES* ssl, char* cmd)
@@ -3154,6 +3264,12 @@ execute_cmd(struct daemon_remote* rc, RES* ssl, char* cmd,
do_data_remove(ssl, worker->daemon->local_zones, skipwhite(p+17));
} else if(cmdcmp(p, "local_datas_remove", 18)) {
do_datas_remove(ssl, worker->daemon->local_zones);
} else if(cmdcmp(p, "local_zone_do_ede_enable", 24)) {
do_zone_enable_ede(ssl, worker->daemon->local_zones, skipwhite(p+24));
} else if(cmdcmp(p, "local_zone_do_ede_disable", 25)) {
do_zone_disable_ede(ssl, worker->daemon->local_zones, skipwhite(p+25));
} else if(cmdcmp(p, "local_data", 10)) {
do_data_add(ssl, worker->daemon->local_zones, skipwhite(p+10));
} else if(cmdcmp(p, "local_datas", 11)) {
@@ -3196,6 +3312,10 @@ execute_cmd(struct daemon_remote* rc, RES* ssl, char* cmd,
do_rpz_enable(ssl, worker, skipwhite(p+10));
} else if(cmdcmp(p, "rpz_disable", 11)) {
do_rpz_disable(ssl, worker, skipwhite(p+11));
} else if(cmdcmp(p, "rpz_do_ede_enable", 17)) {
do_rpz_do_ede_enable(ssl, worker, skipwhite(p+17));
} else if(cmdcmp(p, "rpz_do_ede_disable", 18)) {
do_rpz_do_ede_disable(ssl, worker, skipwhite(p+18));
} else {
(void)ssl_printf(ssl, "error unknown command '%s'\n", p);
}
+142 -5
View File
@@ -484,6 +484,8 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo,
msg->rep, LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad,
worker->env.now_tv))
return 0;
EDNS_OPT_LIST_APPEND_EDE(&edns->opt_list_out,
worker->scratchpad, LDNS_EDE_DNSSEC_BOGUS, "");
error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL,
&msg->qinfo, id, flags, edns);
if(worker->stats.extended) {
@@ -499,6 +501,9 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo,
secure = 1;
break;
case sec_status_indeterminate:
EDNS_OPT_LIST_APPEND_EDE(&edns->opt_list_out,
worker->scratchpad, LDNS_EDE_DNSSEC_INDETERMINATE, "");
/* fallthrough */
case sec_status_insecure:
default:
/* not secure */
@@ -654,6 +659,8 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad,
worker->env.now_tv))
goto bail_out;
EDNS_OPT_LIST_APPEND_EDE(&edns->opt_list_out,
worker->scratchpad, LDNS_EDE_DNSSEC_BOGUS, "");
error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL,
qinfo, id, flags, edns);
rrset_array_unlock_touch(worker->env.rrset_cache,
@@ -1020,6 +1027,8 @@ deny_refuse(struct comm_point* c, enum acl_access acl,
worker->stats.unwanted_queries++;
return 0;
} else if(acl == refuse) {
size_t opt_rr_mark;
log_addr(VERB_ALGO, "refused query from",
&repinfo->addr, repinfo->addrlen);
log_buf(VERB_ALGO, "refuse", c->buffer);
@@ -1029,15 +1038,124 @@ deny_refuse(struct comm_point* c, enum acl_access acl,
comm_point_drop_reply(repinfo);
return 0; /* discard this */
}
sldns_buffer_set_limit(c->buffer, LDNS_HEADER_SIZE);
sldns_buffer_write_at(c->buffer, 4,
(uint8_t*)"\0\0\0\0\0\0\0\0", 8);
log_assert(LDNS_QDCOUNT(sldns_buffer_begin(c->buffer)) == 1);
sldns_buffer_skip(c->buffer, LDNS_HEADER_SIZE); /* skip header */
if (!query_dname_len(c->buffer)) {
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
LDNS_RCODE_FORMERR);
sldns_buffer_flip(c->buffer);
return 1;
}
if (sldns_buffer_remaining(c->buffer) < 2 * sizeof(uint16_t)) {
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
LDNS_RCODE_FORMERR);
sldns_buffer_flip(c->buffer);
return 1;
}
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
LDNS_RCODE_REFUSED);
sldns_buffer_set_position(c->buffer, LDNS_HEADER_SIZE);
sldns_buffer_skip(c->buffer, (ssize_t)sizeof(uint16_t)); /* skip qtype */
/* check the qclass */
if (sldns_buffer_read_u16(c->buffer) != LDNS_RR_CLASS_IN) {
LDNS_QDCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
sldns_buffer_flip(c->buffer);
return 1;
}
/* check edns section is present */
if(LDNS_ARCOUNT(sldns_buffer_begin(c->buffer)) != 1) {
LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
sldns_buffer_flip(c->buffer);
return 1;
}
/* The OPT RR to be returned should come directly after
* the query, so mark this spot.
*/
opt_rr_mark = sldns_buffer_position(c->buffer);
/* Skip through the RR records */
if(LDNS_ANCOUNT(sldns_buffer_begin(c->buffer)) != 0 ||
LDNS_NSCOUNT(sldns_buffer_begin(c->buffer)) != 0) {
if(!skip_pkt_rrs(c->buffer,
((int)LDNS_ANCOUNT(sldns_buffer_begin(c->buffer)))+
((int)LDNS_NSCOUNT(sldns_buffer_begin(c->buffer))))) {
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
LDNS_RCODE_FORMERR);
sldns_buffer_flip(c->buffer);
return 1;
}
}
/* Do we have a valid OPT RR here? If not return FORMERR */
/* domain name must be the root of length 1. */
if(pkt_dname_len(c->buffer) != 1) {
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
LDNS_RCODE_FORMERR);
return 1;
}
if(sldns_buffer_remaining(c->buffer) < 2 ||
sldns_buffer_read_u16(c->buffer) != LDNS_RR_TYPE_OPT) {
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
LDNS_RCODE_FORMERR);
sldns_buffer_flip(c->buffer);
return 1;
}
/* Write OPT RR directly after the query,
* so without the (possibly skipped) Answer and NS RRs
*/
LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
sldns_buffer_set_position(c->buffer, opt_rr_mark);
/* Check if OPT record can be written
* 17 == root label (1) + RR type (2) + UDP Size (2)
* + Fields (4) + rdata len (2) + EDE Option code (2)
* + EDE Option length (2) + EDE info-code (2)
*/
if (sldns_buffer_available(c->buffer, 17) == 0) {
LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
sldns_buffer_flip(c->buffer);
return 1;
}
LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 1);
/* root label */
sldns_buffer_write_u8(c->buffer, 0);
sldns_buffer_write_u16(c->buffer, LDNS_RR_TYPE_OPT);
sldns_buffer_write_u16(c->buffer, EDNS_ADVERTISED_SIZE);
/* write OPT Record TTL Field */
sldns_buffer_write_u32(c->buffer, 0);
/* write rdata len: EDE option + length + info-code */
sldns_buffer_write_u16(c->buffer, 6);
/* write OPTIONS; add EDE option code */
sldns_buffer_write_u16(c->buffer, LDNS_EDNS_EDE);
/* write single EDE option length (for just 1 info-code) */
sldns_buffer_write_u16(c->buffer, 2);
/* write single EDE info-code */
sldns_buffer_write_u16(c->buffer, LDNS_EDE_PROHIBITED);
sldns_buffer_flip(c->buffer);
return 1;
}
return -1;
@@ -1382,12 +1500,15 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
* ACLs allow the snooping. */
if(!(LDNS_RD_WIRE(sldns_buffer_begin(c->buffer))) &&
acl != acl_allow_snoop ) {
EDNS_OPT_LIST_APPEND_EDE(&edns.opt_list_out,
worker->scratchpad, LDNS_EDE_NOT_AUTHORITATIVE, "");
error_encode(c->buffer, LDNS_RCODE_REFUSED, &qinfo,
*(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
sldns_buffer_read_u16_at(c->buffer, 2), NULL);
sldns_buffer_read_u16_at(c->buffer, 2), &edns);
regional_free_all(worker->scratchpad);
log_addr(VERB_ALGO, "refused nonrec (cache snoop) query from",
&repinfo->addr, repinfo->addrlen);
goto send_reply;
}
@@ -1460,10 +1581,23 @@ lookup_cache:
< *worker->env.now)
leeway = 0;
lock_rw_unlock(&e->lock);
// @TODO test this
// // stale answer?
// if (worker->env.cfg->serve_expired &&
// *worker->env.now >= ((struct reply_info*)e->data)->ttl) {
// EDNS_OPT_LIST_APPEND_EDE(&edns.opt_list_out,
// worker->scratchpad, LDNS_EDE_STALE_ANSWER, "");
// }
// add EDNS struct?
reply_and_prefetch(worker, lookup_qinfo,
sldns_buffer_read_u16_at(c->buffer, 2),
repinfo, leeway,
(partial_rep || need_drop));
if(!partial_rep) {
rc = 0;
regional_free_all(worker->scratchpad);
@@ -1500,6 +1634,9 @@ lookup_cache:
verbose(VERB_ALGO, "answer from the cache failed");
lock_rw_unlock(&e->lock);
}
// @TODO Extended DNS Error Code 13 - Cached Error? place not clear
if(!LDNS_RD_WIRE(sldns_buffer_begin(c->buffer))) {
if(answer_norec_from_cache(worker, &qinfo,
*(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
+60 -1
View File
@@ -30,7 +30,7 @@ can be used to check unbound.conf prior to usage.
An example config file is shown below. Copy this to /etc/unbound/unbound.conf
and start the server with:
.P
.nf
.nfvalidator:val_inform_super
$ unbound \-c /etc/unbound/unbound.conf
.fi
.P
@@ -1178,6 +1178,8 @@ happens with validation. Use a diagnosis tool, such as dig or drill,
to find out why validation is failing for these queries. At 2, not only
the query that failed is printed but also the reason why Unbound thought
it was wrong and which server sent the faulty data.
Enabling this influences the Extended DNS Errors (RFC 8914) messages, as
the reason is added in the EDE message.
.TP
.B val\-permissive\-mode: \fI<yes or no>
Instruct the validator to mark bogus messages as indeterminate. The security
@@ -1562,6 +1564,60 @@ Use this localzone type, regardless the type configured for the local-zone
(both tagged and untagged) and regardless the type configured using
access\-control\-tag\-action.
.TP 5
.B ede\-local\-zones: \fI<yes or no>
If enabled, all local zones will respond with Extended DNS Errors (RFC8914).
This is the global setting for the configuration, but it can be overwritten by
specifing setting 'local\-zone\-do\-ede' to "yes". By default this option
is disabled.
Note that the val\-log\-level influences the the reason for the error included
in the EDE message.
.TP 5
.B local\-zone\-do\-ede: \fI<zone> <yes or no>
If enabled, the responses from this local zone will include an Extended DNS
Error (RFC8914). The type of error is dependent on the query. For example a
query for a local-zone type "refuse" will result in EDE code 15 \- Blocked.
By default this option is disabled.
Note that the val\-log\-level influences the the reason for the error included
in the EDE message.
.TP 5
.B local\-zone\-default\-ede: \fI<zone> <EDE code string or integer>
If enabled, this zone will respond to requests resulting in an Extended DNS
Error with the EDE code specified as input. This input can either be an integer
corresponding to the EDE code number (e.g. 15 would be EDE Blocked), or a
keyword from the following list corresponding to an EDE specified in RFC 8914.
.TP 5
EDE keywords:
.nf
\h'5'\fIother\fR
\h'5'\fIunsupported-dnskey-algorithm\fR
\h'5'\fIunsupported-ds-digest-type\fR
\h'5'\fIstale-answer\fR
\h'5'\fIforged\fR
\h'5'\fIdnssec-indeterminate\fR
\h'5'\fIdnssec-bogus\fR
\h'5'\fIsignature-expired\fR
\h'5'\fIsignature-not-yet-valid\fR
\h'5'\fIdnskey-missing\fR
\h'5'\fIrrsigs-missing\fR
\h'5'\fIno-zone-key-bit-set\fR
\h'5'\fInsec-missing\fR
\h'5'\fIcached-error\fR
\h'5'\fInot-ready\fR
\h'5'\fIblocked\fR
\h'5'\fIcensored\fR
\h'5'\fIfiltered\fR
\h'5'\fIprohibited\fR
\h'5'\fIstale-nxdomain-answer\fR
\h'5'\fInot-authoritative\fR
\h'5'\fInot-supported\fR
\h'5'\fIno-reachable-authority\fR
\h'5'\fInetwork-error\fR
\h'5'\fIinvalid-data\fR
.fi
.TP 5
Note that the val\-log\-level influences the the reason for the error included
in the EDE message.
.TP 5
.B response\-ip: \fI<IP-netblock> <action>
This requires use of the "respip" module.
.IP
@@ -2633,6 +2689,9 @@ Log all applied RPZ actions for this RPZ zone. Default is no.
.B rpz\-log\-name: \fI<name>
Specify a string to be part of the log line, for easy referencing.
.TP
.B rpz\-do\-ede: \fI<yes or no>
Specify if this zone RPZ responds with Extended DNS Errors (RFC 8914). The
default is no.
.B rpz\-signal\-nxdomain\-ra: \fI<yes or no>
Signal when a query is blocked by the RPZ with NXDOMAIN with an unset RA flag.
This allows certain clients, like dnsmasq, to infer that the domain is
+299 -21
View File
@@ -194,6 +194,8 @@ local_zone_create(uint8_t* nm, size_t len, int labs,
z->name = nm;
z->namelen = len;
z->namelabs = labs;
z->do_ede = -1; /* do not set EDE (RFC8914) (0/1 is set) */
z->default_ede = -1; /* do not overwrite EDE (RFC8914) codes */
lock_rw_init(&z->lock);
z->region = regional_create_nochunk(sizeof(struct regional));
if(!z->region) {
@@ -695,6 +697,177 @@ lz_enter_zone_tag(struct local_zones* zones, char* zname, uint8_t* list,
return r;
}
/** enter do-ede option into zone */
static int
lz_enter_respond_ede(struct local_zones* zones, char* zname, char* option)
{
uint8_t dname[LDNS_MAX_DOMAINLEN+1];
size_t dname_len = sizeof(dname);
int dname_label_count;
struct local_zone* z;
/* parse zone name */
if(sldns_str2wire_dname_buf(zname, dname, &dname_len) != 0) {
log_err("cannot parse zone name in local-zone-do-ede: %s",
zname);
return 0;
}
dname_label_count = dname_count_labels(dname);
/* find localzone entry */
lock_rw_rdlock(&zones->lock);
z = local_zones_find(zones, dname,
dname_len, dname_label_count, LDNS_RR_CLASS_IN);
if (!z) {
lock_rw_unlock(&zones->lock);
log_err("no local-zone for local-zone-do-ede: %s", zname);
return 0;
}
lock_rw_wrlock(&z->lock);
lock_rw_unlock(&zones->lock);
if (z->do_ede != -1) {
lock_rw_unlock(&z->lock);
log_err("duplicate local-zone-do-ede: %s", zname);
return 1;
}
/* parse option and check that the global default is also negative */
if ((strcmp(option, "no") == 0)) {
z->do_ede = 0;
lock_rw_unlock(&z->lock);
return 1;
}
z->do_ede = 1; /* respond with EDEs in this local-zone */
lock_rw_unlock(&z->lock);
return 1;
}
static int
ede_string_to_sldns_ede_code(char* code)
{
if (strcmp("other", code) == 0)
return LDNS_EDE_OTHER;
else if (strcmp("unsupported_dnskey_algorithm", code) == 0)
return LDNS_EDE_UNSUPPORTED_DNSKEY_ALG;
else if (strcmp("unsupported_ds_digest_type", code) == 0)
return LDNS_EDE_UNSUPPORTED_DS_DIGEST;
else if (strcmp("stale_answer", code) == 0)
return LDNS_EDE_STALE_ANSWER;
else if (strcmp("forged", code) == 0)
return LDNS_EDE_FORGED_ANSWER;
else if (strcmp("dnssec_indeterminate", code) == 0)
return LDNS_EDE_DNSSEC_INDETERMINATE;
else if (strcmp("dnssec_bogus", code) == 0)
return LDNS_EDE_DNSSEC_BOGUS;
else if (strcmp("signature_expired", code) == 0)
return LDNS_EDE_SIGNATURE_EXPIRED;
else if (strcmp("signature_not_yet_valid", code) == 0)
return LDNS_EDE_SIGNATURE_NOT_YET_VALID;
else if (strcmp("dnskey_missing", code) == 0)
return LDNS_EDE_DNSKEY_MISSING;
else if (strcmp("rrsigs_missing", code) == 0)
return LDNS_EDE_RRSIGS_MISSING;
else if (strcmp("no_zone_key_bit_set", code) == 0)
return LDNS_EDE_NO_ZONE_KEY_BIT_SET;
else if (strcmp("nsec_missing", code) == 0)
return LDNS_EDE_NSEC_MISSING;
else if (strcmp("cached_error", code) == 0)
return LDNS_EDE_CACHED_ERROR;
else if (strcmp("not_ready", code) == 0)
return LDNS_EDE_NOT_READY;
else if (strcmp("blocked", code) == 0)
return LDNS_EDE_BLOCKED;
else if (strcmp("censored", code) == 0)
return LDNS_EDE_CENSORED;
else if (strcmp("filtered", code) == 0)
return LDNS_EDE_FILTERED;
else if (strcmp("prohibited", code) == 0)
return LDNS_EDE_PROHIBITED;
else if (strcmp("stale_nxdomain_answer", code) == 0)
return LDNS_EDE_STALE_NXDOMAIN_ANSWER;
else if (strcmp("not_authoritative", code) == 0)
return LDNS_EDE_NOT_AUTHORITATIVE;
else if (strcmp("not_supported", code) == 0)
return LDNS_EDE_NOT_SUPPORTED;
else if (strcmp("no_reachable_authority", code) == 0)
return LDNS_EDE_NO_REACHABLE_AUTHORITY;
else if (strcmp("network_error", code) == 0)
return LDNS_EDE_NETWORK_ERROR;
else if (strcmp("invalid_data", code) == 0)
return LDNS_EDE_INVALID_DATA;
return -1;
}
static int
lz_enter_default_ede_response(struct local_zones* zones, char* zname, char* code)
{
uint8_t dname[LDNS_MAX_DOMAINLEN+1];
size_t dname_len = sizeof(dname);
int dname_label_count;
struct local_zone* z;
int default_ede;
/* parse zone name */
if(sldns_str2wire_dname_buf(zname, dname, &dname_len) != 0) {
log_err("cannot parse zone name in local-zone-default-ede: %s",
zname);
return 0;
}
dname_label_count = dname_count_labels(dname);
/* parse option in case of a textual string or integer value */
if (atoi(code) != 0) {
default_ede = (int) ede_string_to_sldns_ede_code(code);
if (default_ede == -1) {
log_err("incorect EDE code string found for "
"local-zone-default-ede: %s", zname);
return 0;
}
} else {
int tmp = atoi(code);
if (!(tmp >= 0 && tmp < 65635)) {
log_err("incorrect EDE code integer value for"
"local-zone-default-ede: %s", zname);
return 0;
}
default_ede = tmp;
}
/* find localzone entry */
lock_rw_rdlock(&zones->lock);
z = local_zones_find(zones, dname,
dname_len, dname_label_count, LDNS_RR_CLASS_IN);
if(!z) {
lock_rw_unlock(&zones->lock);
log_err("no local-zone for local-zone-default-ede: %s", zname);
return 0;
}
lock_rw_wrlock(&z->lock);
lock_rw_unlock(&zones->lock);
if (z->default_ede) {
lock_rw_unlock(&z->lock);
log_err("duplicate local-zone-default-ede: %s", zname);
return 1;
}
if (!(z->default_ede >= 0)) {
lock_rw_unlock(&z->lock);
log_err("default-ede set for zone that does not have"
"local-zone-do-ede enabled: %s", zname);
return 1;
}
z->default_ede = default_ede; /* respond with EDEs in this local-zone */
lock_rw_unlock(&z->lock);
return 1;
}
/** enter override into zone */
static int
lz_enter_override(struct local_zones* zones, char* zname, char* netblock,
@@ -981,6 +1154,30 @@ lz_enter_overrides(struct local_zones* zones, struct config_file* cfg)
return 1;
}
/** parse local-zone-do-ede: statements */
static int
lz_enter_respond_ede_zones(struct local_zones* zones, struct config_file* cfg)
{
struct config_str2list* p;
for(p = cfg->local_zone_do_ede; p; p = p->next) {
if(!lz_enter_respond_ede(zones, p->str, p->str2))
return 0;
}
return 1;
}
/** parse local_zone_default_ede: statements */
static int
lz_enter_default_ede_response_zones(struct local_zones* zones, struct config_file* cfg)
{
struct config_str2list* p;
for(p = cfg->local_zone_default_ede; p; p = p->next) {
if(!lz_enter_default_ede_response(zones, p->str, p->str2))
return 0;
}
return 1;
}
/** setup parent pointers, so that a lookup can be done for closest match */
static void
init_parents(struct local_zones* zones)
@@ -1194,6 +1391,15 @@ local_zones_apply_cfg(struct local_zones* zones, struct config_file* cfg)
if(!lz_enter_overrides(zones, cfg)) {
return 0;
}
/* enter EDE (RFC8914) response options for local zones */
if(!lz_enter_respond_ede_zones(zones, cfg)) {
return 0;
}
/* enter default EDE (RFC8914) response options for local zones */
if(!lz_enter_default_ede_response_zones(zones, cfg)) {
return 0;
}
/* create implicit transparent zone from data. */
if(!lz_setup_implicit(zones, cfg)) {
return 0;
@@ -1324,11 +1530,65 @@ local_encode(struct query_info* qinfo, struct module_env* env,
return 1;
}
/** encode answer consisting of 1 rrset (with EDE code) */
static int
local_encode_ede(struct local_zone* zone, struct query_info* qinfo,
struct module_env* env, struct edns_data* edns,
struct comm_reply* repinfo, sldns_buffer* buf, struct regional* temp,
struct ub_packed_rrset_key* rrset, int ansec, int rcode,
sldns_ede_code ede_code, const char* ede_txt, int do_ede)
{
struct reply_info rep;
uint16_t udpsize;
/* make answer with time=0 for fixed TTL values */
memset(&rep, 0, sizeof(rep));
rep.flags = (uint16_t)((BIT_QR | BIT_AA | BIT_RA) | rcode);
rep.qdcount = 1;
if(ansec)
rep.an_numrrsets = 1;
else rep.ns_numrrsets = 1;
rep.rrset_count = 1;
rep.rrsets = &rrset;
udpsize = edns->udp_size;
edns->edns_version = EDNS_ADVERTISED_VERSION;
edns->udp_size = EDNS_ADVERTISED_SIZE;
edns->ext_rcode = 0;
edns->bits &= EDNS_DO;
if(!inplace_cb_reply_local_call(env, qinfo, NULL, &rep, rcode, edns,
repinfo, temp, env->now_tv)) {
error_encode(buf, (LDNS_RCODE_SERVFAIL|BIT_AA), qinfo,
*(uint16_t*)sldns_buffer_begin(buf),
sldns_buffer_read_u16_at(buf, 2), edns);
return 1;
}
/* check global and local-zone EDE settings */
if (do_ede == 1 || /* local precedes global */
(do_ede == -1 &&
env->cfg->ede_local_zones == 1)){ /* global set, but local not */
if (zone != NULL && zone->default_ede != -1)
ede_code = zone->default_ede;
edns_opt_list_append_ede(&edns->opt_list_out, temp, ede_code, ede_txt);
}
if(!reply_info_answer_encode(qinfo, &rep,
*(uint16_t*)sldns_buffer_begin(buf), sldns_buffer_read_u16_at(buf, 2),
buf, 0, 0, temp, udpsize, edns, (int)(edns->bits&EDNS_DO), 0)) {
error_encode(buf, (LDNS_RCODE_SERVFAIL|BIT_AA), qinfo,
*(uint16_t*)sldns_buffer_begin(buf),
sldns_buffer_read_u16_at(buf, 2), edns);
}
return 1;
}
/** encode local error answer */
static void
local_error_encode(struct query_info* qinfo, struct module_env* env,
struct edns_data* edns, struct comm_reply* repinfo, sldns_buffer* buf,
struct regional* temp, int rcode, int r)
local_error_encode(struct local_zone* zone, struct query_info* qinfo,
struct module_env* env, struct edns_data* edns,
struct comm_reply* repinfo, sldns_buffer* buf, struct regional* temp,
int rcode, int r, sldns_ede_code ede_code, const char* ede_txt,
int do_ede)
{
edns->edns_version = EDNS_ADVERTISED_VERSION;
edns->udp_size = EDNS_ADVERTISED_SIZE;
@@ -1338,6 +1598,16 @@ local_error_encode(struct query_info* qinfo, struct module_env* env,
if(!inplace_cb_reply_local_call(env, qinfo, NULL, NULL,
rcode, edns, repinfo, temp, env->now_tv))
edns->opt_list_inplace_cb_out = NULL;
/* check global and local-zone ede settings */
if (do_ede == 1 || /* local precedes global */
(do_ede == -1 &&
env->cfg->ede_local_zones == 1)){ /* global set, but local not */
if (zone != NULL && zone->default_ede != -1)
ede_code = zone->default_ede;
edns_opt_list_append_ede(&edns->opt_list_out, temp, ede_code, ede_txt);
}
error_encode(buf, r, qinfo, *(uint16_t*)sldns_buffer_begin(buf),
sldns_buffer_read_u16_at(buf, 2), edns);
}
@@ -1460,7 +1730,7 @@ local_data_answer(struct local_zone* z, struct module_env* env,
struct comm_reply* repinfo, sldns_buffer* buf,
struct regional* temp, int labs, struct local_data** ldp,
enum localzone_type lz_type, int tag, struct config_strlist** tag_datas,
size_t tag_datas_size, char** tagname, int num_tags)
size_t tag_datas_size, char** tagname, int num_tags, int do_ede)
{
struct local_data key;
struct local_data* ld;
@@ -1533,9 +1803,11 @@ local_data_answer(struct local_zone* z, struct module_env* env,
if(newtargetlen > LDNS_MAX_DOMAINLEN) {
qinfo->local_alias = NULL;
local_error_encode(qinfo, env, edns, repinfo,
local_error_encode(z, qinfo, env, edns,repinfo,
buf, temp, LDNS_RCODE_YXDOMAIN,
(LDNS_RCODE_YXDOMAIN|BIT_AA));
(LDNS_RCODE_YXDOMAIN|BIT_AA),
LDNS_EDE_OTHER,
"DNAME expansion became too large", do_ede);
return 1;
}
memset(&qinfo->local_alias->rrset->entry, 0,
@@ -1580,8 +1852,8 @@ local_data_answer(struct local_zone* z, struct module_env* env,
return local_encode(qinfo, env, edns, repinfo, buf, temp, &r, 1,
LDNS_RCODE_NOERROR);
}
return local_encode(qinfo, env, edns, repinfo, buf, temp, lr->rrset, 1,
LDNS_RCODE_NOERROR);
return local_encode_ede(z, qinfo, env, edns, repinfo, buf, temp, lr->rrset, 1,
LDNS_RCODE_NOERROR, LDNS_EDE_FORGED_ANSWER, "", do_ede);
}
/**
@@ -1626,7 +1898,7 @@ int
local_zones_zone_answer(struct local_zone* z, struct module_env* env,
struct query_info* qinfo, struct edns_data* edns,
struct comm_reply* repinfo, sldns_buffer* buf, struct regional* temp,
struct local_data* ld, enum localzone_type lz_type)
struct local_data* ld, enum localzone_type lz_type, int do_ede)
{
if(lz_type == local_zone_deny ||
lz_type == local_zone_always_deny ||
@@ -1637,8 +1909,9 @@ local_zones_zone_answer(struct local_zone* z, struct module_env* env,
return 1;
} else if(lz_type == local_zone_refuse
|| lz_type == local_zone_always_refuse) {
local_error_encode(qinfo, env, edns, repinfo, buf, temp,
LDNS_RCODE_REFUSED, (LDNS_RCODE_REFUSED|BIT_AA));
local_error_encode(z, qinfo, env, edns, repinfo, buf, temp,
LDNS_RCODE_REFUSED, (LDNS_RCODE_REFUSED|BIT_AA),
LDNS_EDE_BLOCKED, "", do_ede);
return 1;
} else if(lz_type == local_zone_static ||
lz_type == local_zone_redirect ||
@@ -1663,8 +1936,8 @@ local_zones_zone_answer(struct local_zone* z, struct module_env* env,
if(z != NULL && z->soa && z->soa_negative)
return local_encode(qinfo, env, edns, repinfo, buf, temp,
z->soa_negative, 0, rcode);
local_error_encode(qinfo, env, edns, repinfo, buf, temp, rcode,
(rcode|BIT_AA));
local_error_encode(z, qinfo, env, edns, repinfo, buf, temp,
rcode, (rcode|BIT_AA), LDNS_EDE_BLOCKED, "", do_ede);
return 1;
} else if(lz_type == local_zone_typetransparent
|| lz_type == local_zone_always_transparent) {
@@ -1702,15 +1975,17 @@ local_zones_zone_answer(struct local_zone* z, struct module_env* env,
d.rr_len = &rr_len;
d.rr_data = &rr_datas;
d.rr_ttl = &rr_ttl;
return local_encode(qinfo, env, edns, repinfo, buf, temp,
&lrr, 1, LDNS_RCODE_NOERROR);
return local_encode_ede(z, qinfo, env, edns, repinfo, buf, temp,
&lrr, 1, LDNS_RCODE_NOERROR, LDNS_EDE_FORGED_ANSWER, "", do_ede);
} else {
local_error_encode(qinfo, env, edns, repinfo, buf,
/* NODATA: No EDE needed */
local_error_encode(z, qinfo, env, edns, repinfo, buf,
temp, LDNS_RCODE_NOERROR,
(LDNS_RCODE_NOERROR|BIT_AA));
(LDNS_RCODE_NOERROR|BIT_AA), -1, NULL, 0);
}
return 1;
}
/* else lz_type == local_zone_transparent */
/* if the zone is transparent and the name exists, but the type
@@ -1720,8 +1995,9 @@ local_zones_zone_answer(struct local_zone* z, struct module_env* env,
if(z != NULL && z->soa && z->soa_negative)
return local_encode(qinfo, env, edns, repinfo, buf, temp,
z->soa_negative, 0, rcode);
local_error_encode(qinfo, env, edns, repinfo, buf, temp, rcode,
(rcode|BIT_AA));
/* NODATA: No EDE needed */
local_error_encode(z, qinfo, env, edns, repinfo, buf, temp, rcode,
(rcode|BIT_AA), -1, NULL, 0);
return 1;
}
@@ -1884,13 +2160,15 @@ local_zones_answer(struct local_zones* zones, struct module_env* env,
&& lzt != local_zone_always_nodata
&& lzt != local_zone_always_deny
&& local_data_answer(z, env, qinfo, edns, repinfo, buf, temp, labs,
&ld, lzt, tag, tag_datas, tag_datas_size, tagname, num_tags)) {
&ld, lzt, tag, tag_datas, tag_datas_size, tagname, num_tags,
z->do_ede)) {
lock_rw_unlock(&z->lock);
/* We should tell the caller that encode is deferred if we found
* a local alias. */
return !qinfo->local_alias;
}
r = local_zones_zone_answer(z, env, qinfo, edns, repinfo, buf, temp, ld, lzt);
r = local_zones_zone_answer(z, env, qinfo, edns, repinfo, buf, temp, ld,
lzt, z->do_ede);
lock_rw_unlock(&z->lock);
return r && !qinfo->local_alias; /* see above */
}
+8 -2
View File
@@ -47,6 +47,7 @@
#include "util/module.h"
#include "services/view.h"
#include "sldns/sbuffer.h"
#include "sldns/rrdef.h"
struct packed_rrset_data;
struct ub_packed_rrset_key;
struct regional;
@@ -164,6 +165,10 @@ struct local_zone {
* artificial negative SOA rrset (TTL is the minimum of the TTL and the
* SOA.MINIMUM). */
struct ub_packed_rrset_key* soa_negative;
/** should local_data result in EDE (RFC8914) code inclusion? */
int do_ede;
/** the default EDE (RFC8914) code for this zone */
int default_ede;
};
/**
@@ -343,7 +348,8 @@ int
local_zones_zone_answer(struct local_zone* z, struct module_env* env,
struct query_info* qinfo, struct edns_data* edns,
struct comm_reply* repinfo, sldns_buffer* buf, struct regional* temp,
struct local_data* ld, enum localzone_type lz_type);
struct local_data* ld, enum localzone_type lz_type,
int do_ede);
/**
* Parse the string into localzone type.
@@ -608,7 +614,7 @@ local_data_answer(struct local_zone* z, struct module_env* env,
struct comm_reply* repinfo, sldns_buffer* buf,
struct regional* temp, int labs, struct local_data** ldp,
enum localzone_type lz_type, int tag, struct config_strlist** tag_datas,
size_t tag_datas_size, char** tagname, int num_tags);
size_t tag_datas_size, char** tagname, int num_tags, int do_ede);
/**
* Add RR to local zone.
+18
View File
@@ -1290,6 +1290,22 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
&r->edns, &r->query_reply, m->s.region, &r->start_time))
r->edns.opt_list_inplace_cb_out = NULL;
}
/* Send along EDE BOGUS EDNS0 option when answer is bogus */
if(rcode == LDNS_RCODE_SERVFAIL &&
m->s.env->need_to_validate && (!(r->qflags&BIT_CD) ||
m->s.env->cfg->ignore_cd) && rep &&
(rep->security <= sec_status_bogus ||
rep->security == sec_status_secure_sentinel_fail)) {
char *reason = m->s.env->cfg->val_log_level >= 2
? errinf_to_str_bogus(&m->s) : NULL;
sldns_ede_code reason_bogus = rep->reason_bogus != LDNS_EDE_DNSSEC_BOGUS
? rep->reason_bogus : errinf_to_reason_bogus(&m->s);
edns_opt_list_append_ede(&r->edns.opt_list_out, m->s.region,
reason_bogus, reason);
free(reason);
}
error_encode(r_buffer, rcode, &m->s.qinfo, r->qid,
r->qflags, &r->edns);
m->reply_list = NULL;
@@ -1313,6 +1329,8 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
if(!inplace_cb_reply_servfail_call(m->s.env, &m->s.qinfo, &m->s,
rep, LDNS_RCODE_SERVFAIL, &r->edns, &r->query_reply, m->s.region, &r->start_time))
r->edns.opt_list_inplace_cb_out = NULL;
/* internal server error (probably malloc failure) so no
* EDE (RFC8914) needed */
error_encode(r_buffer, LDNS_RCODE_SERVFAIL,
&m->s.qinfo, r->qid, r->qflags, &r->edns);
}
+37 -3
View File
@@ -513,6 +513,13 @@ rpz_create(struct config_auth* p)
goto err;
}
/* Respond with EDEs (RFC 8914) in this zone*/
if (p->rpz_do_ede)
r->do_ede = 1;
else
r->do_ede = 0;
r->taglistlen = p->rpz_taglistlen;
r->taglist = memdup(p->rpz_taglist, r->taglistlen);
if(p->rpz_action_override) {
@@ -1893,6 +1900,8 @@ rpz_synthesize_qname_localdata(struct module_env* env, struct rpz* r,
{
struct local_data* ld = NULL;
int ret = 0;
int do_ede = 0;
if(r->action_override == RPZ_CNAME_OVERRIDE_ACTION) {
qinfo->local_alias = regional_alloc_zero(temp, sizeof(struct local_rrset));
if(qinfo->local_alias == NULL) {
@@ -1913,9 +1922,13 @@ rpz_synthesize_qname_localdata(struct module_env* env, struct rpz* r,
return 0;
}
/* check the rpz if we want to respond with EDE (RFC8914) */
if (r->do_ede)
do_ede = r->do_ede;
if(lzt == local_zone_redirect && local_data_answer(z, env, qinfo,
edns, repinfo, buf, temp, dname_count_labels(qinfo->qname),
&ld, lzt, -1, NULL, 0, NULL, 0)) {
&ld, lzt, -1, NULL, 0, NULL, 0, do_ede)) {
if(r->log) {
log_rpz_apply("qname", z->name, NULL,
localzone_type_to_rpz_action(lzt), qinfo,
@@ -1926,7 +1939,7 @@ rpz_synthesize_qname_localdata(struct module_env* env, struct rpz* r,
}
ret = local_zones_zone_answer(z, env, qinfo, edns, repinfo, buf, temp,
0 /* no local data used */, lzt);
0 /* no local data used */, lzt, do_ede);
if(r->signal_nxdomain_ra && LDNS_RCODE_WIRE(sldns_buffer_begin(buf))
== LDNS_RCODE_NXDOMAIN)
LDNS_RA_CLR(sldns_buffer_begin(buf));
@@ -2276,6 +2289,7 @@ rpz_apply_maybe_clientip_trigger(struct auth_zones* az, struct module_env* env,
enum rpz_action client_action;
struct clientip_synthesized_rr* node = rpz_resolve_client_action_and_zone(
az, qinfo, repinfo, taglist, taglen, stats, z_out, a_out, r_out);
int do_ede;
client_action = ((node == NULL) ? RPZ_INVALID_ACTION : node->action);
@@ -2300,9 +2314,15 @@ rpz_apply_maybe_clientip_trigger(struct auth_zones* az, struct module_env* env,
(node?&node->node:NULL),
client_action, qinfo, repinfo, NULL,
(*r_out)->log_name);
/* check the rpz zone if we want to respond with EDE (RFC8914) */
if (*r_out && (*r_out)->do_ede)
do_ede = (*r_out)->do_ede;
else
do_ede = 0;
local_zones_zone_answer(*z_out /*likely NULL, no zone*/, env, qinfo, edns,
repinfo, buf, temp, 0 /* no local data used */,
rpz_action_to_localzone_type(client_action));
rpz_action_to_localzone_type(client_action), do_ede);
if(*r_out && (*r_out)->signal_nxdomain_ra &&
LDNS_RCODE_WIRE(sldns_buffer_begin(buf))
== LDNS_RCODE_NXDOMAIN)
@@ -2392,3 +2412,17 @@ void rpz_disable(struct rpz* r)
return;
r->disabled = 1;
}
void rpz_do_ede_enable(struct rpz* r)
{
if(!r)
return;
r->do_ede = 1;
}
void rpz_do_ede_disable(struct rpz* r)
{
if(!r)
return;
r->do_ede = 0;
}
+13
View File
@@ -127,6 +127,7 @@ struct rpz {
int signal_nxdomain_ra;
struct regional* region;
int disabled;
int do_ede;
};
/**
@@ -261,4 +262,16 @@ void rpz_enable(struct rpz* r);
*/
void rpz_disable(struct rpz* r);
/**
* Enable RPZ EDE (RFC 8914) responses
* @param r: RPZ struct containing member to disable
*/
void rpz_do_ede_enable(struct rpz* r);
/**
* Disable RPZ EDE (RFC 8914) responses
* @param r: RPZ struct containing member to disable
*/
void rpz_do_ede_disable(struct rpz* r);
#endif /* SERVICES_RPZ_H */
+4
View File
@@ -97,18 +97,22 @@ extern "C" {
#define QDCOUNT(wirebuf) (ntohs(*(uint16_t *)(wirebuf+QDCOUNT_OFF)))
*/
#define LDNS_QDCOUNT(wirebuf) (sldns_read_uint16(wirebuf+LDNS_QDCOUNT_OFF))
#define LDNS_QDCOUNT_SET(wirebuf, i) (sldns_write_uint16(wirebuf+LDNS_QDCOUNT_OFF, i))
/* Counter of the answer section */
#define LDNS_ANCOUNT_OFF 6
#define LDNS_ANCOUNT(wirebuf) (sldns_read_uint16(wirebuf+LDNS_ANCOUNT_OFF))
#define LDNS_ANCOUNT_SET(wirebuf, i) (sldns_write_uint16(wirebuf+LDNS_ANCOUNT_OFF, i))
/* Counter of the authority section */
#define LDNS_NSCOUNT_OFF 8
#define LDNS_NSCOUNT(wirebuf) (sldns_read_uint16(wirebuf+LDNS_NSCOUNT_OFF))
#define LDNS_NSCOUNT_SET(wirebuf, i) (sldns_write_uint16(wirebuf+LDNS_NSCOUNT_OFF, i))
/* Counter of the additional section */
#define LDNS_ARCOUNT_OFF 10
#define LDNS_ARCOUNT(wirebuf) (sldns_read_uint16(wirebuf+LDNS_ARCOUNT_OFF))
#define LDNS_ARCOUNT_SET(wirebuf, i) (sldns_write_uint16(wirebuf+LDNS_ARCOUNT_OFF, i))
/**
* The sections of a packet
+31
View File
@@ -435,10 +435,41 @@ enum sldns_enum_edns_option
LDNS_EDNS_CLIENT_SUBNET = 8, /* RFC7871 */
LDNS_EDNS_KEEPALIVE = 11, /* draft-ietf-dnsop-edns-tcp-keepalive*/
LDNS_EDNS_PADDING = 12, /* RFC7830 */
LDNS_EDNS_EDE = 15, /* RFC8914 */
LDNS_EDNS_CLIENT_TAG = 16 /* draft-bellis-dnsop-edns-tags-01 */
};
typedef enum sldns_enum_edns_option sldns_edns_option;
enum sldns_enum_ede_code
{
LDNS_EDE_OTHER = 0,
LDNS_EDE_UNSUPPORTED_DNSKEY_ALG = 1,
LDNS_EDE_UNSUPPORTED_DS_DIGEST = 2,
LDNS_EDE_STALE_ANSWER = 3,
LDNS_EDE_FORGED_ANSWER = 4,
LDNS_EDE_DNSSEC_INDETERMINATE = 5,
LDNS_EDE_DNSSEC_BOGUS = 6,
LDNS_EDE_SIGNATURE_EXPIRED = 7,
LDNS_EDE_SIGNATURE_NOT_YET_VALID = 8,
LDNS_EDE_DNSKEY_MISSING = 9,
LDNS_EDE_RRSIGS_MISSING = 10,
LDNS_EDE_NO_ZONE_KEY_BIT_SET = 11,
LDNS_EDE_NSEC_MISSING = 12,
LDNS_EDE_CACHED_ERROR = 13,
LDNS_EDE_NOT_READY = 14,
LDNS_EDE_BLOCKED = 15,
LDNS_EDE_CENSORED = 16,
LDNS_EDE_FILTERED = 17,
LDNS_EDE_PROHIBITED = 18,
LDNS_EDE_STALE_NXDOMAIN_ANSWER = 19,
LDNS_EDE_NOT_AUTHORITATIVE = 20,
LDNS_EDE_NOT_SUPPORTED = 21,
LDNS_EDE_NO_REACHABLE_AUTHORITY = 22,
LDNS_EDE_NETWORK_ERROR = 23,
LDNS_EDE_INVALID_DATA = 24
};
typedef enum sldns_enum_ede_code sldns_ede_code;
#define LDNS_EDNS_MASK_DO_BIT 0x8000
/** TSIG and TKEY extended rcodes (16bit), 0-15 are the normal rcodes. */
+82 -8
View File
@@ -128,6 +128,8 @@ static void matchline(char* line, struct entry* e)
e->match_answer = 1;
} else if(str_keyword(&parse, "subdomain")) {
e->match_subdomain = 1;
} else if(str_keyword(&parse, "all_noedns")) {
e->match_all_noedns = 1;
} else if(str_keyword(&parse, "all")) {
e->match_all = 1;
} else if(str_keyword(&parse, "ttl")) {
@@ -148,7 +150,15 @@ static void matchline(char* line, struct entry* e)
error("expected = or : in MATCH: %s", line);
parse++;
e->ixfr_soa_serial = (uint32_t)strtol(parse, (char**)&parse, 10);
while(isspace((unsigned char)*parse))
while(isspace((unsigned char)*parse))
parse++;
} else if(str_keyword(&parse, "ede")) {
e->match_ede = 1;
if(*parse != '=' && *parse != ':')
error("expected = or : in MATCH: %s", line);
parse++;
e->ede_info_code = (uint16_t)strtol(parse, (char**)&parse, 10);
while(isspace((unsigned char)*parse))
parse++;
} else {
error("could not parse MATCH: '%s'", parse);
@@ -266,11 +276,14 @@ static struct entry* new_entry(void)
e->match_answer = 0;
e->match_subdomain = 0;
e->match_all = 0;
e->match_all_noedns = 0;
e->match_ttl = 0;
e->match_do = 0;
e->match_noedns = 0;
e->match_serial = 0;
e->ixfr_soa_serial = 0;
e->match_ede = 0;
e->ede_info_code = 0;
e->match_transport = transport_any;
e->reply_list = NULL;
e->copy_id = 0;
@@ -817,7 +830,7 @@ static uint32_t get_serial(uint8_t* p, size_t plen)
return 0;
}
/** get ptr to EDNS OPT record (and remaining length); behind the type u16 */
/** get ptr to EDNS OPT record (and remaining length); after the type u16 */
static int
pkt_find_edns_opt(uint8_t** p, size_t* plen)
{
@@ -884,6 +897,30 @@ get_do_flag(uint8_t* pkt, size_t len)
return (int)(edns_bits&LDNS_EDNS_MASK_DO_BIT);
}
/** return the EDNS EDE INFO-CODE if found, else -1 */
static int
get_ede_info_code(uint8_t* pkt, size_t len)
{
uint8_t *rdata;
uint16_t rdlen, optlen;
/* use arguments as temporary variables */
if(!pkt_find_edns_opt(&pkt, &len)) return -1;
if(len < 8) return -1; /* malformed */
rdlen = sldns_read_uint16(pkt+6);
rdata = pkt + 8;
while(rdlen > 0) {
if(rdlen < 4) return -1; /* malformed */
if(sldns_read_uint16(rdata) == LDNS_EDNS_EDE) {
if(rdlen < 6) return -1; /* malformed */
return sldns_read_uint16(rdata+4);
}
optlen = sldns_read_uint16(rdata+2);
rdlen -= optlen;
rdata += 4 + optlen;
}
return -1;
}
/** zero TTLs in packet */
static void
zerottls(uint8_t* pkt, size_t pktlen)
@@ -1201,7 +1238,7 @@ match_question(uint8_t* q, size_t qlen, uint8_t* p, size_t plen, int mttl)
return 0;
}
/* remove after answer section, (;; AUTH, ;; ADD, ;; MSG size ..) */
/* remove after answer section, (;; ANS, ;; AUTH, ;; ADD ..) */
s = strstr(qcmpstr, ";; ANSWER SECTION");
if(!s) s = strstr(qcmpstr, ";; AUTHORITY SECTION");
if(!s) s = strstr(qcmpstr, ";; ADDITIONAL SECTION");
@@ -1292,10 +1329,28 @@ match_answer(uint8_t* q, size_t qlen, uint8_t* p, size_t plen, int mttl)
return r;
}
/** ignore EDNS lines in the string by overwriting them with what's left or
* zero out if at end of the string */
static int
ignore_edns_lines(char* str) {
char* current = str, *edns = str, *n;
size_t str_len = strlen(str);
while((edns = strstr(edns, "; EDNS"))) {
n = strchr(edns, '\n');
if(!n) {
/* EDNS at end of string; zero */
*edns = 0;
break;
}
memmove(edns, n+1, str_len-(n-str));
}
return 1;
}
/** match all of the packet */
int
match_all(uint8_t* q, size_t qlen, uint8_t* p, size_t plen, int mttl,
int noloc)
int noloc, int noedns)
{
char* qstr, *pstr;
uint8_t* qb = q, *pb = p;
@@ -1313,6 +1368,11 @@ match_all(uint8_t* q, size_t qlen, uint8_t* p, size_t plen, int mttl,
qstr = sldns_wire2str_pkt(qb, qlen);
pstr = sldns_wire2str_pkt(pb, plen);
if(!qstr || !pstr) error("cannot pkt2string");
/* should we ignore EDNS lines? */
if(noedns) {
ignore_edns_lines(qstr);
ignore_edns_lines(pstr);
}
r = (strcmp(qstr, pstr) == 0);
if(!r) {
/* remove ;; MSG SIZE (at end of string) */
@@ -1321,8 +1381,8 @@ match_all(uint8_t* q, size_t qlen, uint8_t* p, size_t plen, int mttl,
s = strstr(pstr, ";; MSG SIZE");
if(s) *s=0;
r = (strcmp(qstr, pstr) == 0);
if(!r && !noloc) {
/* we are going to fail see if it is because of EDNS */
if(!r && !noloc && !noedns) {
/* we are going to fail, see if the cause is EDNS */
char* a = strstr(qstr, "; EDNS");
char* b = strstr(pstr, "; EDNS");
if( (a&&!b) || (b&&!a) ) {
@@ -1434,7 +1494,7 @@ find_match(struct entry* entries, uint8_t* query_pkt, size_t len,
verbose(3, "comparepkt: ");
reply = p->reply_list->reply_pkt;
rlen = p->reply_list->reply_len;
if(p->match_opcode && get_opcode(query_pkt, len) !=
if(p->match_opcode && get_opcode(query_pkt, len) !=
get_opcode(reply, rlen)) {
verbose(3, "bad opcode\n");
continue;
@@ -1485,6 +1545,15 @@ find_match(struct entry* entries, uint8_t* query_pkt, size_t len,
verbose(3, "bad serial\n");
continue;
}
if(p->match_ede) {
int info_code = get_ede_info_code(query_pkt, len);
if(info_code == -1 ||
(uint16_t)info_code != p->ede_info_code) {
verbose(3, "bad EDE INFO-CODE. Expected: %d, and got: %d\n",
p->ede_info_code, info_code);
continue;
}
}
if(p->match_do && !get_do_flag(query_pkt, len)) {
verbose(3, "no DO bit set\n");
continue;
@@ -1502,8 +1571,13 @@ find_match(struct entry* entries, uint8_t* query_pkt, size_t len,
verbose(3, "bad transport\n");
continue;
}
if(p->match_all_noedns && !match_all(query_pkt, len, reply,
rlen, (int)p->match_ttl, 0, 1)) {
verbose(3, "bad all_noedns match\n");
continue;
}
if(p->match_all && !match_all(query_pkt, len, reply, rlen,
(int)p->match_ttl, 0)) {
(int)p->match_ttl, 0, 0)) {
verbose(3, "bad allmatch\n");
continue;
}
+35 -17
View File
@@ -40,20 +40,25 @@ struct sldns_file_parse_state;
ENTRY_BEGIN
; first give MATCH lines, that say what queries are matched
; by this entry.
; 'opcode' makes the query match the opcode from the reply
; if you leave it out, any opcode matches this entry.
; 'qtype' makes the query match the qtype from the reply
; 'qname' makes the query match the qname from the reply
; 'subdomain' makes the query match subdomains of qname from the reply
; 'serial=1023' makes the query match if ixfr serial is 1023.
; 'opcode' makes the query match the opcode from the reply;
; if you leave it out, any opcode matches this entry.
; 'qtype' makes the query match the qtype from the reply.
; 'qname' makes the query match the qname from the reply.
; 'subdomain' makes the query match subdomains of qname from the reply.
; 'serial=1023' makes the query match if ixfr serial is 1023.
; 'all' has to match header byte for byte and all rrs in packet.
; 'all_noedns' has to match header byte for byte and all rrs in packet;
; ignoring EDNS.
; 'ttl' used with all, rrs in packet must also have matching TTLs.
; 'DO' will match only queries with DO bit set.
; 'noedns' matches queries without EDNS OPT records.
; 'rcode' makes the query match the rcode from the reply
; 'question' makes the query match the question section
; 'answer' makes the query match the answer section
; 'rcode' makes the query match the rcode from the reply.
; 'question' makes the query match the question section.
; 'answer' makes the query match the answer section.
; 'ednsdata' matches queries to HEX_EDNS section.
; 'UDP' matches if the transport is UDP.
; 'TCP' matches if the transport is TCP.
; 'ede=2' makes the query match if the EDNS EDE info-code is 2.
MATCH [opcode] [qtype] [qname] [serial=<value>] [all] [ttl]
MATCH [UDP|TCP] DO
MATCH ...
@@ -72,6 +77,12 @@ struct sldns_file_parse_state;
; 'sleep=10' sleeps for 10 seconds before giving the answer (TCP is open)
ADJUST [sleep=<num>] ; sleep before giving any reply
ADJUST [packet_sleep=<num>] ; sleep before this packet in sequence
; 'copy_ednsdata_assume_clientsubnet' copies ednsdata to reply, assumes
; it is clientsubnet and adjusts scopemask to match sourcemask.
ADJUST copy_ednsdata_assume_clientsubnet
; 'increment_ecs_scope' increments the ECS scope copied from the
; sourcemask by one.
ADJUST increment_ecs_scope
SECTION QUESTION
<RRs, one per line> ; the RRcount is determined automatically.
SECTION ANSWER
@@ -167,11 +178,11 @@ struct entry {
/* match */
/* How to match an incoming query with this canned reply */
/** match query opcode with answer opcode */
uint8_t match_opcode;
uint8_t match_opcode;
/** match qtype with answer qtype */
uint8_t match_qtype;
uint8_t match_qtype;
/** match qname with answer qname */
uint8_t match_qname;
uint8_t match_qname;
/** match rcode with answer rcode */
uint8_t match_rcode;
/** match question section */
@@ -179,11 +190,15 @@ struct entry {
/** match answer section */
uint8_t match_answer;
/** match qname as subdomain of answer qname */
uint8_t match_subdomain;
uint8_t match_subdomain;
/** match SOA serial number, from auth section */
uint8_t match_serial;
uint8_t match_serial;
/** match EDNS EDE info-code */
uint8_t match_ede;
/** match all of the packet */
uint8_t match_all;
/** match all of the packet; ignore EDNS */
uint8_t match_all_noedns;
/** match ttls in the packet */
uint8_t match_ttl;
/** match DO bit */
@@ -193,9 +208,11 @@ struct entry {
/** match edns data field given in hex */
uint8_t match_ednsdata_raw;
/** match query serial with this value. */
uint32_t ixfr_soa_serial;
uint32_t ixfr_soa_serial;
/** match on UDP/TCP */
enum transport_type match_transport;
enum transport_type match_transport;
/** match EDNS EDE info-code with this value. */
uint16_t ede_info_code;
/** pre canned reply */
struct reply_packet *reply_list;
@@ -260,10 +277,11 @@ struct entry* find_match(struct entry* entries, uint8_t* query_pkt,
* @param mttl: if true, ttls must match, if false, ttls do not need to match
* @param noloc: if true, rrs may be reordered in their packet-section.
* rrs are then matches without location of the rr being important.
* @param noedns: if true, edns is not compared, if false, edns must match.
* @return true if matched.
*/
int match_all(uint8_t* q, size_t qlen, uint8_t* p, size_t plen, int mttl,
int noloc);
int noloc, int noedns);
/**
* copy & adjust packet, mallocs a copy.
+1 -1
View File
@@ -137,7 +137,7 @@ test_buffers(sldns_buffer* pkt, sldns_buffer* out)
/* compare packets */
unit_assert(match_all(sldns_buffer_begin(pkt), sldns_buffer_limit(pkt),
sldns_buffer_begin(out), sldns_buffer_limit(out), 1,
matches_nolocation));
matches_nolocation, 0));
return 0;
}
+1 -1
View File
@@ -150,7 +150,7 @@ ENTRY_END
STEP 20 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
MATCH all_noedns ede=9
REPLY QR RD RA DO SERVFAIL
SECTION QUESTION
www.example.com. IN A
+1 -1
View File
@@ -138,7 +138,7 @@ ENTRY_END
STEP 20 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
MATCH all_noedns ede=6
REPLY QR RD RA DO SERVFAIL
SECTION QUESTION
www.example.com. IN A
+1 -1
View File
@@ -155,7 +155,7 @@ ENTRY_END
STEP 30 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
MATCH all_noedns ede=9
REPLY QR RD RA DO SERVFAIL
SECTION QUESTION
www.example.com. IN A
+1 -1
View File
@@ -155,7 +155,7 @@ ENTRY_END
STEP 30 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
MATCH all_noedns ede=6
REPLY QR RD RA DO SERVFAIL
SECTION QUESTION
www.example.com. IN A
+2 -2
View File
@@ -578,7 +578,7 @@ ENTRY_END
; recursion happens here.
STEP 10 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
MATCH all_noedns ede=7
REPLY QR RD RA DO SERVFAIL
SECTION QUESTION
www.sub.example.com. IN A
@@ -595,7 +595,7 @@ ENTRY_END
STEP 120 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
MATCH all_noedns ede=6
REPLY QR RD RA DO SERVFAIL
SECTION QUESTION
ftp.sub.example.com. IN A
+2 -2
View File
@@ -560,7 +560,7 @@ ENTRY_END
; recursion happens here.
STEP 10 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
MATCH all_noedns ede=7
REPLY QR RD RA DO SERVFAIL
SECTION QUESTION
www.sub.example.com. IN A
@@ -577,7 +577,7 @@ ENTRY_END
STEP 120 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
MATCH all_noedns ede=6
REPLY QR RD RA DO SERVFAIL
SECTION QUESTION
ftp.sub.example.com. IN A
+2 -2
View File
@@ -285,7 +285,7 @@ ENTRY_END
; recursion happens here.
STEP 10 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
MATCH all_noedns ede=7
REPLY QR RD RA DO SERVFAIL
SECTION QUESTION
www.example.com. IN A
@@ -304,7 +304,7 @@ ENTRY_END
; recursion happens here.
STEP 120 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
MATCH all_noedns ede=6
REPLY QR RD RA DO SERVFAIL
SECTION QUESTION
ftp.example.com. IN A
+1
View File
@@ -0,0 +1 @@
rm -f K* piece1 base expired notyetincepted trust-anchors dnssec-failures.test.signed dnskey-failures.test.signed nsec-failures.test.signed rrsig-failures.test.signed
+10
View File
@@ -0,0 +1,10 @@
$ORIGIN dnskey-failures.test.
@ SOA ns hostmaster (
1 ; serial
14400 ; refresh (4 hours)
1800 ; retry (30 minutes)
2419200 ; expire (4 weeks)
300 ; minimum (5 minutes)
)
A 192.0.2.1
+15
View File
@@ -0,0 +1,15 @@
$ORIGIN dnssec-failures.test.
@ SOA ns hostmaster (
1 ; serial
14400 ; refresh (4 hours)
1800 ; retry (30 minutes)
2419200 ; expire (4 weeks)
300 ; minimum (5 minutes)
)
NS ns
ns A 192.0.2.1
notyetincepted TXT "Not yet incepted"
expired TXT "Expired"
sigsinvalid TXT "Signatures invalid"
missingrrsigs TXT "Signatures missing"
+54
View File
@@ -0,0 +1,54 @@
#!/usr/bin/env bash
# create oudated zones
CSK=`ldns-keygen -a ECDSAP256SHA256 -k -r /dev/urandom dnssec-failures.test`
echo $CSK
echo ". IN DS 20326 8 2 e06d44b80b8f1d39a95c0b0d7c65d08458e880409bbc683457104237c7f8ec8d" | \
cat $CSK.ds - > bogus/trust-anchors
ONEMONTHAGO=`date -d 'now - 1 month' +%Y%m%d`
YESTERDAY=`date -d 'now - 2 days' +%Y%m%d`
TOMORROW=`date -d 'now + 2 days' +%Y%m%d`
ldns-signzone -i $YESTERDAY bogus/dnssec-failures.test $CSK -f - | \
grep -v '^missingrrsigs\.dnssec-failures\.test\..*IN.*RRSIG.*TXT' | \
sed 's/Signatures invalid/Signatures INVALID/g' | \
grep -v '^notyetincepted\.dnssec-failures\.test\..*IN.*TXT' | \
grep -v '^notyetincepted\.dnssec-failures\.test\..*IN.*RRSIG.*TXT' | \
grep -v '^expired\.dnssec-failures\.test\..*IN.*TXT' | \
grep -v '^expired\.dnssec-failures\.test\..*IN.*RRSIG.*TXT' > base
ldns-signzone -i $ONEMONTHAGO -e $YESTERDAY bogus/dnssec-failures.test $CSK -f - | \
grep -v '[ ]NSEC[ ]' | \
grep '^expired\.dnssec-failures\.test\..*IN.*TXT' > expired
ldns-signzone -i $TOMORROW bogus/dnssec-failures.test $CSK -f - | \
grep -v '[ ]NSEC[ ]' | \
grep '^notyetincepted\.dnssec-failures\.test\..*IN.*TXT' > notyetincepted
cat base expired notyetincepted > bogus/dnssec-failures.test.signed
# create zone with DNSKEY missing
CSK=`ldns-keygen -a ECDSAP256SHA256 -k -r /dev/urandom dnskey-failures.test`
echo $CSK
cat $CSK.ds >> bogus/trust-anchors
ldns-signzone bogus/dnskey-failures.test $CSK -f tmp.signed
grep -v ' DNSKEY ' tmp.signed > bogus/dnskey-failures.test.signed
# create zone with NSEC missing
CSK=`ldns-keygen -a ECDSAP256SHA256 -k -r /dev/urandom nsec-failures.test`
echo $CSK
cat $CSK.ds >> bogus/trust-anchors
ldns-signzone bogus/nsec-failures.test $CSK -f tmp.signed
grep -v ' NSEC ' tmp.signed > bogus/nsec-failures.test.signed
# create zone with RRSIGs missing
CSK=`ldns-keygen -a ECDSAP256SHA256 -k -r /dev/urandom rrsig-failures.test`
echo $CSK
cat $CSK.ds >> bogus/trust-anchors
ldns-signzone bogus/rrsig-failures.test $CSK -f tmp.signed
grep -v ' RRSIG ' tmp.signed > bogus/rrsig-failures.test.signed
# cleanup
rm -f base expired notyetincepted tmp.signed $CSK.*
+10
View File
@@ -0,0 +1,10 @@
$ORIGIN nsec-failures.test.
@ SOA ns hostmaster (
1 ; serial
14400 ; refresh (4 hours)
1800 ; retry (30 minutes)
2419200 ; expire (4 weeks)
300 ; minimum (5 minutes)
)
A 192.0.2.1
+10
View File
@@ -0,0 +1,10 @@
$ORIGIN rrsig-failures.test.
@ SOA ns hostmaster (
1 ; serial
14400 ; refresh (4 hours)
1800 ; retry (30 minutes)
2419200 ; expire (4 weeks)
300 ; minimum (5 minutes)
)
A 192.0.2.1
+25
View File
@@ -0,0 +1,25 @@
server:
verbosity: 1
use-syslog: no
chroot: ""
username: ""
directory: ""
local-zone: test nodefault
port: @PORT2@
auth-zone:
name: "dnssec-failures.test"
zonefile: "bogus/dnssec-failures.test.signed"
auth-zone:
name: "dnskey-failures.test"
zonefile: "bogus/dnskey-failures.test.signed"
auth-zone:
name: "nsec-failures.test"
zonefile: "bogus/nsec-failures.test.signed"
auth-zone:
name: "rrsig-failures.test"
zonefile: "bogus/rrsig-failures.test.signed"
+56
View File
@@ -0,0 +1,56 @@
server:
verbosity: 2
interface: 127.0.0.1
port: @PORT@
use-syslog: no
directory: .
pidfile: "unbound.pid"
chroot: ""
username: ""
directory: ""
val-log-level: 2
# @TODO change this to local file
#auto-trust-anchor-file: "/var/lib/unbound/root.key"
trust-anchor-file: "bogus/trust-anchors"
module-config: "respip validator iterator"
access-control: 127.0.0.2/32 refuse
#ede-local-zones: yes
local-zone: hopsa.kidee. always_refuse
#local-zone-do-ede: hopsa.kidee. yes
local-data: "hopsa.kidee. TXT hela hola"
local-zone: nlnetlabs.nl transparent
local-data: "hopsa.nlnetlabs.nl. TXT hela hola"
local-zone: uva.nl. always_null
local-zone: example.com redirect
local-data: "example.com CNAME *.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaa."
local-zone: test nodefault
do-not-query-localhost: no
# @TODO add rpz?
#rpz-do-ede: yes
forward-zone:
name: "dnssec-failures.test"
forward-addr: 127.0.0.1@@PORT2@
forward-zone:
name: "dnskey-failures.test"
forward-addr: 127.0.0.1@@PORT2@
forward-zone:
name: "nsec-failures.test"
forward-addr: 127.0.0.1@@PORT2@
forward-zone:
name: "rrsig-failures.test"
forward-addr: 127.0.0.1@@PORT2@
+16
View File
@@ -0,0 +1,16 @@
BaseName: svcb
Version: 1.0
Description: Test Extended DNS Errors (rfc8914)
CreationDate: Fri Aug 20 15:42:11 UTC 2021
Maintainer: Tom Carpay
Category:
Component:
CmdDepends:
Depends:
Help:
Pre:
Post:
Test: ede.test
AuxFiles:
Passed:
Failure:
+31
View File
@@ -0,0 +1,31 @@
# #-- fwd_tcp.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
. ../common.sh
get_random_port 2
UNBOUND_PORT=$RND_PORT
FWD_PORT=$(($RND_PORT + 1))
echo "UNBOUND_PORT=$UNBOUND_PORT" >> .tpkg.var.test
echo "FWD_PORT=$FWD_PORT" >> .tpkg.var.test
# start forwarder
get_ldns_testns
$LDNS_TESTNS -p $FWD_PORT fwd_tcp.testns >fwd.log 2>&1 &
FWD_PID=$!
echo "FWD_PID=$FWD_PID" >> .tpkg.var.test
# make config file
sed -e 's/@PORT\@/'$UNBOUND_PORT'/' -e 's/@TOPORT\@/'$FWD_PORT'/' < fwd_tcp.conf > ub.conf
# start unbound in the background
PRE="../.."
$PRE/unbound -d -c ub.conf >unbound.log 2>&1 &
UNBOUND_PID=$!
echo "UNBOUND_PID=$UNBOUND_PID" >> .tpkg.var.test
cat .tpkg.var.test
wait_ldns_testns_up fwd.log
wait_unbound_up unbound.log
+32
View File
@@ -0,0 +1,32 @@
# #-- fwd_tcp.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
. ../common.sh
get_random_port 2
UNBOUND_PORT=$RND_PORT
FWD_PORT=$(($RND_PORT + 1))
echo "UNBOUND_PORT=$UNBOUND_PORT" >> .tpkg.var.test
echo "FWD_PORT=$FWD_PORT" >> .tpkg.var.test
# start forwarder
get_ldns_testns
$LDNS_TESTNS -p $FWD_PORT fwd_tcp.testns >fwd.log 2>&1 &
FWD_PID=$!
echo "FWD_PID=$FWD_PID" >> .tpkg.var.test
# rewrite config file with created ports
sed -e 's/@PORT\@/'$UNBOUND_PORT'/' -e 's/@TOPORT\@/'$FWD_PORT'/' < fwd_tcp.conf > ub.conf
# start unbound in the background
PRE="../.."
$PRE/unbound -d -c ub.conf > unbound.log 2>&1 &
UNBOUND_PID=$!
echo "UNBOUND_PID=$UNBOUND_PID" >> .tpkg.var.test
cat .tpkg.var.test
wait_ldns_testns_up fwd.log
wait_unbound_up unbound.log
+203
View File
@@ -0,0 +1,203 @@
# #-- svcb.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
. ../common.sh
get_random_port 2
UNBOUND_PORT=$RND_PORT
UNBOUND_PORT2=$(($RND_PORT + 1))
echo "UNBOUND_PORT=$UNBOUND_PORT" >> .tpkg.var.test
echo "UNBOUND_PORT2=$UNBOUND_PORT2" >> .tpkg.var.test
# rewrite config file with created ports
sed -e 's/@PORT\@/'$UNBOUND_PORT'/' < ede.conf > temp.conf
sed -e 's/@PORT2\@/'$UNBOUND_PORT2'/' < temp.conf > ub.conf
sed -e 's/@PORT2\@/'$UNBOUND_PORT2'/' < ede-auth.conf > ub2.conf
# create broken dnssec zone
bogus/make-broken-zone.sh
# start unbound in the background
PRE="../.."
$PRE/unbound -d -c ub.conf > unbound.log 2>&1 &
UNBOUND_PID=$!
echo "UNBOUND_PID=$UNBOUND_PID" >> .tpkg.var.test
# start authoritative unbound in the background
$PRE/unbound -d -c ub2.conf > unbound.log 2>&1 &
UNBOUND_PID2=$!
echo "UNBOUND_PID2=$UNBOUND_PID2" >> .tpkg.var.test
# @TODO did we fix this? -> we do not trigger this anymore
# # query with bad edns keepalive
# dig @127.0.0.1 -p $UNBOUND_PORT +tcp +ednsopt=11:010203 > keepalive.txt
#
# if ! grep -q "OPT=15: 00 00 71 75 65 72 79 20 77 69 74 68 20 62 61 64 20 65 64 6e 73 20 6b 65 65 70 61 6c 69 76 65" keepalive.txt
# then
# echo "Incorect bad edns keepalive output"
# exit 1
# fi
# refused nonrec (cache snoop) (Not Auth)
dig @127.0.0.1 -p $UNBOUND_PORT +norec > snoop.txt
if ! grep -q "OPT=15: 00 14" snoop.txt
then
echo "Incorect cache snoop output"
cat snoop.txt
exit 1
fi
# local-zone always_refuse
dig @127.0.0.1 -p $UNBOUND_PORT qwerqwer.hopsa.kidee. TXT +dnssec > local_zone_refuse.txt
if ! grep -q "OPT=15: 00 0f" local_zone_refuse.txt
then
echo "query to qwerqwer.hopsa.kidee. should be EDE blocked"
cat local_zone_refuse.txt
exit 1
fi
# DNAME expansion
# @TODO do we have this?
# RPZ DNAME expansion too long
dig @127.0.0.1 -p $UNBOUND_PORT www.qhqwer.qwer.qwer.h.example.com A > dname_expansion.txt
if ! grep -q "OPT=15: 00 00 44 4e 41 4d 45 20 65 78 70 61 6e 73 69 6f 6e 20 62 65 63 61 6d 65 20 74 6f 6f 20 6c 61 72 67 65" dname_expansion.txt
then
echo "No DNAME expansion for CNAME EDE message"
cat dname_expansion.txt
exit 1
fi
# local-zone always_null gets EDE forged
dig @127.0.0.1 -p $UNBOUND_PORT uva.nl A > local_zone_always_null_forged.txt
if ! grep -q "OPT=15: 00 04" local_zone_always_null_forged.txt
then
echo "local-zone always_null must have EDE forged code"
cat local_zone_always_null_forged.txt
exit 1
fi
# RPZ always_refuse
dig @127.0.0.1 -p $UNBOUND_PORT hopsa.kidee. A > local_zone_rpz_always_refuse.txt
if ! grep -q "OPT=15: 00 0f" local_zone_rpz_always_refuse.txt
then
echo "local-zone always_refuse must have EDE blocked code"
cat local_zone_rpz_always_refuse.txt
exit 1
fi
# @TODO trigger mesh DNSSEC bogus
dig @127.0.0.1 -p $UNBOUND_PORT servfail.nl > servfail.txt
if ! grep -q "OPT=15: 00 07" servfail.txt
then
echo "query to servfail.nl should return EDE signature expired"
cat servfail.txt
exit 1
fi
# local data forged answer
dig @127.0.0.1 -p $UNBOUND_PORT hopsa.nlnetlabs.nl TXT > local_data_forged.txt
if ! grep -q "OPT=15: 00 04" local_data_forged.txt
then
echo "query to hopsa.nlnetlabs.nl does not give EDE forged"
cat local_data_forged.txt
exit 1
fi
# ACL refused, EDE prohibited
dig @127.0.0.1 -p $UNBOUND_PORT -b 127.0.0.2 example.com > acl_refused.txt
if ! grep -q "OPT=15: 00 12" acl_refused.txt
then
echo "ACL refused does not give EDE prohibited"
cat acl_refused.txt
exit 1
fi
# start authoritative unbound in the background
$PRE/unbound -d -c ub.conf > unbound.log 2>&1 &
UNBOUND_PID2=$!
echo "UNBOUND_PID2=$UNBOUND_PID2" >> .tpkg.var.test
# DNSSEC failure: key not incepted
dig @127.0.0.1 -p $UNBOUND_PORT notyetincepted.dnssec-failures.test. TXT +dnssec > sig_notyetincepted.txt
if ! grep -q "OPT=15: 00 08" sig_notyetincepted.txt
then
echo "Signature not yet valid does not return EDE Signature Not Yet Valid"
cat sig_notyetincepted.txt
exit 1
fi
# DNSSEC failure: key expired
dig @127.0.0.1 -p $UNBOUND_PORT expired.dnssec-failures.test. TXT +dnssec > sig_expired.txt
if ! grep -q "OPT=15: 00 07" sig_expired.txt
then
echo "Expired signature does not return EDE Signature expired"
cat sig_expired.txt
exit 1
fi
# DNSSEC failure: missing rrsigs
dig @127.0.0.1 -p $UNBOUND_PORT missingrrsigs.dnssec-failures.test. TXT +dnssec > missingrrsigs.txt
if ! grep -q "OPT=15: 00 0a" missingrrsigs.txt
then
echo "Expired signature does not return EDE RRSIGs missing"
cat missingrrsigs.txt
exit 1
fi
# signed zone with DNSKEY missing
dig @127.0.0.1 -p $UNBOUND_PORT dnskey-failures.test > dnskey-failure.txt
if ! grep -q "OPT=15: 00 09" dnskey-failure.txt
then
echo "Expired signature does not return EDE DNSKEY missing"
cat dnskey-failure.txt
exit 1
fi
# signed zone with RRSIGs missing
dig @127.0.0.1 -p $UNBOUND_PORT rrsig-failures.test > rrsig-failure.txt
if ! grep -q "OPT=15: 00 0a" rrsig-failure.txt
then
echo "Expired signature does not return EDE RRSIGs missing"
cat rrsig-failure.txt
exit 1
fi
# signed zone with NSEC missing
dig @127.0.0.1 -p $UNBOUND_PORT abc.nsec-failures.test > nsec-failure.txt
if ! grep -q "OPT=15: 00 0c" nsec-failure.txt
then
echo "Expired signature does not return EDE NSEC missing"
cat nsec-failure.txt
exit 1
fi
# @TODO DNSSEC indeterminate
# @TODO touch other validator codepath: val_inform_super() -> touched by other .rpls!
# teardown
kill_pid $UNBOUND_PID
kill_pid $UNBOUND_PID2
+1 -5
View File
@@ -47,14 +47,10 @@ STEP 1 QUERY
STEP 10 CHECK_ANSWER
ENTRY_BEGIN
MATCH TCP ednsdata
MATCH TCP
REPLY RD FORMERR
SECTION QUESTION
www.example.com. IN A
SECTION ADDITIONAL
HEX_EDNSDATA_BEGIN
; Empty
HEX_EDNSDATA_END
ENTRY_END
STEP 20 QUERY
+2 -2
View File
@@ -138,7 +138,7 @@ ENTRY_END
; recursion happens here.
STEP 22 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
MATCH all_noedns ede=6
REPLY QR RD RA DO SERVFAIL
SECTION QUESTION
root-key-sentinel-not-ta-19036. IN A
@@ -154,7 +154,7 @@ ENTRY_END
; recursion happens here.
STEP 33 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
MATCH all_noedns ede=6
REPLY QR RD RA DO SERVFAIL
SECTION QUESTION
root-key-sentinel-is-ta-20326. IN A
+1 -1
View File
@@ -88,7 +88,7 @@ ENTRY_END
; recursion happens here.
STEP 10 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
MATCH all_noedns ede=9
REPLY QR RD RA DO SERVFAIL
SECTION QUESTION
www.example.com. IN AAAA
+1 -2
View File
@@ -254,12 +254,11 @@ ENTRY_END
; recursion happens here.
STEP 10 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
MATCH all_noedns ede=10
REPLY QR RD RA DO SERVFAIL
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
SECTION ADDITIONAL
ENTRY_END
SCENARIO_END
+1 -3
View File
@@ -253,13 +253,11 @@ ENTRY_END
; recursion happens here.
STEP 10 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
MATCH all_noedns ede=6
REPLY QR RD RA DO SERVFAIL
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
SECTION AUTHORITY
SECTION ADDITIONAL
ENTRY_END
SCENARIO_END
+1 -1
View File
@@ -261,7 +261,7 @@ ENTRY_END
; recursion happens here.
STEP 10 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
MATCH all_noedns ede=10
REPLY QR RD RA DO SERVFAIL
SECTION QUESTION
foo.www.example.com. IN A
+1 -3
View File
@@ -256,13 +256,11 @@ ENTRY_END
; recursion happens here.
STEP 10 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
MATCH all_noedns ede=6
REPLY QR RD RA DO SERVFAIL
SECTION QUESTION
www.sub.example.com. IN A
SECTION ANSWER
SECTION AUTHORITY
SECTION ADDITIONAL
ENTRY_END
SCENARIO_END
+1 -2
View File
@@ -195,11 +195,10 @@ ENTRY_END
; recursion happens here.
STEP 10 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
MATCH all_noedns ede=10
REPLY QR RD RA DO SERVFAIL
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
ENTRY_END
SCENARIO_END
+2 -1
View File
@@ -160,11 +160,12 @@ ENTRY_END
; recursion happens here.
STEP 10 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
MATCH all_noedns ede=9
REPLY QR RD RA DO SERVFAIL
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
SECTION ADDITIONAL
ENTRY_END
SCENARIO_END
+1 -3
View File
@@ -154,13 +154,11 @@ ENTRY_END
; recursion happens here.
STEP 10 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
MATCH all_noedns ede=6
REPLY QR RD RA DO SERVFAIL
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
SECTION AUTHORITY
SECTION ADDITIONAL
ENTRY_END
SCENARIO_END
+1 -3
View File
@@ -60,13 +60,11 @@ ENTRY_END
; recursion happens here.
STEP 10 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
MATCH all_noedns ede=6
REPLY QR RD RA DO SERVFAIL
SECTION QUESTION
_25._tcp.mail.nsecwc.nlnetlabs.nl. IN TLSA
SECTION ANSWER
SECTION AUTHORITY
SECTION ADDITIONAL
ENTRY_END
SCENARIO_END
+1 -1
View File
@@ -153,7 +153,7 @@ ENTRY_END
STEP 10 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
MATCH all_noedns ede=9
REPLY QR RD RA DO SERVFAIL
SECTION QUESTION
www.example.com. IN A
+1 -2
View File
@@ -133,7 +133,7 @@ ENTRY_END
; recursion happens here.
STEP 10 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
MATCH all_noedns ede=6
REPLY QR RD RA DO SERVFAIL
SECTION QUESTION
a.c.x.w.example. IN A
@@ -145,7 +145,6 @@ SECTION AUTHORITY
; 0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example. RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 ( 40430 example. OSgWSm26B+cS+dDL8b5QrWr/dEWhtCsKlwKL IBHYH6blRxK9rC0bMJPwQ4mLIuw85H2EY762 BOCXJZMnpuwhpA== )
; b4um86eghhds6nea196smvmlo4ors995.example. NSEC3 1 1 12 aabbccdd ( gjeqe526plbf1g8mklp59enfd789njgi MX RRSIG )
; b4um86eghhds6nea196smvmlo4ors995.example. RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 ( 40430 example. ZkPG3M32lmoHM6pa3D6gZFGB/rhL//Bs3Omh 5u4m/CUiwtblEVOaAKKZd7S959OeiX43aLX3 pOv0TSTyiTxIZg== )
SECTION ADDITIONAL
ENTRY_END
SCENARIO_END
+1 -3
View File
@@ -127,13 +127,11 @@ ENTRY_END
; recursion happens here.
STEP 10 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
MATCH all_noedns ede=12
REPLY QR RD RA DO SERVFAIL
SECTION QUESTION
ns1.example. IN MX
SECTION ANSWER
SECTION AUTHORITY
SECTION ADDITIONAL
ENTRY_END
SCENARIO_END
+1 -3
View File
@@ -186,13 +186,11 @@ ENTRY_END
; recursion happens here.
STEP 10 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
MATCH all_noedns ede=6
REPLY QR RD RA DO SERVFAIL
SECTION QUESTION
ent.example.com. IN A
SECTION ANSWER
SECTION AUTHORITY
SECTION ADDITIONAL
ENTRY_END
SCENARIO_END
+1 -3
View File
@@ -226,13 +226,11 @@ ENTRY_END
; recursion happens here.
STEP 10 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
MATCH all_noedns ede=9
REPLY QR RD RA DO SERVFAIL
SECTION QUESTION
www.sub.example.com. IN A
SECTION ANSWER
SECTION AUTHORITY
SECTION ADDITIONAL
ENTRY_END
SCENARIO_END
+1 -3
View File
@@ -58,13 +58,11 @@ ENTRY_END
; recursion happens here.
STEP 10 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
MATCH all_noedns ede=6
REPLY QR RD RA DO SERVFAIL
SECTION QUESTION
a.nsecwc.nlnetlabs.nl. IN TXT
SECTION ANSWER
SECTION AUTHORITY
SECTION ADDITIONAL
ENTRY_END
SCENARIO_END
+1 -3
View File
@@ -154,13 +154,11 @@ ENTRY_END
; recursion happens here.
STEP 10 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
MATCH all_noedns ede=6
REPLY QR RD RA DO SERVFAIL
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
SECTION AUTHORITY
SECTION ADDITIONAL
ENTRY_END
SCENARIO_END
+1 -1
View File
@@ -223,7 +223,7 @@ ENTRY_END
; recursion happens here.
STEP 10 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
MATCH all_noedns ede=10
REPLY QR RD RA DO SERVFAIL
SECTION QUESTION
www.sub.example.com. IN A
+1 -1
View File
@@ -165,7 +165,7 @@ ENTRY_END
; recursion happens here.
STEP 10 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
MATCH all_noedns ede=9
REPLY QR RD RA DO SERVFAIL
SECTION QUESTION
www.example.com. IN A
+47 -2
View File
@@ -373,6 +373,9 @@ config_create(void)
cfg->ipset_name_v4 = NULL;
cfg->ipset_name_v6 = NULL;
#endif
cfg->local_zone_do_ede = NULL;
cfg->local_zone_default_ede = NULL;
cfg->ede_local_zones = 0;
return cfg;
error_exit:
config_delete(cfg);
@@ -790,7 +793,8 @@ int config_set_option(struct config_file* cfg, const char* opt,
}
oi[cfg->num_out_ifs++] = d;
cfg->out_ifs = oi;
} else {
} else S_YNO("ede-local-zones:", ede_local_zones)
else {
/* unknown or unsupported (from the set_option interface):
* interface, outgoing-interface, access-control,
* stub-zone, name, stub-addr, stub-host, stub-prime
@@ -1239,6 +1243,8 @@ config_get_option(struct config_file* cfg, const char* opt,
#ifdef USE_IPSET
else O_STR(opt, "name-v4", ipset_name_v4)
else O_STR(opt, "name-v6", ipset_name_v6)
else O_LS3(opt, "local-zone-do-ede", local_zone_do_ede)
else O_LS3(opt, "local-zone-default-ede",local_zone_default_ede)
#endif
/* not here:
* outgoing-permit, outgoing-avoid - have list of ports
@@ -2545,6 +2551,7 @@ void errinf(struct module_qstate* qstate, const char* str)
}
p->next = NULL;
p->str = regional_strdup(qstate->region, str);
p->reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
if(!p->str) {
log_err("malloc failure in validator-error-info string");
return;
@@ -2552,7 +2559,34 @@ void errinf(struct module_qstate* qstate, const char* str)
/* add at end */
if(qstate->errinf) {
struct config_strlist* q = qstate->errinf;
while(q->next)
while(q->next)
q = q->next;
q->next = p;
} else qstate->errinf = p;
}
void errinf_ede(struct module_qstate* qstate,
const char* str, sldns_ede_code reason_bogus)
{
struct config_strlist* p;
if((qstate->env->cfg->val_log_level < 2 && !qstate->env->cfg->log_servfail) || !str)
return;
p = (struct config_strlist*)regional_alloc(qstate->region, sizeof(*p));
if(!p) {
log_err("malloc failure in validator-error-info string");
return;
}
p->next = NULL;
p->str = regional_strdup(qstate->region, str);
p->reason_bogus = reason_bogus;
if(!p->str) {
log_err("malloc failure in validator-error-info string");
return;
}
/* add at end */
if(qstate->errinf) {
struct config_strlist* q = qstate->errinf;
while(q->next)
q = q->next;
q->next = p;
} else qstate->errinf = p;
@@ -2603,6 +2637,17 @@ char* errinf_to_str_bogus(struct module_qstate* qstate)
return p;
}
sldns_ede_code errinf_to_reason_bogus(struct module_qstate* qstate)
{
struct config_strlist* s;
for(s=qstate->errinf; s; s=s->next) {
if (s->reason_bogus != LDNS_EDE_DNSSEC_BOGUS) {
return s->reason_bogus;
}
}
return LDNS_EDE_DNSSEC_BOGUS;
}
char* errinf_to_str_servfail(struct module_qstate* qstate)
{
char buf[20480];
+21
View File
@@ -41,6 +41,7 @@
#ifndef UTIL_CONFIG_FILE_H
#define UTIL_CONFIG_FILE_H
#include "sldns/rrdef.h"
struct config_stub;
struct config_auth;
struct config_view;
@@ -668,6 +669,13 @@ struct config_file {
char* ipset_name_v4;
char* ipset_name_v6;
#endif
/** should a local_zone results inlude an EDE (RFC8914) code? */
struct config_str2list* local_zone_do_ede;
/** which EDE (RFC8914) should be the default */
struct config_str2list* local_zone_default_ede;
/** should the default for local_zone results inlude an EDE (RFC8914) code?*/
int ede_local_zones;
};
/** from cfg username, after daemonize setup performed */
@@ -745,6 +753,8 @@ struct config_auth {
/** Always reply with this CNAME target if the cname override action is
* used */
char* rpz_cname;
/** Respond with EDEs (RFC 8914) for this zone */
int rpz_do_ede;
/** signal nxdomain block with unset RA */
int rpz_signal_nxdomain_ra;
/** Check ZONEMD records for this zone */
@@ -788,6 +798,8 @@ struct config_strlist {
struct config_strlist* next;
/** config option string */
char* str;
/** EDE code companion to the error str */
sldns_ede_code reason_bogus;
};
/**
@@ -1237,6 +1249,8 @@ char* cfg_ptr_reverse(char* str);
* Failures to allocate are logged.
*/
void errinf(struct module_qstate* qstate, const char* str);
void errinf_ede(struct module_qstate* qstate, const char* str,
sldns_ede_code reason_bogus);
/**
* Append text to error info: from 1.2.3.4
@@ -1271,6 +1285,13 @@ void errinf_dname(struct module_qstate* qstate, const char* str,
* This string is malloced and has to be freed by caller.
*/
char* errinf_to_str_bogus(struct module_qstate* qstate);
/**
* Check the sldns_ede_code of the qstate.
* @param qstate: query state.
* @return LDNS_EDE_DNSSEC_BOGUS by default, or another sldns_ede_code
* if this is set.
*/
sldns_ede_code errinf_to_reason_bogus(struct module_qstate* qstate);
/**
* Create error info in string. For other servfails.
+2856 -2806
View File
File diff suppressed because it is too large Load Diff
+4
View File
@@ -347,6 +347,7 @@ rpz-action-override{COLON} { YDVAR(1, VAR_RPZ_ACTION_OVERRIDE) }
rpz-cname-override{COLON} { YDVAR(1, VAR_RPZ_CNAME_OVERRIDE) }
rpz-log{COLON} { YDVAR(1, VAR_RPZ_LOG) }
rpz-log-name{COLON} { YDVAR(1, VAR_RPZ_LOG_NAME) }
rpz-do-ede{COLON} { YDVAR(1, VAR_RPZ_DO_EDE) }
rpz-signal-nxdomain-ra{COLON} { YDVAR(1, VAR_RPZ_SIGNAL_NXDOMAIN_RA) }
zonefile{COLON} { YDVAR(1, VAR_ZONEFILE) }
master{COLON} { YDVAR(1, VAR_MASTER) }
@@ -550,6 +551,9 @@ tcp-connection-limit{COLON} { YDVAR(2, VAR_TCP_CONNECTION_LIMIT) }
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 ) }
local-zone-do-ede{COLON} { YDVAR(2, VAR_LOCAL_DATA_DO_EDE) }
local-zone-default-ede{COLON} { YDVAR(2, VAR_LOCAL_ZONE_DEFAULT_EDE)}
ede-local-zones{COLON} { YDVAR(1, VAR_EDE_LOCAL_ZONES) }
<INITIAL,val>{NEWLINE} { LEXOUT(("NL\n")); cfg_parser->line++; }
/* Quoted strings. Strip leading and ending quotes */
+2044 -2633
View File
File diff suppressed because it is too large Load Diff
+31 -22
View File
@@ -1,8 +1,8 @@
/* A Bison parser, made by GNU Bison 3.6.4. */
/* A Bison parser, made by GNU Bison 3.7.6. */
/* Bison interface for Yacc-like parsers in C
Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2020 Free Software Foundation,
Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation,
Inc.
This program is free software: you can redistribute it and/or modify
@@ -16,7 +16,7 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
along with this program. If not, see <https://www.gnu.org/licenses/>. */
/* As a special exception, you may create a larger work that contains
part or all of the Bison parser skeleton and distribute that work
@@ -364,19 +364,24 @@ extern int yydebug;
VAR_RPZ_CNAME_OVERRIDE = 565, /* VAR_RPZ_CNAME_OVERRIDE */
VAR_RPZ_LOG = 566, /* VAR_RPZ_LOG */
VAR_RPZ_LOG_NAME = 567, /* VAR_RPZ_LOG_NAME */
VAR_DYNLIB = 568, /* VAR_DYNLIB */
VAR_DYNLIB_FILE = 569, /* VAR_DYNLIB_FILE */
VAR_EDNS_CLIENT_STRING = 570, /* VAR_EDNS_CLIENT_STRING */
VAR_EDNS_CLIENT_STRING_OPCODE = 571, /* VAR_EDNS_CLIENT_STRING_OPCODE */
VAR_NSID = 572, /* VAR_NSID */
VAR_ZONEMD_PERMISSIVE_MODE = 573, /* VAR_ZONEMD_PERMISSIVE_MODE */
VAR_ZONEMD_CHECK = 574, /* VAR_ZONEMD_CHECK */
VAR_ZONEMD_REJECT_ABSENCE = 575, /* VAR_ZONEMD_REJECT_ABSENCE */
VAR_RPZ_SIGNAL_NXDOMAIN_RA = 576 /* VAR_RPZ_SIGNAL_NXDOMAIN_RA */
VAR_RPZ_DO_EDE = 568, /* VAR_RPZ_DO_EDE */
VAR_DYNLIB = 569, /* VAR_DYNLIB */
VAR_DYNLIB_FILE = 570, /* VAR_DYNLIB_FILE */
VAR_EDNS_CLIENT_STRING = 571, /* VAR_EDNS_CLIENT_STRING */
VAR_EDNS_CLIENT_STRING_OPCODE = 572, /* VAR_EDNS_CLIENT_STRING_OPCODE */
VAR_NSID = 573, /* VAR_NSID */
VAR_ZONEMD_PERMISSIVE_MODE = 574, /* VAR_ZONEMD_PERMISSIVE_MODE */
VAR_ZONEMD_CHECK = 575, /* VAR_ZONEMD_CHECK */
VAR_ZONEMD_REJECT_ABSENCE = 576, /* VAR_ZONEMD_REJECT_ABSENCE */
VAR_LOCAL_DATA_DO_EDE = 577, /* VAR_LOCAL_DATA_DO_EDE */
VAR_LOCAL_ZONE_DEFAULT_EDE = 578, /* VAR_LOCAL_ZONE_DEFAULT_EDE */
VAR_EDE_LOCAL_ZONES = 579, /* VAR_EDE_LOCAL_ZONES */
VAR_RPZ_SIGNAL_NXDOMAIN_RA = 580 /* VAR_RPZ_SIGNAL_NXDOMAIN_RA */
};
typedef enum yytokentype yytoken_kind_t;
#endif
/* Token kinds. */
#define YYEMPTY -2
#define YYEOF 0
#define YYerror 256
#define YYUNDEF 257
@@ -690,15 +695,19 @@ extern int yydebug;
#define VAR_RPZ_CNAME_OVERRIDE 565
#define VAR_RPZ_LOG 566
#define VAR_RPZ_LOG_NAME 567
#define VAR_DYNLIB 568
#define VAR_DYNLIB_FILE 569
#define VAR_EDNS_CLIENT_STRING 570
#define VAR_EDNS_CLIENT_STRING_OPCODE 571
#define VAR_NSID 572
#define VAR_ZONEMD_PERMISSIVE_MODE 573
#define VAR_ZONEMD_CHECK 574
#define VAR_ZONEMD_REJECT_ABSENCE 575
#define VAR_RPZ_SIGNAL_NXDOMAIN_RA 576
#define VAR_RPZ_DO_EDE 568
#define VAR_DYNLIB 569
#define VAR_DYNLIB_FILE 570
#define VAR_EDNS_CLIENT_STRING 571
#define VAR_EDNS_CLIENT_STRING_OPCODE 572
#define VAR_NSID 573
#define VAR_ZONEMD_PERMISSIVE_MODE 574
#define VAR_ZONEMD_CHECK 575
#define VAR_ZONEMD_REJECT_ABSENCE 576
#define VAR_LOCAL_DATA_DO_EDE 577
#define VAR_LOCAL_ZONE_DEFAULT_EDE 578
#define VAR_EDE_LOCAL_ZONES 579
#define VAR_RPZ_SIGNAL_NXDOMAIN_RA 580
/* Value type. */
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
@@ -708,7 +717,7 @@ union YYSTYPE
char* str;
#line 712 "util/configparser.h"
#line 721 "util/configparser.h"
};
typedef union YYSTYPE YYSTYPE;
+75 -3
View File
@@ -183,10 +183,11 @@ extern struct config_parser_state* cfg_parser;
%token VAR_STREAM_WAIT_SIZE VAR_TLS_CIPHERS VAR_TLS_CIPHERSUITES VAR_TLS_USE_SNI
%token VAR_IPSET VAR_IPSET_NAME_V4 VAR_IPSET_NAME_V6
%token VAR_TLS_SESSION_TICKET_KEYS VAR_RPZ VAR_TAGS VAR_RPZ_ACTION_OVERRIDE
%token VAR_RPZ_CNAME_OVERRIDE VAR_RPZ_LOG VAR_RPZ_LOG_NAME
%token VAR_RPZ_CNAME_OVERRIDE VAR_RPZ_LOG VAR_RPZ_LOG_NAME VAR_RPZ_DO_EDE
%token VAR_DYNLIB VAR_DYNLIB_FILE VAR_EDNS_CLIENT_STRING
%token VAR_EDNS_CLIENT_STRING_OPCODE VAR_NSID
%token VAR_ZONEMD_PERMISSIVE_MODE VAR_ZONEMD_CHECK VAR_ZONEMD_REJECT_ABSENCE
%token VAR_LOCAL_DATA_DO_EDE VAR_LOCAL_ZONE_DEFAULT_EDE VAR_EDE_LOCAL_ZONES
%token VAR_RPZ_SIGNAL_NXDOMAIN_RA
%%
@@ -309,7 +310,9 @@ content_server: server_num_threads | server_verbosity | server_port |
server_tls_use_sni | server_edns_client_string |
server_edns_client_string_opcode | server_nsid |
server_zonemd_permissive_mode | server_max_reuse_tcp_queries |
server_tcp_reuse_timeout | server_tcp_auth_query_timeout
server_tcp_reuse_timeout | server_tcp_auth_query_timeout |
server_local_zone_do_ede | server_local_zone_default_ede |
server_ede_local_zones
;
stubstart: VAR_STUB_ZONE
@@ -466,6 +469,17 @@ rpz_signal_nxdomain_ra: VAR_RPZ_SIGNAL_NXDOMAIN_RA STRING_ARG
}
;
rpz_do_ede: VAR_RPZ_DO_EDE STRING_ARG
{
OUTYY(("P(rpz_do_ede:%s)\n", $2));
if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
yyerror("expected yes or no.");
else cfg_parser->cfg->auths->rpz_do_ede =
(strcmp($2, "yes")==0);
free($2);
}
;
rpzstart: VAR_RPZ
{
struct config_auth* s;
@@ -488,7 +502,7 @@ contents_rpz: contents_rpz content_rpz
| ;
content_rpz: auth_name | auth_zonefile | rpz_tag | auth_master | auth_url |
auth_allow_notify | rpz_action_override | rpz_cname_override |
rpz_log | rpz_log_name | rpz_signal_nxdomain_ra
rpz_log | rpz_log_name | rpz_do_ede | rpz_signal_nxdomain_ra
;
server_num_threads: VAR_NUM_THREADS STRING_ARG
{
@@ -2216,6 +2230,64 @@ server_local_data_ptr: VAR_LOCAL_DATA_PTR STRING_ARG
}
}
;
server_local_zone_do_ede: VAR_LOCAL_DATA_DO_EDE STRING_ARG STRING_ARG
{
OUTYY(("P(server_local_zone_do_ede:%s %s)\n", $2, $3));
if(strcmp($3, "yes") != 0 && strcmp($3, "no") != 0)
yyerror("expected yes or no.");
if(!cfg_str2list_insert(&cfg_parser->cfg->local_zone_do_ede,
$2, $3)) {
yyerror("out of memory adding local-zone-do-ede");
}
}
;
server_local_zone_default_ede: VAR_LOCAL_ZONE_DEFAULT_EDE STRING_ARG STRING_ARG
{
OUTYY(("P(server_local_zone_default_ede:%s %s)\n", $2, $3));
if (!(strcmp($3, "other") == 0) &&
!(strcmp($3, "unsupported-dnskey-algorithm") == 0) &&
!(strcmp($3, "unsupported-ds-digest-type") == 0) &&
!(strcmp($3, "stale-answer") == 0) &&
!(strcmp($3, "forged") == 0) &&
!(strcmp($3, "dnssec-indeterminate") == 0) &&
!(strcmp($3, "dnssec-bogus") == 0) &&
!(strcmp($3, "signature-expired") == 0) &&
!(strcmp($3, "signature-not-yet-valid") == 0) &&
!(strcmp($3, "dnskey-missing") == 0) &&
!(strcmp($3, "rrsigs-missing") == 0) &&
!(strcmp($3, "no-zone-key-bit-set") == 0) &&
!(strcmp($3, "nsec-missing") == 0) &&
!(strcmp($3, "cached-error") == 0) &&
!(strcmp($3, "not-ready") == 0) &&
!(strcmp($3, "blocked") == 0) &&
!(strcmp($3, "censored") == 0) &&
!(strcmp($3, "filtered") == 0) &&
!(strcmp($3, "prohibited") == 0) &&
!(strcmp($3, "stale-nxdomain-answer") == 0) &&
!(strcmp($3, "not-authoritative") == 0) &&
!(strcmp($3, "not-supported") == 0) &&
!(strcmp($3, "no-reachable-authority") == 0) &&
!(strcmp($3, "network-error") == 0) &&
!(strcmp($3, "invalid-data") == 0) &&
!(atoi($3) == 0))
yyerror("expected default-ede keyword or integer"
"refering to the respecive ede code");
if(!cfg_str2list_insert(&cfg_parser->cfg->local_zone_default_ede,
$2, $3)) {
yyerror("out of memory adding local-zone-default-ede");
}
}
;
server_ede_local_zones: VAR_EDE_LOCAL_ZONES STRING_ARG
{
OUTYY(("P(server_ede_local_zones:%s)\n", $2));
if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
yyerror("expected yes or no.");
else cfg_parser->cfg->ede_local_zones =
(strcmp($2, "yes")==0);
free($2);
}
;
server_minimal_responses: VAR_MINIMAL_RESPONSES STRING_ARG
{
OUTYY(("P(server_minimal_responses:%s)\n", $2));
+1 -1
View File
@@ -1157,7 +1157,7 @@ skip_pkt_rr(sldns_buffer* pkt)
}
/** skip RRs from packet */
static int
int
skip_pkt_rrs(sldns_buffer* pkt, int num)
{
int i;
+8
View File
@@ -293,6 +293,14 @@ int parse_packet(struct sldns_buffer* pkt, struct msg_parse* msg,
int parse_extract_edns_from_response_msg(struct msg_parse* msg,
struct edns_data* edns, struct regional* region);
/**
* Skip RRs from packet
* @param pkt:the packet. position at start must be right after the query
* section. At end, right after EDNS data or no movement if failed.
* @param num: Limit of the number of records we want to parse.
* @return: 0 on success, 1 on failure*/
int skip_pkt_rrs(struct sldns_buffer* pkt, int num);
/**
* If EDNS data follows a query section, extract it and initialize edns struct.
* @param pkt: the packet. position at start must be right after the query
+30
View File
@@ -117,6 +117,7 @@ construct_reply_info_base(struct regional* region, uint16_t flags, size_t qd,
rep->ar_numrrsets = ar;
rep->rrset_count = total;
rep->security = sec;
rep->reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
rep->authoritative = 0;
/* array starts after the refs */
if(region)
@@ -989,6 +990,35 @@ parse_reply_in_temp_region(sldns_buffer* pkt, struct regional* region,
return rep;
}
int edns_opt_list_append_ede(struct edns_option** list, struct regional* region,
sldns_ede_code code, const char *txt)
{
struct edns_option** prevp;
struct edns_option* opt;
size_t txt_len = txt ? strlen(txt) : 0;
/* allocate new element */
opt = (struct edns_option*)regional_alloc(region, sizeof(*opt));
if(!opt)
return 0;
opt->next = NULL;
opt->opt_code = LDNS_EDNS_EDE;
opt->opt_len = txt_len + sizeof(uint16_t);
opt->opt_data = regional_alloc(region, txt_len + sizeof(uint16_t));
if(!opt->opt_data)
return 0;
sldns_write_uint16(opt->opt_data, (uint16_t)code);
if (txt_len)
memmove(opt->opt_data + 2, txt, txt_len);
/* append at end of list */
prevp = list;
while(*prevp != NULL)
prevp = &((*prevp)->next);
*prevp = opt;
return 1;
}
int edns_opt_list_append(struct edns_option** list, uint16_t code, size_t len,
uint8_t* data, struct regional* region)
{
+35
View File
@@ -43,6 +43,7 @@
#define UTIL_DATA_MSGREPLY_H
#include "util/storage/lruhash.h"
#include "util/data/packed_rrset.h"
#include "sldns/rrdef.h"
struct sldns_buffer;
struct comm_reply;
struct alloc_cache;
@@ -167,6 +168,11 @@ struct reply_info {
*/
enum sec_status security;
/**
* EDE (rfc8914) code with reason for DNSSEC bogus status.
*/
sldns_ede_code reason_bogus;
/**
* Number of RRsets in each section.
* The answer section. Add up the RRs in every RRset to calculate
@@ -530,6 +536,35 @@ void log_query_info(enum verbosity_value v, const char* str,
int edns_opt_list_append(struct edns_option** list, uint16_t code, size_t len,
uint8_t* data, struct regional* region);
/**
* Append edns EDE option to edns options list
* @param LIST: the edns option list to append the edns option to.
* @param REGION: region to allocate the new edns option.
* @param CODE: the EDE code.
* @param TXT: Additional text for the option
*/
#define EDNS_OPT_LIST_APPEND_EDE(LIST, REGION, CODE, TXT) \
do { \
struct { \
uint16_t code; \
char text[sizeof(TXT) - 1]; \
} ede = { htons(CODE), TXT }; \
edns_opt_list_append((LIST), LDNS_EDNS_EDE, \
sizeof(uint16_t) + sizeof(TXT) - 1, \
(void *)&ede, (REGION)); \
} while(0)
/**
* Append edns EDE option to edns options list
* @param list: the edns option list to append the edns option to.
* @param region: region to allocate the new edns option.
* @param code: the EDE code.
* @param txt: Additional text for the option
* @return false on failure.
*/
int edns_opt_list_append_ede(struct edns_option** list, struct regional* region,
sldns_ede_code code, const char *txt);
/**
* Remove any option found on the edns option list that matches the code.
* @param list: the list of edns options.
+110 -11
View File
@@ -530,6 +530,24 @@ dnskeyset_verify_rrset(struct module_env* env, struct val_env* ve,
struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey,
uint8_t* sigalg, char** reason, sldns_pkt_section section,
struct module_qstate* qstate)
{
return dnskeyset_verify_rrset_ede(
env, ve, rrset, dnskey, sigalg, reason, NULL, section, qstate);
}
static enum sec_status
dnskeyset_verify_rrset_sig(struct module_env* env, struct val_env* ve,
time_t now, struct ub_packed_rrset_key* rrset,
struct ub_packed_rrset_key* dnskey, size_t sig_idx,
struct rbtree_type** sortree,
char** reason, sldns_ede_code *reason_bogus,
sldns_pkt_section section, struct module_qstate* qstate);
enum sec_status
dnskeyset_verify_rrset_ede(struct module_env* env, struct val_env* ve,
struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey,
uint8_t* sigalg, char** reason, sldns_ede_code *reason_bogus,
sldns_pkt_section section, struct module_qstate* qstate)
{
enum sec_status sec;
size_t i, num;
@@ -543,6 +561,8 @@ dnskeyset_verify_rrset(struct module_env* env, struct val_env* ve,
verbose(VERB_QUERY, "rrset failed to verify due to a lack of "
"signatures");
*reason = "no signatures";
if (reason_bogus)
*reason_bogus = LDNS_EDE_RRSIGS_MISSING;
return sec_status_bogus;
}
@@ -551,12 +571,15 @@ dnskeyset_verify_rrset(struct module_env* env, struct val_env* ve,
if(algo_needs_num_missing(&needs) == 0) {
verbose(VERB_QUERY, "zone has no known algorithms");
*reason = "zone has no known algorithms";
if (reason_bogus)
*reason_bogus = LDNS_EDE_UNSUPPORTED_DNSKEY_ALG;
return sec_status_insecure;
}
}
for(i=0; i<num; i++) {
sec = dnskeyset_verify_rrset_sig(env, ve, *env->now, rrset,
dnskey, i, &sortree, reason, section, qstate);
dnskey, i, &sortree, reason, reason_bogus,
section, qstate);
/* see which algorithm has been fixed up */
if(sec == sec_status_secure) {
if(!sigalg)
@@ -599,6 +622,25 @@ dnskey_verify_rrset(struct module_env* env, struct val_env* ve,
struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey,
size_t dnskey_idx, char** reason, sldns_pkt_section section,
struct module_qstate* qstate)
{
return dnskey_verify_rrset_ede(env, ve, rrset, dnskey, dnskey_idx,
reason, NULL, section, qstate);
}
static enum sec_status
dnskey_verify_rrset_sig_ede(struct regional* region, sldns_buffer* buf,
struct val_env* ve, time_t now,
struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey,
size_t dnskey_idx, size_t sig_idx,
struct rbtree_type** sortree, int* buf_canon,
char** reason, sldns_ede_code *reason_bogus,
sldns_pkt_section section, struct module_qstate* qstate);
enum sec_status
dnskey_verify_rrset_ede(struct module_env* env, struct val_env* ve,
struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey,
size_t dnskey_idx, char** reason, sldns_ede_code *reason_bogus,
sldns_pkt_section section, struct module_qstate* qstate)
{
enum sec_status sec;
size_t i, num, numchecked = 0;
@@ -612,6 +654,8 @@ dnskey_verify_rrset(struct module_env* env, struct val_env* ve,
verbose(VERB_QUERY, "rrset failed to verify due to a lack of "
"signatures");
*reason = "no signatures";
if(reason_bogus)
*reason_bogus = LDNS_EDE_RRSIGS_MISSING;
return sec_status_bogus;
}
for(i=0; i<num; i++) {
@@ -620,10 +664,10 @@ dnskey_verify_rrset(struct module_env* env, struct val_env* ve,
tag != rrset_get_sig_keytag(rrset, i))
continue;
buf_canon = 0;
sec = dnskey_verify_rrset_sig(env->scratch,
sec = dnskey_verify_rrset_sig_ede(env->scratch,
env->scratch_buffer, ve, *env->now, rrset,
dnskey, dnskey_idx, i, &sortree, &buf_canon, reason,
section, qstate);
reason_bogus, section, qstate);
if(sec == sec_status_secure)
return sec;
numchecked ++;
@@ -633,12 +677,13 @@ dnskey_verify_rrset(struct module_env* env, struct val_env* ve,
return sec_status_bogus;
}
enum sec_status
static enum sec_status
dnskeyset_verify_rrset_sig(struct module_env* env, struct val_env* ve,
time_t now, struct ub_packed_rrset_key* rrset,
struct ub_packed_rrset_key* dnskey, size_t sig_idx,
struct rbtree_type** sortree, char** reason, sldns_pkt_section section,
struct module_qstate* qstate)
struct rbtree_type** sortree,
char** reason, sldns_ede_code *reason_bogus,
sldns_pkt_section section, struct module_qstate* qstate)
{
/* find matching keys and check them */
enum sec_status sec = sec_status_bogus;
@@ -649,6 +694,8 @@ dnskeyset_verify_rrset_sig(struct module_env* env, struct val_env* ve,
int buf_canon = 0;
verbose(VERB_ALGO, "verify sig %d %d", (int)tag, algo);
if(!dnskey_algo_id_is_supported(algo)) {
if (reason_bogus)
*reason_bogus = LDNS_EDE_UNSUPPORTED_DNSKEY_ALG;
verbose(VERB_QUERY, "verify sig: unknown algorithm");
return sec_status_insecure;
}
@@ -661,14 +708,17 @@ dnskeyset_verify_rrset_sig(struct module_env* env, struct val_env* ve,
numchecked ++;
/* see if key verifies */
sec = dnskey_verify_rrset_sig(env->scratch,
sec = dnskey_verify_rrset_sig_ede(env->scratch,
env->scratch_buffer, ve, now, rrset, dnskey, i,
sig_idx, sortree, &buf_canon, reason, section, qstate);
sig_idx, sortree, &buf_canon, reason, reason_bogus,
section, qstate);
if(sec == sec_status_secure)
return sec;
}
if(numchecked == 0) {
*reason = "signatures from unknown keys";
if (reason_bogus)
*reason_bogus = LDNS_EDE_DNSKEY_MISSING;
verbose(VERB_QUERY, "verify: could not find appropriate key");
return sec_status_bogus;
}
@@ -1361,8 +1411,8 @@ subtract_1982(uint32_t a, uint32_t b)
/** check rrsig dates */
static int
check_dates(struct val_env* ve, uint32_t unow,
uint8_t* expi_p, uint8_t* incep_p, char** reason)
check_dates(struct val_env* ve, uint32_t unow, uint8_t* expi_p,
uint8_t* incep_p, char** reason, sldns_ede_code *reason_bogus)
{
/* read out the dates */
uint32_t expi, incep, now;
@@ -1386,6 +1436,14 @@ check_dates(struct val_env* ve, uint32_t unow,
sigdate_error("verify: inception after expiration, "
"signature bad", expi, incep, now);
*reason = "signature inception after expiration";
if (reason_bogus){
/* from RFC8914 on Signature Not Yet Valid: The resolver
* attempted to perform DNSSEC validation, but no
* signatures are presently valid and at least some are
* not yet valid. */
*reason_bogus = LDNS_EDE_SIGNATURE_NOT_YET_VALID;
}
return 0;
}
if(compare_1982(incep, now) > 0) {
@@ -1397,6 +1455,8 @@ check_dates(struct val_env* ve, uint32_t unow,
sigdate_error("verify: signature bad, current time is"
" before inception date", expi, incep, now);
*reason = "signature before inception date";
if (reason_bogus)
*reason_bogus = LDNS_EDE_SIGNATURE_NOT_YET_VALID;
return 0;
}
sigdate_error("verify warning suspicious signature inception "
@@ -1410,6 +1470,8 @@ check_dates(struct val_env* ve, uint32_t unow,
sigdate_error("verify: signature expired", expi,
incep, now);
*reason = "signature expired";
if (reason_bogus)
*reason_bogus = LDNS_EDE_SIGNATURE_EXPIRED;
return 0;
}
sigdate_error("verify warning suspicious signature expiration "
@@ -1475,6 +1537,20 @@ dnskey_verify_rrset_sig(struct regional* region, sldns_buffer* buf,
size_t dnskey_idx, size_t sig_idx,
struct rbtree_type** sortree, int* buf_canon, char** reason,
sldns_pkt_section section, struct module_qstate* qstate)
{
return dnskey_verify_rrset_sig_ede(region, buf, ve, now, rrset, dnskey,
dnskey_idx, sig_idx, sortree, buf_canon, reason, NULL,
section, qstate);
}
static enum sec_status
dnskey_verify_rrset_sig_ede(struct regional* region, sldns_buffer* buf,
struct val_env* ve, time_t now,
struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey,
size_t dnskey_idx, size_t sig_idx,
struct rbtree_type** sortree, int* buf_canon,
char** reason, sldns_ede_code *reason_bogus,
sldns_pkt_section section, struct module_qstate* qstate)
{
enum sec_status sec;
uint8_t* sig; /* RRSIG rdata */
@@ -1492,12 +1568,16 @@ dnskey_verify_rrset_sig(struct regional* region, sldns_buffer* buf,
if(siglen < 2+20) {
verbose(VERB_QUERY, "verify: signature too short");
*reason = "signature too short";
if(reason_bogus)
*reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
return sec_status_bogus;
}
if(!(dnskey_get_flags(dnskey, dnskey_idx) & DNSKEY_BIT_ZSK)) {
verbose(VERB_QUERY, "verify: dnskey without ZSK flag");
*reason = "dnskey without ZSK flag";
if(reason_bogus)
*reason_bogus = LDNS_EDE_NO_ZONE_KEY_BIT_SET;
return sec_status_bogus;
}
@@ -1505,6 +1585,8 @@ dnskey_verify_rrset_sig(struct regional* region, sldns_buffer* buf,
/* RFC 4034 says DNSKEY PROTOCOL MUST be 3 */
verbose(VERB_QUERY, "verify: dnskey has wrong key protocol");
*reason = "dnskey has wrong protocolnumber";
if(reason_bogus)
*reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
return sec_status_bogus;
}
@@ -1514,17 +1596,23 @@ dnskey_verify_rrset_sig(struct regional* region, sldns_buffer* buf,
if(!signer_len) {
verbose(VERB_QUERY, "verify: malformed signer name");
*reason = "signer name malformed";
if(reason_bogus)
*reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
return sec_status_bogus; /* signer name invalid */
}
if(!dname_subdomain_c(rrset->rk.dname, signer)) {
verbose(VERB_QUERY, "verify: signer name is off-tree");
*reason = "signer name off-tree";
if(reason_bogus)
*reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
return sec_status_bogus; /* signer name offtree */
}
sigblock = (unsigned char*)signer+signer_len;
if(siglen < 2+18+signer_len+1) {
verbose(VERB_QUERY, "verify: too short, no signature data");
*reason = "signature too short, no signature data";
if(reason_bogus)
*reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
return sec_status_bogus; /* sig rdf is < 1 byte */
}
sigblock_len = (unsigned int)(siglen - 2 - 18 - signer_len);
@@ -1537,6 +1625,8 @@ dnskey_verify_rrset_sig(struct regional* region, sldns_buffer* buf,
log_nametypeclass(VERB_QUERY, "the key name is",
dnskey->rk.dname, 0, 0);
*reason = "signer name mismatches key name";
if(reason_bogus)
*reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
return sec_status_bogus;
}
@@ -1545,18 +1635,24 @@ dnskey_verify_rrset_sig(struct regional* region, sldns_buffer* buf,
if(memcmp(sig+2, &rrset->rk.type, 2) != 0) {
verbose(VERB_QUERY, "verify: wrong type covered");
*reason = "signature covers wrong type";
if(reason_bogus)
*reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
return sec_status_bogus;
}
/* verify keytag and sig algo (possibly again) */
if((int)sig[2+2] != dnskey_get_algo(dnskey, dnskey_idx)) {
verbose(VERB_QUERY, "verify: wrong algorithm");
*reason = "signature has wrong algorithm";
if(reason_bogus)
*reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
return sec_status_bogus;
}
ktag = htons(dnskey_calc_keytag(dnskey, dnskey_idx));
if(memcmp(sig+2+16, &ktag, 2) != 0) {
verbose(VERB_QUERY, "verify: wrong keytag");
*reason = "signature has wrong keytag";
if(reason_bogus)
*reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
return sec_status_bogus;
}
@@ -1564,6 +1660,8 @@ dnskey_verify_rrset_sig(struct regional* region, sldns_buffer* buf,
if((int)sig[2+3] > dname_signame_label_count(rrset->rk.dname)) {
verbose(VERB_QUERY, "verify: labelcount out of range");
*reason = "signature labelcount out of range";
if(reason_bogus)
*reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
return sec_status_bogus;
}
@@ -1598,7 +1696,8 @@ dnskey_verify_rrset_sig(struct regional* region, sldns_buffer* buf,
/* verify inception, expiration dates
* Do this last so that if you ignore expired-sigs the
* rest is sure to be OK. */
if(!check_dates(ve, now, sig+2+8, sig+2+12, reason)) {
if(!check_dates(ve, now, sig+2+8, sig+2+12,
reason, reason_bogus)) {
return sec_status_bogus;
}
}
+15
View File
@@ -45,6 +45,7 @@
#define VALIDATOR_VAL_SIGCRYPT_H
#include "util/data/packed_rrset.h"
#include "sldns/pkthdr.h"
#include "sldns/rrdef.h"
struct val_env;
struct module_env;
struct module_qstate;
@@ -266,6 +267,12 @@ enum sec_status dnskeyset_verify_rrset(struct module_env* env,
struct val_env* ve, struct ub_packed_rrset_key* rrset,
struct ub_packed_rrset_key* dnskey, uint8_t* sigalg, char** reason,
sldns_pkt_section section, struct module_qstate* qstate);
enum sec_status dnskeyset_verify_rrset_ede(struct module_env* env,
struct val_env* ve, struct ub_packed_rrset_key* rrset,
struct ub_packed_rrset_key* dnskey, uint8_t* sigalg,
char** reason, sldns_ede_code *reason_bogus,
sldns_pkt_section section, struct module_qstate* qstate);
/**
* verify rrset against one specific dnskey (from rrset)
@@ -285,6 +292,13 @@ enum sec_status dnskey_verify_rrset(struct module_env* env,
struct ub_packed_rrset_key* dnskey, size_t dnskey_idx, char** reason,
sldns_pkt_section section, struct module_qstate* qstate);
enum sec_status
dnskey_verify_rrset_ede(struct module_env* env, struct val_env* ve,
struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey,
size_t dnskey_idx, char** reason, sldns_ede_code *reason_bogus,
sldns_pkt_section section, struct module_qstate* qstate);
#if 0
/**
* verify rrset, with dnskey rrset, for a specific rrsig in rrset
* @param env: module environment, scratch space is used.
@@ -306,6 +320,7 @@ enum sec_status dnskeyset_verify_rrset_sig(struct module_env* env,
struct ub_packed_rrset_key* dnskey, size_t sig_idx,
struct rbtree_type** sortree, char** reason, sldns_pkt_section section,
struct module_qstate* qstate);
#endif
/**
* verify rrset, with specific dnskey(from set), for a specific rrsig
+99 -23
View File
@@ -332,11 +332,11 @@ rrset_get_ttl(struct ub_packed_rrset_key* rrset)
return d->ttl;
}
enum sec_status
static enum sec_status
val_verify_rrset(struct module_env* env, struct val_env* ve,
struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* keys,
uint8_t* sigalg, char** reason, sldns_pkt_section section,
struct module_qstate* qstate)
uint8_t* sigalg, char** reason, sldns_ede_code *reason_bogus,
sldns_pkt_section section, struct module_qstate* qstate)
{
enum sec_status sec;
struct packed_rrset_data* d = (struct packed_rrset_data*)rrset->
@@ -358,8 +358,8 @@ val_verify_rrset(struct module_env* env, struct val_env* ve,
}
log_nametypeclass(VERB_ALGO, "verify rrset", rrset->rk.dname,
ntohs(rrset->rk.type), ntohs(rrset->rk.rrset_class));
sec = dnskeyset_verify_rrset(env, ve, rrset, keys, sigalg, reason,
section, qstate);
sec = dnskeyset_verify_rrset_ede(env, ve, rrset, keys, sigalg, reason,
reason_bogus, section, qstate);
verbose(VERB_ALGO, "verify result: %s", sec_status_to_string(sec));
regional_free_all(env->scratch);
@@ -393,6 +393,16 @@ enum sec_status
val_verify_rrset_entry(struct module_env* env, struct val_env* ve,
struct ub_packed_rrset_key* rrset, struct key_entry_key* kkey,
char** reason, sldns_pkt_section section, struct module_qstate* qstate)
{
return val_verify_rrset_entry_ede(
env, ve, rrset, kkey, reason, NULL, section, qstate);
}
enum sec_status
val_verify_rrset_entry_ede(struct module_env* env, struct val_env* ve,
struct ub_packed_rrset_key* rrset, struct key_entry_key* kkey,
char** reason, sldns_ede_code *reason_bogus,
sldns_pkt_section section, struct module_qstate* qstate)
{
/* temporary dnskey rrset-key */
struct ub_packed_rrset_key dnskey;
@@ -406,16 +416,28 @@ val_verify_rrset_entry(struct module_env* env, struct val_env* ve,
dnskey.entry.key = &dnskey;
dnskey.entry.data = kd->rrset_data;
sec = val_verify_rrset(env, ve, rrset, &dnskey, kd->algo, reason,
section, qstate);
reason_bogus, section, qstate);
return sec;
}
/** verify that a DS RR hashes to a key and that key signs the set */
#if 0
static enum sec_status
verify_dnskeys_with_ds_rr(struct module_env* env, struct val_env* ve,
struct ub_packed_rrset_key* dnskey_rrset,
struct ub_packed_rrset_key* ds_rrset, size_t ds_idx, char** reason,
struct module_qstate* qstate)
{
return verify_dnskeys_with_ds_rr_ede( env, ve, dnskey_rrset, ds_rrset,
ds_idx, reason, NULL, qstate);
}
#endif
static enum sec_status
verify_dnskeys_with_ds_rr_ede(struct module_env* env, struct val_env* ve,
struct ub_packed_rrset_key* dnskey_rrset,
struct ub_packed_rrset_key* ds_rrset, size_t ds_idx, char** reason,
sldns_ede_code *reason_bogus, struct module_qstate* qstate)
{
enum sec_status sec = sec_status_bogus;
size_t i, num, numchecked = 0, numhashok = 0, numsizesupp = 0;
@@ -450,8 +472,8 @@ verify_dnskeys_with_ds_rr(struct module_env* env, struct val_env* ve,
/* Otherwise, we have a match! Make sure that the DNSKEY
* verifies *with this key* */
sec = dnskey_verify_rrset(env, ve, dnskey_rrset,
dnskey_rrset, i, reason, LDNS_SECTION_ANSWER, qstate);
sec = dnskey_verify_rrset_ede(env, ve, dnskey_rrset, dnskey_rrset,
i, reason, reason_bogus, LDNS_SECTION_ANSWER, qstate);
if(sec == sec_status_secure) {
return sec;
}
@@ -488,11 +510,26 @@ int val_favorite_ds_algo(struct ub_packed_rrset_key* ds_rrset)
return digest_algo;
}
enum sec_status
/**
* This function (without EDE (RFC 8914)) is currently only used in
* authzone, after a zone-transfer. This does not invoke a query-response
* so we can leave this wrapper in-place.
*/
enum sec_status
val_verify_DNSKEY_with_DS(struct module_env* env, struct val_env* ve,
struct ub_packed_rrset_key* dnskey_rrset,
struct ub_packed_rrset_key* ds_rrset, uint8_t* sigalg, char** reason,
struct module_qstate* qstate)
{
return val_verify_DNSKEY_with_DS_ede(env, ve, dnskey_rrset, ds_rrset,
sigalg, reason, NULL, qstate);
}
enum sec_status
val_verify_DNSKEY_with_DS_ede(struct module_env* env, struct val_env* ve,
struct ub_packed_rrset_key* dnskey_rrset,
struct ub_packed_rrset_key* ds_rrset, uint8_t* sigalg, char** reason,
sldns_ede_code *reason_bogus, struct module_qstate* qstate)
{
/* as long as this is false, we can consider this DS rrset to be
* equivalent to no DS rrset. */
@@ -528,8 +565,8 @@ val_verify_DNSKEY_with_DS(struct module_env* env, struct val_env* ve,
continue;
}
sec = verify_dnskeys_with_ds_rr(env, ve, dnskey_rrset,
ds_rrset, i, reason, qstate);
sec = verify_dnskeys_with_ds_rr_ede(env, ve, dnskey_rrset,
ds_rrset, i, reason, reason_bogus, qstate);
if(sec == sec_status_insecure)
continue;
@@ -560,7 +597,7 @@ val_verify_DNSKEY_with_DS(struct module_env* env, struct val_env* ve,
if(!has_useful_ds) {
verbose(VERB_ALGO, "No usable DS records were found -- "
"treating as insecure.");
return sec_status_insecure;
return sec_status_insecure;
}
/* If any were understandable, then it is bad. */
verbose(VERB_QUERY, "Failed to match any usable DS to a DNSKEY.");
@@ -571,15 +608,26 @@ val_verify_DNSKEY_with_DS(struct module_env* env, struct val_env* ve,
return sec_status_bogus;
}
struct key_entry_key*
struct key_entry_key*
val_verify_new_DNSKEYs(struct regional* region, struct module_env* env,
struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset,
struct ub_packed_rrset_key* ds_rrset, int downprot, char** reason,
struct module_qstate* qstate)
{
return val_verify_new_DNSKEYs_ede(region, env, ve,dnskey_rrset, ds_rrset,
downprot, reason, NULL, qstate);
}
struct key_entry_key*
val_verify_new_DNSKEYs_ede(struct regional* region, struct module_env* env,
struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset,
struct ub_packed_rrset_key* ds_rrset, int downprot, char** reason,
sldns_ede_code *reason_bogus, struct module_qstate* qstate)
{
uint8_t sigalg[ALGO_NEEDS_MAX+1];
enum sec_status sec = val_verify_DNSKEY_with_DS(env, ve,
dnskey_rrset, ds_rrset, downprot?sigalg:NULL, reason, qstate);
enum sec_status sec = val_verify_DNSKEY_with_DS_ede(env, ve,
dnskey_rrset, ds_rrset, downprot?sigalg:NULL, reason,
reason_bogus, qstate);
if(sec == sec_status_secure) {
return key_entry_create_rrset(region,
@@ -597,12 +645,23 @@ val_verify_new_DNSKEYs(struct regional* region, struct module_env* env,
BOGUS_KEY_TTL, *env->now);
}
enum sec_status
enum sec_status
val_verify_DNSKEY_with_TA(struct module_env* env, struct val_env* ve,
struct ub_packed_rrset_key* dnskey_rrset,
struct ub_packed_rrset_key* ta_ds,
struct ub_packed_rrset_key* ta_dnskey, uint8_t* sigalg, char** reason,
struct module_qstate* qstate)
{
return val_verify_DNSKEY_with_TA_ede(env, ve, dnskey_rrset, ta_ds,
ta_dnskey, sigalg, reason, NULL, qstate);
}
enum sec_status
val_verify_DNSKEY_with_TA_ede(struct module_env* env, struct val_env* ve,
struct ub_packed_rrset_key* dnskey_rrset,
struct ub_packed_rrset_key* ta_ds,
struct ub_packed_rrset_key* ta_dnskey, uint8_t* sigalg, char** reason,
sldns_ede_code *reason_bogus, struct module_qstate* qstate)
{
/* as long as this is false, we can consider this anchor to be
* equivalent to no anchor. */
@@ -617,6 +676,8 @@ val_verify_DNSKEY_with_TA(struct module_env* env, struct val_env* ve,
verbose(VERB_QUERY, "DNSKEY RRset did not match DS RRset "
"by name");
*reason = "DNSKEY RRset did not match DS RRset by name";
if (reason_bogus)
*reason_bogus = LDNS_EDE_DNSKEY_MISSING;
return sec_status_bogus;
}
if(ta_dnskey && (dnskey_rrset->rk.dname_len != ta_dnskey->rk.dname_len
@@ -625,6 +686,8 @@ val_verify_DNSKEY_with_TA(struct module_env* env, struct val_env* ve,
verbose(VERB_QUERY, "DNSKEY RRset did not match anchor RRset "
"by name");
*reason = "DNSKEY RRset did not match anchor RRset by name";
if (reason_bogus)
*reason_bogus = LDNS_EDE_DNSKEY_MISSING;
return sec_status_bogus;
}
@@ -647,8 +710,8 @@ val_verify_DNSKEY_with_TA(struct module_env* env, struct val_env* ve,
ds_get_digest_algo(ta_ds, i) != digest_algo)
continue;
sec = verify_dnskeys_with_ds_rr(env, ve, dnskey_rrset,
ta_ds, i, reason, qstate);
sec = verify_dnskeys_with_ds_rr_ede(env, ve, dnskey_rrset,
ta_ds, i, reason, reason_bogus, qstate);
if(sec == sec_status_insecure)
continue;
@@ -721,26 +784,39 @@ val_verify_DNSKEY_with_TA(struct module_env* env, struct val_env* ve,
return sec_status_bogus;
}
#if 0
struct key_entry_key*
val_verify_new_DNSKEYs_with_ta(struct regional* region, struct module_env* env,
struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset,
struct ub_packed_rrset_key* ta_ds_rrset,
struct ub_packed_rrset_key* ta_dnskey_rrset, int downprot,
char** reason, struct module_qstate* qstate)
{
return val_verify_rrset_entry_ede(region, env, ve, dnskey_rrset,
ta_ds_rrset, ta_dnskey_rrset,downprot, reason, NULL, qstate);
}
#endif
struct key_entry_key*
val_verify_new_DNSKEYs_with_ta_ede(struct regional* region, struct module_env* env,
struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset,
struct ub_packed_rrset_key* ta_ds_rrset,
struct ub_packed_rrset_key* ta_dnskey_rrset, int downprot,
char** reason, sldns_ede_code *reason_bogus, struct module_qstate* qstate)
{
uint8_t sigalg[ALGO_NEEDS_MAX+1];
enum sec_status sec = val_verify_DNSKEY_with_TA(env, ve,
enum sec_status sec = val_verify_DNSKEY_with_TA_ede(env, ve,
dnskey_rrset, ta_ds_rrset, ta_dnskey_rrset,
downprot?sigalg:NULL, reason, qstate);
downprot?sigalg:NULL, reason, reason_bogus, qstate);
if(sec == sec_status_secure) {
return key_entry_create_rrset(region,
return key_entry_create_rrset(region,
dnskey_rrset->rk.dname, dnskey_rrset->rk.dname_len,
ntohs(dnskey_rrset->rk.rrset_class), dnskey_rrset,
downprot?sigalg:NULL, *env->now);
} else if(sec == sec_status_insecure) {
return key_entry_create_null(region, dnskey_rrset->rk.dname,
dnskey_rrset->rk.dname_len,
dnskey_rrset->rk.dname_len,
ntohs(dnskey_rrset->rk.rrset_class),
rrset_get_ttl(dnskey_rrset), *env->now);
}
@@ -749,7 +825,7 @@ val_verify_new_DNSKEYs_with_ta(struct regional* region, struct module_env* env,
BOGUS_KEY_TTL, *env->now);
}
int
int
val_dsset_isusable(struct ub_packed_rrset_key* ds_rrset)
{
size_t i;
+32
View File
@@ -43,6 +43,7 @@
#define VALIDATOR_VAL_UTILS_H
#include "util/data/packed_rrset.h"
#include "sldns/pkthdr.h"
#include "sldns/rrdef.h"
struct query_info;
struct reply_info;
struct val_env;
@@ -113,6 +114,7 @@ void val_find_signer(enum val_classification subtype,
struct query_info* qinf, struct reply_info* rep,
size_t cname_skip, uint8_t** signer_name, size_t* signer_len);
#if 0
/**
* Verify RRset with keys
* @param env: module environment (scratch buffer)
@@ -130,6 +132,7 @@ enum sec_status val_verify_rrset(struct module_env* env, struct val_env* ve,
struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* keys,
uint8_t* sigalg, char** reason, sldns_pkt_section section,
struct module_qstate* qstate);
#endif
/**
* Verify RRset with keys from a keyset.
@@ -147,6 +150,12 @@ enum sec_status val_verify_rrset_entry(struct module_env* env,
struct key_entry_key* kkey, char** reason, sldns_pkt_section section,
struct module_qstate* qstate);
enum sec_status val_verify_rrset_entry_ede(struct module_env* env,
struct val_env* ve, struct ub_packed_rrset_key* rrset,
struct key_entry_key* kkey, char** reason, sldns_ede_code *reason_bogus,
sldns_pkt_section section, struct module_qstate* qstate);
/**
* Verify DNSKEYs with DS rrset. Like val_verify_new_DNSKEYs but
* returns a sec_status instead of a key_entry.
@@ -168,6 +177,11 @@ enum sec_status val_verify_DNSKEY_with_DS(struct module_env* env,
struct ub_packed_rrset_key* ds_rrset, uint8_t* sigalg, char** reason,
struct module_qstate* qstate);
enum sec_status val_verify_DNSKEY_with_DS_ede(struct module_env* env,
struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset,
struct ub_packed_rrset_key* ds_rrset, uint8_t* sigalg, char** reason,
sldns_ede_code *reason_bogus, struct module_qstate* qstate);
/**
* Verify DNSKEYs with DS and DNSKEY rrset. Like val_verify_DNSKEY_with_DS
* but for a trust anchor.
@@ -191,6 +205,12 @@ enum sec_status val_verify_DNSKEY_with_TA(struct module_env* env,
struct ub_packed_rrset_key* ta_dnskey, uint8_t* sigalg, char** reason,
struct module_qstate* qstate);
enum sec_status val_verify_DNSKEY_with_TA_ede(struct module_env* env,
struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset,
struct ub_packed_rrset_key* ta_ds,
struct ub_packed_rrset_key* ta_dnskey, uint8_t* sigalg, char** reason,
sldns_ede_code *reason_bogus, struct module_qstate* qstate);
/**
* Verify new DNSKEYs with DS rrset. The DS contains hash values that should
* match the DNSKEY keys.
@@ -221,6 +241,11 @@ struct key_entry_key* val_verify_new_DNSKEYs(struct regional* region,
struct ub_packed_rrset_key* ds_rrset, int downprot, char** reason,
struct module_qstate* qstate);
struct key_entry_key* val_verify_new_DNSKEYs_ede(struct regional* region,
struct module_env* env, struct val_env* ve,
struct ub_packed_rrset_key* dnskey_rrset,
struct ub_packed_rrset_key* ds_rrset, int downprot, char** reason,
sldns_ede_code *reason_bogus, struct module_qstate* qstate);
/**
* Verify rrset with trust anchor: DS and DNSKEY rrset.
@@ -252,6 +277,13 @@ struct key_entry_key* val_verify_new_DNSKEYs_with_ta(struct regional* region,
struct ub_packed_rrset_key* ta_dnskey_rrset,
int downprot, char** reason, struct module_qstate* qstate);
struct key_entry_key* val_verify_new_DNSKEYs_with_ta_ede(struct regional* region,
struct module_env* env, struct val_env* ve,
struct ub_packed_rrset_key* dnskey_rrset,
struct ub_packed_rrset_key* ta_ds_rrset,
struct ub_packed_rrset_key* ta_dnskey_rrset, int downprot,
char** reason, sldns_ede_code *reason_bogus, struct module_qstate* qstate);
/**
* Determine if DS rrset is usable for validator or not.
* Returns true if the algorithms for key and DShash are supported,
+51 -26
View File
@@ -592,6 +592,7 @@ validate_msg_signatures(struct module_qstate* qstate, struct module_env* env,
enum sec_status sec;
int dname_seen = 0;
char* reason = NULL;
sldns_ede_code reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
/* validate the ANSWER section */
for(i=0; i<chase_reply->an_numrrsets; i++) {
@@ -612,8 +613,8 @@ validate_msg_signatures(struct module_qstate* qstate, struct module_env* env,
}
/* Verify the answer rrset */
sec = val_verify_rrset_entry(env, ve, s, key_entry, &reason,
LDNS_SECTION_ANSWER, qstate);
sec = val_verify_rrset_entry_ede(env, ve, s, key_entry, &reason,
&reason_bogus, LDNS_SECTION_ANSWER, qstate);
/* If the (answer) rrset failed to validate, then this
* message is BAD. */
if(sec != sec_status_secure) {
@@ -627,6 +628,7 @@ validate_msg_signatures(struct module_qstate* qstate, struct module_env* env,
errinf(qstate, "for DNAME");
errinf_origin(qstate, qstate->reply_origin);
chase_reply->security = sec_status_bogus;
chase_reply->reason_bogus = reason_bogus;
return 0;
}
@@ -642,8 +644,8 @@ validate_msg_signatures(struct module_qstate* qstate, struct module_env* env,
for(i=chase_reply->an_numrrsets; i<chase_reply->an_numrrsets+
chase_reply->ns_numrrsets; i++) {
s = chase_reply->rrsets[i];
sec = val_verify_rrset_entry(env, ve, s, key_entry, &reason,
LDNS_SECTION_AUTHORITY, qstate);
sec = val_verify_rrset_entry_ede(env, ve, s, key_entry, &reason,
&reason_bogus, LDNS_SECTION_AUTHORITY, qstate);
/* If anything in the authority section fails to be secure,
* we have a bad message. */
if(sec != sec_status_secure) {
@@ -654,6 +656,7 @@ validate_msg_signatures(struct module_qstate* qstate, struct module_env* env,
errinf_origin(qstate, qstate->reply_origin);
errinf_rrset(qstate, s);
chase_reply->security = sec_status_bogus;
chase_reply->reason_bogus = reason_bogus;
return 0;
}
}
@@ -669,6 +672,7 @@ validate_msg_signatures(struct module_qstate* qstate, struct module_env* env,
/* only validate rrs that have signatures with the key */
/* leave others unchecked, those get removed later on too */
val_find_rrset_signer(s, &sname, &slen);
if(sname && query_dname_compare(sname, key_entry->name)==0)
(void)val_verify_rrset_entry(env, ve, s, key_entry,
&reason, LDNS_SECTION_ADDITIONAL, qstate);
@@ -1557,6 +1561,7 @@ processInit(struct module_qstate* qstate, struct val_qstate* vq,
verbose(VERB_QUERY, "unsigned parent zone denies"
" trust anchor, indeterminate");
vq->chase_reply->security = sec_status_indeterminate;
vq->chase_reply->reason_bogus = LDNS_EDE_DNSSEC_INDETERMINATE;
vq->state = VAL_FINISHED_STATE;
return 1;
}
@@ -1588,6 +1593,7 @@ processInit(struct module_qstate* qstate, struct val_qstate* vq,
if(vq->key_entry == NULL && anchor == NULL) {
/*response isn't under a trust anchor, so we cannot validate.*/
vq->chase_reply->security = sec_status_indeterminate;
vq->chase_reply->reason_bogus = LDNS_EDE_DNSSEC_INDETERMINATE;
/* go to finished state to cache this result */
vq->state = VAL_FINISHED_STATE;
return 1;
@@ -1635,7 +1641,7 @@ processInit(struct module_qstate* qstate, struct val_qstate* vq,
} else if(key_entry_isbad(vq->key_entry)) {
/* key is bad, chain is bad, reply is bogus */
errinf_dname(qstate, "key for validation", vq->key_entry->name);
errinf(qstate, "is marked as invalid");
errinf_ede(qstate, "is marked as invalid", LDNS_EDE_DNSSEC_BOGUS);
if(key_entry_get_reason(vq->key_entry)) {
errinf(qstate, "because of a previous");
errinf(qstate, key_entry_get_reason(vq->key_entry));
@@ -1643,6 +1649,7 @@ processInit(struct module_qstate* qstate, struct val_qstate* vq,
/* no retries, stop bothering the authority until timeout */
vq->restart_count = ve->max_restart;
vq->chase_reply->security = sec_status_bogus;
vq->chase_reply->reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
vq->state = VAL_FINISHED_STATE;
return 1;
}
@@ -1713,9 +1720,10 @@ processFindKey(struct module_qstate* qstate, struct val_qstate* vq, int id)
vq->empty_DS_name) == 0) {
/* do not query for empty_DS_name again */
verbose(VERB_ALGO, "Cannot retrieve DS for signature");
errinf(qstate, "no signatures");
errinf_ede(qstate, "no signatures", LDNS_EDE_RRSIGS_MISSING);
errinf_origin(qstate, qstate->reply_origin);
vq->chase_reply->security = sec_status_bogus;
vq->chase_reply->reason_bogus = LDNS_EDE_RRSIGS_MISSING;
vq->state = VAL_FINISHED_STATE;
return 1;
}
@@ -1848,7 +1856,9 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq,
"of trust to keys for", vq->key_entry->name,
LDNS_RR_TYPE_DNSKEY, vq->key_entry->key_class);
vq->chase_reply->security = sec_status_bogus;
errinf(qstate, "while building chain of trust");
vq->chase_reply->reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
errinf_ede(qstate, "while building chain of trust",
LDNS_EDE_DNSKEY_MISSING);
if(vq->restart_count >= ve->max_restart)
key_cache_insert(ve->kcache, vq->key_entry, qstate);
return 1;
@@ -1861,9 +1871,10 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq,
"signer name", &vq->qchase);
verbose(VERB_DETAIL, "Could not establish validation of "
"INSECURE status of unsigned response.");
errinf(qstate, "no signatures");
errinf_ede(qstate, "no signatures", LDNS_EDE_RRSIGS_MISSING);
errinf_origin(qstate, qstate->reply_origin);
vq->chase_reply->security = sec_status_bogus;
vq->chase_reply->reason_bogus = LDNS_EDE_RRSIGS_MISSING;
return 1;
}
subtype = val_classify_response(qstate->query_flags, &qstate->qinfo,
@@ -2001,17 +2012,21 @@ processFinished(struct module_qstate* qstate, struct val_qstate* vq,
vq->orig_msg->rep, vq->rrset_skip);
/* store overall validation result in orig_msg */
if(vq->rrset_skip == 0)
if(vq->rrset_skip == 0) {
vq->orig_msg->rep->security = vq->chase_reply->security;
else if(subtype != VAL_CLASS_REFERRAL ||
vq->orig_msg->rep->reason_bogus = vq->chase_reply->reason_bogus;
} else if(subtype != VAL_CLASS_REFERRAL ||
vq->rrset_skip < vq->orig_msg->rep->an_numrrsets +
vq->orig_msg->rep->ns_numrrsets) {
/* ignore sec status of additional section if a referral
* type message skips there and
* use the lowest security status as end result. */
if(vq->chase_reply->security < vq->orig_msg->rep->security)
if(vq->chase_reply->security < vq->orig_msg->rep->security) {
vq->orig_msg->rep->security =
vq->chase_reply->security;
vq->orig_msg->rep->reason_bogus =
vq->chase_reply->reason_bogus;
}
}
if(subtype == VAL_CLASS_REFERRAL) {
@@ -2304,6 +2319,7 @@ primeResponseToKE(struct ub_packed_rrset_key* dnskey_rrset,
struct key_entry_key* kkey = NULL;
enum sec_status sec = sec_status_unchecked;
char* reason = NULL;
sldns_ede_code reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
int downprot = qstate->env->cfg->harden_algo_downgrade;
if(!dnskey_rrset) {
@@ -2311,7 +2327,7 @@ primeResponseToKE(struct ub_packed_rrset_key* dnskey_rrset,
"could not fetch DNSKEY rrset",
ta->name, LDNS_RR_TYPE_DNSKEY, ta->dclass);
if(qstate->env->cfg->harden_dnssec_stripped) {
errinf(qstate, "no DNSKEY rrset");
errinf_ede(qstate, "no DNSKEY rrset", LDNS_EDE_DNSKEY_MISSING);
kkey = key_entry_create_bad(qstate->region, ta->name,
ta->namelen, ta->dclass, BOGUS_KEY_TTL,
*qstate->env->now);
@@ -2325,9 +2341,9 @@ primeResponseToKE(struct ub_packed_rrset_key* dnskey_rrset,
return kkey;
}
/* attempt to verify with trust anchor DS and DNSKEY */
kkey = val_verify_new_DNSKEYs_with_ta(qstate->region, qstate->env, ve,
kkey = val_verify_new_DNSKEYs_with_ta_ede(qstate->region, qstate->env, ve,
dnskey_rrset, ta->ds_rrset, ta->dnskey_rrset, downprot,
&reason, qstate);
&reason, &reason_bogus, qstate);
if(!kkey) {
log_err("out of memory: verifying prime TA");
return NULL;
@@ -2346,7 +2362,7 @@ primeResponseToKE(struct ub_packed_rrset_key* dnskey_rrset,
/* NOTE: in this case, we should probably reject the trust
* anchor for longer, perhaps forever. */
if(qstate->env->cfg->harden_dnssec_stripped) {
errinf(qstate, reason);
errinf_ede(qstate, reason, reason_bogus);
kkey = key_entry_create_bad(qstate->region, ta->name,
ta->namelen, ta->dclass, BOGUS_KEY_TTL,
*qstate->env->now);
@@ -2389,6 +2405,7 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
{
struct val_env* ve = (struct val_env*)qstate->env->modinfo[id];
char* reason = NULL;
sldns_ede_code reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
enum val_classification subtype;
if(rcode != LDNS_RCODE_NOERROR) {
char rc[16];
@@ -2397,7 +2414,8 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
/* errors here pretty much break validation */
verbose(VERB_DETAIL, "DS response was error, thus bogus");
errinf(qstate, rc);
errinf(qstate, "no DS");
errinf_ede(qstate, "no DS", reason_bogus);
goto return_bogus;
}
@@ -2411,17 +2429,17 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
if(!ds) {
log_warn("internal error: POSITIVE DS response was "
"missing DS.");
errinf(qstate, "no DS record");
errinf_ede(qstate, "no DS record", reason_bogus);
goto return_bogus;
}
/* Verify only returns BOGUS or SECURE. If the rrset is
* bogus, then we are done. */
sec = val_verify_rrset_entry(qstate->env, ve, ds,
vq->key_entry, &reason, LDNS_SECTION_ANSWER, qstate);
sec = val_verify_rrset_entry_ede(qstate->env, ve, ds,
vq->key_entry, &reason, &reason_bogus, LDNS_SECTION_ANSWER, qstate);
if(sec != sec_status_secure) {
verbose(VERB_DETAIL, "DS rrset in DS response did "
"not verify");
errinf(qstate, reason);
errinf_ede(qstate, reason, reason_bogus);
goto return_bogus;
}
@@ -2430,6 +2448,9 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
if(!val_dsset_isusable(ds)) {
/* If they aren't usable, then we treat it like
* there was no DS. */
// @TODO add EDE Unsupported DS Digest Type
*ke = key_entry_create_null(qstate->region,
qinfo->qname, qinfo->qname_len, qinfo->qclass,
ub_packed_rrset_ttl(ds), *qstate->env->now);
@@ -2452,7 +2473,7 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
/* make sure there are NSECs or NSEC3s with signatures */
if(!val_has_signed_nsecs(msg->rep, &reason)) {
verbose(VERB_ALGO, "no NSECs: %s", reason);
errinf(qstate, reason);
errinf_ede(qstate, reason, LDNS_EDE_NSEC_MISSING);
goto return_bogus;
}
@@ -2676,7 +2697,7 @@ process_ds_response(struct module_qstate* qstate, struct val_qstate* vq,
* @param origin: the origin of msg.
*/
static void
process_dnskey_response(struct module_qstate* qstate, struct val_qstate* vq,
process_dnskey_response(struct module_qstate* qstate, struct val_qstate* vq,
int id, int rcode, struct dns_msg* msg, struct query_info* qinfo,
struct sock_list* origin)
{
@@ -2685,6 +2706,7 @@ process_dnskey_response(struct module_qstate* qstate, struct val_qstate* vq,
struct ub_packed_rrset_key* dnskey = NULL;
int downprot;
char* reason = NULL;
sldns_ede_code reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
if(rcode == LDNS_RCODE_NOERROR)
dnskey = reply_find_answer_rrset(qinfo, msg->rep);
@@ -2693,6 +2715,9 @@ process_dnskey_response(struct module_qstate* qstate, struct val_qstate* vq,
/* bad response */
verbose(VERB_DETAIL, "Missing DNSKEY RRset in response to "
"DNSKEY query.");
reason_bogus = LDNS_EDE_DNSKEY_MISSING;
if(vq->restart_count < ve->max_restart) {
val_blacklist(&vq->chain_blacklist, qstate->region,
origin, 1);
@@ -2707,7 +2732,7 @@ process_dnskey_response(struct module_qstate* qstate, struct val_qstate* vq,
log_err("alloc failure in missing dnskey response");
/* key_entry is NULL for failure in Validate */
}
errinf(qstate, "No DNSKEY record");
errinf_ede(qstate, "No DNSKEY record", reason_bogus);
errinf_origin(qstate, origin);
errinf_dname(qstate, "for key", qinfo->qname);
vq->state = VAL_VALIDATE_STATE;
@@ -2720,8 +2745,8 @@ process_dnskey_response(struct module_qstate* qstate, struct val_qstate* vq,
return;
}
downprot = qstate->env->cfg->harden_algo_downgrade;
vq->key_entry = val_verify_new_DNSKEYs(qstate->region, qstate->env,
ve, dnskey, vq->ds_rrset, downprot, &reason, qstate);
vq->key_entry = val_verify_new_DNSKEYs_ede(qstate->region, qstate->env,
ve, dnskey, vq->ds_rrset, downprot, &reason, &reason_bogus, qstate);
if(!vq->key_entry) {
log_err("out of memory in verify new DNSKEYs");
@@ -2742,7 +2767,7 @@ process_dnskey_response(struct module_qstate* qstate, struct val_qstate* vq,
}
verbose(VERB_DETAIL, "Did not match a DS to a DNSKEY, "
"thus bogus.");
errinf(qstate, reason);
errinf_ede(qstate, reason, reason_bogus);
errinf_origin(qstate, origin);
errinf_dname(qstate, "for key", qinfo->qname);
}