update to unbound 1.16.0, discussed with florian@, test from Renaud Allard
authorsthen <sthen@openbsd.org>
Tue, 7 Jun 2022 15:39:58 +0000 (15:39 +0000)
committersthen <sthen@openbsd.org>
Tue, 7 Jun 2022 15:39:58 +0000 (15:39 +0000)
13 files changed:
usr.sbin/unbound/ipset/ipset.c
usr.sbin/unbound/services/rpz.c
usr.sbin/unbound/services/rpz.h
usr.sbin/unbound/sldns/pkthdr.h
usr.sbin/unbound/testcode/testpkts.c
usr.sbin/unbound/testcode/testpkts.h
usr.sbin/unbound/testcode/unitldns.c
usr.sbin/unbound/testcode/unitmsgparse.c
usr.sbin/unbound/testcode/unitverify.c
usr.sbin/unbound/testcode/unitzonemd.c
usr.sbin/unbound/validator/val_kcache.c
usr.sbin/unbound/validator/val_kentry.c
usr.sbin/unbound/validator/val_kentry.h

index f6e2c4a..c61ebc2 100644 (file)
@@ -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;
index 322e9d1..77b6266 100644 (file)
@@ -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];
index c29d30d..5378119 100644 (file)
@@ -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.
index de9952e..c32e7d2 100644 (file)
@@ -97,18 +97,22 @@ extern "C" {
 #define        QDCOUNT(wirebuf)                (ntohs(*(uint16_t *)(wirebuf+QDCOUNT_OFF)))
 */
 #define        LDNS_QDCOUNT(wirebuf)           (sldns_read_uint16(wirebuf+LDNS_QDCOUNT_OFF))
+#define LDNS_QDCOUNT_SET(wirebuf, i)    (sldns_write_uint16(wirebuf+LDNS_QDCOUNT_OFF, i))
 
 /* Counter of the answer section */
 #define LDNS_ANCOUNT_OFF               6
 #define        LDNS_ANCOUNT(wirebuf)           (sldns_read_uint16(wirebuf+LDNS_ANCOUNT_OFF))
+#define LDNS_ANCOUNT_SET(wirebuf, i)    (sldns_write_uint16(wirebuf+LDNS_ANCOUNT_OFF, i))
 
 /* Counter of the authority section */
 #define LDNS_NSCOUNT_OFF               8
 #define        LDNS_NSCOUNT(wirebuf)           (sldns_read_uint16(wirebuf+LDNS_NSCOUNT_OFF))
+#define LDNS_NSCOUNT_SET(wirebuf, i)    (sldns_write_uint16(wirebuf+LDNS_NSCOUNT_OFF, i))
 
 /* Counter of the additional section */
 #define LDNS_ARCOUNT_OFF               10
 #define        LDNS_ARCOUNT(wirebuf)           (sldns_read_uint16(wirebuf+LDNS_ARCOUNT_OFF))
+#define LDNS_ARCOUNT_SET(wirebuf, i)    (sldns_write_uint16(wirebuf+LDNS_ARCOUNT_OFF, i))
 
 /**
  * The sections of a packet
index dee4517..3702c3f 100644 (file)
@@ -128,6 +128,8 @@ static void matchline(char* line, struct entry* e)
                        e->match_answer = 1;
                } else if(str_keyword(&parse, "subdomain")) {
                        e->match_subdomain = 1;
+               } else if(str_keyword(&parse, "all_noedns")) {
+                       e->match_all_noedns = 1;
                } else if(str_keyword(&parse, "all")) {
                        e->match_all = 1;
                } else if(str_keyword(&parse, "ttl")) {
@@ -148,7 +150,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;
 }
 
index 6e032fa..2768040 100644 (file)
@@ -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.
index 6397f29..d226ee2 100644 (file)
@@ -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);
index 6f1edc6..a873140 100644 (file)
@@ -137,7 +137,7 @@ test_buffers(sldns_buffer* pkt, sldns_buffer* out)
        /* compare packets */
        unit_assert(match_all(sldns_buffer_begin(pkt), sldns_buffer_limit(pkt),
                sldns_buffer_begin(out), sldns_buffer_limit(out), 1,
-               matches_nolocation));
+               matches_nolocation, 0));
        return 0;
 }
 
index 9e10132..ff069a1 100644 (file)
@@ -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),
index 5caa68a..23c9f70 100644 (file)
@@ -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);
index e0b88b6..c190085 100644 (file)
@@ -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, 
index 93fe214..a47feba 100644 (file)
@@ -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;
index ade6557..ded45be 100644 (file)
@@ -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