예제 #1
0
static int sign_ctx_add_self(dnssec_sign_ctx_t *ctx, const uint8_t *rdata)
{
	assert(ctx);
	assert(rdata);

	int result;

	// static header

	dnssec_binary_t header = { 0 };
	header.data = (uint8_t *)rdata;
	header.size = RRSIG_RDATA_SIGNER_OFFSET;

	result = dnssec_sign_add(ctx, &header);
	if (result != DNSSEC_EOK) {
		return result;
	}

	// signer name

	const uint8_t *rdata_signer = rdata + RRSIG_RDATA_SIGNER_OFFSET;
	dnssec_binary_t signer = { 0 };
	signer.data = knot_dname_copy(rdata_signer, NULL);
	signer.size = knot_dname_size(signer.data);

	result = dnssec_sign_add(ctx, &signer);
	free(signer.data);

	return result;
}
예제 #2
0
/**
 * Adjust TTL in wire format.
 * @param wire      RR Set in wire format.
 * @param wire_size Size of the wire data portion.
 * @param new_ttl   TTL value to be set for all RRs.
 * @return          0 or error code.
 */
static int adjust_wire_ttl(uint8_t *wire, size_t wire_size, uint32_t new_ttl)
{
	assert(wire);
	assert(sizeof(uint16_t) == 2);
	assert(sizeof(uint32_t) == 4);
	uint16_t rdlen;

	int ret;

	new_ttl = htonl(new_ttl);

	size_t i = 0;
	/* RR wire format in RFC1035 3.2.1 */
	while(i < wire_size) {
		ret = knot_dname_size(wire + i);
		if (ret < 0) {
			return ret;
		}
		i += ret + 4;
		memcpy(wire + i, &new_ttl, sizeof(uint32_t));
		i += sizeof(uint32_t);

		memcpy(&rdlen, wire + i, sizeof(uint16_t));
		rdlen = ntohs(rdlen);
		i += sizeof(uint16_t) + rdlen;

		assert(i <= wire_size);
	}

	return kr_ok();
}
예제 #3
0
파일: conf.c 프로젝트: idtek/knot
conf_val_t conf_zone_get_txn(
	conf_t *conf,
	knot_db_txn_t *txn,
	const yp_name_t *key1_name,
	const knot_dname_t *dname)
{
	conf_val_t val = { NULL };

	if (key1_name == NULL || dname == NULL) {
		val.code = KNOT_EINVAL;
		CONF_LOG(LOG_DEBUG, "conf_zone_get (%s)", knot_strerror(val.code));
		return val;
	}

	int dname_size = knot_dname_size(dname);

	// Try to get explicit value.
	conf_db_get(conf, txn, C_ZONE, key1_name, dname, dname_size, &val);
	switch (val.code) {
	case KNOT_EOK:
		return val;
	default:
		CONF_LOG_ZONE(LOG_ERR, dname, "failed to read '%s/%s' (%s)",
		              C_ZONE + 1, key1_name + 1, knot_strerror(val.code));
		// FALLTHROUGH
	case KNOT_ENOENT:
		break;
	}

	// Check if a template is available.
	conf_db_get(conf, txn, C_ZONE, C_TPL, dname, dname_size, &val);
	switch (val.code) {
	case KNOT_EOK:
		// Use the specified template.
		conf_val(&val);
		conf_db_get(conf, txn, C_TPL, key1_name, val.data, val.len, &val);
		break;
	default:
		CONF_LOG_ZONE(LOG_ERR, dname, "failed to read '%s/%s' (%s)",
		              C_ZONE + 1, C_TPL + 1, knot_strerror(val.code));
		// FALLTHROUGH
	case KNOT_ENOENT:
		// Use the default template.
		conf_db_get(conf, txn, C_TPL, key1_name, CONF_DEFAULT_ID + 1,
		            CONF_DEFAULT_ID[0], &val);
	}

	switch (val.code) {
	default:
		CONF_LOG_ZONE(LOG_ERR, dname, "failed to read '%s/%s' (%s)",
		              C_TPL + 1, key1_name + 1, knot_strerror(val.code));
		// FALLTHROUGH
	case KNOT_EOK:
	case KNOT_ENOENT:
		break;
	}

	return val;
}
예제 #4
0
파일: dname.c 프로젝트: gitter-badger/knot
/*----------------------------------------------------------------------------*/
_public_
knot_dname_t *knot_dname_copy(const knot_dname_t *name, mm_ctx_t *mm)
{
	if (name == NULL)
		return NULL;

	return knot_dname_copy_part(name, knot_dname_size(name), mm);
}
예제 #5
0
static int eval_nsrep(const char *k, void *v, void *baton)
{
	struct kr_query *qry = baton;
	struct kr_nsrep *ns = &qry->ns;
	struct kr_context *ctx = ns->ctx;
	unsigned score = KR_NS_MAX_SCORE;
	unsigned reputation = 0;
	uint8_t *addr = NULL;

	/* Fetch NS reputation */
	if (ctx->cache_rep) {
		unsigned *cached = lru_get(ctx->cache_rep, k, knot_dname_size((const uint8_t *)k));
		if (cached) {
			reputation = *cached;
		}
	}

	/* Favour nameservers with unknown addresses to probe them,
	 * otherwise discover the current best address for the NS. */
	pack_t *addr_set = (pack_t *)v;
	if (addr_set->len == 0) {
		score = KR_NS_UNKNOWN;
		/* If the server doesn't have IPv6, give it disadvantage. */
		if (reputation & KR_NS_NOIP6) {
			score += FAVOUR_IPV6;
			/* If the server is unknown but has rep record, treat it as timeouted */
			if (reputation & KR_NS_NOIP4) {
				score = KR_NS_TIMEOUT;
				reputation = 0; /* Start with clean slate */
			}
		}
	} else {
		score = eval_addr_set(addr_set, ctx->cache_rtt, score, &addr);
	}

	/* Probabilistic bee foraging strategy (naive).
	 * The fastest NS is preferred by workers until it is depleted (timeouts or degrades),
	 * at the same time long distance scouts probe other sources (low probability).
	 * Servers on TIMEOUT (depleted) can be probed by the dice roll only */
	if (score < ns->score && (qry->flags & QUERY_NO_THROTTLE || score < KR_NS_TIMEOUT)) {
		update_nsrep(ns, (const knot_dname_t *)k, addr, score);
		ns->reputation = reputation;
	} else {
		/* With 5% chance, probe server with a probability given by its RTT / MAX_RTT */
		if ((kr_rand_uint(100) < 5) && (kr_rand_uint(KR_NS_MAX_SCORE) >= score)) {
			/* If this is a low-reliability probe, go with TCP to get ICMP reachability check. */
			if (score >= KR_NS_LONG) {
				qry->flags |= QUERY_TCP;
			}
			update_nsrep(ns, (const knot_dname_t *)k, addr, score);
			ns->reputation = reputation;
			return 1; /* Stop evaluation */
		}
	}

	return kr_ok();
}
예제 #6
0
파일: synth_record.c 프로젝트: dnstap/knot
static int reverse_rr(char *addr_str, synth_template_t *tpl, knot_pkt_t *pkt, knot_rrset_t *rr)
{
	/* Synthetize PTR record data. */
	knot_dname_t *ptrname = synth_ptrname(addr_str, tpl);
	if (ptrname == NULL) {
		return KNOT_ENOMEM;
	}

	rr->type = KNOT_RRTYPE_PTR;
	knot_rrset_add_rdata(rr, ptrname, knot_dname_size(ptrname), tpl->ttl, &pkt->mm);
	knot_dname_free(&ptrname, NULL);

	return KNOT_EOK;
}
예제 #7
0
파일: dname.c 프로젝트: gitter-badger/knot
/*----------------------------------------------------------------------------*/
_public_
int knot_dname_to_wire(uint8_t *dst, const knot_dname_t *src, size_t maxlen)
{
	if (dst == NULL || src == NULL) {
		return KNOT_EINVAL;
	}

	int len = knot_dname_size(src);
	if (len > maxlen) {
		return KNOT_ESPACE;
	}

	memcpy(dst, src, len);
	return len;
}
예제 #8
0
int kr_nsrep_update_rep(struct kr_nsrep *ns, unsigned reputation, kr_nsrep_lru_t *cache)
{
	if (!ns || !cache ) {
		return kr_error(EINVAL);
	}

	/* Store in the struct */
	ns->reputation = reputation;
	/* Store reputation in the LRU cache */
	unsigned *cur = lru_set(cache, (const char *)ns->name, knot_dname_size(ns->name));
	if (!cur) {
		return kr_error(ENOMEM);
	}
	*cur = reputation;
	return kr_ok();
}
예제 #9
0
파일: dname.c 프로젝트: gitter-badger/knot
/*----------------------------------------------------------------------------*/
_public_
knot_dname_t *knot_dname_replace_suffix(const knot_dname_t *name, unsigned labels,
					const knot_dname_t *suffix)
{
	if (name == NULL)
		return NULL;

	/* Calculate prefix and suffix lengths. */
	int dname_lbs = knot_dname_labels(name, NULL);
	assert(dname_lbs >= labels);
	unsigned prefix_lbs = dname_lbs - labels;

	/* Trim 1 octet from prefix, as it is measured as FQDN. */
	int prefix_len = knot_dname_prefixlen(name, prefix_lbs, NULL) - 1;
	int suffix_len = knot_dname_size(suffix);
	if (prefix_len < 0 || suffix_len < 0)
		return NULL;

	/* Create target name. */
	int new_len = prefix_len + suffix_len;
	knot_dname_t *out = malloc(new_len);
	if (out == NULL)
		return NULL;

	/* Copy prefix. */
	uint8_t *dst = out;
	while (prefix_lbs > 0) {
		memcpy(dst, name, *name + 1);
		dst += *name + 1;
		name = knot_wire_next_label(name, NULL);
		--prefix_lbs;
	}

	/* Copy suffix. */
	while (*suffix != '\0') {
		memcpy(dst, suffix, *suffix + 1);
		dst += *suffix + 1;
		suffix = knot_wire_next_label(suffix, NULL);
	}
	*dst = '\0';
	return out;
}
예제 #10
0
/*!
 * \brief Create NSEC3 owner name from regular owner name.
 *
 * \param owner      Node owner name.
 * \param zone_apex  Zone apex name.
 * \param params     Params for NSEC3 hashing function.
 *
 * \return NSEC3 owner name, NULL in case of error.
 */
