Commit adccbea5 authored by Vladimír Čunát's avatar Vladimír Čunát

Merge branch 'master' and update deckard

We need this to fix the tests.
parents 81c4fd8f b7141688
Pipeline #2699 passed with stages
in 5 minutes and 43 seconds
......@@ -27,6 +27,9 @@
#include "daemon/worker.h"
#include "daemon/tls.h"
#define xstr(s) str(s)
#define str(s) #s
/** @internal Annotate for static checkers. */
KR_NORETURN int lua_error (lua_State *L);
......@@ -225,7 +228,7 @@ static int net_listen(lua_State *L)
int n = lua_gettop(L);
if (n < 1 || n > 3) {
format_error(L, "expected one to three arguments; usage:\n"
"net.listen(addressses, [port = 53, flags = {tls = (port == 853)}])\n");
"net.listen(addressses, [port = " xstr(KR_DNS_PORT) ", flags = {tls = (port == " xstr(KR_DNS_TLS_PORT) ")}])\n");
lua_error(L);
}
......@@ -327,7 +330,7 @@ static int net_bufsize(lua_State *L)
}
int bufsize = lua_tointeger(L, 1);
if (bufsize < 512 || bufsize > UINT16_MAX) {
format_error(L, "bufsize must be within <512, 65535>");
format_error(L, "bufsize must be within <512, " xstr(UINT16_MAX) ">");
lua_error(L);
}
knot_edns_set_payload(opt_rr, (uint16_t) bufsize);
......@@ -347,7 +350,7 @@ static int net_pipeline(lua_State *L)
}
int len = lua_tointeger(L, 1);
if (len < 0 || len > UINT16_MAX) {
format_error(L, "tcp_pipeline must be within <0, 65535>");
format_error(L, "tcp_pipeline must be within <0, " xstr(UINT16_MAX) ">");
lua_error(L);
}
worker->tcp_pipeline_max = len;
......@@ -414,7 +417,7 @@ static int net_tls_padding(lua_State *L)
}
int padding = lua_tointeger(L, 1);
if ((padding < 0) || (padding > MAX_TLS_PADDING)) {
lua_pushstring(L, "net.tls_padding parameter has to be a number between <0, 4096>");
lua_pushstring(L, "net.tls_padding parameter has to be a number between <0, " xstr(MAX_TLS_PADDING) ">");
lua_error(L);
}
engine->resolver.tls_padding = padding;
......@@ -578,7 +581,7 @@ static int cache_max_ttl(lua_State *L)
uint32_t min = cache->ttl_min;
int64_t ttl = lua_tonumber(L, 1);
if (ttl < 0 || ttl <= min || ttl > UINT32_MAX) {
format_error(L, "max_ttl must be larger than minimum TTL, and in range <1, UINT32_MAX>'");
format_error(L, "max_ttl must be larger than minimum TTL, and in range <1, " xstr(UINT32_MAX) ">'");
lua_error(L);
}
cache->ttl_max = ttl;
......@@ -602,7 +605,7 @@ static int cache_min_ttl(lua_State *L)
uint32_t max = cache->ttl_max;
int64_t ttl = lua_tonumber(L, 1);
if (ttl < 0 || ttl >= max || ttl > UINT32_MAX) {
format_error(L, "min_ttl must be smaller than maximum TTL, and in range <0, UINT32_MAX>'");
format_error(L, "min_ttl must be smaller than maximum TTL, and in range <0, " xstr(UINT32_MAX) ">'");
lua_error(L);
}
cache->ttl_min = ttl;
......@@ -626,7 +629,7 @@ static int cache_open(lua_State *L)
lua_Number csize_lua = lua_tonumber(L, 1);
if (!(csize_lua >= 8192 && csize_lua < SIZE_MAX)) { /* min. is basically arbitrary */
format_error(L, "invalid cache size specified");
format_error(L, "invalid cache size specified, it must be in range <8192, " xstr(SIZE_MAX) ">");
lua_error(L);
}
size_t cache_size = csize_lua;
......
......@@ -69,7 +69,7 @@ static inline int __attribute__((__cold__)) kr_error(int x) {
#define KR_DNS_TLS_PORT 853
#define KR_EDNS_VERSION 0
#define KR_EDNS_PAYLOAD 4096 /* Default UDP payload (max unfragmented UDP is 1452B) */
#define KR_DEFAULT_TLS_PADDING 128 /* Default EDNS(0) Padding is 128 */
#define KR_DEFAULT_TLS_PADDING 468 /* Default EDNS(0) Padding is 468 */
#define KR_CACHE_DEFAULT_MAXTTL (6 * 24 * 3600) /* 6 days, like the root NS TTL */
/*
......
......@@ -214,6 +214,10 @@ int kr_rrset_validate_with_key(kr_rrset_validation_ctx_t *vctx,
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 == kr_error(DNSSEC_OUT_OF_RANGE)) {
ret = 0;
vctx->flags |= KR_DNSSEC_VFLG_OPTOUT;
}
}
if (ret != 0) {
continue;
......
......@@ -43,6 +43,7 @@ void kr_crypto_reinit(void);
struct dseckey;
#define KR_DNSSEC_VFLG_WEXPAND 0x01
#define KR_DNSSEC_VFLG_OPTOUT 0x02
/** DNSSEC validation context. */
struct kr_rrset_validation_ctx {
......
......@@ -89,13 +89,30 @@ static int nsec_nonamematch(const knot_rrset_t *nsec, const knot_dname_t *sname)
#define FLG_NOEXIST_WILDCARD (1 << 2) /**< No wildcard covering <SNAME, SCLASS> exists. */
#define FLG_NOEXIST_CLOSER (1 << 3) /**< Wildcard covering <SNAME, SCLASS> exists, but doesn't match STYPE. */
/**
* According to set flags determine whether NSEC proving
* RRset or RRType non-existense has been found.
* @param f Flags to inspect.
* @return True if required NSEC exists.
*/
#define kr_nsec_rrset_noexist(f) \
((f) & (FLG_NOEXIST_RRTYPE | FLG_NOEXIST_RRSET))
/**
* According to set flags determine whether wildcard non-existense
* has been proven.
* @param f Flags to inspect.
* @return True if wildcard not exists.
*/
#define kr_nsec_wcard_noexist(f) ((f) & FLG_NOEXIST_WILDCARD)
/**
* According to set flags determine whether authenticated denial of existence has been proven.
* @param f Flags to inspect.
* @return True if denial of existence proven.
*/
#define kr_nsec_existence_denied(f) \
(((f) & (FLG_NOEXIST_RRTYPE | FLG_NOEXIST_RRSET)) && ((f) & FLG_NOEXIST_WILDCARD))
((kr_nsec_rrset_noexist(f)) && (kr_nsec_wcard_noexist(f)))
/**
* Name error response check (RFC4035 3.1.3.2; RFC4035 5.4, bullet 2).
......@@ -254,6 +271,47 @@ static int no_data_wildcard_existence_check(int *flags, const knot_rrset_t *nsec
return kr_ok();
}
/**
* Perform check for NSEC wildcard existence that covers sname and
* have no stype bit set.
* @param pkt Packet structure to be processed.
* @param sec Packet section to work with.
* @param sname Queried domain name.
* @param stype Queried type.
* @return 0 or error code.
*/
static int wildcard_match_check(const knot_pkt_t *pkt, const knot_pktsection_t *sec,
const knot_dname_t *sname, uint16_t stype)
{
if (!sec || !sname) {
return kr_error(EINVAL);
}
int flags = 0;
for (unsigned i = 0; i < sec->count; ++i) {
const knot_rrset_t *rrset = knot_pkt_rr(sec, i);
if (rrset->type != KNOT_RRTYPE_NSEC) {
continue;
}
if (!knot_dname_is_wildcard(rrset->owner)) {
continue;
}
int wcard_labels = knot_dname_labels(rrset->owner, NULL);
int common_labels = knot_dname_matched_labels(rrset->owner, sname);
int rrsig_labels = coverign_rrsig_labels(rrset, sec);
if (wcard_labels <= 1 ||
common_labels != wcard_labels - 1 ||
common_labels != rrsig_labels) {
continue;
}
int ret = no_data_response_check_rrtype(&flags, rrset, stype);
if (ret != 0) {
return ret;
}
}
return (flags & FLG_NOEXIST_RRTYPE) ? kr_ok() : kr_error(ENOENT);
}
int kr_nsec_no_data_response_check(const knot_pkt_t *pkt, knot_section_t section_id,
const knot_dname_t *sname, uint16_t stype)
{
......@@ -323,8 +381,23 @@ int kr_nsec_existence_denial(const knot_pkt_t *pkt, knot_section_t section_id,
}
no_data_wildcard_existence_check(&flags, rrset, sec);
}
return kr_nsec_existence_denied(flags) ? kr_ok() : kr_error(ENOENT);
if (kr_nsec_existence_denied(flags)) {
/* denial of existence proved accordignly to 4035 5.4 -
* NSEC proving either rrset non-existance or
* qtype non-existance has been found,
* and no wildcard expansion occured.
*/
return kr_ok();
} else if (kr_nsec_rrset_noexist(flags)) {
/* NSEC proving either rrset non-existance or
* qtype non-existance has been found,
* but wildcard expansion occurs.
* Try to find matching wildcard and check
* corresponding types.
*/
return wildcard_match_check(pkt, sec, sname, stype);
}
return kr_error(ENOENT);
}
int kr_nsec_ref_to_unsigned(const knot_pkt_t *pkt)
......
......@@ -669,7 +669,8 @@ int kr_nsec3_wildcard_answer_response_check(const knot_pkt_t *pkt, knot_section_
return ret;
}
if (flags & FLG_NAME_COVERED) {
return kr_ok();
return has_optout(rrset) ?
kr_error(DNSSEC_OUT_OF_RANGE) : kr_ok();
}
}
......
......@@ -35,7 +35,10 @@ int kr_nsec3_name_error_response_check(const knot_pkt_t *pkt, knot_section_t sec
* @param section_id Packet section to be processed.
* @param sname Name to be checked.
* @param trim_to_next Number of labels to remove to obtain next closer name.
* @return 0 or error code.
* @return 0 or error code:
* DNSSEC_OUT_OF_RANGE - NSEC3 RR that covers a wildcard
* has been found, but has opt-out flag set;
* otherwise - error.
*/
int kr_nsec3_wildcard_answer_response_check(const knot_pkt_t *pkt, knot_section_t section_id,
const knot_dname_t *sname, int trim_to_next);
......
......@@ -326,10 +326,12 @@ static int process_authority(knot_pkt_t *pkt, struct kr_request *req)
#endif
/* Remember current bailiwick for NS processing. */
const knot_dname_t *current_zone_cut = qry->zone_cut.name;
bool ns_record_exists = false;
/* Update zone cut information. */
for (unsigned i = 0; i < ns->count; ++i) {
const knot_rrset_t *rr = knot_pkt_rr(ns, i);
if (rr->type == KNOT_RRTYPE_NS) {
ns_record_exists = true;
int state = update_cut(pkt, rr, req, current_zone_cut);
switch(state) {
case KR_STATE_DONE: result = state; break;
......@@ -343,8 +345,11 @@ static int process_authority(knot_pkt_t *pkt, struct kr_request *req)
}
if ((qry->flags & QUERY_DNSSEC_WANT) && (result == KR_STATE_CONSUME)) {
if (knot_wire_get_aa(pkt->wire) == 0 && knot_wire_get_ancount(pkt->wire) == 0) {
/* Prevent from validating as an autoritative answer */
if (knot_wire_get_aa(pkt->wire) == 0 &&
knot_wire_get_ancount(pkt->wire) == 0 &&
ns_record_exists) {
/* Unhelpful referral
Prevent from validating as an authoritative answer */
result = KR_STATE_DONE;
}
}
......
......@@ -166,11 +166,15 @@ static int validate_records(struct kr_request *req, knot_pkt_t *answer, knot_mm_
}
/* Records were validated.
* If there is wildcard expansion in answer, flag the query.
* If there is wildcard expansion in answer,
* or optout - flag the query.
*/
if (an_flags & KR_DNSSEC_VFLG_WEXPAND) {
qry->flags |= QUERY_DNSSEC_WEXPAND;
}
if (an_flags & KR_DNSSEC_VFLG_OPTOUT) {
qry->flags |= QUERY_DNSSEC_OPTOUT;
}
return ret;
}
......@@ -225,10 +229,12 @@ static int validate_keyset(struct kr_request *req, knot_pkt_t *answer, bool has_
return ret;
}
if (vctx.flags & KR_DNSSEC_VFLG_WEXPAND)
{
if (vctx.flags & KR_DNSSEC_VFLG_WEXPAND) {
qry->flags |= QUERY_DNSSEC_WEXPAND;
}
if (vctx.flags & KR_DNSSEC_VFLG_OPTOUT) {
qry->flags |= QUERY_DNSSEC_OPTOUT;
}
}
return kr_ok();
......@@ -508,6 +514,26 @@ static int check_validation_result(kr_layer_t *ctx, ranked_rr_array_t *arr)
return ret;
}
static bool check_empty_answer(kr_layer_t *ctx, knot_pkt_t *pkt)
{
struct kr_request *req = ctx->req;
struct kr_query *qry = req->current_query;
ranked_rr_array_t *arr = &req->answ_selected;
size_t num_entries = 0;
for (size_t i = 0; i < arr->len; ++i) {
ranked_rr_array_entry_t *entry = arr->at[i];
const knot_rrset_t *rr = entry->rr;
if (rr->type == KNOT_RRTYPE_RRSIG && qry->stype != KNOT_RRTYPE_RRSIG) {
continue;
}
if (entry->qry_uid == qry->uid) {
++num_entries;
}
}
const knot_pktsection_t *an = knot_pkt_section(pkt, KNOT_ANSWER);
return ((an->count != 0) && (num_entries == 0)) ? false : true;
}
static int check_signer(kr_layer_t *ctx, knot_pkt_t *pkt)
{
struct kr_request *req = ctx->req;
......@@ -611,6 +637,13 @@ static int validate(kr_layer_t *ctx, knot_pkt_t *pkt)
const bool no_data = (an->count == 0 && knot_wire_get_aa(pkt->wire));
if (!(qry->flags & QUERY_CACHED) && knot_wire_get_aa(pkt->wire)) {
/* Check if answer if not empty,
* but iterator has not selected any records. */
if (!check_empty_answer(ctx, pkt)) {
VERBOSE_MSG(qry, "<= no useful RR in authoritative answer\n");
qry->flags |= QUERY_DNSSEC_BOGUS;
return KR_STATE_FAIL;
}
/* Track difference between current TA and signer name.
* This indicates that the NS is auth for both parent-child,
* and we must update DS/DNSKEY to validate it.
......
......@@ -842,6 +842,14 @@ static int trust_chain_check(struct kr_request *request, struct kr_query *qry)
if (kr_ta_get(negative_anchors, qry->zone_cut.name)){
VERBOSE_MSG(qry, ">< negative TA, going insecure\n");
qry->flags &= ~QUERY_DNSSEC_WANT;
qry->flags |= QUERY_DNSSEC_INSECURE;
}
if (qry->flags & QUERY_DNSSEC_NODS) {
/* This is the next query iteration with minimized qname.
* At previous iteration DS non-existance has been proven */
qry->flags &= ~QUERY_DNSSEC_NODS;
qry->flags &= ~QUERY_DNSSEC_WANT;
qry->flags |= QUERY_DNSSEC_INSECURE;
}
/* Enable DNSSEC if enters a new island of trust. */
bool want_secured = (qry->flags & QUERY_DNSSEC_WANT) &&
......
......@@ -371,9 +371,19 @@ int kr_straddr_subnet(void *dst, const char *addr)
int kr_bitcmp(const char *a, const char *b, int bits)
{
if (!a || !b || bits == 0) {
return kr_error(ENOMEM);
/* We're using the function from lua directly, so at least for now
* we avoid crashing on bogus inputs. Meaning: NULL is ordered before
* anything else, and negative length is the same as zero.
* TODO: review the call sites and probably remove the checks. */
if (bits <= 0 || (!a && !b)) {
return 0;
} else if (!a) {
return -1;
} else if (!b) {
return 1;
}
assert((a && b && bits >= 0) || bits == 0);
/* Compare part byte-divisible part. */
const size_t chunk = bits / 8;
int ret = memcmp(a, b, chunk);
......
......@@ -173,7 +173,10 @@ struct sockaddr * kr_straddr_socket(const char *addr, int port);
* @warning 'dst' must be at least `sizeof(struct in6_addr)` long. */
KR_EXPORT
int kr_straddr_subnet(void *dst, const char *addr);
/** Compare memory bitwise. */
/** Compare memory bitwise. The semantics is "the same" as for memcmp().
* The partial byte is considered with more-significant bits first,
* so this is e.g. suitable for comparing IP prefixes. */
KR_EXPORT KR_PURE
int kr_bitcmp(const char *a, const char *b, int bits);
......
......@@ -40,6 +40,8 @@ Example configuration
view:addr('192.168.1.0/24', policy.rpz(policy.PASS, 'whitelist.rpz'))
-- Forward all queries from given subnet to proxy
view:addr('10.0.0.0/8', policy.all(policy.FORWARD('2001:DB8::1')))
-- Drop everything that hasn't matched
view:addr('0.0.0.0/0', function (req, qry) return policy.DROP end)
Properties
^^^^^^^^^^
......
Subproject commit b96ef5cd589ddb71eefb89e09fee1087a49edf35
Subproject commit b985a91d0e5f2f30d430d3fb4823f20f78661c70
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment