summaryrefslogtreecommitdiff
path: root/usr.sbin/unbound
diff options
context:
space:
mode:
authorStuart Henderson <sthen@cvs.openbsd.org>2022-06-07 15:40:05 +0000
committerStuart Henderson <sthen@cvs.openbsd.org>2022-06-07 15:40:05 +0000
commitcc53b6cd1e045f1be19cb4ca4729fa99b75576ba (patch)
treeaeb9d773a05c2e96cb6a09baf8b00070bcb45655 /usr.sbin/unbound
parent416e774a6cce51d7a46f4dec30d036f9cd31f95e (diff)
update to unbound 1.16.0, discussed with florian@, test from Renaud Allard
Diffstat (limited to 'usr.sbin/unbound')
-rw-r--r--usr.sbin/unbound/ipset/ipset.c71
-rw-r--r--usr.sbin/unbound/services/rpz.c41
-rw-r--r--usr.sbin/unbound/services/rpz.h4
-rw-r--r--usr.sbin/unbound/sldns/pkthdr.h4
-rw-r--r--usr.sbin/unbound/testcode/testpkts.c129
-rw-r--r--usr.sbin/unbound/testcode/testpkts.h59
-rw-r--r--usr.sbin/unbound/testcode/unitldns.c14
-rw-r--r--usr.sbin/unbound/testcode/unitmsgparse.c2
-rw-r--r--usr.sbin/unbound/testcode/unitverify.c2
-rw-r--r--usr.sbin/unbound/testcode/unitzonemd.c4
-rw-r--r--usr.sbin/unbound/validator/val_kcache.c1
-rw-r--r--usr.sbin/unbound/validator/val_kentry.c20
-rw-r--r--usr.sbin/unbound/validator/val_kentry.h19
13 files changed, 287 insertions, 83 deletions
diff --git a/usr.sbin/unbound/ipset/ipset.c b/usr.sbin/unbound/ipset/ipset.c
index f6e2c4a9d8a..c61ebc205ee 100644
--- a/usr.sbin/unbound/ipset/ipset.c
+++ b/usr.sbin/unbound/ipset/ipset.c
@@ -138,10 +138,10 @@ ipset_add_rrset_data(struct ipset_env *ie, struct mnl_socket *mnl,
static int
ipset_check_zones_for_rrset(struct module_env *env, struct ipset_env *ie,
struct mnl_socket *mnl, struct ub_packed_rrset_key *rrset,
- const char *setname, int af)
+ const char *qname, const int qlen, const char *setname, int af)
{
static char dname[BUFF_LEN];
- const char *s;
+ const char *ds, *qs;
int dlen, plen;
struct config_strlist *p;
@@ -152,70 +152,73 @@ ipset_check_zones_for_rrset(struct module_env *env, struct ipset_env *ie,
log_err("bad domain name");
return -1;
}
- if (dname[dlen - 1] == '.') {
- dlen--;
- }
for (p = env->cfg->local_zones_ipset; p; p = p->next) {
+ ds = NULL;
+ qs = NULL;
plen = strlen(p->str);
if (dlen >= plen) {
- s = dname + (dlen - plen);
-
- if (strncasecmp(p->str, s, plen) == 0) {
- d = (struct packed_rrset_data*)rrset->entry.data;
- ipset_add_rrset_data(ie, mnl, d, setname,
- af, dname);
- break;
- }
+ ds = dname + (dlen - plen);
+ }
+ if (qlen >= plen) {
+ qs = qname + (qlen - plen);
+ }
+ if ((ds && strncasecmp(p->str, ds, plen) == 0)
+ || (qs && strncasecmp(p->str, qs, plen) == 0)) {
+ d = (struct packed_rrset_data*)rrset->entry.data;
+ ipset_add_rrset_data(ie, mnl, d, setname,
+ af, dname);
+ break;
}
}
return 0;
}
-static int ipset_update(struct module_env *env, struct dns_msg *return_msg, struct ipset_env *ie) {
+static int ipset_update(struct module_env *env, struct dns_msg *return_msg,
+ struct query_info qinfo, struct ipset_env *ie)
+{
struct mnl_socket *mnl;
-
size_t i;
-
const char *setname;
-
struct ub_packed_rrset_key *rrset;
-
int af;
-
+ static char qname[BUFF_LEN];
+ int qlen;
mnl = (struct mnl_socket *)ie->mnl;
if (!mnl) {
- // retry to create mnl socket
+ /* retry to create mnl socket */
mnl = open_mnl_socket();
if (!mnl) {
return -1;
}
-
ie->mnl = mnl;
}
- for (i = 0; i < return_msg->rep->rrset_count; ++i) {
- setname = NULL;
+ qlen = sldns_wire2str_dname_buf(qinfo.qname, qinfo.qname_len,
+ qname, BUFF_LEN);
+ if(qlen == 0) {
+ log_err("bad domain name");
+ return -1;
+ }
+ for(i = 0; i < return_msg->rep->rrset_count; i++) {
+ setname = NULL;
rrset = return_msg->rep->rrsets[i];
-
- if (rrset->rk.type == htons(LDNS_RR_TYPE_A)) {
+ if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_A &&
+ ie->v4_enabled == 1) {
af = AF_INET;
- if ((ie->v4_enabled == 1)) {
- setname = ie->name_v4;
- }
- } else {
+ setname = ie->name_v4;
+ } else if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_AAAA &&
+ ie->v6_enabled == 1) {
af = AF_INET6;
- if ((ie->v6_enabled == 1)) {
- setname = ie->name_v6;
- }
+ setname = ie->name_v6;
}
if (setname) {
if(ipset_check_zones_for_rrset(env, ie, mnl, rrset,
- setname, af) == -1)
+ qname, qlen, setname, af) == -1)
return -1;
}
}
@@ -311,7 +314,7 @@ void ipset_operate(struct module_qstate *qstate, enum module_ev event, int id,
if (iq && (event == module_event_moddone)) {
if (qstate->return_msg && qstate->return_msg->rep) {
- ipset_update(qstate->env, qstate->return_msg, ie);
+ ipset_update(qstate->env, qstate->return_msg, qstate->qinfo, ie);
}
qstate->ext_state[id] = module_finished;
return;
diff --git a/usr.sbin/unbound/services/rpz.c b/usr.sbin/unbound/services/rpz.c
index 322e9d1393c..77b6266fecb 100644
--- a/usr.sbin/unbound/services/rpz.c
+++ b/usr.sbin/unbound/services/rpz.c
@@ -526,13 +526,13 @@ rpz_create(struct config_auth* p)
size_t nmlen = sizeof(nm);
if(!p->rpz_cname) {
- log_err("RPZ override with cname action found, but no "
+ log_err("rpz: override with cname action found, but no "
"rpz-cname-override configured");
goto err;
}
if(sldns_str2wire_dname_buf(p->rpz_cname, nm, &nmlen) != 0) {
- log_err("cannot parse RPZ cname override: %s",
+ log_err("rpz: cannot parse cname override: %s",
p->rpz_cname);
goto err;
}
@@ -614,7 +614,7 @@ rpz_insert_local_zones_trigger(struct local_zones* lz, uint8_t* dname,
return; /* no need to log these types as unsupported */
}
dname_str(dname, str);
- verbose(VERB_ALGO, "RPZ: qname trigger, %s skipping unsupported action: %s",
+ verbose(VERB_ALGO, "rpz: qname trigger, %s skipping unsupported action: %s",
str, rpz_action_to_string(a));
free(dname);
return;
@@ -999,7 +999,7 @@ rpz_insert_response_ip_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen,
rpz_action_to_respip_action(a) == respip_invalid) {
char str[255+1];
dname_str(dname, str);
- verbose(VERB_ALGO, "RPZ: respip trigger, %s skipping unsupported action: %s",
+ verbose(VERB_ALGO, "rpz: respip trigger, %s skipping unsupported action: %s",
str, rpz_action_to_string(a));
return 0;
}
@@ -1560,7 +1560,9 @@ rpz_local_encode(struct module_env* env, struct query_info* qinfo,
}
static struct local_rrset*
-rpz_find_synthesized_rrset(int qtype, struct clientip_synthesized_rr* data) {
+rpz_find_synthesized_rrset(uint16_t qtype,
+ struct clientip_synthesized_rr* data)
+{
struct local_rrset* cursor = data->data;
while( cursor != NULL) {
struct packed_rrset_key* packed_rrset = &cursor->rrset->rk;
@@ -1997,6 +1999,7 @@ rpz_apply_nsip_trigger(struct module_qstate* ms, struct rpz* r,
break;
case RPZ_PASSTHRU_ACTION:
ret = NULL;
+ ms->rpz_passthru = 1;
break;
default:
verbose(VERB_ALGO, "rpz: nsip: bug: unhandled or invalid action: '%s'",
@@ -2051,6 +2054,7 @@ rpz_apply_nsdname_trigger(struct module_qstate* ms, struct rpz* r,
break;
case RPZ_PASSTHRU_ACTION:
ret = NULL;
+ ms->rpz_passthru = 1;
break;
default:
verbose(VERB_ALGO, "rpz: nsip: bug: unhandled or invalid action: '%s'",
@@ -2114,6 +2118,11 @@ rpz_callback_from_iterator_module(struct module_qstate* ms, struct iter_qstate*
struct local_zone* z = NULL;
struct matched_delegation_point match = {0};
+ if(ms->rpz_passthru) {
+ verbose(VERB_ALGO, "query is rpz_passthru, no further processing");
+ return NULL;
+ }
+
if(ms->env == NULL || ms->env->auth_zones == NULL) { return 0; }
az = ms->env->auth_zones;
@@ -2179,6 +2188,11 @@ struct dns_msg* rpz_callback_from_iterator_cname(struct module_qstate* ms,
enum localzone_type lzt;
struct dns_msg* ret = NULL;
+ if(ms->rpz_passthru) {
+ verbose(VERB_ALGO, "query is rpz_passthru, no further processing");
+ return NULL;
+ }
+
if(ms->env == NULL || ms->env->auth_zones == NULL) { return 0; }
az = ms->env->auth_zones;
@@ -2253,6 +2267,7 @@ struct dns_msg* rpz_callback_from_iterator_cname(struct module_qstate* ms,
break;
case RPZ_PASSTHRU_ACTION:
ret = NULL;
+ ms->rpz_passthru = 1;
break;
default:
verbose(VERB_ALGO, "rpz: qname trigger after cname: bug: unhandled or invalid action: '%s'",
@@ -2270,7 +2285,8 @@ rpz_apply_maybe_clientip_trigger(struct auth_zones* az, struct module_env* env,
uint8_t* taglist, size_t taglen, struct ub_server_stats* stats,
sldns_buffer* buf, struct regional* temp,
/* output parameters */
- struct local_zone** z_out, struct auth_zone** a_out, struct rpz** r_out)
+ struct local_zone** z_out, struct auth_zone** a_out, struct rpz** r_out,
+ int* passthru)
{
int ret = 0;
enum rpz_action client_action;
@@ -2278,7 +2294,9 @@ rpz_apply_maybe_clientip_trigger(struct auth_zones* az, struct module_env* env,
az, qinfo, repinfo, taglist, taglen, stats, z_out, a_out, r_out);
client_action = ((node == NULL) ? RPZ_INVALID_ACTION : node->action);
-
+ if(client_action == RPZ_PASSTHRU_ACTION) {
+ *passthru = 1;
+ }
if(*z_out == NULL || (client_action != RPZ_INVALID_ACTION &&
client_action != RPZ_PASSTHRU_ACTION)) {
if(client_action == RPZ_PASSTHRU_ACTION
@@ -2323,7 +2341,7 @@ int
rpz_callback_from_worker_request(struct auth_zones* az, struct module_env* env,
struct query_info* qinfo, struct edns_data* edns, sldns_buffer* buf,
struct regional* temp, struct comm_reply* repinfo, uint8_t* taglist,
- size_t taglen, struct ub_server_stats* stats)
+ size_t taglen, struct ub_server_stats* stats, int* passthru)
{
struct rpz* r = NULL;
struct auth_zone* a = NULL;
@@ -2332,7 +2350,8 @@ rpz_callback_from_worker_request(struct auth_zones* az, struct module_env* env,
enum localzone_type lzt;
int clientip_trigger = rpz_apply_maybe_clientip_trigger(az, env, qinfo,
- edns, repinfo, taglist, taglen, stats, buf, temp, &z, &a, &r);
+ edns, repinfo, taglist, taglen, stats, buf, temp, &z, &a, &r,
+ passthru);
if(clientip_trigger >= 0) {
if(a) {
lock_rw_unlock(&a->lock);
@@ -2357,6 +2376,10 @@ rpz_callback_from_worker_request(struct auth_zones* az, struct module_env* env,
} else {
lzt = rpz_action_to_localzone_type(r->action_override);
}
+ if(r->action_override == RPZ_PASSTHRU_ACTION ||
+ lzt == local_zone_always_transparent /* RPZ_PASSTHRU_ACTION */) {
+ *passthru = 1;
+ }
if(verbosity >= VERB_ALGO) {
char nm[255+1], zn[255+1];
diff --git a/usr.sbin/unbound/services/rpz.h b/usr.sbin/unbound/services/rpz.h
index c29d30dff50..53781197aee 100644
--- a/usr.sbin/unbound/services/rpz.h
+++ b/usr.sbin/unbound/services/rpz.h
@@ -176,12 +176,14 @@ void rpz_remove_rr(struct rpz* r, size_t aznamelen, uint8_t* dname,
* @param taglist: taglist to lookup.
* @param taglen: length of taglist.
* @param stats: worker stats struct
+ * @param passthru: returns if the query can passthru further rpz processing.
* @return: 1 if client answer is ready, 0 to continue resolving
*/
int rpz_callback_from_worker_request(struct auth_zones* az, struct module_env* env,
struct query_info* qinfo, struct edns_data* edns, sldns_buffer* buf,
struct regional* temp, struct comm_reply* repinfo,
- uint8_t* taglist, size_t taglen, struct ub_server_stats* stats);
+ uint8_t* taglist, size_t taglen, struct ub_server_stats* stats,
+ int* passthru);
/**
* Callback to process when the iterator module is about to send queries.
diff --git a/usr.sbin/unbound/sldns/pkthdr.h b/usr.sbin/unbound/sldns/pkthdr.h
index de9952ea71f..c32e7d28556 100644
--- a/usr.sbin/unbound/sldns/pkthdr.h
+++ b/usr.sbin/unbound/sldns/pkthdr.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
diff --git a/usr.sbin/unbound/testcode/testpkts.c b/usr.sbin/unbound/testcode/testpkts.c
index dee45176167..3702c3f1840 100644
--- a/usr.sbin/unbound/testcode/testpkts.c
+++ b/usr.sbin/unbound/testcode/testpkts.c
@@ -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,22 @@ 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++;
+ while(isspace((unsigned char)*parse))
+ parse++;
+ if(str_keyword(&parse, "any")) {
+ e->match_ede_any = 1;
+ } else {
+ 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 +283,15 @@ 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->match_ede_any = 0;
+ e->ede_info_code = -1;
e->match_transport = transport_any;
e->reply_list = NULL;
e->copy_id = 0;
@@ -817,7 +838,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 +905,39 @@ get_do_flag(uint8_t* pkt, size_t len)
return (int)(edns_bits&LDNS_EDNS_MASK_DO_BIT);
}
+/** Snips the EDE option out of the OPT record and returns the EDNS EDE
+ * INFO-CODE if found, else -1 */
+static int
+extract_ede(uint8_t* pkt, size_t len)
+{
+ uint8_t *rdata, *opt_position = pkt;
+ uint16_t rdlen, optlen;
+ size_t remaining = len;
+ int ede_code;
+ if(!pkt_find_edns_opt(&opt_position, &remaining)) return -1;
+ if(remaining < 8) return -1; /* malformed */
+ rdlen = sldns_read_uint16(opt_position+6);
+ rdata = opt_position + 8;
+ while(rdlen > 0) {
+ if(rdlen < 4) return -1; /* malformed */
+ optlen = sldns_read_uint16(rdata+2);
+ if(sldns_read_uint16(rdata) == LDNS_EDNS_EDE) {
+ if(rdlen < 6) return -1; /* malformed */
+ ede_code = sldns_read_uint16(rdata+4);
+ /* snip option from packet; assumes len is correct */
+ memmove(rdata, rdata+4+optlen,
+ (pkt+len)-(rdata+4+optlen));
+ /* update OPT size */
+ sldns_write_uint16(opt_position+6,
+ sldns_read_uint16(opt_position+6)-(4+optlen));
+ return ede_code;
+ }
+ rdlen -= 4 + optlen;
+ rdata += 4 + optlen;
+ }
+ return -1;
+}
+
/** zero TTLs in packet */
static void
zerottls(uint8_t* pkt, size_t pktlen)
@@ -1201,7 +1255,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,18 +1346,36 @@ 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* 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;
int r;
- /* zero TTLs */
qb = memdup(q, qlen);
pb = memdup(p, plen);
if(!qb || !pb) error("out of memory");
+ /* zero TTLs */
if(!mttl) {
zerottls(qb, qlen);
zerottls(pb, plen);
@@ -1313,6 +1385,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 +1398,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) ) {
@@ -1428,13 +1505,32 @@ find_match(struct entry* entries, uint8_t* query_pkt, size_t len,
enum transport_type transport)
{
struct entry* p = entries;
- uint8_t* reply;
- size_t rlen;
+ uint8_t* reply, *query_pkt_orig;
+ size_t rlen, query_pkt_orig_len;
+ /* Keep the original packet; it may be modified */
+ query_pkt_orig = memdup(query_pkt, len);
+ query_pkt_orig_len = len;
for(p=entries; p; p=p->next) {
verbose(3, "comparepkt: ");
reply = p->reply_list->reply_pkt;
rlen = p->reply_list->reply_len;
- if(p->match_opcode && get_opcode(query_pkt, len) !=
+ /* Restore the original packet for each entry */
+ memcpy(query_pkt, query_pkt_orig, query_pkt_orig_len);
+ /* EDE should be first since it may modify the query_pkt */
+ if(p->match_ede) {
+ int info_code = extract_ede(query_pkt, len);
+ if(info_code == -1) {
+ verbose(3, "bad EDE. Expected but not found\n");
+ continue;
+ } else if(!p->match_ede_any &&
+ (uint16_t)info_code != p->ede_info_code) {
+ verbose(3, "bad EDE INFO-CODE. Expected: %d, "
+ "and got: %d\n", (int)p->ede_info_code,
+ info_code);
+ continue;
+ }
+ }
+ if(p->match_opcode && get_opcode(query_pkt, len) !=
get_opcode(reply, rlen)) {
verbose(3, "bad opcode\n");
continue;
@@ -1502,14 +1598,25 @@ 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;
}
verbose(3, "match!\n");
+ /* Restore the original packet */
+ memcpy(query_pkt, query_pkt_orig, query_pkt_orig_len);
+ free(query_pkt_orig);
return p;
}
+ /* Restore the original packet */
+ memcpy(query_pkt, query_pkt_orig, query_pkt_orig_len);
+ free(query_pkt_orig);
return NULL;
}
diff --git a/usr.sbin/unbound/testcode/testpkts.h b/usr.sbin/unbound/testcode/testpkts.h
index 6e032fa90a6..2768040c68c 100644
--- a/usr.sbin/unbound/testcode/testpkts.h
+++ b/usr.sbin/unbound/testcode/testpkts.h
@@ -40,20 +40,30 @@ 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.
+ ; It also snips the EDE record out of the packet to facilitate
+ ; other matches.
+ ; 'ede=any' makes the query match any EDNS EDE info-code.
+ ; It also snips the EDE record out of the packet to facilitate
+ ; other matches.
MATCH [opcode] [qtype] [qname] [serial=<value>] [all] [ttl]
MATCH [UDP|TCP] DO
MATCH ...
@@ -72,6 +82,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 +183,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 +195,17 @@ 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 any EDNS EDE info-code */
+ uint8_t match_ede_any;
/** 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 +215,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 +284,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.
diff --git a/usr.sbin/unbound/testcode/unitldns.c b/usr.sbin/unbound/testcode/unitldns.c
index 6397f29dbe2..d226ee203c1 100644
--- a/usr.sbin/unbound/testcode/unitldns.c
+++ b/usr.sbin/unbound/testcode/unitldns.c
@@ -243,28 +243,28 @@ b64_test(void)
memset(target, 0, sizeof(target));
result = sldns_b64_pton(p1, (uint8_t*)target, tarsize);
- unit_assert(result == strlen("hello") && strcmp(target, "hello") == 0);
+ unit_assert(result == (int)strlen("hello") && strcmp(target, "hello") == 0);
memset(target, 0, sizeof(target));
result = sldns_b64_pton(p2, (uint8_t*)target, tarsize);
- unit_assert(result == strlen("hello>") && strcmp(target, "hello>") == 0);
+ unit_assert(result == (int)strlen("hello>") && strcmp(target, "hello>") == 0);
memset(target, 0, sizeof(target));
result = sldns_b64_pton(p3, (uint8_t*)target, tarsize);
- unit_assert(result == strlen("hello?!") && strcmp(target, "hello?!") == 0);
+ unit_assert(result == (int)strlen("hello?!") && strcmp(target, "hello?!") == 0);
memset(target, 0, sizeof(target));
result = sldns_b64_pton(p4, (uint8_t*)target, tarsize);
/* when padding is used everything that is not a block of 4 will be
* ignored */
- unit_assert(result == strlen("hel") && strcmp(target, "hel") == 0);
+ unit_assert(result == (int)strlen("hel") && strcmp(target, "hel") == 0);
memset(target, 0, sizeof(target));
result = sldns_b64url_pton(u1, strlen(u1), (uint8_t*)target, tarsize);
- unit_assert(result == strlen("hello") && strcmp(target, "hello") == 0);
+ unit_assert(result == (int)strlen("hello") && strcmp(target, "hello") == 0);
memset(target, 0, sizeof(target));
result = sldns_b64url_pton(u2, strlen(u2), (uint8_t*)target, tarsize);
- unit_assert(result == strlen("hello>") && strcmp(target, "hello>") == 0);
+ unit_assert(result == (int)strlen("hello>") && strcmp(target, "hello>") == 0);
memset(target, 0, sizeof(target));
result = sldns_b64url_pton(u3, strlen(u3), (uint8_t*)target, tarsize);
- unit_assert(result == strlen("hello+/") && strcmp(target, "hello?!") == 0);
+ unit_assert(result == (int)strlen("hello+/") && strcmp(target, "hello?!") == 0);
/* one item in block of four is not allowed */
memset(target, 0, sizeof(target));
result = sldns_b64url_pton(u4, strlen(u4), (uint8_t*)target, tarsize);
diff --git a/usr.sbin/unbound/testcode/unitmsgparse.c b/usr.sbin/unbound/testcode/unitmsgparse.c
index 6f1edc6e9d6..a87314019d1 100644
--- a/usr.sbin/unbound/testcode/unitmsgparse.c
+++ b/usr.sbin/unbound/testcode/unitmsgparse.c
@@ -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;
}
diff --git a/usr.sbin/unbound/testcode/unitverify.c b/usr.sbin/unbound/testcode/unitverify.c
index 9e101324960..ff069a1bb03 100644
--- a/usr.sbin/unbound/testcode/unitverify.c
+++ b/usr.sbin/unbound/testcode/unitverify.c
@@ -187,7 +187,7 @@ verifytest_rrset(struct module_env* env, struct val_env* ve,
}
setup_sigalg(dnskey, sigalg); /* check all algorithms in the dnskey */
/* ok to give null as qstate here, won't be used for answer section. */
- sec = dnskeyset_verify_rrset(env, ve, rrset, dnskey, sigalg, &reason,
+ sec = dnskeyset_verify_rrset(env, ve, rrset, dnskey, sigalg, &reason, NULL,
LDNS_SECTION_ANSWER, NULL);
if(vsig) {
printf("verify outcome is: %s %s\n", sec_status_to_string(sec),
diff --git a/usr.sbin/unbound/testcode/unitzonemd.c b/usr.sbin/unbound/testcode/unitzonemd.c
index 5caa68a102c..23c9f701064 100644
--- a/usr.sbin/unbound/testcode/unitzonemd.c
+++ b/usr.sbin/unbound/testcode/unitzonemd.c
@@ -221,10 +221,10 @@ static void zonemd_check_test(void)
unit_assert(result && reason == NULL);
result = auth_zone_generate_zonemd_check(z, 241, hashalgo,
hash, hashlen, region, buf, &reason);
- unit_assert(!result && strcmp(reason, "unsupported scheme")==0);
+ unit_assert(result && strcmp(reason, "unsupported scheme")==0);
result = auth_zone_generate_zonemd_check(z, scheme, 242,
hash, hashlen, region, buf, &reason);
- unit_assert(!result && strcmp(reason, "unsupported algorithm")==0);
+ unit_assert(result && strcmp(reason, "unsupported algorithm")==0);
result = auth_zone_generate_zonemd_check(z, scheme, hashalgo,
hash, 2, region, buf, &reason);
unit_assert(!result && strcmp(reason, "digest length too small, less than 12")==0);
diff --git a/usr.sbin/unbound/validator/val_kcache.c b/usr.sbin/unbound/validator/val_kcache.c
index e0b88b6df81..c190085b56f 100644
--- a/usr.sbin/unbound/validator/val_kcache.c
+++ b/usr.sbin/unbound/validator/val_kcache.c
@@ -90,6 +90,7 @@ key_cache_insert(struct key_cache* kcache, struct key_entry_key* kkey,
qstate->env->cfg->val_log_level >= 2) {
/* on malloc failure there is simply no reason string */
key_entry_set_reason(k, errinf_to_str_bogus(qstate));
+ key_entry_set_reason_bogus(k, errinf_to_reason_bogus(qstate));
}
key_entry_hash(k);
slabhash_insert(kcache->slab, k->entry.hash, &k->entry,
diff --git a/usr.sbin/unbound/validator/val_kentry.c b/usr.sbin/unbound/validator/val_kentry.c
index 93fe2145e6f..a47feba61a9 100644
--- a/usr.sbin/unbound/validator/val_kentry.c
+++ b/usr.sbin/unbound/validator/val_kentry.c
@@ -244,6 +244,15 @@ key_entry_set_reason(struct key_entry_key* kkey, char* reason)
d->reason = reason;
}
+void
+key_entry_set_reason_bogus(struct key_entry_key* kkey, sldns_ede_code ede)
+{
+ struct key_entry_data* d = (struct key_entry_data*)kkey->entry.data;
+ if (ede != LDNS_EDE_NONE) { /* reason_bogus init is LDNS_EDE_NONE already */
+ d->reason_bogus = ede;
+ }
+}
+
char*
key_entry_get_reason(struct key_entry_key* kkey)
{
@@ -251,6 +260,14 @@ key_entry_get_reason(struct key_entry_key* kkey)
return d->reason;
}
+sldns_ede_code
+key_entry_get_reason_bogus(struct key_entry_key* kkey)
+{
+ struct key_entry_data* d = (struct key_entry_data*)kkey->entry.data;
+ return d->reason_bogus;
+
+}
+
/** setup key entry in region */
static int
key_entry_setup(struct regional* region,
@@ -286,6 +303,7 @@ key_entry_create_null(struct regional* region,
d->ttl = now + ttl;
d->isbad = 0;
d->reason = NULL;
+ d->reason_bogus = LDNS_EDE_NONE;
d->rrset_type = LDNS_RR_TYPE_DNSKEY;
d->rrset_data = NULL;
d->algo = NULL;
@@ -306,6 +324,7 @@ key_entry_create_rrset(struct regional* region,
d->ttl = rd->ttl + now;
d->isbad = 0;
d->reason = NULL;
+ d->reason_bogus = LDNS_EDE_NONE;
d->rrset_type = ntohs(rrset->rk.type);
d->rrset_data = (struct packed_rrset_data*)regional_alloc_init(region,
rd, packed_rrset_sizeof(rd));
@@ -332,6 +351,7 @@ key_entry_create_bad(struct regional* region,
d->ttl = now + ttl;
d->isbad = 1;
d->reason = NULL;
+ d->reason_bogus = LDNS_EDE_NONE;
d->rrset_type = LDNS_RR_TYPE_DNSKEY;
d->rrset_data = NULL;
d->algo = NULL;
diff --git a/usr.sbin/unbound/validator/val_kentry.h b/usr.sbin/unbound/validator/val_kentry.h
index ade65571a57..ded45beaa71 100644
--- a/usr.sbin/unbound/validator/val_kentry.h
+++ b/usr.sbin/unbound/validator/val_kentry.h
@@ -45,6 +45,7 @@ struct packed_rrset_data;
struct regional;
struct ub_packed_rrset_key;
#include "util/storage/lruhash.h"
+#include "sldns/rrdef.h"
/**
* A key entry for the validator.
@@ -80,6 +81,8 @@ struct key_entry_data {
struct packed_rrset_data* rrset_data;
/** not NULL sometimes to give reason why bogus */
char* reason;
+ /** not NULL to give reason why bogus */
+ sldns_ede_code reason_bogus;
/** list of algorithms signalled, ends with 0, or NULL */
uint8_t* algo;
/** DNS RR type of the rrset data (host order) */
@@ -151,6 +154,15 @@ int key_entry_isbad(struct key_entry_key* kkey);
void key_entry_set_reason(struct key_entry_key* kkey, char* reason);
/**
+ * Set the EDE (RFC8914) code why the key is bad, if it
+ * exists (so not LDNS_EDE_NONE).
+ * @param kkey: bad key.
+ * @param ede: EDE code to attach to this key.
+ */
+void key_entry_set_reason_bogus(struct key_entry_key* kkey, sldns_ede_code ede);
+
+
+/**
* Get reason why a key is bad.
* @param kkey: bad key
* @return pointer to string.
@@ -159,6 +171,13 @@ void key_entry_set_reason(struct key_entry_key* kkey, char* reason);
char* key_entry_get_reason(struct key_entry_key* kkey);
/**
+ * Get the EDE (RFC8914) code why a key is bad. Can return LDNS_EDE_NONE.
+ * @param kkey: bad key
+ * @return the ede code.
+ */
+sldns_ede_code key_entry_get_reason_bogus(struct key_entry_key* kkey);
+
+/**
* Create a null entry, in the given region.
* @param region: where to allocate
* @param name: the key name