knot_dname_t *knot_create_nsec3_owner(const knot_dname_t *owner,
                                      const knot_dname_t *zone_apex,
                                      const knot_nsec3_params_t *params)
{
	if (owner == NULL || zone_apex == NULL || params == NULL) {
		return NULL;
	}

	int owner_size = knot_dname_size(owner);
	if (owner_size < 0) {
		return NULL;
	}

	dnssec_binary_t data = { 0 };
	data.data = (uint8_t *)owner;
	data.size = owner_size;

	dnssec_binary_t hash = { 0 };
	dnssec_nsec3_params_t xparams = {
		.algorithm = params->algorithm,
		.flags = params->flags,
		.iterations = params->iterations,
		.salt = {
			.data = params->salt,
			.size = params->salt_length
		}
	};

	int r = dnssec_nsec3_hash(&data, &xparams, &hash);
	if (r != DNSSEC_EOK) {
		return NULL;
	}

	knot_dname_t *result = knot_nsec3_hash_to_dname(hash.data, hash.size, zone_apex);

	dnssec_binary_free(&hash);

	return result;
}
예제 #11
0
/*!
 * \brief Create NSEC3 owner name from hash and zone apex.
 */
knot_dname_t *knot_nsec3_hash_to_dname(const uint8_t *hash, size_t hash_size,
                                       const knot_dname_t *zone_apex)
{
	assert(zone_apex);

	// encode raw hash to first label

	uint8_t label[KNOT_DNAME_MAXLEN];
	int32_t label_size;
	label_size = base32hex_encode(hash, hash_size, label, sizeof(label));
	if (label_size <= 0) {
		return NULL;
	}

	// allocate result

	size_t zone_apex_size = knot_dname_size(zone_apex);
	size_t result_size = 1 + label_size + zone_apex_size;
	knot_dname_t *result = malloc(result_size);
	if (!result) {
		return NULL;
	}

	// build the result

	uint8_t *write = result;

	*write = (uint8_t)label_size;
	write += 1;
	memcpy(write, label, label_size);
	write += label_size;
	memcpy(write, zone_apex, zone_apex_size);
	write += zone_apex_size;

	assert(write == result + result_size);
	knot_dname_to_lower(result);

	return result;
}
예제 #12
0
파일: nsec-chain.c 프로젝트: dnstap/knot
/*!
 * \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;
}
예제 #13
0
파일: rrl.c 프로젝트: nice-redbull/knot
static int rrl_clsname(char *dst, size_t maxlen, uint8_t cls,
                       rrl_req_t *p, const knot_zone_t *z)
{
	const knot_dname_t *dn = NULL;
	const uint8_t *n = (const uint8_t*)"\x00"; /* Fallback zone (for errors etc.) */
	int nb = 1;
	if (z) { /* Found associated zone. */
		dn = knot_zone_name(z);
	}
	switch (cls) {
	case CLS_ERROR:    /* Could be a non-existent zone or garbage. */
	case CLS_NXDOMAIN: /* Queries to non-existent names in zone. */
	case CLS_WILDCARD: /* Queries to names covered by a wildcard. */
		dbg_rrl_verb("%s: using zone/fallback name\n", __func__);
		break;
	default:
		if (p->qst) dn = p->qst->qname;
		break;
	}

	if (dn) { /* Check used dname. */
		assert(dn); /* Should be always set. */
		n = knot_dname_name(dn);
		nb = (int)knot_dname_size(dn);
	}

	/* Write to wire */
	if (nb > maxlen) return KNOT_ESPACE;
	if (memcpy(dst, n, nb) == NULL) {
		dbg_rrl("%s: failed to serialize name=%p len=%u\n",
		        __func__, n, nb);
		return KNOT_ERROR;
	}

	return nb;
}
예제 #14
0
파일: dname.c 프로젝트: gitter-badger/knot
/*----------------------------------------------------------------------------*/
_public_
char *knot_dname_to_str(char *dst, const knot_dname_t *name, size_t maxlen)
{
	if (name == NULL) {
		return NULL;
	}

	int dname_size = knot_dname_size(name);
	if (dname_size <= 0) {
		return NULL;
	}

	/* Check the size for len(dname) + 1 char termination. */
	size_t alloc_size = (dst == NULL) ? dname_size + 1 : maxlen;
	if (alloc_size < dname_size + 1) {
		return NULL;
	}

	char *res = (dst == NULL) ? malloc(alloc_size) : dst;
	if (res == NULL) {
		return NULL;
	}

	uint8_t label_len = 0;
	size_t  str_len = 0;

	for (unsigned i = 0; i < dname_size; i++) {
		uint8_t c = name[i];

		/* Read next label size. */
		if (label_len == 0) {
			label_len = c;

			/* Write label separation. */
			if (str_len > 0 || dname_size == 1) {
				res[str_len++] = '.';
			}

			continue;
		}

		if (isalnum(c) != 0 || c == '-' || c == '_' || c == '*' ||
		    c == '/') {
			res[str_len++] = c;
		} else if (ispunct(c) != 0 && c != '#') {
			/* Exclusion of '#' character is to avoid possible
			 * collision with rdata hex notation '\#'. So it is
			 * encoded in \ddd notation.
			 */

			if (dst != NULL) {
				if (maxlen <= str_len + 2) {
					return NULL;
				}
			} else {
				/* Extend output buffer for \x format. */
				alloc_size += 1;
				char *extended = realloc(res, alloc_size);
				if (extended == NULL) {
					free(res);
					return NULL;
				}
				res = extended;
			}

			/* Write encoded character. */
			res[str_len++] = '\\';
			res[str_len++] = c;
		} else {
			if (dst != NULL) {
				if (maxlen <= str_len + 4) {
					return NULL;
				}
			} else {
				/* Extend output buffer for \DDD format. */
				alloc_size += 3;
				char *extended = realloc(res, alloc_size);
				if (extended == NULL) {
					free(res);
					return NULL;
				}
				res = extended;
			}

			/* Write encoded character. */
			int ret = snprintf(res + str_len, alloc_size - str_len,
			                   "\\%03u", c);
			if (ret <= 0 || ret >= alloc_size - str_len) {
				if (dst == NULL) {
					free(res);
				}
				return NULL;
			}

			str_len += ret;
		}

		label_len--;
	}

	/* String_termination. */
	res[str_len] = 0;

	return res;
}
예제 #15
0
/*!
 * \brief Entry point of 'knsec3hash'.
 */
