Пример #1
0
/*!
 * \brief Connect two nodes by adding a NSEC RR into the first node.
 *
 * Callback function, signature chain_iterate_cb.
 *
 * \param a     First node.
 * \param b     Second node (immediate follower of a).
 * \param data  Pointer to nsec_chain_iterate_data_t holding parameters
 *              including changeset.
 *
 * \return Error code, KNOT_EOK if successful.
 */
static int connect_nsec_nodes(zone_node_t *a, zone_node_t *b,
                              nsec_chain_iterate_data_t *data)
{
	assert(a);
	assert(b);
	assert(data);

	if (b->rrset_count == 0 || b->flags & NODE_FLAGS_NONAUTH) {
		return NSEC_NODE_SKIP;
	}

	int ret = 0;

	/*!
	 * If the node has no other RRSets than NSEC (and possibly RRSIGs),
	 * just remove the NSEC and its RRSIG, they are redundant
	 */
	if (node_rrtype_exists(b, KNOT_RRTYPE_NSEC)
	    && knot_nsec_empty_nsec_and_rrsigs_in_node(b)) {
		ret = knot_nsec_changeset_remove(b, data->changeset);
		if (ret != KNOT_EOK) {
			return ret;
		}
		// Skip the 'b' node
		return NSEC_NODE_SKIP;
	}

	// create new NSEC
	knot_rrset_t *new_nsec = create_nsec_rrset(a, b, data->ttl);
	if (!new_nsec) {
		dbg_dnssec_detail("Failed to create new NSEC.\n");
		return KNOT_ENOMEM;
	}

	knot_rrset_t old_nsec = node_rrset(a, KNOT_RRTYPE_NSEC);
	if (!knot_rrset_empty(&old_nsec)) {
		if (knot_rrset_equal(new_nsec, &old_nsec,
		                     KNOT_RRSET_COMPARE_WHOLE)) {
			// current NSEC is valid, do nothing
			dbg_dnssec_detail("NSECs equal.\n");
			knot_rrset_free(&new_nsec, NULL);
			return KNOT_EOK;
		}

		dbg_dnssec_detail("NSECs not equal, replacing.\n");
		// Mark the node so that we do not sign this NSEC
		a->flags |= NODE_FLAGS_REMOVED_NSEC;
		ret = knot_nsec_changeset_remove(a, data->changeset);
		if (ret != KNOT_EOK) {
			knot_rrset_free(&new_nsec, NULL);
			return ret;
		}
	}

	dbg_dnssec_detail("Adding new NSEC to changeset.\n");
	// Add new NSEC to the changeset (no matter if old was removed)
	return knot_changeset_add_rrset(data->changeset, new_nsec,
	                                KNOT_CHANGESET_ADD);
}
Пример #2
0
/*!
 * \brief Add entry for removed NSEC to the changeset.
 */
