#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)
{
{
static const luaL_Reg lib[] = {
{ "resolve_unwrapped", wrk_resolve },
+ { "resolve_unwrapped_pkt", wrk_resolve_pkt },
{ "stats", wrk_stats },
{ NULL, NULL }
};
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);
]]
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
/** 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;
--- /dev/null
+#include <knot/lib/pkt.h>
+
+uint32_t packet_ttl(const knot_pkt_t *pkt, bool is_negative);
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 = {}
--- /dev/null
+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},
+ }
+}
lua_mod_src += [
lua_http,
+ files('http_doh.lua'),
files('http_trace.lua'),
files('prometheus.lua'),
]