From c2862f4157f13c1308608b6de9e05a4429a9fe71 Mon Sep 17 00:00:00 2001 From: sthen Date: Tue, 7 Jun 2022 15:39:58 +0000 Subject: [PATCH] update to unbound 1.16.0, discussed with florian@, test from Renaud Allard --- usr.sbin/unbound/ipset/ipset.c | 71 +++++++------ usr.sbin/unbound/services/rpz.c | 41 +++++-- usr.sbin/unbound/services/rpz.h | 4 +- usr.sbin/unbound/sldns/pkthdr.h | 4 + usr.sbin/unbound/testcode/testpkts.c | 129 +++++++++++++++++++++-- usr.sbin/unbound/testcode/testpkts.h | 59 ++++++++--- usr.sbin/unbound/testcode/unitldns.c | 14 +-- usr.sbin/unbound/testcode/unitmsgparse.c | 2 +- usr.sbin/unbound/testcode/unitverify.c | 2 +- usr.sbin/unbound/testcode/unitzonemd.c | 4 +- usr.sbin/unbound/validator/val_kcache.c | 1 + usr.sbin/unbound/validator/val_kentry.c | 20 ++++ usr.sbin/unbound/validator/val_kentry.h | 19 ++++ 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=] [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=] ; sleep before giving any reply ADJUST [packet_sleep=] ; 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 ; 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) */ @@ -150,6 +153,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 @@ -158,6 +170,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 -- 2.20.1