Пример #1
0
_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;
}
Пример #2
0
/*----------------------------------------------------------------------------*/
_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;
}
Пример #3
0
/*----------------------------------------------------------------------------*/
_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);
}
Пример #4
0
int main(int argc, char *argv[])
{
	plan(9);

	// Test array size
	size_t array_size = knot_rdata_array_size(16);
	ok(array_size == sizeof(struct rr_offsets) + 16, "rdata: array size.");

	// Test init
	knot_rdata_t rdata[array_size];
	uint8_t payload[16] = "abcdefghijklmnop";
	knot_rdata_init(rdata, 16, payload, 3600);
	const bool set_ok = knot_rdata_rdlen(rdata) == 16 &&
	                    knot_rdata_ttl(rdata) == 3600 &&
	                    memcmp(knot_rdata_data(rdata), payload, 16) == 0;
	ok(set_ok, "rdata: init.");

	// Test setters
	knot_rdata_set_ttl(rdata, 1234);
	ok(knot_rdata_ttl(rdata) == 1234, "rdata: set TTL.");
	knot_rdata_set_rdlen(rdata, 1);
	ok(knot_rdata_rdlen(rdata) == 1, "rdata: set RDLEN.");

	// Test compare
	knot_rdata_set_rdlen(rdata, 16);
	ok(knot_rdata_cmp(rdata, rdata) == 0, "rdata: cmp eq.");

	knot_rdata_t *lower = rdata;
	knot_rdata_t greater[knot_rdata_array_size(16)];
	knot_rdata_init(greater, 16, (uint8_t *)"qrstuvwxyz123456", 1234);
	ok(knot_rdata_cmp(lower, greater) < 0, "rdata: cmp lower.");
	ok(knot_rdata_cmp(greater, lower) > 0, "rdata: cmp greater.");

	// Payloads will be the same.
	memcpy(knot_rdata_data(greater), knot_rdata_data(lower), 16);
	assert(knot_rdata_cmp(lower, greater) == 0);

	knot_rdata_set_rdlen(lower, 15);
	ok(knot_rdata_cmp(lower, greater) < 0, "rdata: cmp lower size.");
	ok(knot_rdata_cmp(greater, lower) > 0, "rdata: cmp greater size.");

	return 0;
}
Пример #5
0
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;
    }
}
Пример #6
0
Файл: edns.c Проект: idtek/knot
static bool check_option(knot_rdata_t *rdata, uint16_t opt_code,
                         uint16_t opt_len, uint8_t *opt_data, char *msg,
                         int *done)
{
	assert(rdata != NULL);
	bool success = true;

	uint8_t *data = knot_rdata_data(rdata);
	uint16_t data_len = knot_rdata_rdlen(rdata);

	/* Check RDLENGTH according to given data length. */
	bool check = (data_len >= 4 + opt_len);
	ok(check, "%s: RDLENGTH (%u)", msg, data_len);
	success &= check;
	(*done)++;

	/* Find the desired option. */
	bool found = false;
	int pos = 0;
	while (pos <= data_len - 4) {
		uint16_t code = wire_read_u16(data + pos + OFFSET_OPT_CODE);
		if (code == opt_code) {
			found = true;
			break;
		}
		uint16_t len = wire_read_u16(data + pos + OFFSET_OPT_SIZE);
		pos += 4 + len;
	}

	/* Check that the option is present. */
	ok(found, "%s: find OPTION %u in OPT RR", msg, opt_code);
	success &= found;
	(*done)++;

	/* Check that the first OPTION's size si the size of the option data. */
	uint16_t opt_size = wire_read_u16(data + pos + OFFSET_OPT_SIZE);
	check = (opt_size == opt_len);
	ok(check, "%s: OPTION data size", msg);
	success &= check;
	(*done)++;

	/* Check the actual NSID data. */
	check = (memcmp(data + pos + OFFSET_OPT_DATA, opt_data, opt_len)) == 0;
	ok(check, "%s: OPTION data", msg);
	success &= check;
	(*done)++;

	return success;
}
Пример #7
0
/*!
 * \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);
}
Пример #8
0
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;
}
Пример #9
0
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;
}
Пример #10
0
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);
}
Пример #11
0
/*!
 * \brief Find OPTION with the given code in the OPT RDATA.
 *
 * \param rdata     RDATA to search in.
 * \param opt_code  Code of the OPTION to find.
 * \param[out] pos  Position of the OPTION or NULL if not found.
 */
static uint8_t *find_option(knot_rdata_t *rdata, uint16_t opt_code)
{
	assert(rdata != NULL);

	uint8_t *data = knot_rdata_data(rdata);
	uint16_t rdlength = knot_rdata_rdlen(rdata);

	uint8_t *pos = NULL;

	int i = 0;
	while (i + KNOT_EDNS_OPTION_HDRLEN <= rdlength) {
		uint16_t code = wire_read_u16(data + i);
		if (opt_code == code) {
			pos = data + i;
			break;
		}
		uint16_t opt_len = wire_read_u16(data + i
		                                      + sizeof(uint16_t));
		i += (KNOT_EDNS_OPTION_HDRLEN + opt_len);
	}

	return pos;
}
Пример #12
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);
}