Commit a365d68e authored by Marek Vavruša's avatar Marek Vavruša

Merge branch 'cache-rrsig-wip'

parents 1b931863 d515cb64
......@@ -29,6 +29,7 @@ $(eval $(call find_bin,python))
$(eval $(call find_lib,libmemcached,1.0))
$(eval $(call find_lib,hiredis))
$(eval $(call find_lib,socket_wrapper))
$(eval $(call find_lib,libdnssec))
# Work around luajit on OS X
ifeq ($(PLATFORM), Darwin)
......@@ -37,7 +38,7 @@ ifneq (,$(findstring luajit, $(lua_LIBS)))
endif
endif
CFLAGS += $(libknot_CFLAGS) $(libuv_CFLAGS) $(cmocka_CFLAGS) $(python_CFLAGS) $(lua_CFLAGS)
CFLAGS += $(libknot_CFLAGS) $(libuv_CFLAGS) $(cmocka_CFLAGS) $(python_CFLAGS) $(lua_CFLAGS) $(libdnssec_CFLAGS)
# Sub-targets
include help.mk
......
......@@ -3,51 +3,85 @@
Knot DNS Resolver daemon
************************
Requirements
============
The server is in the `daemon` directory, it works out of the box without any configuration.
* libuv_ 1.0+ (a multi-platform support library with a focus on asynchronous I/O)
* Lua_ 5.1+ (embeddable scripting language, LuaJIT_ is preferred)
.. code-block:: bash
$ kresd -h # Get help
$ kresd -a ::1
Running
=======
Enabling DNSSEC
===============
There is a separate resolver library in the `lib` directory, and a minimalistic daemon in
the `daemon` directory.
The resolver supports DNSSEC including :rfc:`5011` automated DNSSEC TA updates and :rfc:`7646` negative trust anchors.
To enable it, you need to provide at least _one_ trust anchor. This step is not automatic, as you're supposed to obtain
the trust anchor `using a secure channel <http://jpmens.net/2015/01/21/opendnssec-rfc-5011-bind-and-unbound/>`_.
From there, the Knot DNS Resolver can perform automatic updates for you.
1. Check the current TA published on `IANA website <https://data.iana.org/root-anchors/root-anchors.xml>`_
2. Fetch current keys, verify
3. Deploy them
.. code-block:: bash
$ ./daemon/kresd -h
$ kdig DNSKEY . @a.root-servers.net +noall +answer | grep 257 > root.keys
$ ldns-key2ds -n root.keys
... verify that digest matches TA published by IANA ...
$ kresd -k root.keys
Interacting with the daemon
---------------------------
You've just enabled DNSSEC!
The daemon features a CLI interface if launched interactively, type ``help`` to see the list of available commands.
You can load modules this way and use their properties to get information about statistics and such.
CLI interface
=============
The daemon features a CLI interface, type ``help`` to see the list of available commands.
.. code-block:: bash
$ kresd /var/run/knot-resolver
[system] started in interactive mode, type 'help()'
> cache.count()
53
$ kresd /var/run/knot-resolver
[system] started in interactive mode, type 'help()'
> cache.count()
53
.. role:: lua(code)
:language: lua
Running in forked mode
----------------------
Verbose output
--------------
If the debug logging is compiled in, you can turn on verbose tracing of server operation with the ``-v`` option.
You can also toggle it on runtime with ``verbose(true|false)`` command.
.. code-block:: bash
$ kresd -v
Scaling out
===========
The server can clone itself into multiple processes upon startup, this enables you to scale it on multiple cores.
Multiple processes can serve different addresses, but still share the same working directory and cache.
You can add start and stop processes on runtime based on the load.
.. code-block:: bash
$ kresd -f 2 rundir > kresd.log
$ kresd -f 4 rundir > kresd.log &
$ kresd -f 2 rundir > kresd_2.log & # Extra instances
$ pstree $$ -g
bash(3533)─┬─kresd(19212)─┬─kresd(19212)
│ ├─kresd(19212)
│ └─kresd(19212)
├─kresd(19399)───kresd(19399)
└─pstree(19411)
$ kill 19399 # Kill group 2, former will continue to run
bash(3533)─┬─kresd(19212)─┬─kresd(19212)
│ ├─kresd(19212)
│ └─kresd(19212)
└─pstree(19460)
.. note:: On recent Linux supporting ``SO_REUSEPORT`` (since 3.9, backported to RHEL 2.6.32) it is also able to bind to the same endpoint and distribute the load between the forked processes. If the kernel doesn't support it, you can still fork multiple processes on different ports, and do load balancing externally (on firewall or with `dnsdist <http://dnsdist.org/>`_).
Notice it isn't interactive, but you can attach to the the consoles for each process, they are in ``rundir/tty/PID``.
Notice the absence of an interactive CLI. You can attach to the the consoles for each process, they are in ``rundir/tty/PID``.
.. code-block:: bash
......@@ -77,11 +111,8 @@ comfortable in the current working directory.
And you're good to go for most use cases! If you want to use modules or configure daemon behavior, read on.
There are several choices on how you can configure the daemon, a RPC interface a CLI and a configuration file.
Fortunately all share common syntax and are transparent to each other, e.g. changes made during the runtime are kept
in the redo log and are immediately visible.
.. warning:: Redo log is not yet implemented, changes are visible during the process lifetime only.
There are several choices on how you can configure the daemon, a RPC interface, a CLI, and a configuration file.
Fortunately all share common syntax and are transparent to each other.
Configuration example
---------------------
......@@ -90,9 +121,9 @@ Configuration example
-- 10MB cache
cache.size = 10*MB
-- load some modules
modules = { 'hints', 'cachectl' }
modules = { 'policy', 'cachectl' }
-- interfaces
net = { '127.0.0.1' }
net = { '127.0.0.1', '::1' }
Configuration syntax
--------------------
......@@ -123,8 +154,6 @@ the modules use as the :ref:`input configuration <mod-properties>`.
}
}
The possible simple data types are: string, integer or float, and boolean.
.. tip:: The configuration and CLI syntax is Lua language, with which you may already be familiar with.
If not, you can read the `Learn Lua in 15 minutes`_ for a syntax overview. Spending just a few minutes
will allow you to break from static configuration, write more efficient configuration with iteration, and
......@@ -170,7 +199,7 @@ to download cache from parent, to avoid cold-cache start.
sink = ltn12.sink.file(io.open('cache.mdb', 'w'))
}
-- reopen cache with 100M limit
cache.open(100*MB)
cache.size = 100*MB
end
Events and services
......@@ -241,6 +270,10 @@ Environment
:return: Machine hostname.
.. function:: verbose(true | false)
:return: Toggle verbose logging.
Network configuration
^^^^^^^^^^^^^^^^^^^^^
......@@ -320,6 +353,65 @@ For when listening on ``localhost`` just doesn't cut it.
.. tip:: You can use ``net.<iface>`` as a shortcut for specific interface, e.g. ``net.eth0``
.. function:: net.bufsize([udp_bufsize])
Get/set maximum EDNS payload available. Default is 1452 (the maximum unfragmented datagram size).
You cannot set less than 1220 (minimum size for DNSSEC) or more than 65535 octets.
Example output:
.. code-block:: lua
> net.bufsize(4096)
> net.bufsize()
4096
Trust anchors and DNSSEC
^^^^^^^^^^^^^^^^^^^^^^^^
.. function:: trust_anchors.config(keyfile)
:param string keyfile: File containing DNSKEY records, should be writeable.
You can use only DNSKEY records in managed mode. It is equivalent to CLI parameter `-k <keyfile>` or `trust_anchors.file = keyfile`.
Example output:
.. code-block:: lua
> trust_anchors.config('root.keys')
[trust_anchors] key: 19036 state: Valid
.. function:: trust_anchors.set_insecure(nta_set)
:param table nta_list: List of domain names (text format) representing NTAs.
When you use a domain name as an NTA, DNSSEC validation will be turned off at/below these names.
Each function call replaces the previous NTA set. You can find the current active set in `trust_anchors.insecure` variable.
.. tip:: Use the `trust_anchors.negative = {}` alias for easier configuration.
Example output:
.. code-block:: lua
> trust_anchors.negative = { 'bad.boy', 'example.com' }
> trust_anchors.insecure
[1] => bad.boy
[2] => example.com
.. function:: trust_anchors.add(rr_string)
:param string rr_string: DS/DNSKEY records in presentation format (e.g. `. 3600 IN DS 19036 8 2 49AAC11...`)
Inserts DS/DNSKEY record(s) into current keyset. These will not be managed or updated.
Example output:
.. code-block:: lua
> trust_anchors.add('. 3600 IN DS 19036 8 2 49AAC11...')
Modules configuration
^^^^^^^^^^^^^^^^^^^^^
......@@ -521,17 +613,15 @@ you can see the statistics or schedule new queries.
print(worker.stats().concurrent)
.. function:: worker.resolve(qname, qtype[, qclass = kres.class.IN, options = 0])
.. function:: worker.resolve(qname, qtype[, qclass = kres.class.IN, options = 0, callback = nil])
:param string qname: Query name (e.g. 'com.')
:param number qtype: Query type (e.g. ``kres.type.NS``)
:param number qclass: Query class *(optional)* (e.g. ``kres.class.IN``)
:param number options: Resolution options (see query flags)
:param function callback: Callback to be executed when resolution completes (e.g. `function cb (pkt) end`). The callback gets a packet containing the final answer and doesn't have to return anything.
:return: boolean
Resolve a query, there is currently no callback when its finished, but you can track the query
progress in layers, just like any other query.
.. _`JSON-encoded`: http://json.org/example
.. _`Learn Lua in 15 minutes`: http://tylerneylon.com/a/learn-lua/
.. _`PowerDNS Recursor`: https://doc.powerdns.com/md/recursor/scripting/
......
......@@ -267,6 +267,24 @@ static int net_interfaces(lua_State *L)
return 1;
}
/** Set UDP maximum payload size. */
static int net_bufsize(lua_State *L)
{
struct engine *engine = engine_luaget(L);
knot_rrset_t *opt_rr = engine->resolver.opt_rr;
if (!lua_isnumber(L, 1)) {
lua_pushnumber(L, knot_edns_get_payload(opt_rr));
return 1;
}
int bufsize = lua_tointeger(L, 1);
if (bufsize < KNOT_EDNS_MIN_DNSSEC_PAYLOAD || bufsize > UINT16_MAX) {
format_error(L, "bufsize must be within <1220, 65535>");
lua_error(L);
}
knot_edns_set_payload(opt_rr, (uint16_t) bufsize);
return 0;
}
int lib_net(lua_State *L)
{
static const luaL_Reg lib[] = {
......@@ -274,6 +292,7 @@ int lib_net(lua_State *L)
{ "listen", net_listen },
{ "close", net_close },
{ "interfaces", net_interfaces },
{ "bufsize", net_bufsize },
{ NULL, NULL }
};
register_lib(L, "net", lib);
......@@ -433,23 +452,28 @@ static void event_free(uv_timer_t *timer)
free(timer);
}
static int execute_callback(lua_State *L, int argc)
{
int ret = engine_pcall(L, argc);
if (ret != 0) {
fprintf(stderr, "error: %s\n", lua_tostring(L, -1));
}
/* Clear the stack, there may be event a/o enything returned */
lua_settop(L, 0);
lua_gc(L, LUA_GCCOLLECT, 0);
return ret;
}
static void event_callback(uv_timer_t *timer)
{
struct worker_ctx *worker = timer->loop->data;
lua_State *L = worker->engine->L;
/* Retrieve callback and execute */
int top = lua_gettop(L);
lua_rawgeti(L, LUA_REGISTRYINDEX, (intptr_t) timer->data);
lua_rawgeti(L, -1, 1);
lua_pushinteger(L, (intptr_t) timer->data);
int ret = engine_pcall(L, 1);
if (ret != 0) {
fprintf(stderr, "error: %s\n", lua_tostring(L, -1));
}
/* Clear the stack, there may be event a/o enything returned */
lua_settop(L, top);
lua_gc(L, LUA_GCCOLLECT, 0);
int ret = execute_callback(L, 1);
/* Free callback if not recurrent or an error */
if (ret != 0 || uv_timer_get_repeat(timer) == 0) {
uv_close((uv_handle_t *)timer, (uv_close_cb) event_free);
......@@ -522,15 +546,16 @@ static int event_cancel(lua_State *L)
/* Fetch event if it exists */
lua_rawgeti(L, LUA_REGISTRYINDEX, lua_tointeger(L, 1));
if (!lua_istable(L, -1)) {
format_error(L, "event not exists");
lua_error(L);
lua_pushboolean(L, false);
return 1;
}
/* Close the timer */
lua_rawgeti(L, -1, 2);
uv_handle_t *timer = lua_touserdata(L, -1);
uv_close(timer, (uv_close_cb) event_free);
return 0;
lua_pushboolean(L, true);
return 1;
}
int lib_event(lua_State *L)
......@@ -553,6 +578,20 @@ static inline struct worker_ctx *wrk_luaget(lua_State *L) {
return worker;
}
/* @internal Call the Lua callback stored in baton. */
static void resolve_callback(struct worker_ctx *worker, struct kr_request *req, void *baton)
{
assert(worker);
assert(req);
assert(baton);
lua_State *L = worker->engine->L;
intptr_t cb_ref = (intptr_t) baton;
lua_rawgeti(L, LUA_REGISTRYINDEX, cb_ref);
luaL_unref(L, LUA_REGISTRYINDEX, cb_ref);
lua_pushlightuserdata(L, req->answer);
(void) execute_callback(L, 1);
}
static int wrk_resolve(lua_State *L)
{
struct worker_ctx *worker = wrk_luaget(L);
......@@ -580,18 +619,22 @@ static int wrk_resolve(lua_State *L)
knot_pkt_put_question(pkt, dname, rrclass, rrtype);
knot_wire_set_rd(pkt->wire);
/* Add OPT RR */
pkt->opt_rr = mm_alloc(&pkt->mm, sizeof(*pkt->opt_rr));
pkt->opt_rr = knot_rrset_copy(worker->engine->resolver.opt_rr, &pkt->mm);
if (!pkt->opt_rr) {
return kr_error(ENOMEM);
}
int ret = knot_edns_init(pkt->opt_rr, KR_EDNS_PAYLOAD, 0, KR_EDNS_VERSION, &pkt->mm);
if (ret != 0) {
knot_pkt_free(&pkt);
return 0;
}
/* Resolve it */
}
/* Add completion callback */
int ret = 0;
unsigned options = lua_tointeger(L, 4);
ret = worker_resolve(worker, pkt, options);
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_pkt_free(&pkt);
lua_pushboolean(L, ret == 0);
return 1;
......
......@@ -16,12 +16,12 @@ daemon/engine.o: daemon/lua/sandbox.inc daemon/lua/config.inc
%.inc: %.lua
@$(call quiet,XXD,$<) $< > $@
# Installed FFI bindings
bindings-install: daemon/lua/kres.lua
$(INSTALL) $< $(PREFIX)/$(MODULEDIR)
bindings-install: daemon/lua/kres.lua daemon/lua/trust_anchors.lua
$(INSTALL) $^ $(PREFIX)/$(MODULEDIR)
# Dependencies
kresd_DEPEND := $(libkres)
kresd_LIBS := $(libkres_TARGET) $(libknot_LIBS) $(libuv_LIBS) $(lua_LIBS)
kresd_LIBS := $(libkres_TARGET) $(libknot_LIBS) $(libdnssec_LIBS) $(libuv_LIBS) $(lua_LIBS)
# Make binary
ifeq ($(HAS_lua)|$(HAS_libuv), yes|yes)
......
......@@ -27,6 +27,7 @@
#include "lib/nsrep.h"
#include "lib/cache.h"
#include "lib/defines.h"
#include "lib/dnssec/ta.h"
/** @internal Compatibility wrapper for Lua < 5.2 */
#if LUA_VERSION_NUM < 502
......@@ -52,6 +53,7 @@ static int l_help(lua_State *L)
"help()\n show this help\n"
"quit()\n quit\n"
"hostname()\n hostname\n"
"verbose(true|false)\n toggle verbose mode\n"
"option(opt[, new_val])\n get/set server option\n"
;
lua_pushstring(L, help_str);
......@@ -61,12 +63,20 @@ static int l_help(lua_State *L)
/** Quit current executable. */
static int l_quit(lua_State *L)
{
/* Stop engine */
engine_stop(engine_luaget(L));
/* No results */
return 0;
}
/** Toggle verbose mode. */
static int l_verbose(lua_State *L)
{
if (lua_isboolean(L, 1) || lua_isnumber(L, 1)) {
log_debug_enable(lua_toboolean(L, 1));
}
lua_pushboolean(L, log_debug_status());
return 1;
}
/** Return hostname. */
static int l_hostname(lua_State *L)
{
......@@ -96,7 +106,7 @@ static int l_option(lua_State *L)
}
}
/* Get or set */
if (lua_isboolean(L, 2)) {
if (lua_isboolean(L, 2) || lua_isnumber(L, 2)) {
if (lua_toboolean(L, 2)) {
engine->resolver.options |= opt_code;
} else {
......@@ -234,6 +244,8 @@ void *namedb_lmdb_mkopts(const char *conf, size_t maxsize)
static int init_resolver(struct engine *engine)
{
/* Open resolution context */
engine->resolver.trust_anchors = map_make();
engine->resolver.negative_anchors = map_make();
engine->resolver.pool = engine->pool;
engine->resolver.modules = &engine->modules;
/* Create OPT RR */
......@@ -257,6 +269,7 @@ static int init_resolver(struct engine *engine)
/* Load basic modules */
engine_register(engine, "iterate");
engine_register(engine, "validate");
engine_register(engine, "rrcache");
engine_register(engine, "pktcache");
......@@ -283,10 +296,12 @@ static int init_state(struct engine *engine)
lua_setglobal(engine->L, "help");
lua_pushcfunction(engine->L, l_quit);
lua_setglobal(engine->L, "quit");
lua_pushcfunction(engine->L, l_option);
lua_setglobal(engine->L, "option");
lua_pushcfunction(engine->L, l_hostname);
lua_setglobal(engine->L, "hostname");
lua_pushcfunction(engine->L, l_verbose);
lua_setglobal(engine->L, "verbose");
lua_pushcfunction(engine->L, l_option);
lua_setglobal(engine->L, "option");
lua_pushlightuserdata(engine->L, engine);
lua_setglobal(engine->L, "__engine");
return kr_ok();
......@@ -345,17 +360,19 @@ void engine_deinit(struct engine *engine)
lru_deinit(engine->resolver.cache_rtt);
lru_deinit(engine->resolver.cache_rep);
/* Unload modules. */
/* Unload modules and engine. */
for (size_t i = 0; i < engine->modules.len; ++i) {
engine_unload(engine, engine->modules.at[i]);
}
array_clear(engine->modules);
array_clear(engine->storage_registry);
if (engine->L) {
lua_close(engine->L);
}
/* Free data structures */
array_clear(engine->modules);
array_clear(engine->storage_registry);
kr_ta_clear(&engine->resolver.trust_anchors);
kr_ta_clear(&engine->resolver.negative_anchors);
}
int engine_pcall(lua_State *L, int argc)
......@@ -390,6 +407,12 @@ int engine_cmd(struct engine *engine, const char *str)
static int engine_loadconf(struct engine *engine)
{
/* Use module path for including Lua scripts */
static const char l_paths[] = "package.path = package.path..';" PREFIX MODULEDIR "/?.lua'";
int ret = l_dobytecode(engine->L, l_paths, sizeof(l_paths) - 1, "");
if (ret != 0) {
lua_pop(engine->L, 1);
}
/* Init environment */
static const char sandbox_bytecode[] = {
#include "daemon/lua/sandbox.inc"
......@@ -399,12 +422,6 @@ static int engine_loadconf(struct engine *engine)
lua_pop(engine->L, 1);
return kr_error(ENOEXEC);
}
/* Use module path for including Lua scripts */
int ret = engine_cmd(engine, "package.path = package.path..';" PREFIX MODULEDIR "/?.lua'");
if (ret > 0) {
lua_pop(engine->L, 1);
}
/* Load config file */
if(access("config", F_OK ) != -1 ) {
ret = l_dosandboxfile(engine->L, "config");
......
-- Default configuration
cache.open(10*MB)
-- Listen on localhost
if not next(net.list()) then
if not pcall(net.listen, '127.0.0.1') then
......
......@@ -86,6 +86,13 @@ struct pkt_rcode {
static const int NOTZONE = 10;
static const int BADVERS = 16;
};
struct query_flag {
static const int NO_MINIMIZE = 1 << 0;
static const int CACHED = 1 << 8;
static const int NO_CACHE = 1 << 9;
static const int EXPIRING = 1 << 10;
};
/*
* Data structures
*/
......@@ -97,13 +104,16 @@ struct sockaddr {
};
/* libknot */
typedef int knot_section_t; /* Do not touch */
typedef void knot_rrinfo_t; /* Do not touch */
typedef struct node {
struct node *next, *prev;
} node_t;
typedef uint8_t knot_dname_t;
typedef uint8_t knot_rdata_t;
typedef struct knot_rdataset {
uint16_t count;
uint8_t *data;
knot_rdata_t *data;
} knot_rdataset_t;
typedef struct knot_rrset {
knot_dname_t *_owner;
......@@ -111,6 +121,11 @@ typedef struct knot_rrset {
uint16_t class;
knot_rdataset_t rr;
} knot_rrset_t;
typedef struct {
struct knot_pkt *pkt;
uint16_t pos;
uint16_t count;
} knot_pktsection_t;
typedef struct {
uint8_t *wire;
size_t size;
......@@ -122,9 +137,24 @@ typedef struct {
uint16_t flags;
knot_rrset_t *opt;
knot_rrset_t *tsig;
knot_section_t _current;
knot_pktsection_t _sections[3];
size_t _rrset_allocd;
knot_rrinfo_t *_rr_info;
knot_rrset_t *_rr;
uint8_t _stub[]; /* Do not touch */
} knot_pkt_t;
/* generics */
typedef void *(*map_alloc_f)(void *, size_t);
typedef void (*map_free_f)(void *baton, void *ptr);
typedef struct {
void *root;
map_alloc_f malloc;
map_free_f free;
void *baton;
} map_t;
/* libkres */
struct kr_query {
node_t _node;
......@@ -141,32 +171,53 @@ struct kr_rplan {
uint8_t _stub[]; /* Do not touch */
};
struct kr_request {
struct kr_context *_ctx;
struct kr_context *ctx;
knot_pkt_t *answer;
struct {
const knot_rrset_t *key;
const struct sockaddr *addr;
} qsource;
struct {
const knot_rrset_t *key;
const struct sockaddr *addr;
} qsource;
uint32_t options;
int state;
uint8_t _stub[]; /* Do not touch */
};
struct kr_context
{
uint32_t options;
knot_rrset_t *opt_rr;
map_t trust_anchors;
map_t negative_anchors;
uint8_t _stub[]; /* Do not touch */
};
/* libknot API
/*
* libc APIs
*/
void free(void *ptr);
/*
* libknot APIs
*/
/* Domain names */
int knot_dname_size(const knot_dname_t *name);
knot_dname_t *knot_dname_from_str(uint8_t *dst, const char *name, size_t maxlen);
char *knot_dname_to_str(char *dst, const knot_dname_t *name, size_t maxlen);
/* Resource records */
uint16_t knot_rdata_rdlen(const knot_rdata_t *rr);
uint8_t *knot_rdata_data(const knot_rdata_t *rr);
knot_rdata_t *knot_rdataset_at(const knot_rdataset_t *rrs, size_t pos);
uint32_t knot_rrset_ttl(const knot_rrset_t *rrset);
/* Packet */
const knot_dname_t *knot_pkt_qname(const knot_pkt_t *pkt);
uint16_t knot_pkt_qtype(const knot_pkt_t *pkt);
uint16_t knot_pkt_qclass(const knot_pkt_t *pkt);
int knot_pkt_begin(knot_pkt_t *pkt, int section_id);
int knot_pkt_put_question(knot_pkt_t *pkt, const knot_dname_t *qname, uint16_t qclass, uint16_t qtype);
const knot_rrset_t *knot_pkt_rr(const knot_pktsection_t *section, uint16_t i);
/* libkres API
/*
* libkres API
*/
/* Resolution request */
struct kr_rplan *kr_resolve_plan(struct kr_request *request);
/* Resolution plan */
......@@ -178,6 +229,18 @@ int kr_pkt_put(knot_pkt_t *pkt, const knot_dname_t *name, uint32_t ttl,
uint16_t rclass, uint16_t rtype, const uint8_t *rdata, uint16_t rdlen);
const char *kr_inaddr(const struct sockaddr *addr);
int kr_inaddr_len(const struct sockaddr *addr);
/* Trust anchors */
knot_rrset_t *kr_ta_get(map_t *trust_anchors, const knot_dname_t *name);
int kr_ta_add(map_t *trust_anchors, const knot_dname_t *name, uint16_t type,
uint32_t ttl, const uint8_t *rdata, uint16_t rdlen);
int kr_ta_del(map_t *trust_anchors, const knot_dname_t *name);
void kr_ta_clear(map_t *trust_anchors);
/* DNSSEC */
bool kr_dnssec_key_ksk(const uint8_t *dnskey_rdata);
bool kr_dnssec_key_revoked(const uint8_t *dnskey_rdata);
int kr_dnssec_key_tag(uint16_t rrtype, const uint8_t *rdata, size_t rdlen);
int kr_dnssec_key_match(const uint8_t *key_a_rdata, size_t key_a_rdlen,
const uint8_t *key_b_rdata, size_t key_b_rdlen);
]]
-- Metatype for sockaddr
......@@ -193,7 +256,19 @@ ffi.metatype( sockaddr_t, {
local knot_rrset_t = ffi.typeof('knot_rrset_t')
ffi.metatype( knot_rrset_t, {
__index = {
owner = function(rr) return ffi.string(rr._owner) end,
owner = function(rr) return ffi.string(rr._owner, knot.knot_dname_size(rr._owner)) end,
ttl = function(rr) return tonumber(knot.knot_rrset_ttl(rr)) end,
rdata = function(rr, i)
local rdata = knot.knot_rdataset_at(rr.rr, i)
return ffi.string(knot.knot_rdata_data(rdata), knot.knot_rdata_rdlen(rdata))
end,
get = function(rr, i)
return {owner = rr:owner(),
ttl = rr:ttl(),
class = tonumber(rr.class),
type = tonumber(rr.type),
rdata = rr:rdata(i)}
end,
}
})
......@@ -201,7 +276,10 @@ ffi.metatype( knot_rrset_t, {
local knot_pkt_t = ffi.typeof('knot_pkt_t')
ffi.metatype( knot_pkt_t, {
__index = {
qname = function(pkt) return ffi.string(knot.knot_pkt_qname(pkt)) end,
qname = function(pkt)
local qname = knot.knot_pkt_qname(pkt)
return ffi.string(qname, knot.knot_dname_size(qname))
end,
qclass = function(pkt) return knot.knot_pkt_qclass(pkt) end,
qtype = function(pkt) return knot.knot_pkt_qtype(pkt) end,