diff --git a/daemon/bindings/kres.c b/daemon/bindings/kres.c index f9d11c1625a4a9be9acea3f7071cb036f314e042..8ca2600295c2060521f050480299e331d373c048 100644 --- a/daemon/bindings/kres.c +++ b/daemon/bindings/kres.c @@ -17,13 +17,37 @@ #include "daemon/bindings/kres.h" #include "daemon/bindings.h" +/** @internal Create userdata of given type. */ +#define UDATA_CREATE(L, type, val, meta) do { \ + type *udata = lua_newuserdata(L, sizeof(*udata)); \ + *udata = (val); \ + luaL_getmetatable(L, (meta)); \ + lua_setmetatable(L, -2); \ +} while (0) + +#define WRAP_NUMBER(L, name, val) \ + lua_pushnumber((L), (val)); \ + lua_setfield((L), -2, (name)) + +#define WRAP_CONST(L, name, prefix...) \ + WRAP_NUMBER(L, #name, prefix ## name) + +#define WRAP_LUT(L, prefix, table) \ + lua_newtable(L); \ + for (const lookup_table_t *elm = (table); elm->name; ++elm) { \ + WRAP_NUMBER((L), elm->name, elm->id); \ + } \ + lua_setfield((L), -2, (prefix)) + /** @internal Register metatable. */ -#define META_REGISTER(L, funcs, name) \ - luaL_newmetatable((L), (name)); \ - luaL_setfuncs((L), (funcs), 0); \ - lua_pushvalue((L), -1); \ - lua_setfield((L), -2, "__index"); \ - lua_pop((L), 1); +static void lua_register_meta(lua_State *L, const luaL_Reg *funcs, const char *name) +{ + luaL_newmetatable(L, name); \ + luaL_setfuncs(L, funcs, 0); \ + lua_pushvalue(L, -1); \ + lua_setfield(L, -2, "__index"); \ + lua_pop(L, 1); +} /** @internal Shortcut for dname conversion. */ static inline void lua_pushdname(lua_State *L, const knot_dname_t *name) @@ -35,6 +59,7 @@ static inline void lua_pushdname(lua_State *L, const knot_dname_t *name) /* * Packet interface + * @note Packets are always light userdata, use single pointers. */ #define WIRE_FLAGS(X) \ @@ -95,17 +120,68 @@ static int pkt_qclass(lua_State *L) { knot_pkt_t *pkt = lua_touserdata(L, 1); lua_pushnumber(L, knot_pkt_qclass(pkt)); - return 1; + return 1; } static int pkt_qname(lua_State *L) { knot_pkt_t *pkt = lua_touserdata(L, 1); lua_pushdname(L, knot_pkt_qname(pkt)); - return 1; + return 1; +} + +static int pkt_question(lua_State *L) +{ + knot_pkt_t *pkt = lua_touserdata(L, 1); + if (lua_gettop(L) < 4) { + return 0; + } + uint8_t dname[KNOT_DNAME_MAXLEN]; + knot_dname_from_str(dname, lua_tostring(L, 2), sizeof(dname)); + if (!knot_dname_is_equal(knot_pkt_qname(pkt), dname)) { + uint8_t header[KNOT_WIRE_HEADER_SIZE]; + memcpy(header, pkt->wire, sizeof(header)); + knot_pkt_clear(pkt); + memcpy(pkt->wire, header, sizeof(header)); + size_t max_size = pkt->max_size; + knot_pkt_put_question(pkt, dname, lua_tointeger(L, 3), lua_tointeger(L, 4)); + // pkt->parsed = pkt->size; + pkt->max_size = max_size; + } + return 0; } -#warning TODO: record interfaces +static int pkt_begin(lua_State *L) +{ + knot_pkt_t *pkt = lua_touserdata(L, 1); + knot_pkt_begin(pkt, lua_tointeger(L, 2)); + return 0; +} + +static int pkt_add(lua_State *L) +{ + knot_pkt_t *pkt = lua_touserdata(L, 1); + if (lua_gettop(L) < 6) { + return 0; + } + /* Create empty RR */ + uint8_t dname[KNOT_DNAME_MAXLEN]; + knot_dname_from_str(dname, lua_tostring(L, 2), sizeof(dname)); + knot_rrset_t rr; + knot_rrset_init(&rr, knot_dname_copy(dname, &pkt->mm), lua_tointeger(L, 3), lua_tointeger(L, 4)); + /* Create RDATA */ + uint32_t ttl = lua_tointeger(L, 5); + size_t rdlen = 0; + const char *raw_data = lua_tolstring(L, 6, &rdlen); + knot_rdata_t rdata[knot_rdata_array_size(rdlen)]; + knot_rdata_init(rdata, rdlen, (const uint8_t *)raw_data, ttl); + knot_rdataset_add(&rr.rrs, rdata, &pkt->mm); + /* Append RR */ + int ret = knot_pkt_put(pkt, 0, &rr, KNOT_PF_FREE); + lua_pushboolean(L, ret == 0); + pkt->parsed = pkt->size; + return 1; +} static int pkt_meta_register(lua_State *L) { @@ -116,93 +192,97 @@ static int pkt_meta_register(lua_State *L) { "qtype", pkt_qtype }, { "qclass", pkt_qclass }, { "qname", pkt_qname }, + { "question", pkt_question }, + { "begin", pkt_begin }, + { "add", pkt_add }, { NULL, NULL } }; - META_REGISTER (L, wrap, META_PKT); + lua_register_meta(L, wrap, META_PKT); return 0; } /** * Query interface. + * @note Query is a full userdata, use double pointers. */ static int query_qtype(lua_State *L) { - struct kr_query *qry = lua_touserdata(L, 1); - lua_pushnumber(L, qry->stype); + struct kr_query **qry = lua_touserdata(L, 1); + lua_pushnumber(L, (*qry)->stype); return 1; } static int query_qclass(lua_State *L) { - struct kr_query *qry = lua_touserdata(L, 1); - lua_pushnumber(L, qry->sclass); + struct kr_query **qry = lua_touserdata(L, 1); + lua_pushnumber(L, (*qry)->sclass); return 1; } static int query_qname(lua_State *L) { - struct kr_query *qry = lua_touserdata(L, 1); - lua_pushdname(L, qry->sname); + struct kr_query **qry = lua_touserdata(L, 1); + lua_pushdname(L, (*qry)->sname); return 1; } -static int query_meta_register(lua_State *L) +static int query_flag(lua_State *L) { - static const luaL_Reg wrap[] = { - { "qtype", query_qtype }, - { "qclass", query_qclass }, - { "qname", query_qname }, - { NULL, NULL } - }; - META_REGISTER (L, wrap, META_QUERY); + struct kr_query **qry = lua_touserdata(L, 1); + if (lua_gettop(L) < 2 || !lua_isnumber(L, 2)) { + return 0; + } + (*qry)->flags |= lua_tointeger(L, 2); return 0; } -/** - * Resolution context interface. - */ +static int query_clear_flag(lua_State *L) +{ + struct kr_query **qry = lua_touserdata(L, 1); + if (lua_gettop(L) < 2 || !lua_isnumber(L, 2)) { + return 0; + } + (*qry)->flags &= ~lua_tointeger(L, 2); + return 0; +} -static int rplan_query(lua_State *L) +static int query_has_flag(lua_State *L) { - struct kr_rplan *rplan = lua_touserdata(L, 1); - lua_pushlightuserdata(L, kr_rplan_current(rplan)); - luaL_getmetatable(L, META_QUERY); - lua_setmetatable(L, -2); + struct kr_query **qry = lua_touserdata(L, 1); + if (lua_gettop(L) < 2 || !lua_isnumber(L, 2)) { + return 0; + } + lua_pushboolean(L, (*qry)->flags & lua_tointeger(L, 2)); return 1; } -static int rplan_meta_register(lua_State *L) +static int query_meta_register(lua_State *L) { static const luaL_Reg wrap[] = { - { "query", rplan_query }, - // { "pending", rplan_pending }, - // { "resolved", rplan_resolved }, + { "qtype", query_qtype }, + { "qclass", query_qclass }, + { "qname", query_qname }, + { "flag", query_flag }, + { "clear_flag", query_clear_flag }, + { "has_flag", query_has_flag }, { NULL, NULL } }; - META_REGISTER (L, wrap, META_RPLAN); + lua_register_meta (L, wrap, META_QUERY); return 0; } -#warning TODO: context interface, rplan - -#define WRAP_NUMBER(L, name, val) \ - lua_pushnumber((L), (val)); \ - lua_setfield((L), -2, (name)) - -#define WRAP_CONST(L, name, prefix...) \ - WRAP_NUMBER(L, #name, prefix ## name) - -#define WRAP_LUT(L, prefix, table) \ - lua_newtable(L); \ - for (lookup_table_t *elm = (table); elm->name; ++elm) { \ - WRAP_NUMBER((L), elm->name, elm->id); \ - } \ - lua_setfield((L), -2, (prefix)) +static int query_current(lua_State *L) +{ + struct kr_request *req = lua_touserdata(L, 1); + UDATA_CREATE(L, struct kr_query *, kr_rplan_current(&req->rplan), META_QUERY); + return 1; +} int lib_kres(lua_State *L) { static const luaL_Reg lib[] = { + { "query_current", query_current }, { NULL, NULL } }; /* Create module and register functions */ @@ -213,13 +293,17 @@ int lib_kres(lua_State *L) WRAP_CONST(L, PRODUCE, KNOT_STATE_); WRAP_CONST(L, DONE, KNOT_STATE_); WRAP_CONST(L, FAIL, KNOT_STATE_); + /* Register packet sections */ + WRAP_CONST(L, ANSWER, KNOT_); + WRAP_CONST(L, AUTHORITY, KNOT_); + WRAP_CONST(L, ADDITIONAL, KNOT_); /* Register RCODE, OPCODE */ WRAP_LUT(L, "rcode", knot_rcode_names); WRAP_LUT(L, "opcode", knot_opcode_names); WRAP_LUT(L, "wire", wire_flag_names); + WRAP_LUT(L, "query", query_flag_names); /* Register metatables */ pkt_meta_register(L); query_meta_register(L); - rplan_meta_register(L); return 1; } \ No newline at end of file diff --git a/daemon/ffimodule.c b/daemon/ffimodule.c index 26eed9674097a4422581dbfa44e27c4f1536366d..c920ffb22c221581201ee7e761147ed352a4a245 100644 --- a/daemon/ffimodule.c +++ b/daemon/ffimodule.c @@ -141,13 +141,6 @@ static int l_ffi_deinit(struct kr_module *module) } \ lua_pushnumber(L, ctx->state) -/** @internal Push rplan and metatable. */ -#define LAYER_PUSH_RPLAN(ctx) do { \ - struct kr_request *req = (ctx)->data; \ - lua_pushlightuserdata(L, &req->rplan); \ - set_metatable(L, META_RPLAN); \ -} while (0) - static int l_ffi_layer_begin(knot_layer_t *ctx, void *module_param) { ctx->data = module_param; @@ -159,21 +152,21 @@ static int l_ffi_layer_begin(knot_layer_t *ctx, void *module_param) static int l_ffi_layer_reset(knot_layer_t *ctx) { LAYER_FFI_CALL(ctx, "reset"); - LAYER_PUSH_RPLAN(ctx); + lua_pushlightuserdata(L, ctx->data); return l_ffi_call(L, 2); } static int l_ffi_layer_finish(knot_layer_t *ctx) { LAYER_FFI_CALL(ctx, "finish"); - LAYER_PUSH_RPLAN(ctx); + lua_pushlightuserdata(L, ctx->data); return l_ffi_call(L, 2); } static int l_ffi_layer_consume(knot_layer_t *ctx, knot_pkt_t *pkt) { LAYER_FFI_CALL(ctx, "consume"); - LAYER_PUSH_RPLAN(ctx); + lua_pushlightuserdata(L, ctx->data); lua_pushlightuserdata(L, pkt); set_metatable(L, META_PKT); return l_ffi_call(L, 3); @@ -182,7 +175,7 @@ static int l_ffi_layer_consume(knot_layer_t *ctx, knot_pkt_t *pkt) static int l_ffi_layer_produce(knot_layer_t *ctx, knot_pkt_t *pkt) { LAYER_FFI_CALL(ctx, "produce"); - LAYER_PUSH_RPLAN(ctx); + lua_pushlightuserdata(L, ctx->data); lua_pushlightuserdata(L, pkt); set_metatable(L, META_PKT); return l_ffi_call(L, 3); @@ -191,7 +184,7 @@ static int l_ffi_layer_produce(knot_layer_t *ctx, knot_pkt_t *pkt) static int l_ffi_layer_fail(knot_layer_t *ctx, knot_pkt_t *pkt) { LAYER_FFI_CALL(ctx, "fail"); - LAYER_PUSH_RPLAN(ctx); + lua_pushlightuserdata(L, ctx->data); lua_pushlightuserdata(L, pkt); set_metatable(L, META_PKT); return l_ffi_call(L, 3); @@ -237,7 +230,6 @@ static const knot_layer_api_t* l_ffi_layer(struct kr_module *module) #undef LAYER_REGISTER #undef LAYER_FFI_CALL -#undef LAYER_PUSH_RPLAN /** @internal Helper macro for function presence check. */ #define REGISTER_FFI_CALL(L, attr, name, cb) do { \ diff --git a/modules/block/block.lua b/modules/block/block.lua index facd35f3377bfe49b276b2f70278965ed91153d9..39e9470a288f8c2525d973c397200da09d4c1e58 100644 --- a/modules/block/block.lua +++ b/modules/block/block.lua @@ -47,7 +47,7 @@ local block = { -- @function Block requests which QNAME matches given zone list function block.in_zone(zone_list) return function(pkt, qry) - local qname = pkt:qname() + local qname = qry:qname() for _,zone in pairs(zone_list) do if qname:sub(-zone:len()) == zone then return block.DENY @@ -70,21 +70,25 @@ end -- @function Block layer implementation block.layer = { - produce = function(state, data, pkt) + produce = function(state, req, pkt) -- Only when a query isn't already answered if state ~= kres.CONSUME then return state end - -- @todo Interpret QUERY (as it has final name) -- Interpret packet in Lua and evaluate - local pkt = kres.packet(pkt) - local action = block:evaluate(pkt, nil) + local qry = kres.query_current(req) + local action = block:evaluate(pkt, qry) if action == block.DENY then + -- Answer full question + qry:flag(kres.query.NO_MINIMIZE) + pkt:question(qry:qname(), qry:qclass(), qry:qtype()) pkt:flag(kres.wire.QR) pkt:flag(kres.wire.AA) - pkt:flag(kres.wire.CD) + -- Write authority information pkt:rcode(kres.rcode.NXDOMAIN) - -- @todo add SOA record + pkt:begin(kres.AUTHORITY) + -- pkt:add(qry:qname(), qry:qclass(), 6, 900, + -- 'abcd\0efgh\0'..'\0\0\0\1'..'\0\0\0\0'..'\132\3\0\0'..'\132\3\0\0'..'\132\3\0\0') return kres.DONE elseif action == block.DROP then return kres.FAIL