mirror of
https://github.com/NLnetLabs/unbound.git
synced 2026-08-17 21:25:50 +02:00
Compare commits
69
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8c96e26074 | ||
|
|
9ae988cea6 | ||
|
|
80957b6da3 | ||
|
|
69e188b5cf | ||
|
|
49f2960089 | ||
|
|
94f04a77d9 | ||
|
|
fe8ef6e53d | ||
|
|
79024484a7 | ||
|
|
05e06fdcf5 | ||
|
|
df229db074 | ||
|
|
4f37d6489e | ||
|
|
ea1a5f35e4 | ||
|
|
dc38aacefc | ||
|
|
63e6604b2a | ||
|
|
65ee2f2c39 | ||
|
|
db98a8b825 | ||
|
|
3ccb4c6c26 | ||
|
|
ff356b940b | ||
|
|
7926874669 | ||
|
|
575a6865be | ||
|
|
0572870592 | ||
|
|
0747d016e4 | ||
|
|
4a43aee99e | ||
|
|
a3171a1d48 | ||
|
|
f22e42f554 | ||
|
|
787d7a5952 | ||
|
|
0eba781ed3 | ||
|
|
df984d9c6f | ||
|
|
fed0fb42dd | ||
|
|
abd948f3d7 | ||
|
|
f7bb7f2a94 | ||
|
|
9bff0b94dd | ||
|
|
d2a719f606 | ||
|
|
b825bb668d | ||
|
|
8a6b3f088b | ||
|
|
86e8050352 | ||
|
|
c42c2cbbff | ||
|
|
7df2df0fc9 | ||
|
|
320aa64d18 | ||
|
|
3ba8ea321a | ||
|
|
42ba5ae4a2 | ||
|
|
732ad94729 | ||
|
|
84da2409b3 | ||
|
|
0b376cc42f | ||
|
|
b606c8273d | ||
|
|
4df2965459 | ||
|
|
65852bcbc4 | ||
|
|
4d15603a8c | ||
|
|
5617de6867 | ||
|
|
3576033b62 | ||
|
|
a664e8cec4 | ||
|
|
2360120562 | ||
|
|
9df75a842b | ||
|
|
7079f0b5aa | ||
|
|
33445be8df | ||
|
|
fba1c302ac | ||
|
|
ec4cf69eb7 | ||
|
|
d9a947f267 | ||
|
|
a98659791e | ||
|
|
5fff0f7e30 | ||
|
|
935634dcae | ||
|
|
b3f60db184 | ||
|
|
a9e6f6bc23 | ||
|
|
6b5f314a3a | ||
|
|
eac4eb3a9e | ||
|
|
0703a38243 | ||
|
|
4049885da2 | ||
|
|
a8d78b2083 | ||
|
|
285f93ff82 |
+120
@@ -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
@@ -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
@@ -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
@@ -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 */
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -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
|
||||
|
||||
Vendored
+1
-1
@@ -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
|
||||
|
||||
Vendored
+1
-1
@@ -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
|
||||
|
||||
Vendored
+1
-1
@@ -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
|
||||
|
||||
Vendored
+2
-2
@@ -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
|
||||
|
||||
Vendored
+2
-2
@@ -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
|
||||
|
||||
Vendored
+2
-2
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
Vendored
+25
@@ -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"
|
||||
|
||||
Vendored
+56
@@ -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@
|
||||
|
||||
Vendored
+16
@@ -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:
|
||||
Vendored
+31
@@ -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
|
||||
|
||||
Vendored
+32
@@ -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
|
||||
|
||||
Vendored
+203
@@ -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
|
||||
Vendored
+1
-5
@@ -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
|
||||
|
||||
Vendored
+2
-2
@@ -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
|
||||
|
||||
Vendored
+1
-1
@@ -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
@@ -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
|
||||
|
||||
Vendored
+1
-3
@@ -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
|
||||
|
||||
Vendored
+1
-1
@@ -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
|
||||
|
||||
Vendored
+1
-3
@@ -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
|
||||
|
||||
Vendored
+1
-2
@@ -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
|
||||
|
||||
Vendored
+2
-1
@@ -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
|
||||
|
||||
Vendored
+1
-3
@@ -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
|
||||
|
||||
Vendored
+1
-3
@@ -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
|
||||
|
||||
Vendored
+1
-1
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
Vendored
+1
-3
@@ -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
|
||||
|
||||
Vendored
+1
-3
@@ -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
|
||||
|
||||
Vendored
+1
-3
@@ -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
|
||||
|
||||
Vendored
+1
-1
@@ -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
|
||||
|
||||
Vendored
+1
-1
@@ -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
@@ -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];
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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
File diff suppressed because it is too large
Load Diff
+31
-22
@@ -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
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user