int knot_nsec_changeset_remove(const zone_node_t *n,
                               knot_changeset_t *changeset)
{
	if (changeset == NULL) {
		return KNOT_EINVAL;
	}

	int result = KNOT_EOK;

	knot_rrset_t *nsec = node_create_rrset(n, KNOT_RRTYPE_NSEC);
	if (nsec == NULL) {
		nsec = node_create_rrset(n, KNOT_RRTYPE_NSEC3);
	}
	if (nsec) {
		// update changeset
		result = knot_changeset_add_rrset(changeset, nsec,
		                                  KNOT_CHANGESET_REMOVE);
		if (result != KNOT_EOK) {
			knot_rrset_free(&nsec, NULL);
			return result;
		}
	}

	knot_rrset_t rrsigs = node_rrset(n, KNOT_RRTYPE_RRSIG);
	if (!knot_rrset_empty(&rrsigs)) {
		knot_rrset_t *synth_rrsigs = knot_rrset_new(n->owner,
							    KNOT_RRTYPE_RRSIG,
							    KNOT_CLASS_IN,
							    NULL);
		if (synth_rrsigs == NULL) {
			return KNOT_ENOMEM;
		}
		result = knot_synth_rrsig(KNOT_RRTYPE_NSEC, &rrsigs.rrs,
		                          &synth_rrsigs->rrs, NULL);
		if (result == KNOT_ENOENT) {
			// Try removing NSEC3 RRSIGs
			result = knot_synth_rrsig(KNOT_RRTYPE_NSEC3, &rrsigs.rrs,
			                          &synth_rrsigs->rrs, NULL);
		}

		if (result != KNOT_EOK) {
			knot_rrset_free(&synth_rrsigs, NULL);
			if (result != KNOT_ENOENT) {
				return result;
			}
			return KNOT_EOK;
		}

		// store RRSIG
		result = knot_changeset_add_rrset(changeset, synth_rrsigs,
		                                  KNOT_CHANGESET_REMOVE);
		if (result != KNOT_EOK) {
			knot_rrset_free(&synth_rrsigs, NULL);
			return result;
		}
	}

	return KNOT_EOK;
}
Пример #3
0
static knot_rrset_t *update_ds(struct kr_zonecut *cut, const knot_pktsection_t *sec)
{
	/* Aggregate DS records (if using multiple keys) */
	knot_rrset_t *new_ds = NULL;
	for (unsigned i = 0; i < sec->count; ++i) {
		const knot_rrset_t *rr = knot_pkt_rr(sec, i);
		if (rr->type != KNOT_RRTYPE_DS) {
			continue;
		}
		int ret = 0;
		if (new_ds) {
			ret = knot_rdataset_merge(&new_ds->rrs, &rr->rrs, cut->pool);
		} else {
			new_ds = knot_rrset_copy(rr, cut->pool);
			if (!new_ds) {
				return NULL;
			}
		}
		if (ret != 0) {
			knot_rrset_free(&new_ds, cut->pool);
			return NULL;
		}
	}
	return new_ds;	
}
Пример #4
0
_public_
int knot_sig0_sign(uint8_t *wire, size_t *wire_size, size_t wire_max_size,
                   knot_dnssec_key_t *key)
{
	knot_rrset_t *sig_rrset = sig0_create_rrset();
	if (!sig_rrset) {
		return KNOT_ENOMEM;
	}

	// SIG(0) headers without signature

	uint8_t *sig_rdata = sig0_create_rdata(sig_rrset, key);
	if (!sig_rdata) {
		knot_rrset_free(&sig_rrset, NULL);
		return KNOT_ENOMEM;
	}

	// convert to wire

	uint8_t *wire_end = wire + *wire_size;
	size_t wire_avail_size = wire_max_size - *wire_size;
	size_t wire_sig_size = 0;

	int result = knot_rrset_to_wire(sig_rrset, wire_end, wire_avail_size, NULL);

	knot_rrset_free(&sig_rrset, NULL);

	if (result < 0) {
		return result;
	}

	wire_sig_size = result;

	// create signature

	result = sig0_write_signature(wire, *wire_size, wire_sig_size, key);
	if (result != KNOT_EOK) {
		return result;
	}

	uint16_t wire_arcount = knot_wire_get_arcount(wire);
	knot_wire_set_arcount(wire, wire_arcount + 1);

	*wire_size += wire_sig_size;

	return KNOT_EOK;
}
Пример #5
0
static int knot_zone_diff_load_soas(const zone_contents_t *zone1,
                                    const zone_contents_t *zone2,
                                    changeset_t *changeset)
{
	if (zone1 == NULL || zone2 == NULL || changeset == NULL) {
		return KNOT_EINVAL;
	}

	const zone_node_t *apex1 = zone1->apex;
	const zone_node_t *apex2 = zone2->apex;
	if (apex1 == NULL || apex2 == NULL) {
		return KNOT_EINVAL;
	}

	knot_rrset_t soa_rrset1 = node_rrset(apex1, KNOT_RRTYPE_SOA);
	knot_rrset_t soa_rrset2 = node_rrset(apex2, KNOT_RRTYPE_SOA);
	if (knot_rrset_empty(&soa_rrset1) || knot_rrset_empty(&soa_rrset2)) {
		return KNOT_EINVAL;
	}

	if (soa_rrset1.rrs.rr_count == 0 ||
	    soa_rrset2.rrs.rr_count == 0) {
		return KNOT_EINVAL;
	}

	int64_t soa_serial1 = knot_soa_serial(&soa_rrset1.rrs);
	int64_t soa_serial2 = knot_soa_serial(&soa_rrset2.rrs);

	if (serial_compare(soa_serial1, soa_serial2) == 0) {
		return KNOT_ENODIFF;
	}

	if (serial_compare(soa_serial1, soa_serial2) > 0) {
		return KNOT_ERANGE;
	}

	assert(changeset);

	changeset->soa_from = knot_rrset_copy(&soa_rrset1, NULL);
	if (changeset->soa_from == NULL) {
		return KNOT_ENOMEM;
	}
	changeset->soa_to = knot_rrset_copy(&soa_rrset2, NULL);
	if (changeset->soa_to == NULL) {
		knot_rrset_free(&changeset->soa_from, NULL);
		return KNOT_ENOMEM;
	}

	dbg_zonediff_verb("zone_diff: load_soas: SOAs diffed. "
	                  "(%"PRId64" -> %"PRId64")\n",
	                  soa_serial1, soa_serial2);

	return KNOT_EOK;
}
Пример #6
0
static int wrk_resolve(lua_State *L)
{
    struct worker_ctx *worker = wrk_luaget(L);
    if (!worker) {
        return 0;
    }
    /* Create query packet */
    knot_pkt_t *pkt = knot_pkt_new(NULL, KNOT_EDNS_MAX_UDP_PAYLOAD, NULL);
    if (!pkt) {
        lua_pushstring(L, strerror(ENOMEM));
        lua_error(L);
    }
    uint8_t dname[KNOT_DNAME_MAXLEN];
    knot_dname_from_str(dname, lua_tostring(L, 1), sizeof(dname));
    /* Check class and type */
    uint16_t rrtype = lua_tointeger(L, 2);
    if (!lua_isnumber(L, 2)) {
        lua_pushstring(L, "invalid RR type");
        lua_error(L);
    }
    uint16_t rrclass = lua_tointeger(L, 3);
    if (!lua_isnumber(L, 3)) { /* Default class is IN */
        rrclass = KNOT_CLASS_IN;
    }
    knot_pkt_put_question(pkt, dname, rrclass, rrtype);
    knot_wire_set_rd(pkt->wire);
    /* Add OPT RR */
    pkt->opt_rr = knot_rrset_copy(worker->engine->resolver.opt_rr, NULL);
    if (!pkt->opt_rr) {
        return kr_error(ENOMEM);
    }
    /* Add completion callback */
    int ret = 0;
    unsigned options = lua_tointeger(L, 4);
    if (lua_isfunction(L, 5)) {
        /* Store callback in registry */
        lua_pushvalue(L, 5);
        int cb = luaL_ref(L, LUA_REGISTRYINDEX);
        ret = worker_resolve(worker, pkt, options, resolve_callback, (void *) (intptr_t)cb);
    } else {
        ret = worker_resolve(worker, pkt, options, NULL, NULL);
    }

    knot_rrset_free(&pkt->opt_rr, NULL);
    knot_pkt_free(&pkt);
    lua_pushboolean(L, ret == 0);
    return 1;
}
Пример #7
0
int knot_tsig_add(uint8_t *msg, size_t *msg_len, size_t msg_max_len,
                  uint16_t tsig_rcode, const knot_rrset_t *tsig_rr)
{
	/*! \todo Revise!! */

	if (!msg || !msg_len || !tsig_rr) {
		return KNOT_EINVAL;
	}

	/*! \todo What key to use, when we do not sign? Does this even work? */
	knot_rrset_t *tmp_tsig =
		knot_rrset_new(tsig_rr->owner, KNOT_RRTYPE_TSIG,
		               KNOT_CLASS_ANY, NULL);
	if (!tmp_tsig) {
		dbg_tsig("TSIG: tmp_tsig = NULL\n");
		return KNOT_ENOMEM;
	}

	assert(tsig_rcode != KNOT_RCODE_BADTIME);
	tsig_create_rdata(tmp_tsig, tsig_rdata_alg_name(tsig_rr), 0, tsig_rcode);
	tsig_rdata_set_time_signed(tmp_tsig, tsig_rdata_time_signed(tsig_rr));

	/* Comparing to BIND it was found out that the Fudge should always be
	 * set to the server's value.
	 */
	tsig_rdata_set_fudge(tmp_tsig, KNOT_TSIG_FUDGE_DEFAULT);

	/* Set original ID */
	tsig_rdata_set_orig_id(tmp_tsig, knot_wire_get_id(msg));

	/* Set other len. */
	tsig_rdata_set_other_data(tmp_tsig, 0, 0);

	/* Append TSIG RR. */
	int ret = knot_tsig_append(msg, msg_len, msg_max_len, tsig_rr);

	/* key_name already referenced in RRSet, no need to free separately. */
	knot_rrset_free(&tmp_tsig, NULL);

	return ret;
}
Пример #8
0
/*!
 * \brief Create NSEC RR set.
 *
 * \param from       Node that should contain the new RRSet
 * \param to         Node that should be pointed to from 'from'
 * \param ttl        Record TTL (SOA's minimum TTL).
 *
 * \return NSEC RR set, NULL on error.
 */
