Commit 14bc2695 authored by Petr Špaček's avatar Petr Špaček

DoH experiment

First version which actually works with Firefox DoH in default
configuration.

Limitations:
- does not support HTTP GET method
- headers for HTTP cache are not generated
- error handling is largely missing
- no tests
- ACLs will not work, modules do not see source IP address of the HTTP
endpoint
parent 287e06a2
......@@ -18,6 +18,73 @@
#include "daemon/worker.h"
static void stackDump (lua_State *L) {
int i;
int top = lua_gettop(L);
for (i = 1; i <= top; i++) { /* repeat for each level */
int t = lua_type(L, i);
printf("%d ", i); /* put a separator */
switch (t) {
case LUA_TSTRING: /* strings */
printf("`%s'", lua_tostring(L, i));
break;
case LUA_TBOOLEAN: /* booleans */
printf(lua_toboolean(L, i) ? "true" : "false");
break;
case LUA_TNUMBER: /* numbers */
printf("%g", lua_tonumber(L, i));
break;
default: /* other values */
printf("%s", lua_typename(L, t));
break;
}
printf(" "); /* put a separator */
}
printf("\n"); /* end the listing */
}
static int wrk_resolve_pkt(lua_State *L)
{
stackDump(L);
struct worker_ctx *worker = wrk_luaget(L);
if (!worker) {
return 0;
}
// FIXME: merge with wrk_resolve
const struct kr_qflags options = {};
knot_pkt_t *pkt = *(knot_pkt_t **)lua_topointer(L, 1);
printf("%p\n", pkt);
if (!pkt)
lua_error_maybe(L, ENOMEM);
printf("%s\n", kr_pkt_text(pkt));
/* Create task and start with a first question */
struct qr_task *task = worker_resolve_start(worker, pkt, options);
if (!task) {
lua_error_p(L, "couldn't create a resolution request");
}
/* Add initialisation callback */
if (lua_isfunction(L, 2)) {
lua_pushvalue(L, 2);
lua_pushlightuserdata(L, worker_task_request(task));
(void) execute_callback(L, 1);
}
/* Start execution */
int ret = worker_resolve_exec(task, pkt);
lua_pushboolean(L, ret == 0);
return 1;
}
static int wrk_resolve(lua_State *L)
{
......@@ -148,6 +215,7 @@ int kr_bindings_worker(lua_State *L)
{
static const luaL_Reg lib[] = {
{ "resolve_unwrapped", wrk_resolve },
{ "resolve_unwrapped_pkt", wrk_resolve_pkt },
{ "stats", wrk_stats },
{ NULL, NULL }
};
......
......@@ -440,4 +440,5 @@ int zs_parse_record(zs_scanner_t *);
int zs_set_input_file(zs_scanner_t *, const char *);
int zs_set_input_string(zs_scanner_t *, const char *, size_t);
const char *zs_strerror(const int);
uint32_t packet_ttl(const knot_pkt_t *pkt, bool is_negative);
]]
......@@ -66,6 +66,28 @@ worker.resolve = function (qname, qtype, qclass, options, finish, init)
return worker.resolve_unwrapped(qname, qtype, qclass, options, init_cb)
end
worker.resolve_pkt = function (pkt, finish, init)
local init_cb, finish_cb = init, nil
if finish then
-- Create callback for finalization
finish_cb = ffi.cast('trace_callback_f', function (req)
req = kres.request_t(req)
finish(req.answer, req)
finish_cb:free()
end)
-- Wrap initialiser to install finish callback
init_cb = function (req)
req = kres.request_t(req)
if init then init(req) end
req.trace_finish = finish_cb
end
end
-- Translate options and resolve
return worker.resolve_unwrapped_pkt(pkt, init_cb)
end
resolve = worker.resolve
-- Shorthand for aggregated per-worker information
......
......@@ -26,7 +26,8 @@
/** Compute TTL for a packet. Generally it's minimum TTL, with extra conditions. */
static uint32_t packet_ttl(const knot_pkt_t *pkt, bool is_negative)
KR_EXPORT
uint32_t packet_ttl(const knot_pkt_t *pkt, bool is_negative)
{
bool has_ttl = false;
uint32_t ttl = UINT32_MAX;
......
#include <knot/lib/pkt.h>
uint32_t packet_ttl(const knot_pkt_t *pkt, bool is_negative);
......@@ -108,6 +108,12 @@ for k, v in pairs(http_trace.endpoints) do
end
M.trace = http_trace
local http_doh = require('kres_modules.http_doh')
for k, v in pairs(http_doh.endpoints) do
M.endpoints[k] = v
end
M.doh = http_doh
-- Export HTTP service page snippets
M.snippets = {}
......
local ffi = require('ffi')
local condition = require('cqueues.condition')
local function get_http_ttl(pkt)
-- minimum TTL from all RRs in ANSWER
if true then
local an_records = pkt:section(kres.section.ANSWER)
local is_negative = #an_records <= 0
-- FIXME: does not work for positive answers
return ffi.C.packet_ttl(pkt, is_negative)
end
-- garbage
if an_count > 0 then
local min_ttl = 4294967295
for i = 1, an_count do
local rr = an_records[i]
min_ttl = math.min(rr.ttl, min_ttl)
end
return min_ttl
end
-- no ANSWER records, try SOA
local auth_records = pkt:section(kres.section.AUTHORITY)
local auth_count = #auth_records
if auth_count > 0 then
for i = 1, an_count do
local rr = an_records[i]
if rr.type == kres.type.SOA then
knot_soa_minimum()
end
end
return 0 -- no SOA, uncacheable
end
end
-- Trace execution of DNS queries
local function serve_doh(h, stream)
local path = h:get(':path')
local input = stream:get_body_as_string(10) -- FIXME: timeout
-- Output buffer
local output = ''
-- Wait for the result of the query
-- Note: We can't do non-blocking write to stream directly from resolve callbacks
-- because they don't run inside cqueue.
local answers, authority = {}, {}
local cond = condition.new()
local waiting, done = false, false
local finish_cb = function (answer, req)
print(tostring(answer))
print('TTL: ', get_http_ttl(answer))
-- binary output
output = ffi.string(answer.wire, answer.size)
if waiting then
cond:signal()
end
done = true
end
-- Resolve query
wire = ffi.cast("void *", input)
local pkt = ffi.C.knot_pkt_new(wire, #input, nil);
if not pkt then
output = 'shit happened in knot_pkt_new'
else
output = 'knot_pkt_new ok'
end
local result = ffi.C.knot_pkt_parse(pkt, 0)
if result > 0 then
output = output .. '\nshit in knot_pkt_parse'
else
output = output .. '\nknot_pkt_parse ok'
end
print(pkt)
print(output)
worker.resolve_pkt(pkt, finish_cb)
-- worker.resolve("www.nic.cz", 666, KNOT_CLASS_IN, NULL, finish_cb)
-- Wait for asynchronous query and free callbacks
if not done then
waiting = true
cond:wait()
end
-- Return buffered data
if not done then
return 504, 'huh?' -- FIXME
end
return output, nil, 'application/dns-message'
end
-- Export endpoints
return {
endpoints = {
['/doh'] = {'text/plain', serve_doh},
}
}
......@@ -11,6 +11,7 @@ lua_http = configure_file(
lua_mod_src += [
lua_http,
files('http_doh.lua'),
files('http_trace.lua'),
files('prometheus.lua'),
]
......
Subproject commit 6edfef4f65e846f3aef0cbf3b80e88f39658a1c9
Subproject commit 13f18ac937867baa4761713305d02939b852680f
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