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

Merge branch 'master' into aho-corasick

... to resolve some simple conflicts.
parents e86a9711 8a005e48
Pipeline #13191 failed with stages
in 16 minutes and 59 seconds
......@@ -31,6 +31,11 @@ test:linux:amd64:
deckard:linux:amd64:
stage: test
script:
- apt purge -y python-dnspython python3-dnspython
- apt update
- apt install python-pip libffi-dev libaugeas-dev -y
- pip install --upgrade pip
- pip install --user dnspython pyyaml python-augeas
- PREFIX=$(pwd)/.local MAKEFLAGS="--jobs $(nproc) --keep-going" make check-integration
dependencies:
- build:linux:amd64
......@@ -43,21 +48,22 @@ respdiff:linux:amd64:
image: cznic/ubuntu-respdif:16.04
stage: test
script:
- LD_LIBRARY_PATH=$(pwd)/.local/lib /home/kresdbench/run.sh $(pwd)/.local/sbin/kresd
- /home/kresdbench/resolver-benchmarking/response_differences/nightly.sh
- cp -r /home/kresdbench/resolver-benchmarking/response_differences/results $(pwd)
- PREFIX=$(pwd)/.local ./ci/respdiff/start-resolvers.sh
- ./ci/respdiff/run-respdiff-tests.sh
- cat ./results/respdiff.txt
- echo 'test if mismatch rate >= 1 %'
- grep -q '^target diagrees.*0\.[0-9][0-9] %' ./results/respdiff.txt
artifacts:
when: always
expire_in: '1 week'
paths:
- results/*.json
- results/*.out
- results/*.log
- results/*.txt
tags:
- docker
- linux
- amd64
allow_failure: true
dependencies:
- build:linux:amd64
#arm_build:
# image: cznic/armhf-ubuntu:16.04
......
Knot Resolver 1.4.0 (2017-0x-yy)
================================
Incompatible changes
--------------------
- lua: query flag-sets are no longer represented as plain integers.
kres.query.* no longer works, and kr_query_t lost trivial methods
'hasflag' and 'resolved'.
You can instead write code like qry.flags.NO_0X20 = true.
Improvements
------------
- policy.suffix: update the aho-corasick code (#200)
Knot Resolver 1.3.3 (2017-08-09)
================================
Security
--------
- Fix a critical DNSSEC flaw. Signatures might be accepted as valid
even if the signed data was not in bailiwick of the DNSKEY used to
sign it, assuming the trust chain to that DNSKEY was valid.
Bugfixes
--------
- iterate: skip RRSIGs with bad label count instead of immediate SERVFAIL
- utils: fix possible incorrect seeding of the random generator
- modules/http: fix compatibility with the Prometheus text format
Improvements
------------
- policy: implement remaining special-use domain names from RFC6761 (#205),
and make these rules apply only if no other non-chain rule applies
Knot Resolver 1.3.2 (2017-07-28)
================================
......
-- Refer to manual: https://knot-resolver.readthedocs.io/en/latest/daemon.html#configuration
-- Listen on localhost and external interface
net.listen('127.0.0.1', 5353)
net.listen('::1', 5353)
-- Auto-maintain root TA
trust_anchors.file = '.local/etc/kresd/root.keys'
-- Large cache size, so we don't need to flush often
-- This can be larger than available RAM, least frequently accessed
-- records will be paged out
cache.size = 1024 * MB
-- Load Useful modules
modules = {
'workarounds < iterate',
'policy', -- Block queries to local zones/bad sites
'view', -- Views for certain clients
'hints', -- Load /etc/hosts and allow custom root hints
'stats', -- Track internal statistics
}
verbose(false)
[sendrecv]
# in seconds
timeout = 5
# number of queries to run simultaneously
jobs = 64
[servers]
names = kresd, bind, unbound
# symbolic names of DNS servers under test
# separate multiple values by ,
# each symbolic name in [servers] section refers to config section
# containing IP address and port of particular server
[kresd]
ip = ::1
port = 5353
[bind]
ip = 127.0.0.1
port = 53533
[unbound]
ip = 127.0.0.1
port = 53535
[diff]
# symbolic name of server under test
# other servers are used as reference when comparing answers from the target
target = kresd
# fields and comparison methods used when comparing two DNS messages
criteria = opcode, rcode, flags, question, qname, qtype, answertypes, answerrrsigs
# other supported criteria values: authority, additional, edns, nsid
[report]
# diffsum reports mismatches in field values in this order
# if particular message has multiple mismatches, it is counted only once into category with highest weight
field_weights = opcode, qcase, qtype, rcode, flags, answertypes, answerrrsigs, answer, authority, additional, edns, nsid
wget https://gitlab.labs.nic.cz/knot/knot-resolver/snippets/69/raw?inline=false -O /tmp/queries.txt
mkdir results;
rm -rf /tmp/respdiff;
python3 /var/opt/respdiff/qprep.py /tmp/respdiff < /tmp/queries.txt && \
python3 /var/opt/respdiff/orchestrator.py /tmp/respdiff -c $(pwd)/ci/respdiff/respdiff.conf && \
python3 /var/opt/respdiff/msgdiff.py /tmp/respdiff -c $(pwd)/ci/respdiff/respdiff.conf && \
python3 /var/opt/respdiff/diffsum.py /tmp/respdiff -c $(pwd)/ci/respdiff/respdiff.conf > results/respdiff.txt
#run unbound
service unbound start && service unbound status;
# dig @localhost -p 53535
#run bind
service bind9 start && service bind9 status;
# dig @localhost -p 53533
#run kresd
LD_LIBRARY_PATH=$PREFIX/lib $PREFIX/sbin/kresd -f 1 -q -c $(pwd)/ci/respdiff/kresd.config &
# dig @localhost -p 5353
# Project
MAJOR := 1
MINOR := 3
PATCH := 2
PATCH := 3
EXTRA :=
ABIVER := 3
ABIVER := 4
BUILDMODE := dynamic
HARDENING := yes
......
......@@ -144,6 +144,13 @@ The watchdog process must notify kresd about active file descriptors, and kresd
The daemon also supports `systemd socket activation`_, it is automatically detected and requires no configuration on users's side.
To run the daemon by hand, such as under ``nohup``, use ``-f 1`` to start a single fork. For example:
.. code-block:: bash
$ nohup ./daemon/kresd -a 127.0.0.1 -f 1 &
Configuration
=============
......@@ -466,7 +473,7 @@ Environment
.. code-block:: lua
-- Send query for root DNSKEY, ignore cache
resolve('.', kres.type.DNSKEY, kres.class.IN, kres.query.NO_CACHE)
resolve('.', kres.type.DNSKEY, kres.class.IN, 'NO_CACHE')
-- Query for AAAA record
resolve('example.com', kres.type.AAAA, kres.class.IN, 0,
......@@ -1143,7 +1150,7 @@ Example:
$ kresd-query.lua www.sub.nic.cz 'assert(kres.dname2str(req:resolved().zone_cut.name) == "nic.cz.")' && echo "yes"
yes
$ kresd-query.lua -C 'trust_anchors.config("root.keys")' nic.cz 'assert(req:resolved():hasflag(kres.query.DNSSEC_WANT))'
$ kresd-query.lua -C 'trust_anchors.config("root.keys")' nic.cz 'assert(req:resolved().flags.DNSSEC_WANT)'
$ echo $?
0
......
......@@ -1208,17 +1208,21 @@ static int wrk_resolve(lua_State *L)
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);
const struct kr_qflags *options = lua_topointer(L, 4);
if (!options) { /* but we rely on the lua wrapper when dereferencing non-NULL */
lua_pushstring(L, "invalid options");
lua_error(L);
}
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);
ret = worker_resolve(worker, pkt, *options, resolve_callback, (void *) (intptr_t)cb);
} else {
ret = worker_resolve(worker, pkt, options, NULL, NULL);
ret = worker_resolve(worker, pkt, *options, NULL, NULL);
}
knot_rrset_free(&pkt->opt_rr, NULL);
......@@ -1282,7 +1286,7 @@ static int wrk_stats(lua_State *L)
int lib_worker(lua_State *L)
{
static const luaL_Reg lib[] = {
{ "resolve", wrk_resolve },
{ "resolve_unwrapped", wrk_resolve },
{ "stats", wrk_stats },
{ NULL, NULL }
};
......
......@@ -267,37 +267,6 @@ static int l_moduledir(lua_State *L)
return 1;
}
/** Get/set context option. */
static int l_option(lua_State *L)
{
struct engine *engine = engine_luaget(L);
/* Look up option name */
unsigned opt_code = 0;
if (lua_isstring(L, 1)) {
const char *opt = lua_tostring(L, 1);
for (const knot_lookup_t *it = kr_query_flag_names(); it->name; ++it) {
if (strcmp(it->name, opt) == 0) {
opt_code = it->id;
break;
}
}
if (!opt_code) {
lua_pushstring(L, "invalid option name");
lua_error(L);
}
}
/* Get or set */
if (lua_isboolean(L, 2) || lua_isnumber(L, 2)) {
if (lua_toboolean(L, 2)) {
engine->resolver.options |= opt_code;
} else {
engine->resolver.options &= ~opt_code;
}
}
lua_pushboolean(L, engine->resolver.options & opt_code);
return 1;
}
/** @internal for l_trustanchor: */
static void ta_add(zs_scanner_t *zs)
{
......@@ -602,8 +571,6 @@ static int init_state(struct engine *engine)
lua_setglobal(engine->L, "moduledir");
lua_pushcfunction(engine->L, l_verbose);
lua_setglobal(engine->L, "verbose");
lua_pushcfunction(engine->L, l_option);
lua_setglobal(engine->L, "option");
lua_pushcfunction(engine->L, l_setuser);
lua_setglobal(engine->L, "user");
lua_pushcfunction(engine->L, l_trustanchor);
......
......@@ -57,6 +57,40 @@ typedef struct {
map_free_f free;
void *baton;
} map_t;
struct kr_qflags {
_Bool NO_MINIMIZE : 1;
_Bool NO_THROTTLE : 1;
_Bool NO_IPV6 : 1;
_Bool NO_IPV4 : 1;
_Bool TCP : 1;
_Bool RESOLVED : 1;
_Bool AWAIT_IPV4 : 1;
_Bool AWAIT_IPV6 : 1;
_Bool AWAIT_CUT : 1;
_Bool SAFEMODE : 1;
_Bool CACHED : 1;
_Bool NO_CACHE : 1;
_Bool EXPIRING : 1;
_Bool ALLOW_LOCAL : 1;
_Bool DNSSEC_WANT : 1;
_Bool DNSSEC_BOGUS : 1;
_Bool DNSSEC_INSECURE : 1;
_Bool STUB : 1;
_Bool ALWAYS_CUT : 1;
_Bool DNSSEC_WEXPAND : 1;
_Bool PERMISSIVE : 1;
_Bool STRICT : 1;
_Bool BADCOOKIE_AGAIN : 1;
_Bool CNAME : 1;
_Bool REORDER_RR : 1;
_Bool TRACE : 1;
_Bool NO_0X20 : 1;
_Bool DNSSEC_NODS : 1;
_Bool DNSSEC_OPTOUT : 1;
_Bool NONAUTH : 1;
_Bool FORWARD : 1;
_Bool DNS64_MARK : 1;
};
typedef struct {
knot_rrset_t **at;
size_t len;
......@@ -113,7 +147,7 @@ struct kr_request {
unsigned int rtt;
const struct sockaddr *addr;
} upstream;
uint32_t options;
struct kr_qflags options;
int state;
ranked_rr_array_t answ_selected;
ranked_rr_array_t auth_selected;
......@@ -145,7 +179,8 @@ struct kr_query {
uint16_t stype;
uint16_t sclass;
uint16_t id;
uint32_t flags;
struct kr_qflags flags;
struct kr_qflags forward_flags;
uint32_t secret;
uint16_t fails;
uint16_t reorder;
......@@ -154,20 +189,21 @@ struct kr_query {
struct kr_nsrep ns;
struct kr_layer_pickle *deferred;
uint32_t uid;
/* ^hidden stub^ */
char _stub[];
struct kr_query *cname_parent;
};
struct kr_context {
uint32_t options;
struct kr_qflags options;
knot_rrset_t *opt_rr;
map_t trust_anchors;
map_t negative_anchors;
struct kr_zonecut root_hints;
char _stub[];
};
struct query_flag {static const int NO_MINIMIZE = 1; static const int NO_THROTTLE = 2; static const int NO_IPV6 = 4; static const int NO_IPV4 = 8; static const int TCP = 16; static const int RESOLVED = 32; static const int AWAIT_IPV4 = 64; static const int AWAIT_IPV6 = 128; static const int AWAIT_CUT = 256; static const int SAFEMODE = 512; static const int CACHED = 1024; static const int NO_CACHE = 2048; static const int EXPIRING = 4096; static const int ALLOW_LOCAL = 8192; static const int DNSSEC_WANT = 16384; static const int DNSSEC_BOGUS = 32768; static const int DNSSEC_INSECURE = 65536; static const int STUB = 131072; static const int ALWAYS_CUT = 262144; static const int DNSSEC_WEXPAND = 524288; static const int PERMISSIVE = 1048576; static const int STRICT = 2097152; static const int BADCOOKIE_AGAIN = 4194304; static const int CNAME = 8388608; static const int REORDER_RR = 16777216; static const int TRACE = 33554432; static const int NO_0X20 = 67108864; static const int DNSSEC_NODS = 134217728; static const int DNSSEC_OPTOUT = 268435456; static const int NONAUTH = 536870912; static const int FORWARD = 1073741824; static const int DNS64_MARK = 2147483648;};
int knot_dname_size(const knot_dname_t *);
knot_dname_t *knot_dname_from_str(uint8_t *, const char *, size_t);
_Bool knot_dname_is_equal(const knot_dname_t *, const knot_dname_t *);
_Bool knot_dname_is_sub(const knot_dname_t *, const knot_dname_t *);
int knot_dname_labels(const uint8_t *, const uint8_t *);
int knot_dname_size(const knot_dname_t *);
char *knot_dname_to_str(char *, const knot_dname_t *, size_t);
uint16_t knot_rdata_rdlen(const knot_rdata_t *);
uint8_t *knot_rdata_data(const knot_rdata_t *);
......@@ -190,7 +226,7 @@ struct kr_query *kr_rplan_push(struct kr_rplan *, struct kr_query *, const knot_
int kr_rplan_pop(struct kr_rplan *, struct kr_query *);
struct kr_query *kr_rplan_resolved(struct kr_rplan *);
int kr_nsrep_set(struct kr_query *, size_t, const struct sockaddr *);
unsigned int kr_rand_uint(unsigned int);
uint32_t kr_rand_uint(uint32_t);
void kr_pkt_make_auth_header(knot_pkt_t *);
int kr_pkt_put(knot_pkt_t *, const knot_dname_t *, uint32_t, uint16_t, uint16_t, const uint8_t *, uint16_t);
int kr_pkt_recycle(knot_pkt_t *);
......@@ -203,6 +239,8 @@ int kr_bitcmp(const char *, const char *, int);
int kr_family_len(int);
struct sockaddr *kr_straddr_socket(const char *, int);
int kr_ranked_rrarray_add(ranked_rr_array_t *, const knot_rrset_t *, uint8_t, _Bool, uint32_t, knot_mm_t *);
void kr_qflags_set(struct kr_qflags *, struct kr_qflags);
void kr_qflags_clear(struct kr_qflags *, struct kr_qflags);
knot_rrset_t *kr_ta_get(map_t *, const knot_dname_t *);
int kr_ta_add(map_t *, const knot_dname_t *, uint16_t, uint32_t, const uint8_t *, uint16_t);
int kr_ta_del(map_t *, const knot_dname_t *);
......
......@@ -47,6 +47,7 @@ typedef void (*map_free_f)(void *baton, void *ptr);
# generics
map_t
# libkres
struct kr_qflags
rr_array_t
struct ranked_rr_array_entry
ranked_rr_array_entry_t
......@@ -70,23 +71,19 @@ genResType "struct knot_rrset" | sed 's/\<owner\>/_owner/'
genResType "struct kr_nsrep" | sed '/union/,$ d'
printf "\t/* beware: hidden stub */\n};\n"
genResType "struct kr_query" | sed '/uint32_t forward_flags/,$ d'
printf "\t/* ^hidden stub^ */\n\tchar _stub[];\n};\n"
genResType "struct kr_query"
genResType "struct kr_context" | sed '/struct kr_cache/,$ d'
printf "\tchar _stub[];\n};\n"
# Getting struct query_flag is a bit complex.
genResType "enum kr_query_flag" | sed -e 's/enum kr_query_flag/struct query_flag/' \
-e 's/QUERY_NO_THROTTLE/& = 2/' `# a special case for consecutive integers` \
-e 's@\<QUERY_\([A-Z_0-9]*\) = \([0-9]*\)@static const int \1 = \2;@g' \
-e 's/,//g'
## libknot API
./scripts/gen-cdefs.sh libknot functions <<-EOF
# Domain names
knot_dname_size
knot_dname_from_str
knot_dname_is_equal
knot_dname_is_sub
knot_dname_labels
knot_dname_size
knot_dname_to_str
# Resource records
knot_rdata_rdlen
......@@ -132,6 +129,8 @@ EOF
kr_family_len
kr_straddr_socket
kr_ranked_rrarray_add
kr_qflags_set
kr_qflags_clear
# Trust anchors
kr_ta_get
kr_ta_add
......
......@@ -116,9 +116,6 @@ int inet_pton(int af, const char *src, void *dst);
require('kres-gen')
-- Constants
local query_flag = ffi.new('struct query_flag')
-- Metatype for sockaddr
local addr_buf = ffi.new('char[16]')
local sockaddr_t = ffi.typeof('struct sockaddr')
......@@ -255,25 +252,6 @@ local kr_query_t = ffi.typeof('struct kr_query')
ffi.metatype( kr_query_t, {
__index = {
name = function(qry) return ffi.string(qry.sname, knot.knot_dname_size(qry.sname)) end,
hasflag = function(qry, flag)
return band(qry.flags, flag) ~= 0
end,
resolved = function(qry)
return qry:hasflag(query_flag.RESOLVED)
end,
final = function(qry)
return qry:resolved() and (qry.parent == nil)
end,
nslist = function(qry, list)
assert(#list <= 4, 'maximum of 4 addresses can be evaluated for each query')
for i, ns in ipairs(list) do
assert(C.kr_nsrep_set(qry, i - 1, ns) == 0);
end
-- If less than maximum NSs, insert guard to terminate the list
if #list < 4 then
assert(C.kr_nsrep_set(qry, #list, nil) == 0);
end
end,
},
})
-- Metatype for request
......@@ -294,10 +272,11 @@ ffi.metatype( kr_request_t, {
end,
push = function(req, qname, qtype, qclass, flags, parent)
assert(req)
flags = kres.mk_qflags(flags) -- compatibility
local rplan = C.kr_resolve_plan(req)
local qry = C.kr_rplan_push(rplan, parent, qname, qclass, qtype)
if qry ~= nil and flags ~= nil then
qry.flags = bor(qry.flags, flags)
C.kr_qflags_set(qry.flags, flags)
end
return qry
end,
......@@ -346,7 +325,25 @@ kres = {
type = ffi.new('struct rr_type'),
section = ffi.new('struct pkt_section'),
rcode = ffi.new('struct pkt_rcode'),
query = query_flag,
-- Create a struct kr_qflags from a single flag name or a list of names.
mk_qflags = function (names)
local kr_qflags = ffi.typeof('struct kr_qflags')
if names == 0 or names == nil then -- compatibility: nil is common in lua
names = {}
elseif type(names) == 'string' then
names = {names}
elseif ffi.istype(kr_qflags, names) then
return names
end
local fs = ffi.new(kr_qflags)
for k_, name in pairs(names) do
fs[name] = true
end
return fs
end,
CONSUME = 1, PRODUCE = 2, DONE = 4, FAIL = 8, YIELD = 16,
-- Metatypes. Beware that any pointer will be cast silently...
pkt_t = function (udata) return ffi.cast('knot_pkt_t *', udata) end,
......
......@@ -24,11 +24,17 @@ end
-- Resolver bindings
kres = require('kres')
trust_anchors = require('trust_anchors')
resolve = worker.resolve
if rawget(kres, 'str2dname') ~= nil then
todname = kres.str2dname
end
-- Compat. wrapper for query flags.
worker.resolve = function (p1, p2, p3, options, p5)
options = kres.mk_qflags(options)
return worker.resolve_unwrapped (p1, p2, p3, options, p5)
end
resolve = worker.resolve
-- Shorthand for aggregated per-worker information
worker.info = function ()
local t = worker.stats()
......@@ -54,6 +60,20 @@ function reorder_RR(val)
return option('REORDER_RR', val)
end
-- Get/set resolver options via name (string)
function option(name, val)
local flags = kres.context().options;
-- Note: no way to test existence of flags[name] but we want error anyway.
name = string.upper(name) -- convenience
if val ~= nil then
if (val ~= true) and (val ~= false) then
panic('invalid option value: ' .. tostring(val))
end
flags[name] = val;
end
return flags[name];
end
-- Function aliases
-- `env.VAR returns os.getenv(VAR)`
env = {}
......
......@@ -176,7 +176,7 @@ local active_refresh, update -- forwards
local function refresh_plan(keyset, delay, priming, is_initial)
local owner_str = kres.dname2str(keyset.owner) -- maybe fix converting back and forth?
keyset.refresh_ev = event.after(delay, function (ev)
resolve(owner_str, kres.type.DNSKEY, kres.class.IN, kres.query.NO_CACHE,
resolve(owner_str, kres.type.DNSKEY, kres.class.IN, 'NO_CACHE',
function (pkt)
-- Schedule itself with updated timeout
local delay_new = active_refresh(keyset, kres.pkt_t(pkt), is_initial)
......
......@@ -387,7 +387,7 @@ static int qr_task_start(struct qr_task *task, knot_pkt_t *query)
worker->stats.queries += 1;
/* Throttle outbound queries only when high pressure */
if (worker->stats.concurrent < QUERY_RATE_THRESHOLD) {
task->req.options |= QUERY_NO_THROTTLE;
task->req.options.NO_THROTTLE = true;
}
return 0;
}
......@@ -1036,7 +1036,8 @@ int worker_process_tcp(struct worker_ctx *worker, uv_stream_t *handle, const uin
return submitted;
}
int worker_resolve(struct worker_ctx *worker, knot_pkt_t *query, unsigned options, worker_cb_t on_complete, void *baton)
int worker_resolve(struct worker_ctx *worker, knot_pkt_t *query, struct kr_qflags options,
worker_cb_t on_complete, void *baton)
{
if (!worker || !query) {
return kr_error(EINVAL);
......@@ -1053,7 +1054,7 @@ int worker_resolve(struct worker_ctx *worker, knot_pkt_t *query, unsigned option
int ret = qr_task_start(task, query);
/* Set options late, as qr_task_start() -> kr_resolve_begin() rewrite it. */
task->req.options |= options;
kr_qflags_set(&task->req.options, options);
if (ret != 0) {
qr_task_unref(task);
......
......@@ -60,8 +60,8 @@ int worker_end_tcp(struct worker_ctx *worker, uv_handle_t *handle);
* @note the options passed are |-combined with struct kr_context::options
* @todo maybe better semantics for this?
*/
int worker_resolve(struct worker_ctx *worker, knot_pkt_t *query, unsigned options,
worker_cb_t on_complete, void *baton);
int worker_resolve(struct worker_ctx *worker, knot_pkt_t *query, struct kr_qflags options,
worker_cb_t on_complete, void *baton);
/** Collect worker mempools */
void worker_reclaim(struct worker_ctx *worker);
......
......@@ -125,6 +125,12 @@ When you have all the dependencies ready, you can build and install.
Production code should be compiled with ``-DNDEBUG``.
If you build the binary with ``-DNOVERBOSELOG``, it won't be possible to turn on verbose logging; we advise packagers against using that flag.
.. note:: If you build with ``PREFIX``, you may need to also set the ``LDFLAGS`` for the libraries:
.. code-block:: bash
make LDFLAGS="-Wl,-rpath=/usr/local/lib" PREFIX="/usr/local"
Alternatively you can build only specific parts of the project, i.e. ``library``.
.. code-block:: bash
......
......@@ -33,7 +33,7 @@ This is the *driver*. The driver is not meant to know *"how"* the query resolves
On the other side are *layers*. They are responsible for dissecting the packets and informing the driver about the results. For example, a *produce* layer generates query, a *consume* layer validates answer.
.. tip:: Layers are executed asynchronously by the driver. If you need some asset beforehand, you can signalize the driver using returning state or current query flags. For example, setting a flag ``QUERY_AWAIT_CUT`` forces driver to fetch zone cut information before the packet is consumed; setting a ``QUERY_RESOLVED`` flag makes it pop a query after the current set of layers is finished; returning ``FAIL`` state makes it fail current query.
.. tip:: Layers are executed asynchronously by the driver. If you need some asset beforehand, you can signalize the driver using returning state or current query flags. For example, setting a flag ``AWAIT_CUT`` forces driver to fetch zone cut information before the packet is consumed; setting a ``RESOLVED`` flag makes it pop a query after the current set of layers is finished; returning ``FAIL`` state makes it fail current query.
Layers can also change course of resolution, for example by appending additional queries.
......@@ -44,7 +44,7 @@ Layers can also change course of resolution, for example by appending additional
if answer:qtype() == kres.type.NS then
req = kres.request_t(req)
local qry = req:push(answer:qname(), kres.type.SOA, kres.class.IN)
qry.flags = kres.query.AWAIT_CUT
qry.flags.AWAIT_CUT = true
end
return state
end
......@@ -62,7 +62,7 @@ This **doesn't** block currently processed query, and the newly created sub-requ
if answer:qtype() == kres.type.NS then
req = kres.request_t(req)
local qry = req:push(answer:qname(), kres.type.SOA, kres.class.IN)
qry.flags = kres.query.AWAIT_CUT
qry.flags.AWAIT_CUT = true
print('planned SOA query, yielding')
return kres.YIELD
end
......@@ -113,7 +113,7 @@ This is only passive processing of the incoming answer. If you want to change th
if (can_satisfy(qry)) {
/* This flag makes the resolver move the query
* to the "resolved" list. */
qry->flags |= QUERY_RESOLVED;
qry->flags.RESOLVED = true;
return KR_STATE_DONE;
}
......@@ -268,7 +268,7 @@ As described in the layers, you can not only retrieve information about current
-- Push new query
local qry = req:push(pkt:qname(), kres.type.SOA, kres.class.IN)
qry.flags = kres.query.AWAIT_CUT
qry.flags.AWAIT_CUT = true
-- Pop the query, this will erase it from resolution plan
req:pop(qry)
......
......@@ -36,6 +36,10 @@
#include "lib/dnssec.h"
#include "lib/resolve.h"
/* forward */
static int kr_rrset_validate_with_key(kr_rrset_validation_ctx_t *vctx,
const knot_rrset_t *covered, size_t key_pos, const struct dseckey *key);
void kr_crypto_init(void)
{
dnssec_crypto_init();
......@@ -147,7 +151,16 @@ int kr_rrset_validate(kr_rrset_validation_ctx_t *vctx, const knot_rrset_t *cover
return kr_error(ENOENT);
}
int kr_rrset_validate_with_key(kr_rrset_validation_ctx_t *vctx,
/**
* Validate RRSet using a specific key.
* @param vctx Pointer to validation context.
* @param covered RRSet covered by a signature. It must be in canonical format.
* @param key_pos Position of the key to be validated with.
* @param key Key to be used to validate.
* If NULL, then key from DNSKEY RRSet is used.
* @return 0 or error code, same as vctx->result.
*/
static int kr_rrset_validate_with_key(kr_rrset_validation_ctx_t *vctx,
const knot_rrset_t *covered,
size_t key_pos, const struct dseckey *key)
{
......@@ -157,6 +170,14 @@ int kr_rrset_validate_with_key(kr_rrset_validation_ctx_t *vctx,
uint32_t timestamp = vctx->timestamp;
bool has_nsec3 = vctx->has_nsec3;
struct dseckey *created_key = NULL;
/* It's just caller's approximation that the RR is in that particular zone.
* We MUST guard against attempts of zones signing out-of-bailiwick records. */
if (!knot_dname_in(zone_name, covered->owner)) {
vctx->result = kr_error(ENOENT);
return vctx->result;
}
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,
......
......@@ -71,18 +71,6 @@ typedef struct kr_rrset_validation_ctx kr_rrset_validation_ctx_t;
int kr_rrset_validate(kr_rrset_validation_ctx_t *vctx,
const knot_rrset_t *covered);
/**
* Validate RRSet using a specific key.
* @param vctx Pointer to validation context.
* @param covered RRSet covered by a signature. It must be in canonical format.
* @param key_pos Position of the key to be validated with.
* @param key Key to be used to validate.
* If NULL, then key from DNSKEY RRSet is used.
* @return 0 or error code, same as vctx->result.
*/
int kr_rrset_validate_with_key(kr_rrset_validation_ctx_t *vctx,
const knot_rrset_t *covered,
size_t key_pos, const struct dseckey *key);
/**
* Check whether the DNSKEY rrset matches the supplied trust anchor RRSet.
* @param vctx Pointer to validation context.
......
This diff is collapsed.
......@@ -17,9 +17,9 @@
/** @file pktcache.c
*
* This builtin module caches whole packets from/for negative answers
* or answers where wildcard expansion has occured (QUERY_DNSSEC_WEXPAND).
* or answers where wildcard expansion has occured (.DNSSEC_WEXPAND).
*
* Note: it also persists some QUERY_DNSSEC_* flags.
* Note: it also persists some DNSSEC_* flags.
* The ranks are stored in *(uint8_t *)rrset->additional (all are the same for one packet).
*/
......@@ -78,7 +78,7 @@ static int loot_pktcache(struct kr_context *ctx, knot_pkt_t *pkt,
uint8_t lowest_rank = KR_RANK_INITIAL | KR_RANK_AUTH;
/* There's probably little sense for NONAUTH in pktcache. */
if (!knot_wire_get_cd(req->answer->wire) && !(qry->flags & QUERY_STUB)) {