]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
daemon/bindings: wip on query and packet bindings
authorMarek Vavruša <marek.vavrusa@nic.cz>
Tue, 16 Jun 2015 00:09:53 +0000 (02:09 +0200)
committerMarek Vavruša <marek.vavrusa@nic.cz>
Tue, 16 Jun 2015 00:09:53 +0000 (02:09 +0200)
daemon/bindings/kres.c
daemon/ffimodule.c
modules/block/block.lua

index f9d11c1625a4a9be9acea3f7071cb036f314e042..8ca2600295c2060521f050480299e331d373c048 100644 (file)
 #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
index 26eed9674097a4422581dbfa44e27c4f1536366d..c920ffb22c221581201ee7e761147ed352a4a245 100644 (file)
@@ -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 { \
index facd35f3377bfe49b276b2f70278965ed91153d9..39e9470a288f8c2525d973c397200da09d4c1e58 100644 (file)
@@ -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