int main(int argc, char *argv[])
{
	bool enable_idn = true;

	struct option options[] = {
		{ "version", no_argument, 0, 'V' },
		{ "help",    no_argument, 0, 'h' },
		{ NULL }
	};

#ifdef LIBIDN
	// Set up localization.
	if (setlocale(LC_CTYPE, "") == NULL) {
		enable_idn = false;
	}
#endif

	int opt = 0;
	int li = 0;
	while ((opt = getopt_long(argc, argv, "hV", options, &li)) != -1) {
		switch(opt) {
		case 'V':
			printf("%s, version %s\n", PROGRAM_NAME, PACKAGE_VERSION);
			return 0;
		case 'h':
			usage(stdout);
			return 0;
		default:
			usage(stderr);
			return 1;
		}
	}

	// knsec3hash <salt> <algorithm> <iterations> <domain>
	if (argc != 5) {
		usage(stderr);
		return 1;
	}

	atexit(knot_crypto_cleanup);

	int exit_code = 1;
	knot_nsec3_params_t nsec3_params = { 0 };
	knot_dname_t *dname = NULL;
	uint8_t *digest = NULL;
	size_t digest_size = 0;
	uint8_t *b32_digest = NULL;
	int32_t b32_length = 0;
	int result = 0;

	if (!parse_nsec3_params(&nsec3_params, argv[1], argv[2], argv[3])) {
		goto fail;
	}

	if (enable_idn) {
		char *ascii_name = name_from_idn(argv[4]);
		if (ascii_name == NULL) {
			fprintf(stderr, "Cannot transform IDN domain name.\n");
			goto fail;
		}
		dname = knot_dname_from_str(ascii_name);
		free(ascii_name);
	} else {
		dname = knot_dname_from_str(argv[4]);
	}
	if (dname == NULL) {
		fprintf(stderr, "Cannot parse domain name.\n");
		goto fail;
	}

	result = knot_nsec3_hash(&nsec3_params, dname, knot_dname_size(dname),
	                         &digest, &digest_size);
	if (result != KNOT_EOK) {
		fprintf(stderr, "Cannot compute hash: %s\n",
		        knot_strerror(result));
		goto fail;
	}

	b32_length = base32hex_encode_alloc(digest, digest_size, &b32_digest);
	if (b32_length < 0) {
		fprintf(stderr, "Cannot encode computed hash: %s\n",
		        knot_strerror(b32_length));
		goto fail;
	}

	exit_code = 0;

	printf("%.*s (salt=%s, hash=%d, iterations=%d)\n", b32_length,
	       b32_digest, argv[1], nsec3_params.algorithm,
	       nsec3_params.iterations);

fail:
	knot_nsec3param_free(&nsec3_params);
	knot_dname_free(&dname, NULL);
	free(digest);
	free(b32_digest);

	return exit_code;
}
예제 #16
0
	}
	return 0; /* Not found, try all. */
}