static knot_rrset_t *create_nsec_rrset(const zone_node_t *from,
                                       const zone_node_t *to,
                                       uint32_t ttl)
{
	assert(from);
	assert(to);
	knot_rrset_t *rrset = knot_rrset_new(from->owner, KNOT_RRTYPE_NSEC,
					     KNOT_CLASS_IN, NULL);
	if (!rrset) {
		return NULL;
	}

	// Create bitmap
	bitmap_t rr_types = { 0 };
	bitmap_add_node_rrsets(&rr_types, from);
	bitmap_add_type(&rr_types, KNOT_RRTYPE_NSEC);
	bitmap_add_type(&rr_types, KNOT_RRTYPE_RRSIG);
	if (node_rrtype_exists(from, KNOT_RRTYPE_SOA)) {
		bitmap_add_type(&rr_types, KNOT_RRTYPE_DNSKEY);
	}

	// Create RDATA
	assert(to->owner);
	size_t next_owner_size = knot_dname_size(to->owner);
	size_t rdata_size = next_owner_size + bitmap_size(&rr_types);
	uint8_t rdata[rdata_size];

	// Fill RDATA
	memcpy(rdata, to->owner, next_owner_size);
	bitmap_write(&rr_types, rdata + next_owner_size);

	int ret = knot_rrset_add_rdata(rrset, rdata, rdata_size, ttl, NULL);
	if (ret != KNOT_EOK) {
		knot_rrset_free(&rrset, NULL);
		return NULL;
	}

	return rrset;
}
Пример #9
0
static knot_rrset_t *synth_rr(char *addr_str, synth_template_t *tpl, knot_pkt_t *pkt, struct query_data *qdata)
{
	knot_rrset_t *rr = knot_rrset_new(qdata->name, 0, KNOT_CLASS_IN,
	                                  &pkt->mm);
	if (rr == NULL) {
		return NULL;
	}

	/* Fill in the specific data. */
	int ret = KNOT_ERROR;
	switch (tpl->type) {
	case SYNTH_REVERSE: ret = reverse_rr(addr_str, tpl, pkt, rr); break;
	case SYNTH_FORWARD: ret = forward_rr(addr_str, tpl, pkt, rr); break;
	default: break;
	}

	if (ret != KNOT_EOK) {
		knot_rrset_free(&rr, &pkt->mm);
		return NULL;
	}

	return rr;
}
Пример #10
0
static void print_section_question(const knot_dname_t *owner,
                                   const uint16_t     qclass,
                                   const uint16_t     qtype,
                                   const style_t      *style)
{
    size_t buflen = 8192;
    char   *buf = calloc(buflen, 1);

    // Don't print zero TTL.
    knot_dump_style_t qstyle = style->style;
    qstyle.empty_ttl = true;

    knot_rrset_t *question = knot_rrset_new(owner, qtype, qclass, NULL);

    if (knot_rrset_txt_dump_header(question, 0, buf, buflen, &qstyle) < 0) {
        WARN("can't print whole question section\n");
    }

    printf("%s\n", buf);

    knot_rrset_free(&question, NULL);
    free(buf);
}
Пример #11
0
Файл: pkt.c Проект: idtek/knot
int main(int argc, char *argv[])
{
	plan(25);

	/* Create memory pool context. */
	int ret = 0;
	knot_mm_t mm;
	mm_ctx_mempool(&mm, MM_DEFAULT_BLKSIZE);

	/* Create names and data. */
	knot_dname_t* dnames[NAMECOUNT] = {0};
	knot_rrset_t* rrsets[NAMECOUNT] = {0};
	for (unsigned i = 0; i < NAMECOUNT; ++i) {
		dnames[i] = knot_dname_from_str_alloc(g_names[i]);
	}

	uint8_t *edns_str = (uint8_t *)"ab";
	/* Create OPT RR. */
	knot_rrset_t opt_rr;
	ret = knot_edns_init(&opt_rr, 1024, 0, 0, &mm);
	if (ret != KNOT_EOK) {
		skip_block(25, "Failed to initialize OPT RR.");
		return 0;
	}
	/* Add NSID */
	ret = knot_edns_add_option(&opt_rr, KNOT_EDNS_OPTION_NSID,
	                           strlen((char *)edns_str), edns_str, &mm);
	if (ret != KNOT_EOK) {
		knot_rrset_clear(&opt_rr, &mm);
		skip_block(25, "Failed to add NSID to OPT RR.");
		return 0;
	}

	/*
	 * Packet writer tests.
	 */

	/* Create packet. */
	knot_pkt_t *out = knot_pkt_new(NULL, MM_DEFAULT_BLKSIZE, &mm);
	ok(out != NULL, "pkt: new");

	/* Mark as response (not part of the test). */
	knot_wire_set_qr(out->wire);

	/* Secure packet. */
	const char *tsig_secret = "abcd";
	knot_tsig_key_t tsig_key;
	tsig_key.algorithm = DNSSEC_TSIG_HMAC_MD5;
	tsig_key.name = dnames[0];
	tsig_key.secret.data = (uint8_t *)strdup(tsig_secret);
	tsig_key.secret.size = strlen(tsig_secret);
	ret = knot_pkt_reserve(out, knot_tsig_wire_maxsize(&tsig_key));
	ok(ret == KNOT_EOK, "pkt: set TSIG key");

	/* Write question. */
	ret = knot_pkt_put_question(out, dnames[0], KNOT_CLASS_IN, KNOT_RRTYPE_A);
	ok(ret == KNOT_EOK, "pkt: put question");

	/* Add OPT to packet (empty NSID). */
	ret = knot_pkt_reserve(out, knot_edns_wire_size(&opt_rr));
	ok(ret == KNOT_EOK, "pkt: reserve OPT RR");

	/* Begin ANSWER section. */
	ret = knot_pkt_begin(out, KNOT_ANSWER);
	ok(ret == KNOT_EOK, "pkt: begin ANSWER");

	/* Write ANSWER section. */
	rrsets[0] = knot_rrset_new(dnames[0], KNOT_RRTYPE_A, KNOT_CLASS_IN, NULL);
	knot_dname_free(&dnames[0], NULL);
	knot_rrset_add_rdata(rrsets[0], RDVAL(0), RDLEN(0), TTL, NULL);
	ret = knot_pkt_put(out, KNOT_COMPR_HINT_QNAME, rrsets[0], 0);
	ok(ret == KNOT_EOK, "pkt: write ANSWER");

	/* Begin AUTHORITY. */
	ret = knot_pkt_begin(out, KNOT_AUTHORITY);
	ok(ret == KNOT_EOK, "pkt: begin AUTHORITY");

	/* Write rest to AUTHORITY. */
	ret = KNOT_EOK;
	for (unsigned i = 1; i < NAMECOUNT; ++i) {
		rrsets[i] = knot_rrset_new(dnames[i], KNOT_RRTYPE_NS, KNOT_CLASS_IN, NULL);
		knot_dname_free(&dnames[i], NULL);
		knot_rrset_add_rdata(rrsets[i], RDVAL(i), RDLEN(i), TTL, NULL);
		ret |= knot_pkt_put(out, KNOT_COMPR_HINT_NONE, rrsets[i], 0);
	}
	ok(ret == KNOT_EOK, "pkt: write AUTHORITY(%u)", NAMECOUNT - 1);

	/* Begin ADDITIONALS */
	ret = knot_pkt_begin(out, KNOT_ADDITIONAL);
	ok(ret == KNOT_EOK, "pkt: begin ADDITIONALS");

	/* Encode OPT RR. */
	ret = knot_pkt_put(out, KNOT_COMPR_HINT_NONE, &opt_rr, 0);
	ok(ret == KNOT_EOK, "pkt: write OPT RR");

	/*
	 * Packet reader tests.
	 */

	/* Create new packet from query packet. */
	knot_pkt_t *in = knot_pkt_new(out->wire, out->size, &out->mm);
	ok(in != NULL, "pkt: create packet for parsing");

	/* Read packet header. */
	ret = knot_pkt_parse_question(in);
	ok(ret == KNOT_EOK, "pkt: read header");

	/* Read packet payload. */
	ret = knot_pkt_parse_payload(in, 0);
	ok(ret == KNOT_EOK, "pkt: read payload");

	/* Compare parsed packet to written packet. */
	packet_match(in, out);

	/*
	 * Copied packet tests.
	 */
	knot_pkt_t *copy = knot_pkt_new(NULL, in->max_size, &in->mm);
	ret = knot_pkt_copy(copy, in);
	ok(ret == KNOT_EOK, "pkt: create packet copy");

	/* Compare copied packet to original. */
	packet_match(in, copy);

	/* Free packets. */
	knot_pkt_free(&copy);
	knot_pkt_free(&out);
	knot_pkt_free(&in);
	ok(in == NULL && out == NULL && copy == NULL, "pkt: free");

	/* Free extra data. */
	for (unsigned i = 0; i < NAMECOUNT; ++i) {
		knot_rrset_free(&rrsets[i], NULL);
	}
	free(tsig_key.secret.data);
	mp_delete((struct mempool *)mm.ctx);

	return 0;
}
Пример #12
0
static int validate_records(struct kr_query *qry, knot_pkt_t *answer, knot_mm_t *pool, bool has_nsec3)
{
	if (!qry->zone_cut.key) {
		DEBUG_MSG(qry, "<= no DNSKEY, can't validate\n");
		return kr_error(EBADMSG);
	}

	kr_rrset_validation_ctx_t vctx = {
		.pkt		= answer,
		.section_id	= KNOT_ANSWER,
		.keys		= qry->zone_cut.key,
		.zone_name	= qry->zone_cut.name,
		.timestamp	= qry->timestamp.tv_sec,
		.has_nsec3	= has_nsec3,
		.flags		= 0,
		.result		= 0
	};

	int ret = validate_section(&vctx, pool);
	if (ret != 0) {
		return ret;
	}

	uint32_t an_flags = vctx.flags;
	vctx.section_id   = KNOT_AUTHORITY;
	/* zone_name can be changed by validate_section(), restore it */
	vctx.zone_name	  = qry->zone_cut.name;
	vctx.flags	  = 0;
	vctx.result	  = 0;

	ret = validate_section(&vctx, pool);
	if (ret != 0) {
		return ret;
	}

	/* Records were validated.
	 * If there is wildcard expansion in answer, flag the query.
         */
	if (an_flags & KR_DNSSEC_VFLG_WEXPAND) {
		qry->flags |= QUERY_DNSSEC_WEXPAND;
	}

	return ret;
}

