_public_ int knot_rdataset_sort_at(knot_rdataset_t *rrs, size_t pos, knot_mm_t *mm) { if (rrs == NULL || rrs->rr_count == 0) { return KNOT_EINVAL; } knot_rdata_t *rr = knot_rdataset_at(rrs, pos); assert(rr); knot_rdata_t *earlier_rr = NULL; for (uint16_t i = 0; i < rrs->rr_count; ++i) { if (i == pos) { // It already is at the position return KNOT_EOK; } earlier_rr = knot_rdataset_at(rrs, i); int cmp = knot_rdata_cmp(earlier_rr, rr); if (cmp == 0) { // Duplication - we need to remove this RR return remove_rr_at(rrs, pos, mm); } else if (cmp > 0) { // Found position to move break; } } // RDATA have to be rearanged. knot_rdata_t *last_rr = knot_rdataset_at(rrs, pos - 1); assert(last_rr); assert(earlier_rr); // Save the RR to be moved const uint16_t size = knot_rdata_rdlen(rr); const uint32_t ttl = knot_rdata_ttl(rr); const uint8_t *rdata = knot_rdata_data(rr); knot_rdata_t tmp_rr[knot_rdata_array_size(size)]; knot_rdata_init(tmp_rr, size, rdata, ttl); // Move the array or just part of it knot_rdata_t *earlier_rr_moved = earlier_rr + knot_rdata_array_size(size); size_t last_rr_size = knot_rdata_array_size(knot_rdata_rdlen(last_rr)); memmove(earlier_rr_moved, earlier_rr, (last_rr + last_rr_size) - earlier_rr); // Set new RR knot_rdata_init(earlier_rr, size, knot_rdata_data(tmp_rr), ttl); return KNOT_EOK; }
static bool check_header(knot_rrset_t *opt_rr, uint16_t payload, uint8_t ver, uint16_t flags, uint8_t ext_rcode, char *msg, int *done) { assert(opt_rr != NULL); assert(done != NULL); bool check; bool success = true; /* Check values in OPT RR by hand. */ /* CLASS == Max UDP payload */ check = (opt_rr->rclass == payload); ok(check, "%s: max payload", msg); success &= check; (*done)++; /* The OPT RR should have exactly one RDATA. */ check = (opt_rr->rrs.rr_count == 1); ok(check, "%s: RR count == 1", msg); success &= check; (*done)++; knot_rdata_t *rdata = knot_rdataset_at(&opt_rr->rrs, 0); check = (rdata != NULL); ok(check, "%s: RDATA exists", msg); success &= check; (*done)++; success &= check_ttl(rdata, ext_rcode, ver, flags, msg, done); return success; }
/*----------------------------------------------------------------------------*/ _public_ bool knot_edns_check_record(knot_rrset_t *opt_rr) { if (opt_rr->rrs.rr_count != 1) { return false; } knot_rdata_t *rdata = knot_rdataset_at(&opt_rr->rrs, 0); if (rdata == NULL) { return false; } uint8_t *data = knot_rdata_data(rdata); uint16_t rdlength = knot_rdata_rdlen(rdata); uint32_t pos = 0; /* RFC2671 4.4: {uint16_t code, uint16_t len, data} */ while (pos + KNOT_EDNS_OPTION_HDRLEN <= rdlength) { uint16_t opt_len = wire_read_u16(data + pos + sizeof(uint16_t)); pos += KNOT_EDNS_OPTION_HDRLEN + opt_len; } /* If not at the end of the RDATA, there are either some redundant data * (pos < rdlength) or the last OPTION is too long (pos > rdlength). */ return pos == rdlength; }
/*----------------------------------------------------------------------------*/ _public_ int knot_edns_add_option(knot_rrset_t *opt_rr, uint16_t code, uint16_t length, const uint8_t *data, mm_ctx_t *mm) { if (opt_rr == NULL || (length != 0 && data == NULL)) { return KNOT_EINVAL; } /* We need to replace the RDATA currently in the OPT RR */ /* 1) create new RDATA by appending the new option after the current * RDATA. */ assert(opt_rr->rrs.rr_count == 1); knot_rdata_t *old_rdata = knot_rdataset_at(&opt_rr->rrs, 0); uint8_t *old_data = knot_rdata_data(old_rdata); uint16_t old_data_len = knot_rdata_rdlen(old_rdata); uint16_t new_data_len = old_data_len + KNOT_EDNS_OPTION_HDRLEN + length; uint8_t new_data[new_data_len]; memcpy(new_data, old_data, old_data_len); // write length and code in wireformat (convert endian) wire_write_u16(new_data + old_data_len, code); wire_write_u16(new_data + old_data_len + sizeof(uint16_t), length); // write the option data memcpy(new_data + old_data_len + KNOT_EDNS_OPTION_HDRLEN, data, length); /* 2) Replace the RDATA in the RRSet. */ uint32_t old_ttl = knot_rdata_ttl(old_rdata); knot_rdataset_clear(&opt_rr->rrs, mm); return knot_rrset_add_rdata(opt_rr, new_data, new_data_len, old_ttl, mm); }
_public_ int knot_rdataset_reserve(knot_rdataset_t *rrs, size_t size, knot_mm_t *mm) { if (rrs == NULL || size > MAX_RDLENGTH) { return KNOT_EINVAL; } size_t total_size = knot_rdataset_size(rrs); size_t new_size = total_size + knot_rdata_array_size(size); uint8_t *tmp = mm_realloc(mm, rrs->data, new_size, total_size); if (tmp == NULL) { return KNOT_ENOMEM; } rrs->data = tmp; rrs->rr_count++; // We have to initialise the 'size' field in the reserved space. knot_rdata_t *rr = knot_rdataset_at(rrs, rrs->rr_count - 1); assert(rr); knot_rdata_set_rdlen(rr, size); return KNOT_EOK; }
static bool rr_exists(const knot_rrset_t *in, const knot_rrset_t *ref, size_t ref_pos) { knot_rdata_t *to_check = knot_rdataset_at(&ref->rrs, ref_pos); const bool compare_ttls = true; return knot_rdataset_member(&in->rrs, to_check, compare_ttls); }
static int rosedb_get(struct cache *cache, MDB_txn *txn, int argc, char *argv[]) { knot_dname_t key[KNOT_DNAME_MAXLEN] = { '\0' }; knot_dname_from_str(key, argv[0], sizeof(key)); knot_dname_to_lower(key); char type_str[16] = { '\0' }; struct iter it; int ret = cache_query_fetch(txn, cache->dbi, &it, key); while (ret == 0) { struct entry entry; cache_iter_val(&it, &entry); knot_rdata_t *rd = knot_rdataset_at(&entry.data.rrs, 0); knot_rrtype_to_string(entry.data.type, type_str, sizeof(type_str)); printf("%s\t%s\tTTL=%u\tRDLEN=%u\t%s\t%s\n", argv[0], type_str, knot_rdata_ttl(rd), knot_rdata_rdlen(rd), entry.threat_code, entry.syslog_ip); if (cache_iter_next(&it) != 0) { break; } } cache_iter_free(&it); return ret; }
static int add_rr_at(knot_rdataset_t *rrs, const knot_rdata_t *rr, size_t pos, knot_mm_t *mm) { if (rrs == NULL || pos > rrs->rr_count) { return KNOT_EINVAL; } const uint16_t size = knot_rdata_rdlen(rr); const uint32_t ttl = knot_rdata_ttl(rr); const uint8_t *rdata = knot_rdata_data(rr); size_t total_size = knot_rdataset_size(rrs); // Realloc data. void *tmp = mm_realloc(mm, rrs->data, total_size + knot_rdata_array_size(size), total_size); if (tmp) { rrs->data = tmp; } else { return KNOT_ENOMEM; } if (rrs->rr_count == 0 || pos == rrs->rr_count) { // No need to rearange RDATA rrs->rr_count++; knot_rdata_t *new_rr = knot_rdataset_at(rrs, pos); knot_rdata_init(new_rr, size, rdata, ttl); return KNOT_EOK; } // RDATA have to be rearanged. knot_rdata_t *last_rr = knot_rdataset_at(rrs, rrs->rr_count - 1); knot_rdata_t *old_rr = knot_rdataset_at(rrs, pos); assert(last_rr); assert(old_rr); // Make space for new data by moving the array memmove(old_rr + knot_rdata_array_size(size), old_rr, (last_rr + knot_rdata_array_size(knot_rdata_rdlen(last_rr))) - old_rr); // Set new RR knot_rdata_init(old_rr, size, rdata, ttl); rrs->rr_count++; return KNOT_EOK; }
_public_ void knot_rdataset_set_ttl(knot_rdataset_t *rrs, uint32_t ttl) { for (uint16_t i = 0; i < rrs->rr_count; ++i) { knot_rdata_t *rrset_rr = knot_rdataset_at(rrs, i); knot_rdata_set_ttl(rrset_rr, ttl); } }
_public_ bool knot_rdataset_eq(const knot_rdataset_t *rrs1, const knot_rdataset_t *rrs2) { if (rrs1->rr_count != rrs2->rr_count) { return false; } for (uint16_t i = 0; i < rrs1->rr_count; ++i) { const knot_rdata_t *rr1 = knot_rdataset_at(rrs1, i); const knot_rdata_t *rr2 = knot_rdataset_at(rrs2, i); if (knot_rdata_cmp(rr1, rr2) != 0) { return false; } } return true; }
static void print_section_opt(const knot_rrset_t *rr, const uint8_t rcode) { uint8_t ercode = knot_edns_get_ext_rcode(rr); uint16_t ext_rcode_id = knot_edns_whole_rcode(ercode, rcode); const char *ext_rcode_str = "Unused"; lookup_table_t *ext_rcode; if (ercode > 0) { ext_rcode = lookup_by_id(knot_rcode_names, ext_rcode_id); if (ext_rcode != NULL) { ext_rcode_str = ext_rcode->name; } else { ext_rcode_str = "Unknown"; } } printf("Version: %u; flags: %s; UDP size: %u B; ext-rcode: %s\n", knot_edns_get_version(rr), (knot_edns_do(rr) != 0) ? "do" : "", knot_edns_get_payload(rr), ext_rcode_str); knot_rdata_t *rdata = knot_rdataset_at(&rr->rrs, 0); assert(rdata != NULL); uint16_t data_len = knot_rdata_rdlen(rdata); uint8_t *data = knot_rdata_data(rdata); int pos = 0; while (pos < data_len - KNOT_EDNS_OPTION_HDRLEN) { uint16_t opt_code = wire_read_u16(data + pos); uint16_t opt_len = wire_read_u16(data + pos + 2); uint8_t *opt_data = data + pos + 4; switch (opt_code) { case KNOT_EDNS_OPTION_NSID: printf(";; NSID: "); short_hex_print(opt_data, opt_len); if (opt_len > 0) { printf(";; : "); txt_print(opt_data, opt_len); } break; case KNOT_EDNS_OPTION_CLIENT_SUBNET: printf(";; CLIENT-SUBNET: "); print_edns_client_subnet(opt_data, opt_len); break; default: printf(";; Option (%u): ", opt_code); short_hex_print(opt_data, opt_len); } pos += 4 + opt_len; } }
/*----------------------------------------------------------------------------*/ _public_ size_t knot_edns_wire_size(knot_rrset_t *opt_rr) { if (opt_rr == NULL) { return 0; } knot_rdata_t *rdata = knot_rdataset_at(&opt_rr->rrs, 0); assert(rdata != NULL); return KNOT_EDNS_MIN_SIZE + knot_rdata_rdlen(rdata); }
/*----------------------------------------------------------------------------*/ _public_ void knot_edns_set_do(knot_rrset_t *opt_rr) { assert(opt_rr != NULL); // Read the TTL uint32_t ttl = knot_rrset_ttl(opt_rr); // Set the DO bit ttl |= EDNS_DO_MASK; // Store the TTL to the RDATA knot_rdata_set_ttl(knot_rdataset_at(&opt_rr->rrs, 0), ttl); }
static int find_rr_pos(const knot_rdataset_t *search_in, const knot_rdata_t *rr) { for (uint16_t i = 0; i < search_in->rr_count; ++i) { const knot_rdata_t *search_rr = knot_rdataset_at(search_in, i); if (knot_rdata_cmp(rr, search_rr) == 0) { return i; } } return KNOT_ENOENT; }
/*----------------------------------------------------------------------------*/ _public_ bool knot_edns_has_option(const knot_rrset_t *opt_rr, uint16_t code) { assert(opt_rr != NULL); knot_rdata_t *rdata = knot_rdataset_at(&opt_rr->rrs, 0); assert(rdata != NULL); uint8_t *pos = find_option(rdata, code); return pos != NULL; }
static int remove_rr_at(knot_rdataset_t *rrs, size_t pos, knot_mm_t *mm) { if (rrs == NULL || pos >= rrs->rr_count) { return KNOT_EINVAL; } knot_rdata_t *old_rr = knot_rdataset_at(rrs, pos); knot_rdata_t *last_rr = knot_rdataset_at(rrs, rrs->rr_count - 1); assert(old_rr); assert(last_rr); size_t total_size = knot_rdataset_size(rrs); uint16_t old_size = knot_rdata_rdlen(old_rr); uint8_t *old_threshold = old_rr + knot_rdata_array_size(old_size); uint8_t *last_threshold = last_rr + knot_rdata_array_size(knot_rdata_rdlen(last_rr)); // Move RDATA memmove(old_rr, old_threshold, last_threshold - old_threshold); if (rrs->rr_count > 1) { // Realloc RDATA void *tmp = mm_realloc(mm, rrs->data, total_size - (knot_rdata_array_size(old_size)), total_size); if (tmp == NULL) { return KNOT_ENOMEM; } else { rrs->data = tmp; } } else { // Free RDATA mm_free(mm, rrs->data); rrs->data = NULL; } rrs->rr_count--; return KNOT_EOK; }
static void set_value_to_ttl(knot_rrset_t *opt_rr, size_t offset, uint8_t value) { uint32_t ttl = 0; uint8_t *ttl_ptr = (uint8_t *)&ttl; // TTL is stored in machine byte order. Convert it to wire order first. wire_write_u32(ttl_ptr, knot_rrset_ttl(opt_rr)); // Set the Extended RCODE in the converted TTL memcpy(ttl_ptr + offset, &value, sizeof(uint8_t)); // Convert it back to machine byte order uint32_t ttl_local = wire_read_u32(ttl_ptr); // Store the TTL to the RDATA knot_rdata_set_ttl(knot_rdataset_at(&opt_rr->rrs, 0), ttl_local); }
/*! * \brief Create and zero SIG(0) RDATA field. * * \param rrset SIG(0) RR set. * \param key Signing key. * * \return SIG(0) RDATA. */ static uint8_t *sig0_create_rdata(knot_rrset_t *rrset, knot_dnssec_key_t *key) { assert(rrset); assert(key); size_t rdata_size = knot_rrsig_rdata_size(key); const uint32_t ttl = 0; uint8_t rdata[rdata_size]; sig0_write_rdata(rdata, key); if (knot_rrset_add_rdata(rrset, rdata, rdata_size, ttl, NULL) != KNOT_EOK) { return NULL; } const knot_rdata_t *rr = knot_rdataset_at(&rrset->rrs, 0); return knot_rdata_data(rr); }
_public_ size_t knot_rdataset_size(const knot_rdataset_t *rrs) { if (rrs == NULL) { return 0; } size_t total_size = 0; for (size_t i = 0; i < rrs->rr_count; ++i) { const knot_rdata_t *rr = knot_rdataset_at(rrs, i); assert(rr); total_size += knot_rdata_array_size(knot_rdata_rdlen(rr)); } return total_size; }
_public_ int knot_rdataset_merge(knot_rdataset_t *rrs1, const knot_rdataset_t *rrs2, knot_mm_t *mm) { if (rrs1 == NULL || rrs2 == NULL) { return KNOT_EINVAL; } for (uint16_t i = 0; i < rrs2->rr_count; ++i) { const knot_rdata_t *rr = knot_rdataset_at(rrs2, i); int ret = knot_rdataset_add(rrs1, rr, mm); if (ret != KNOT_EOK) { return ret; } } return KNOT_EOK; }
int kr_check_signature(const knot_rrset_t *rrsigs, size_t pos, const dnssec_key_t *key, const knot_rrset_t *covered, int trim_labels) { if (!rrsigs || !key || !dnssec_key_can_verify(key)) { return kr_error(EINVAL); } int ret = 0; dnssec_sign_ctx_t *sign_ctx = NULL; dnssec_binary_t signature = {0, }; knot_rrsig_signature(&rrsigs->rrs, pos, &signature.data, &signature.size); if (!signature.data || !signature.size) { ret = kr_error(EINVAL); goto fail; } if (dnssec_sign_new(&sign_ctx, key) != 0) { ret = kr_error(ENOMEM); goto fail; } uint32_t orig_ttl = knot_rrsig_original_ttl(&rrsigs->rrs, pos); const knot_rdata_t *rr_data = knot_rdataset_at(&rrsigs->rrs, pos); uint8_t *rdata = knot_rdata_data(rr_data); if (sign_ctx_add_data(sign_ctx, rdata, covered, orig_ttl, trim_labels) != 0) { ret = kr_error(ENOMEM); goto fail; } if (dnssec_sign_verify(sign_ctx, &signature) != 0) { ret = kr_error(EBADMSG); goto fail; } ret = kr_ok(); fail: dnssec_sign_free(sign_ctx); return ret; }
static int knot_zone_diff_rdata_return_changes(const knot_rrset_t *rrset1, const knot_rrset_t *rrset2, knot_rrset_t *changes) { if (rrset1 == NULL || rrset2 == NULL) { dbg_zonediff("zone_diff: diff_rdata: NULL arguments. (%p) (%p).\n", rrset1, rrset2); return KNOT_EINVAL; } /* * Take one rdata from first list and search through the second list * looking for an exact match. If no match occurs, it means that this * particular RR has changed. * After the list has been traversed, we have a list of * changed/removed rdatas. This has awful computation time. */ /* Create fake RRSet, it will be easier to handle. */ knot_rrset_init(changes, rrset1->owner, rrset1->type, rrset1->rclass); const knot_rdata_descriptor_t *desc = knot_get_rdata_descriptor(rrset1->type); assert(desc); uint16_t rr1_count = rrset1->rrs.rr_count; for (uint16_t i = 0; i < rr1_count; ++i) { if (!rr_exists(rrset2, rrset1, i)) { /* * No such RR is present in 'rrset2'. We'll copy * index 'i' into 'changes' RRSet. */ knot_rdata_t *add_rr = knot_rdataset_at(&rrset1->rrs, i); int ret = knot_rdataset_add(&changes->rrs, add_rr, NULL); if (ret != KNOT_EOK) { knot_rdataset_clear(&changes->rrs, NULL); return ret; } } } return KNOT_EOK; }
_public_ int knot_rdataset_subtract(knot_rdataset_t *from, const knot_rdataset_t *what, knot_mm_t *mm) { if (from == NULL || what == NULL || from->data == what->data) { return KNOT_EINVAL; } for (uint16_t i = 0; i < what->rr_count; ++i) { const knot_rdata_t *to_remove = knot_rdataset_at(what, i); int pos_to_remove = find_rr_pos(from, to_remove); if (pos_to_remove >= 0) { int ret = remove_rr_at(from, pos_to_remove, mm); if (ret != KNOT_EOK) { return ret; } } } return KNOT_EOK; }
_public_ int knot_rdataset_add(knot_rdataset_t *rrs, const knot_rdata_t *rr, knot_mm_t *mm) { if (rrs == NULL || rr == NULL) { return KNOT_EINVAL; } for (uint16_t i = 0; i < rrs->rr_count; ++i) { const knot_rdata_t *rrset_rr = knot_rdataset_at(rrs, i); int cmp = knot_rdata_cmp(rrset_rr, rr); if (cmp == 0) { // Duplication - no need to add this RR return KNOT_EOK; } else if (cmp > 0) { // Found position to insert return add_rr_at(rrs, rr, i, mm); } } // If flow gets here, it means that we should insert at the last position return add_rr_at(rrs, rr, rrs->rr_count, mm); }
int kr_dnskeys_trusted(const knot_pkt_t *pkt, knot_section_t section_id, const knot_rrset_t *keys, const knot_rrset_t *ta, const knot_dname_t *zone_name, uint32_t timestamp, bool has_nsec3) { if (!pkt || !keys || !ta) { return kr_error(EINVAL); } /* RFC4035 5.2, bullet 1 * The supplied DS record has been authenticated. * It has been validated or is part of a configured trust anchor. */ for (uint16_t i = 0; i < keys->rrs.rr_count; ++i) { /* RFC4035 5.3.1, bullet 8 */ /* ZSK */ const knot_rdata_t *krr = knot_rdataset_at(&keys->rrs, i); const uint8_t *key_data = knot_rdata_data(krr); if (!kr_dnssec_key_zsk(key_data) || kr_dnssec_key_revoked(key_data)) { continue; } struct dseckey *key; if (kr_dnssec_key_from_rdata(&key, keys->owner, key_data, knot_rdata_rdlen(krr)) != 0) { continue; } if (kr_authenticate_referral(ta, (dnssec_key_t *) key) != 0) { kr_dnssec_key_free(&key); continue; } if (kr_rrset_validate_with_key(pkt, section_id, keys, keys, i, key, zone_name, timestamp, has_nsec3) != 0) { kr_dnssec_key_free(&key); continue; } kr_dnssec_key_free(&key); return kr_ok(); } /* No useable key found */ return kr_error(ENOENT); }
_public_ bool knot_rdataset_member(const knot_rdataset_t *rrs, const knot_rdata_t *rr, bool cmp_ttl) { for (uint16_t i = 0; i < rrs->rr_count; ++i) { const knot_rdata_t *cmp_rr = knot_rdataset_at(rrs, i); if (cmp_ttl) { if (knot_rdata_ttl(rr) != knot_rdata_ttl(cmp_rr)) { continue; } } int cmp = knot_rdata_cmp(cmp_rr, rr); if (cmp == 0) { // Match. return true; } if (cmp > 0) { // 'Greater' RR present, no need to continue. return false; } } return false; }
_public_ int knot_rdataset_intersect(const knot_rdataset_t *a, const knot_rdataset_t *b, knot_rdataset_t *out, knot_mm_t *mm) { if (a == NULL || b == NULL || out == NULL) { return KNOT_EINVAL; } knot_rdataset_init(out); const bool compare_ttls = false; for (uint16_t i = 0; i < a->rr_count; ++i) { const knot_rdata_t *rr = knot_rdataset_at(a, i); if (knot_rdataset_member(b, rr, compare_ttls)) { // Add RR into output intersection RRSet. int ret = knot_rdataset_add(out, rr, mm); if (ret != KNOT_EOK) { knot_rdataset_clear(out, mm); return ret; } } } return KNOT_EOK; }
_public_ uint32_t knot_rdataset_ttl(const knot_rdataset_t *rrs) { return knot_rdata_ttl(knot_rdataset_at(rrs, 0)); }
int kr_rrset_validate_with_key(const knot_pkt_t *pkt, knot_section_t section_id, const knot_rrset_t *covered, const knot_rrset_t *keys, size_t key_pos, const struct dseckey *key, const knot_dname_t *zone_name, uint32_t timestamp, bool has_nsec3) { struct dseckey *created_key = NULL; if (key == NULL) { const knot_rdata_t *krr = knot_rdataset_at(&keys->rrs, key_pos); int ret = kr_dnssec_key_from_rdata(&created_key, keys->owner, knot_rdata_data(krr), knot_rdata_rdlen(krr)); if (ret != 0) { return ret; } key = created_key; } uint16_t keytag = dnssec_key_get_keytag((dnssec_key_t *)key); int covered_labels = knot_dname_labels(covered->owner, NULL); if (knot_dname_is_wildcard(covered->owner)) { /* The asterisk does not count, RFC4034 3.1.3, paragraph 3. */ --covered_labels; } const knot_pktsection_t *sec = knot_pkt_section(pkt, section_id); for (unsigned i = 0; i < sec->count; ++i) { /* Consider every RRSIG that matches owner and covers the class/type. */ const knot_rrset_t *rrsig = knot_pkt_rr(sec, i); if (rrsig->type != KNOT_RRTYPE_RRSIG) { continue; } if ((covered->rclass != rrsig->rclass) || !knot_dname_is_equal(covered->owner, rrsig->owner)) { continue; } for (uint16_t j = 0; j < rrsig->rrs.rr_count; ++j) { int val_flgs = 0; int trim_labels = 0; if (knot_rrsig_type_covered(&rrsig->rrs, j) != covered->type) { continue; } if (validate_rrsig_rr(&val_flgs, covered_labels, rrsig, j, keys, key_pos, keytag, zone_name, timestamp) != 0) { continue; } if (val_flgs & FLG_WILDCARD_EXPANSION) { trim_labels = wildcard_radix_len_diff(covered->owner, rrsig, j); if (trim_labels < 0) { break; } } if (kr_check_signature(rrsig, j, (dnssec_key_t *) key, covered, trim_labels) != 0) { continue; } if (val_flgs & FLG_WILDCARD_EXPANSION) { int ret = 0; if (!has_nsec3) { ret = kr_nsec_wildcard_answer_response_check(pkt, KNOT_AUTHORITY, covered->owner); } else { ret = kr_nsec3_wildcard_answer_response_check(pkt, KNOT_AUTHORITY, covered->owner, trim_labels - 1); } if (ret != 0) { continue; } } /* Validated with current key, OK */ kr_dnssec_key_free(&created_key); return kr_ok(); } } /* No applicable key found, cannot be validated. */ kr_dnssec_key_free(&created_key); return kr_error(ENOENT); }
int main(int argc, char *argv[]) { plan(34); // Test init knot_rdataset_t rdataset; knot_rdataset_init(&rdataset); ok(rdataset.data == NULL && rdataset.rr_count == 0, "rdataset: init."); // Test rdata addition knot_rdata_t rdata_gt[knot_rdata_array_size(4)]; knot_rdata_init(rdata_gt, 4, (uint8_t *)"wxyz", 3600); int ret = knot_rdataset_add(NULL, NULL, NULL); ok(ret == KNOT_EINVAL, "rdataset: add NULL."); ret = knot_rdataset_add(&rdataset, rdata_gt, NULL); bool add_ok = ret == KNOT_EOK && rdataset.rr_count == 1 && knot_rdata_cmp(rdata_gt, rdataset.data) == 0; ok(add_ok, "rdataset: add."); knot_rdata_t rdata_lo[knot_rdata_array_size(4)]; knot_rdata_init(rdata_lo, 4, (uint8_t *)"abcd", 3600); ret = knot_rdataset_add(&rdataset, rdata_lo, NULL); add_ok = ret == KNOT_EOK && rdataset.rr_count == 2 && knot_rdata_cmp(rdata_lo, rdataset.data) == 0; ok(add_ok, "rdataset: add lower."); // Test getters ok(knot_rdata_cmp(knot_rdataset_at(&rdataset, 0), rdata_lo) == 0 && knot_rdata_cmp(knot_rdataset_at(&rdataset, 1), rdata_gt) == 0, "rdataset: at."); ok(knot_rdataset_size(&rdataset) == knot_rdata_array_size(4) * 2, "rdataset: size."); // Test copy ok(knot_rdataset_copy(NULL, NULL, NULL) == KNOT_EINVAL, "rdataset: copy NULL."); knot_rdataset_t copy; ret = knot_rdataset_copy(©, &rdataset, NULL); const bool copy_ok = ret == KNOT_EOK && copy.rr_count == rdataset.rr_count && knot_rdataset_size(©) == knot_rdataset_size(&rdataset) && memcmp(rdataset.data, copy.data, knot_rdataset_size(&rdataset)) == 0; ok(copy_ok, "rdataset: copy"); // Test eq ok(knot_rdataset_eq(&rdataset, ©), "rdataset: equal"); // Test clear knot_rdataset_clear(©, NULL); ok(copy.rr_count == 0 && copy.data == NULL, "rdataset: clear."); // Test not equal (different count) ok(!knot_rdataset_eq(&rdataset, ©), "rdataset: not equal - count"); // Test member knot_rdata_t not_a_member[knot_rdata_array_size(1)]; knot_rdata_init(not_a_member, 1, (uint8_t *)"?", 3600); ok(knot_rdataset_member(&rdataset, rdata_gt, true), "rdataset: is member."); ok(!knot_rdataset_member(&rdataset, not_a_member, true), "rdataset: is not member."); knot_rdata_set_ttl(rdata_gt, 1234); ok(knot_rdataset_member(&rdataset, rdata_gt, false), "rdataset: is member TTL."); ok(!knot_rdataset_member(&rdataset, rdata_gt, true), "rdataset: is not member TTL."); // Test merge ok(knot_rdataset_merge(NULL, NULL, NULL) == KNOT_EINVAL, "rdataset: merge NULL."); knot_rdataset_t empty; knot_rdataset_init(&empty); ret = knot_rdataset_merge(&empty, &rdataset, NULL); bool merge_ok = ret == KNOT_EOK && knot_rdataset_eq(&empty, &rdataset); ok(merge_ok, "rdataset: merge empty."); knot_rdata_t *data_before = rdataset.data; ret = knot_rdataset_merge(&rdataset, &rdataset, NULL); merge_ok = ret == KNOT_EOK && rdataset.rr_count == 2 && data_before == rdataset.data; ok(merge_ok, "rdataset: merge self."); knot_rdataset_clear(&empty, NULL); // Init structs for merge sort testing knot_rdataset_t rdataset_lo; // "Lower" rdataset knot_rdataset_init(&rdataset_lo); RDATASET_INIT_WITH(rdataset_lo, rdata_lo); knot_rdataset_t rdataset_gt; // "Greater" rdataset knot_rdataset_init(&rdataset_gt); RDATASET_INIT_WITH(rdataset_gt, rdata_gt); // Test not equal - different data ok(!knot_rdataset_eq(&rdataset_gt, &rdataset_lo), "rdataset: data not equal."); // Test that merge keeps the sorted order ret = knot_rdataset_merge(&rdataset_lo, &rdataset_gt, NULL); merge_ok = ret == KNOT_EOK && knot_rdataset_eq(&rdataset_lo, &rdataset); ok(merge_ok, "rdataset: merge into lower."); RDATASET_INIT_WITH(rdataset_lo, rdata_lo); RDATASET_INIT_WITH(rdataset_gt, rdata_gt); ret = knot_rdataset_merge(&rdataset_gt, &rdataset_lo, NULL); merge_ok = ret == KNOT_EOK && knot_rdataset_eq(&rdataset_gt, &rdataset); ok(merge_ok, "rdataset: merge into greater."); // Test intersect ok(knot_rdataset_intersect(NULL, NULL, NULL, NULL) == KNOT_EINVAL, "rdataset: intersect NULL."); knot_rdataset_t intersection; ret = knot_rdataset_intersect(&rdataset, &rdataset, &intersection, NULL); bool intersect_ok = ret == KNOT_EOK && knot_rdataset_eq(&rdataset, &intersection); ok(intersect_ok, "rdataset: intersect self."); knot_rdataset_clear(&intersection, NULL); RDATASET_INIT_WITH(rdataset_lo, rdata_lo); RDATASET_INIT_WITH(rdataset_gt, rdata_gt); ret = knot_rdataset_intersect(&rdataset_lo, &rdataset_gt, &intersection, NULL); intersect_ok = ret == KNOT_EOK && intersection.rr_count == 0; ok(intersect_ok, "rdataset: intersect no common."); ret = knot_rdataset_intersect(&rdataset, &rdataset_lo, &intersection, NULL); intersect_ok = ret == KNOT_EOK && knot_rdataset_eq(&intersection, &rdataset_lo); ok(intersect_ok, "rdataset: intersect normal."); knot_rdataset_clear(&intersection, NULL); // Test subtract ok(knot_rdataset_subtract(NULL, NULL, NULL) == KNOT_EINVAL, "rdataset: subtract NULL."); ok(knot_rdataset_subtract(&rdataset, &rdataset, NULL) == KNOT_EINVAL, "rdataset: subtract self."); ret = knot_rdataset_copy(©, &rdataset, NULL); assert(ret == KNOT_EOK); ret = knot_rdataset_subtract(©, &rdataset, NULL); bool subtract_ok = ret == KNOT_EOK && copy.rr_count == 0; ok(subtract_ok, "rdataset: subtract identical."); RDATASET_INIT_WITH(rdataset_lo, rdata_lo); RDATASET_INIT_WITH(rdataset_gt, rdata_gt); data_before = rdataset_lo.data; ret = knot_rdataset_subtract(&rdataset_lo, &rdataset_gt, NULL); subtract_ok = ret == KNOT_EOK && rdataset_lo.rr_count == 1 && rdataset_lo.data == data_before; ok(subtract_ok, "rdataset: subtract no common."); ret = knot_rdataset_subtract(&rdataset, &rdataset_gt, NULL); subtract_ok = ret == KNOT_EOK && knot_rdataset_eq(&rdataset, &rdataset_lo); ok(subtract_ok, "rdataset: subtract normal."); ret = knot_rdataset_subtract(&rdataset, &rdataset_lo, NULL); subtract_ok = ret == KNOT_EOK && rdataset.rr_count == 0 && rdataset.data == NULL; ok(subtract_ok, "rdataset: subtract last."); ret = knot_rdataset_reserve(&rdataset, 65536, NULL); ok(ret == KNOT_EINVAL, "rdataset: reserve too much"); RDATASET_INIT_WITH(rdataset, rdata_gt); size_t old_rrs_size = knot_rdataset_size(&rdataset); size_t rr_size = knot_rdata_rdlen(rdata_lo); ret = knot_rdataset_reserve(&rdataset, rr_size, NULL); size_t new_rrs_size = knot_rdataset_size(&rdataset); bool reserve_ok = ret == KNOT_EOK && new_rrs_size == (old_rrs_size + knot_rdata_array_size(rr_size)); ok(reserve_ok, "rdataset: reserve normal"); RDATASET_INIT_WITH(copy, rdata_lo); knot_rdataset_add(©, rdata_gt, NULL); knot_rdata_init(knot_rdataset_at(&rdataset, 1), 4, (uint8_t *)"abcd", 3600); ret = knot_rdataset_sort_at(&rdataset, 1, NULL); bool sort_ok = ret == KNOT_EOK && knot_rdataset_eq(&rdataset, ©); ok(sort_ok, "rdataset: sort reserved space"); knot_rdataset_clear(©, NULL); knot_rdataset_clear(&rdataset, NULL); knot_rdataset_clear(&rdataset_lo, NULL); knot_rdataset_clear(&rdataset_gt, NULL); return EXIT_SUCCESS; }