/* @internal We don't need to deal with locale here */
KR_CONST static inline bool isletter(unsigned chr)
{ return (chr | 0x20 /* tolower */) - 'a' <= 'z' - 'a'; }

/* Randomize QNAME letter case.
 * This adds 32 bits of randomness at maximum, but that's more than an average domain name length.
 * https://tools.ietf.org/html/draft-vixie-dnsext-dns0x20-00
 */
static void randomized_qname_case(knot_dname_t * restrict qname, uint32_t secret)
{
	assert(qname);
	const int len = knot_dname_size(qname) - 2; /* Skip first, last label. */
	for (int i = 0; i < len; ++i) {
		if (isletter(*++qname)) {
				*qname ^= ((secret >> (i & 31)) & 1) * 0x20;
		}
	}
}

/** Invalidate current NS/addr pair. */
static int invalidate_ns(struct kr_rplan *rplan, struct kr_query *qry)
{
	if (qry->ns.addr[0].ip.sa_family != AF_UNSPEC) {
		uint8_t *addr = kr_nsrep_inaddr(qry->ns.addr[0]);
		size_t addr_len = kr_nsrep_inaddr_len(qry->ns.addr[0]);
		/* @warning _NOT_ thread-safe */
		static knot_rdata_t rdata_arr[RDATA_ARR_MAX];
예제 #17
0
static MDB_val pack_key(const knot_dname_t *name)
{
	MDB_val key = { knot_dname_size(name), (void *)name };
	return key;
}