static int validate_keyset(struct kr_query *qry, knot_pkt_t *answer, bool has_nsec3)
{
	/* Merge DNSKEY records from answer that are below/at current cut. */
	bool updated_key = false;
	const knot_pktsection_t *an = knot_pkt_section(answer, KNOT_ANSWER);
	for (unsigned i = 0; i < an->count; ++i) {
		const knot_rrset_t *rr = knot_pkt_rr(an, i);
		if ((rr->type != KNOT_RRTYPE_DNSKEY) || !knot_dname_in(qry->zone_cut.name, rr->owner)) {
			continue;
		}
		/* Merge with zone cut (or replace ancestor key). */
		if (!qry->zone_cut.key || !knot_dname_is_equal(qry->zone_cut.key->owner, rr->owner)) {
			qry->zone_cut.key = knot_rrset_copy(rr, qry->zone_cut.pool);
			if (!qry->zone_cut.key) {
				return kr_error(ENOMEM);
			}
			updated_key = true;
		} else {
			int ret = knot_rdataset_merge(&qry->zone_cut.key->rrs,
			                              &rr->rrs, qry->zone_cut.pool);
			if (ret != 0) {
				knot_rrset_free(&qry->zone_cut.key, qry->zone_cut.pool);
				return ret;
			}
			updated_key = true;
		}
	}

	/* Check if there's a key for current TA. */
	if (updated_key && !(qry->flags & QUERY_CACHED)) {

		kr_rrset_validation_ctx_t vctx = {
			.pkt		= answer,
			.section_id	= KNOT_ANSWER,
			.keys		= qry->zone_cut.key,
			.zone_name	= qry->zone_cut.name,
			.timestamp	= qry->timestamp.tv_sec,
			.has_nsec3	= has_nsec3,
			.flags		= 0,
			.result		= 0
		};
		int ret = kr_dnskeys_trusted(&vctx, qry->zone_cut.trust_anchor);
		if (ret != 0) {
			knot_rrset_free(&qry->zone_cut.key, qry->zone_cut.pool);
			return ret;
		}

		if (vctx.flags & KR_DNSSEC_VFLG_WEXPAND)
		{
			qry->flags |= QUERY_DNSSEC_WEXPAND;
		}

	}
	return kr_ok();
}
Пример #13
0
int knot_tsig_sign_next(uint8_t *msg, size_t *msg_len, size_t msg_max_len,
                        const uint8_t *prev_digest, size_t prev_digest_len,
                        uint8_t *digest, size_t *digest_len,
                        const knot_tsig_key_t *key, uint8_t *to_sign,
                        size_t to_sign_len)
{
	if (!msg || !msg_len || !key || !digest || !digest_len) {
		return KNOT_EINVAL;
	}

	uint8_t digest_tmp[KNOT_TSIG_MAX_DIGEST_SIZE];
	size_t digest_tmp_len = 0;
	knot_rrset_t *tmp_tsig = knot_rrset_new(key->name, KNOT_RRTYPE_TSIG,
	                                        KNOT_CLASS_ANY, NULL);
	if (!tmp_tsig) {
		return KNOT_ENOMEM;
	}

	/* Create rdata for TSIG RR. */
	tsig_create_rdata(tmp_tsig, tsig_alg_to_dname(key->algorithm),
	                  knot_tsig_digest_length(key->algorithm), 0);
	tsig_rdata_store_current_time(tmp_tsig);
	tsig_rdata_set_fudge(tmp_tsig, KNOT_TSIG_FUDGE_DEFAULT);

	/* Create wire to be signed. */
	size_t wire_len = prev_digest_len + to_sign_len
	                  + KNOT_TSIG_TIMERS_LENGTH + 2;
	uint8_t *wire = malloc(wire_len);
	if (!wire) {
		ERR_ALLOC_FAILED;
		knot_rrset_free(&tmp_tsig, NULL);
		return KNOT_ENOMEM;
	}
	memset(wire, 0, wire_len);

	/* Write previous digest length. */
	knot_wire_write_u16(wire, prev_digest_len);
	/* Write previous digest. */
	memcpy(wire + 2, prev_digest, sizeof(uint8_t) * prev_digest_len);
	/* Write original message. */
	memcpy(wire + prev_digest_len + 2, to_sign, to_sign_len);
	/* Write timers. */
	knot_tsig_wire_write_timers(wire + prev_digest_len + to_sign_len + 2,
	                            tmp_tsig);

	dbg_tsig_detail("Previous digest: \n");
	dbg_tsig_hex_detail((char *)prev_digest, prev_digest_len);

	dbg_tsig_detail("Timers: \n");
	dbg_tsig_hex_detail((char *)(wire + prev_digest_len + *msg_len),
			    KNOT_TSIG_TIMERS_LENGTH);

	int ret = KNOT_ERROR;
	ret = knot_tsig_compute_digest(wire, wire_len,
	                               digest_tmp, &digest_tmp_len, key);

	/* No matter how the function did, this data is no longer needed. */
	free(wire);
	if (ret != KNOT_EOK) {
		knot_rrset_free(&tmp_tsig, NULL);
		*digest_len = 0;
		return ret;
	}

	if (digest_tmp_len > *digest_len) {
		knot_rrset_free(&tmp_tsig, NULL);
		*digest_len = 0;
		return KNOT_ESPACE;
	}

	/* Set the MAC. */
	tsig_rdata_set_mac(tmp_tsig, digest_tmp_len, digest_tmp);

	/* Set original id. */
	tsig_rdata_set_orig_id(tmp_tsig, knot_wire_get_id(msg));

	/* Set other data. */
	tsig_rdata_set_other_data(tmp_tsig, 0, NULL);

	dbg_tsig_verb("Message max length: %zu, message length: %zu\n",
	              msg_max_len, *msg_len);

	size_t tsig_wire_size = 0;
	uint16_t rr_count = 0;
	ret = knot_rrset_to_wire(tmp_tsig, msg + *msg_len,
	                         &tsig_wire_size, msg_max_len - *msg_len,
	                         &rr_count, NULL);
	if (ret != KNOT_EOK) {
		knot_rrset_free(&tmp_tsig, NULL);
		*digest_len = 0;
		return ret;
	}

	/* This should not happen, at least one rr has to be converted. */
	if (rr_count == 0) {
		knot_rrset_free(&tmp_tsig, NULL);
		return KNOT_EINVAL;
	}

	knot_rrset_free(&tmp_tsig, NULL);

	*msg_len += tsig_wire_size;
	uint16_t arcount = knot_wire_get_arcount(msg);
	knot_wire_set_arcount(msg, ++arcount);

	memcpy(digest, digest_tmp, digest_tmp_len);
	*digest_len = digest_tmp_len;

	return KNOT_EOK;
}
Пример #14
0
int knot_tsig_sign(uint8_t *msg, size_t *msg_len,
                   size_t msg_max_len, const uint8_t *request_mac,
                   size_t request_mac_len,
                   uint8_t *digest, size_t *digest_len,
                   const knot_tsig_key_t *key, uint16_t tsig_rcode,
                   uint64_t request_time_signed)
{
	if (!msg || !msg_len || !key || digest == NULL || digest_len == NULL) {
		return KNOT_EINVAL;
	}

	knot_rrset_t *tmp_tsig =
		knot_rrset_new(key->name, KNOT_RRTYPE_TSIG, KNOT_CLASS_ANY,
		               NULL);
	if (!tmp_tsig) {
		dbg_tsig("TSIG: tmp_tsig = NULL\n");
		return KNOT_ENOMEM;
	}

	/* Create rdata for TSIG RR. */
	uint16_t rdata_rcode = 0;
	if (tsig_rcode == KNOT_RCODE_BADTIME)
		rdata_rcode = tsig_rcode;
	tsig_create_rdata(tmp_tsig, tsig_alg_to_dname(key->algorithm),
	                  knot_tsig_digest_length(key->algorithm), rdata_rcode);

	/* Distinguish BADTIME response. */
	if (tsig_rcode == KNOT_RCODE_BADTIME) {
		/* Set client's time signed into the time signed field. */
		tsig_rdata_set_time_signed(tmp_tsig, request_time_signed);

		/* Store current time into Other data. */
		uint8_t time_signed[6];
		time_t curr_time = time(NULL);

		uint64_t time64 = curr_time;
		knot_wire_write_u48(time_signed, time64);

		tsig_rdata_set_other_data(tmp_tsig, 6, time_signed);
	} else {
		tsig_rdata_store_current_time(tmp_tsig);

		/* Set other len. */
		tsig_rdata_set_other_data(tmp_tsig, 0, 0);
	}

	tsig_rdata_set_fudge(tmp_tsig, KNOT_TSIG_FUDGE_DEFAULT);

	/* Set original ID */
	tsig_rdata_set_orig_id(tmp_tsig, knot_wire_get_id(msg));

	uint8_t digest_tmp[KNOT_TSIG_MAX_DIGEST_SIZE];
	size_t digest_tmp_len = 0;

	int ret = KNOT_ERROR;
	ret = knot_tsig_create_sign_wire(msg, *msg_len, /*msg_max_len,*/
	                                     request_mac, request_mac_len,
	                                     digest_tmp, &digest_tmp_len,
					     tmp_tsig, key);
	if (ret != KNOT_EOK) {
		dbg_tsig("TSIG: could not create wire or sign wire: %s\n",
		         knot_strerror(ret));
		knot_rrset_free(&tmp_tsig, NULL);
		return ret;
	}

	/* Set the digest. */
	size_t tsig_wire_len = 0;
	dbg_tsig("TSIG: msg_len=%zu, msg_max_len=%zu, tsig_max_len=%zu\n",
		 *msg_len, msg_max_len, tsig_wire_len);
	uint16_t rr_count = 0;
	tsig_rdata_set_mac(tmp_tsig, digest_tmp_len, digest_tmp);

	/* Write RRSet to wire */
	ret = knot_rrset_to_wire(tmp_tsig, msg + *msg_len,
	                         &tsig_wire_len, msg_max_len - *msg_len,
	                         &rr_count, NULL);
	if (ret != KNOT_EOK) {
		dbg_tsig("TSIG: rrset_to_wire = %s\n", knot_strerror(ret));
		*digest_len = 0;
		knot_rrset_free(&tmp_tsig, NULL);
		return ret;
	}

	knot_rrset_free(&tmp_tsig, NULL);

	dbg_tsig("TSIG: written TSIG RR (wire len %zu)\n", tsig_wire_len);
	*msg_len += tsig_wire_len;

	uint16_t arcount = knot_wire_get_arcount(msg);
	knot_wire_set_arcount(msg, ++arcount);

	// everything went ok, save the digest to the output parameter
	memcpy(digest, digest_tmp, digest_tmp_len);
	*digest_len = digest_tmp_len;

	return KNOT_EOK;
}
Пример #15
0
int main(int argc, char *argv[])
{
	plan(23);

	// Test with NULL changeset
	ok(changeset_size(NULL) == 0, "changeset: NULL size");
	ok(changeset_empty(NULL), "changeset: NULL empty");

	// Test creation.
	knot_dname_t *d = knot_dname_from_str_alloc("test.");
	assert(d);
	changeset_t *ch = changeset_new(d);
	knot_dname_free(&d, NULL);
	ok(ch != NULL, "changeset: new");
	ok(changeset_empty(ch), "changeset: empty");
	ch->soa_to = (knot_rrset_t *)0xdeadbeef;
	ok(!changeset_empty(ch), "changseset: empty SOA");
	ch->soa_to = NULL;
	ok(changeset_size(ch) == 0, "changeset: empty size");

	// Test additions.
	d = knot_dname_from_str_alloc("non.terminals.test.");
	assert(d);
	knot_rrset_t *apex_txt_rr = knot_rrset_new(d, KNOT_RRTYPE_TXT, KNOT_CLASS_IN, NULL);
	assert(apex_txt_rr);
	uint8_t data[8] = "\7teststr";
	knot_rrset_add_rdata(apex_txt_rr, data, sizeof(data), 3600, NULL);

	int ret = changeset_add_rrset(ch, apex_txt_rr);
	ok(ret == KNOT_EOK, "changeset: add RRSet");
	ok(changeset_size(ch) == 1, "changeset: size add");
	ret = changeset_rem_rrset(ch, apex_txt_rr);
	ok(ret == KNOT_EOK, "changeset: rem RRSet");
	ok(changeset_size(ch) == 2, "changeset: size remove");

	ok(!changeset_empty(ch), "changeset: not empty");

	// Add another RR to node.
	knot_rrset_t *apex_spf_rr = knot_rrset_new(d, KNOT_RRTYPE_SPF, KNOT_CLASS_IN, NULL);
	assert(apex_spf_rr);
	knot_rrset_add_rdata(apex_spf_rr, data, sizeof(data), 3600, NULL);
	ret = changeset_add_rrset(ch, apex_spf_rr);
	ok(ret == KNOT_EOK, "changeset: add multiple");

	// Add another node.
	knot_dname_free(&d, NULL);
	d = knot_dname_from_str_alloc("here.come.more.non.terminals.test");
	assert(d);
	knot_rrset_t *other_rr = knot_rrset_new(d, KNOT_RRTYPE_TXT, KNOT_CLASS_IN, NULL);
	assert(other_rr);
	knot_rrset_add_rdata(other_rr, data, sizeof(data), 3600, NULL);
	ret = changeset_add_rrset(ch, other_rr);
	ok(ret == KNOT_EOK, "changeset: remove multiple");

	// Test add traversal.
	changeset_iter_t it;
	ret = changeset_iter_add(&it, ch, true);
	ok(ret == KNOT_EOK, "changeset: create iter add");
	// Order: non.terminals.test. TXT, SPF, here.come.more.non.terminals.test. TXT.
	knot_rrset_t iter = changeset_iter_next(&it);
	bool trav_ok = knot_rrset_equal(&iter, apex_txt_rr, KNOT_RRSET_COMPARE_WHOLE);
	iter = changeset_iter_next(&it);
	trav_ok = trav_ok && knot_rrset_equal(&iter, apex_spf_rr, KNOT_RRSET_COMPARE_WHOLE);
	iter = changeset_iter_next(&it);
	trav_ok = trav_ok && knot_rrset_equal(&iter, other_rr, KNOT_RRSET_COMPARE_WHOLE);

	ok(trav_ok, "changeset: add traversal");

	iter = changeset_iter_next(&it);
	changeset_iter_clear(&it);
	ok(knot_rrset_empty(&iter), "changeset: traversal: skip non-terminals");

	// Test remove traversal.
	ret = changeset_iter_rem(&it, ch, false);
	ok(ret == KNOT_EOK, "changeset: create iter rem");
	iter = changeset_iter_next(&it);
	ok(knot_rrset_equal(&iter, apex_txt_rr, KNOT_RRSET_COMPARE_WHOLE),
	   "changeset: rem traversal");
	changeset_iter_clear(&it);

	// Test all traversal - just count.
	ret = changeset_iter_all(&it, ch, false);
	ok(ret == KNOT_EOK, "changest: create iter all");
	size_t size = 0;
	iter = changeset_iter_next(&it);
	while (!knot_rrset_empty(&iter)) {
		++size;
		iter = changeset_iter_next(&it);
	}
	changeset_iter_clear(&it);
	ok(size == 4, "changeset: iter all");

	// Create new changeset.
	knot_dname_free(&d, NULL);
	d = knot_dname_from_str_alloc("test.");
	assert(d);
	changeset_t *ch2 = changeset_new(d);
	knot_dname_free(&d, NULL);
	assert(ch2);
	// Add something to add section.
	knot_dname_free(&apex_txt_rr->owner, NULL);
	apex_txt_rr->owner = knot_dname_from_str_alloc("something.test.");
	assert(apex_txt_rr->owner);
	ret = changeset_add_rrset(ch2, apex_txt_rr);
	assert(ret == KNOT_EOK);

	// Add something to remove section.
	knot_dname_free(&apex_txt_rr->owner, NULL);
	apex_txt_rr->owner =
		knot_dname_from_str_alloc("and.now.for.something.completely.different.test.");
	assert(apex_txt_rr->owner);
	ret = changeset_rem_rrset(ch2, apex_txt_rr);
	assert(ret == KNOT_EOK);

	// Test merge.
	ret = changeset_merge(ch, ch2);
	ok(ret == KNOT_EOK && changeset_size(ch) == 6, "changeset: merge");

	// Test cleanup.
	changeset_clear(ch);
	ok(changeset_empty(ch), "changeset: clear");
	free(ch);

	list_t chgs;
	init_list(&chgs);
	add_head(&chgs, &ch2->n);
	changesets_clear(&chgs);
	ok(changeset_empty(ch2), "changeset: clear list");
	free(ch2);

	knot_rrset_free(&apex_txt_rr, NULL);
	knot_rrset_free(&apex_spf_rr, NULL);
	knot_rrset_free(&other_rr, NULL);

	return 0;
}