summaryrefslogtreecommitdiff
path: root/lua
diff options
context:
space:
mode:
authorSam Roberts <vieuxtech@gmail.com>2011-02-03 12:42:05 -0800
committerSam Roberts <vieuxtech@gmail.com>2011-02-03 12:42:05 -0800
commit7d5d54e0422f74a9a1ad4ac879823a0739683595 (patch)
treee5e4fa37cf9c545fb2639fbeaf42dc2f526a0e1e /lua
parentdce44a9ca28c5863e7661c3534f8983851177e6e (diff)
downloadlibnet-7d5d54e0422f74a9a1ad4ac879823a0739683595.tar.gz
nfct and nfq support incremental setup and callbacks
Diffstat (limited to 'lua')
-rw-r--r--lua/nfct.c50
-rw-r--r--lua/nflua.h46
-rw-r--r--lua/nfq.c300
3 files changed, 349 insertions, 47 deletions
diff --git a/lua/nfct.c b/lua/nfct.c
index 21ccd3d..a49f729 100644
--- a/lua/nfct.c
+++ b/lua/nfct.c
@@ -34,6 +34,7 @@ I make full userdata out of one or both of them, thats what it has to be. Don't
confuse them, or you will segfault!
*/
+
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
@@ -55,15 +56,10 @@ confuse them, or you will segfault!
#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
-#define NFCT_REGID "wt.nfct"
+#include "nflua.h"
+#define NFCT_REGID "wt.nfct"
-static void push_error(lua_State* L)
-{
- lua_pushnil(L);
- lua_pushstring(L, strerror(errno));
- lua_pushinteger(L, errno);
-}
static struct nf_conntrack* check_ct(lua_State*L)
{
@@ -96,7 +92,7 @@ static const char* ctmsg_type_string(enum nf_conntrack_msg_type type)
/*-
-- cthandle = nfct.open(subsys, [subscription...])
+-- cthandle = nfct.open(subsys, [subscription...])
subsys is "track" or "expect"
@@ -166,7 +162,7 @@ static int open(lua_State *L)
}
/*-
-- nfct.close(cthandle)
+-- nfct.close(cthandle)
Close the conntrack handle, freeing its resources.
*/
@@ -178,7 +174,7 @@ static int gc(lua_State* L)
}
/*-
-- fd = nfct.fd(cthandle)
+-- fd = nfct.fd(cthandle)
Return the underlying fd used by the conntrack handle, useful for
selecting on.
@@ -231,7 +227,7 @@ static int cb(
/*-
-- cthandle = nfct.callback_register(cthandle, ctmsgtype)
+-- cthandle = nfct.callback_register(cthandle, ctmsgtype)
ctmsgtype is one of "new", "update", "destroy", or "all" (default is "all").
@@ -269,9 +265,10 @@ static int callback_register(lua_State* L)
}
/*-
-- cthandle = nfct.catch(cthandle, cbfn)
+-- cthandle = nfct.catch(cthandle, cbfn)
+-- verdict = cbfn(ctmsgtype, ct)
-cbfn is the callback function, and will be called as
+cbfn - the callback function, and will be called as
function cbfn(ctmsgtype, ct) ...
@@ -324,7 +321,7 @@ static int catch(lua_State* L)
}
/*-
-- nfct.loop(cthandle, ctmsgtype, cbfn)
+-- nfct.loop(cthandle, ctmsgtype, cbfn)
Equivalent to
@@ -332,8 +329,7 @@ Equivalent to
return nfct.catch(cthandle, cbfn)
Registering callbacks repeatedly is unnecessarily slow, so this is best used on
-blocking netlink sockets for scripts that do nothing but use the conntrack
-subsystem.
+blocking netlink sockets by scripts that use only the conntrack subsystem.
*/
static int loop(lua_State* L)
{
@@ -350,7 +346,7 @@ static int loop(lua_State* L)
}
/*-
-- ct = nfct.new()
+-- ct = nfct.new()
Create a new conntrack context (NOT a conntrack handle).
@@ -373,7 +369,7 @@ static int new(lua_State* L)
}
/*-
-- nfct.destroy(ct)
+-- nfct.destroy(ct)
Destroy a conntrack context.
@@ -389,7 +385,7 @@ static int destroy(lua_State* L)
}
/*-
-- ct = nfct.setobjopt(ct, option)
+-- ct = nfct.setobjopt(ct, option)
Sets an option on a conntrack context, option is one of:
"undo-snat",
@@ -561,9 +557,9 @@ static enum nf_conntrack_attr check_attr(lua_State* L)
}
/*-
-- value = nfct.get_attr_u8(ct, attr)
-- value = nfct.get_attr_u16(ct, attr)
-- value = nfct.get_attr_u32(ct, attr)
+-- value = nfct.get_attr_u8(ct, attr)
+-- value = nfct.get_attr_u16(ct, attr)
+-- value = nfct.get_attr_u32(ct, attr)
No error checking is done, values of zero will be returned for
attributes that aren't present, and undefined values will be returned
@@ -638,9 +634,9 @@ See enum nf_conntrack_attr (the aliases are not supported)
/* TODO this could have a much better API, but I've no time for this now. */
/*-
-- ct = nfct.set_attr_u8(ct, attr, value)
-- ct = nfct.set_attr_u16(ct, attr, value)
-- ct = nfct.set_attr_u32(ct, attr, value)
+-- ct = nfct.set_attr_u8(ct, attr, value)
+-- ct = nfct.set_attr_u16(ct, attr, value)
+-- ct = nfct.set_attr_u32(ct, attr, value)
No error checking is done, value will be cast to the necessary type, and who
knows what will happen for values that aren't actually of the correct type for
@@ -672,8 +668,8 @@ ATTR_UX(u16)
ATTR_UX(u32)
/*-
-- h = nfct.ntohs(n)
-- n = nfct.htons(h)
+-- h = nfct.ntohs(n)
+-- n = nfct.htons(h)
Convert a short between network and host byte order. No error or bounds
checking on the numbers is done.
diff --git a/lua/nflua.h b/lua/nflua.h
new file mode 100644
index 0000000..a831bf5
--- /dev/null
+++ b/lua/nflua.h
@@ -0,0 +1,46 @@
+/*
+Copyright (C) 2011 Wurldtech Security Technologies All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED.IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* Code common to the lua netfilter bindings. */
+
+static const char* nfemsg(int eno)
+{
+ switch(errno) {
+ case EAGAIN: return "timeout";
+ }
+ return strerror(eno);
+}
+static int push_error(lua_State* L)
+{
+ lua_pushnil(L);
+ lua_pushstring(L, nfemsg(errno));
+ lua_pushinteger(L, errno);
+
+ return 3;
+}
+
+
diff --git a/lua/nfq.c b/lua/nfq.c
index eeb42bd..9d27afc 100644
--- a/lua/nfq.c
+++ b/lua/nfq.c
@@ -1,5 +1,5 @@
/*
-Copyright (C) 2010 Wurldtech Security Technologies All rights reserved.
+Copyright (C) 2011 Wurldtech Security Technologies All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
@@ -25,7 +25,9 @@ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.
*/
-/*
+/*-
+** nfq - a binding to netfilter's queue subsystem
+
list rules:
@@ -42,7 +44,6 @@ sudo iptables -t filter -I INPUT 1 -p udp -j QUEUE
replace input rule 1:
sudo iptables -t filter -R INPUT 1 -p udp -j QUEUE
-
*/
@@ -66,8 +67,37 @@ sudo iptables -t filter -R INPUT 1 -p udp -j QUEUE
#include <libnetfilter_queue/libnetfilter_queue.h>
+#include "nflua.h"
+
#define NFQ_REGID "wt.nfq"
+static struct nfq_handle *check_handle(lua_State*L)
+{
+ struct nfq_handle* h = lua_touserdata(L, 1);
+
+ luaL_argcheck(L, h, 1, "handle not provided");
+
+ return h;
+}
+
+static struct nfq_q_handle *check_queue(lua_State*L)
+{
+ struct nfq_q_handle* q = lua_touserdata(L, 1);
+
+ luaL_argcheck(L, q, 1, "queue not provided");
+
+ return q;
+}
+
+static struct nfq_data *check_qdata(lua_State*L)
+{
+ struct nfq_data *qdata = lua_touserdata(L, 1);
+
+ luaL_argcheck(L, qdata, 1, "qdata not provided");
+
+ return qdata;
+}
+
static int cb(
struct nfq_q_handle *qh,
struct nfgenmsg *nfmsg,
@@ -75,6 +105,8 @@ static int cb(
void *data
)
{
+ /* TODO - should have an option "delay", to explicitly avoid
+ offering a verdict right away */
static const char* verdict_opt[] = {
"accept", "drop", NULL
};
@@ -113,16 +145,167 @@ static int cb(
}
}
+
+
+/*-
+-- handle = nfq.open()
+
+Return an nfqueue handle on success, or nil,emsg,errno on failure.
+*/
+static int open(lua_State* L)
+{
+ struct nfq_handle *h = nfq_open();
+
+ if(!h) {
+ return push_error(L);
+ }
+
+ lua_pushlightuserdata(L, h);
+
+ return 1;
+}
+
+/*-
+-- nfq.close(handle)
+
+Close the handle, freeing its resources.
+*/
+static int gc(lua_State* L)
+{
+ struct nfq_handle* h = check_handle(L);
+ nfq_close(h);
+ return 0;
+}
+
+/*-
+- fd = nfq.fd(handle)
+
+Return the underlying fd used by the handle, useful for
+selecting on.
+*/
+static int fd(lua_State* L)
+{
+ struct nfq_handle* h = check_handle(L);
+ lua_pushinteger(L, nfq_fd(h));
+ return 1;
+}
+
+static int check_pf(lua_State* L, int narg)
+{
+ /* TODO ... other values from /usr/include/bits/socket.h */
+ static const char* pf_opts[] = {
+ "inet",
+ "inet6",
+ NULL
+ };
+ static int pf_vals[] = {
+ PF_INET,
+ PF_INET6,
+ };
+ int pf_opt = luaL_checkoption(L, narg, NULL, pf_opts);
+ int pf_val = pf_vals[pf_opt];
+
+ return pf_val;
+}
+
+/*-
+-- handle = nfq.unbind_pf(handle, family)
+
+Protocol family is one of "inet", "inet6".
+
+Return is handle on success and nil,emsg,errno on failure.
+*/
+static int unbind_pf(lua_State* L)
+{
+ struct nfq_handle* h = check_handle(L);
+ int pf = check_pf(L, 2);
+
+ if (nfq_unbind_pf(h, pf) < 0) {
+ return push_error(L);
+ }
+ return 1;
+}
+
+/*-
+-- handle = nfq.bind_pf(handle, family)
+
+Protocol family is one of "inet", "inet6".
+
+Note that sample code seems to always unbind before binding, I've no idea why,
+and there is no indication of whether its possible to bind to multiple address
+families.
+
+Return is handle on success and nil,emsg,errno on failure.
+*/
+static int bind_pf(lua_State* L)
+{
+ struct nfq_handle* h = check_handle(L);
+ int pf = check_pf(L, 2);
+
+ if (nfq_bind_pf(h, pf) < 0) {
+ return push_error(L);
+ }
+ return 1;
+}
+
/*-
-- nfq.loop(cb, copy)
+-- handle = nfq.catch(handle, cbfn)
+-- verdict = cbfn(qdata)
-cb - a function called for every queued packet, it returns
-"accept" or "drop" meaning to do that to the packet. For
-no return value, the default is "accept". If it returns a second
-argument, it must be a string, and replaces the current
-packet.
+cbfn - a function called for every queued packet with one argument, qdata. It
+returns "accept" or "drop" meaning to do that to the packet. For no return
+value, the default is "accept". If it returns a second argument, it must be a
+string, and replaces the current packet.
+
+Return handle on success and nil,emsg,errno on failure.
+*/
+/* TODO we allow only one cbfn for all the queues, which differs from
+ the underlying library which allows a cbfn per queue. To do that I'd have to
+ build a table to map the queues to their lua cbfns, which is possible, but I
+ don't have the time for right now.
+ */
+static int catch(lua_State *L)
+{
+ struct nfq_handle* h = check_handle(L);
+ int nffd = nfq_fd(h);
+ char buf[4096] __attribute__ ((aligned));
+ ssize_t bufsz;
+
+ while ((bufsz = recv(nffd, buf, sizeof(buf), 0)) > 0) {
+ if(nfq_handle_packet(h, buf, bufsz) < 0) {
+ return push_error(L);
+ }
+ }
+
+ /* If we get here bufsz is <= 0, so either the netlink socket
+ closed (possible?), would block, or some other error occurred. */
+ if(bufsz == 0) {
+ lua_pushnil(L);
+ lua_pushstring(L, "closed");
+ return 2;
+ }
+
+ return push_error(L);
+}
+
+/*-
+-- loop = nfq.loop(cb, copy)
+
+A one shot way to catch on queue zero, the equivalent of:
+
+ h = nfq.open()
+ nfq.unbind_pf(h, "inet")
+ nfq.bind_pf(h, "inet")
+ q = nfq.create_queue(h, 0)
+ nfq.set_mode(q, copy, 0xffff)
+ ... = nfq.catch(h, cb)
+ nfq.destroy_queue(q)
+ nfq.close(h)
+ return ...
+
+DEPRECATED - don't use it in new code, it will be deleted as soon as
+the existing users of it have been updated.
-copy - "none", "meta", "packet", default to "packet"
*/
static int loop(lua_State *L)
{
@@ -136,7 +319,7 @@ static int loop(lua_State *L)
int af = AF_INET; /* Could be an argument, if we ever did non-INET. */
struct nfq_handle *h = NULL;
struct nfq_q_handle *qh = NULL;
- int fd = -1;
+ int nlfd = -1;
int nreturn = 0;
char buf[4096] __attribute__ ((aligned));
ssize_t recvsz;
@@ -160,9 +343,9 @@ static int loop(lua_State *L)
if (nfq_set_mode(qh, copy, 0xffff /* larger than an ethernet frame */) < 0)
goto err;
- fd = nfq_fd(h);
+ nlfd = nfq_fd(h);
- while ((recvsz = recv(fd, buf, sizeof(buf), 0)) >= 0) {
+ while ((recvsz = recv(nlfd, buf, sizeof(buf), 0)) >= 0) {
nfq_handle_packet(h, buf, recvsz);
}
@@ -185,25 +368,87 @@ cleanup:
nfq_close(h);
return nreturn;
+
+}
+
+
+/*-
+-- queue = nfq.create_queue(handle, queuenum)
+
+queuenum is number of the queue to bind to.
+
+Return a queue on success, or nil,emsg,errno on failure.
+*/
+static int create_queue(lua_State* L)
+{
+ struct nfq_handle* h = check_handle(L);
+ int num = luaL_checkint(L, 2);
+ struct nfq_q_handle *q = nfq_create_queue(h, num, cb, L);
+
+ if(!q) {
+ return push_error(L);
+ }
+
+ lua_pushlightuserdata(L, q);
+
+ return 1;
}
-struct nfq_data *checkudata(lua_State*L)
+/*-
+-- nfq.destroy_queue(queue)
+
+Close the queue, freeing its resources.
+*/
+static int destroy_queue(lua_State* L)
{
- struct nfq_data *nfqdata = lua_touserdata(L, 1);
+ struct nfq_q_handle* q = check_queue(L);
+ nfq_destroy_queue(q);
+ return 0;
+}
+
+/*-
+-- queue = nfq.set_mode(queue, copy, range)
+
+queue is a queue handle returned by nfq.create_queue().
- luaL_argcheck(L, nfqdata, 1, "nfqdata not provided");
+copy is one of "none" (a no-op, don't use it), "meta" (copy just packet
+metadata), or "packet" (copy the full packet) (default is currently "packet").
- return nfqdata;
+range is the size of the packet to copy, and is optional (it defaults to
+0xffff, larger than any ethernet packet can be, and larger than any link
+layer packet I'm aware of).
+
+Returns the queue on success and nil,emsg,errno on failure.
+*/
+static int set_mode(lua_State* L)
+{
+ static const char* copy_opts[] = {
+ "none", "meta", "packet", NULL
+ };
+ static int copy_vals[] = {
+ NFQNL_COPY_NONE, NFQNL_COPY_META, NFQNL_COPY_PACKET
+ };
+ struct nfq_q_handle *q = check_queue(L);
+ int copy_opt = luaL_checkoption(L, 2, "packet", copy_opts);
+ int copy_val = copy_vals[copy_opt];
+ int range = luaL_optint(L, 3, 0xffff);
+
+ if (nfq_set_mode(q, copy_val, range) < 0) {
+ return push_error(L);
+ }
+
+ return 1;
}
+/* FIXME - need to reimplement loop... for backwards compatibility! */
/*-
-str = nfq.get_payload(cbctx)
+-- str = nfq.get_payload(cbctx)
-str is the IP payload, it has been stripped of link-layer headers!
+str is the IP payload, it has been stripped of link-layer headers.
*/
static int get_payload(lua_State* L)
{
- struct nfq_data *nfqdata = checkudata(L);
+ struct nfq_data *nfqdata = check_qdata(L);
char* data = NULL;
int datasz = nfq_get_payload(nfqdata, &data);
luaL_argcheck(L, datasz >= 0, 1, "nfqdata not available");
@@ -215,7 +460,22 @@ static int get_payload(lua_State* L)
static const luaL_reg nfq[] =
{
+ /* return or operate on handle */
+ {"open", open},
+ {"close", gc},
+ {"fd", fd},
+ {"unbind_pf", unbind_pf},
+ {"bind_pf", bind_pf},
+ {"catch", catch},
{"loop", loop},
+
+ /* return or operate on a queue */
+ {"create_queue", create_queue},
+ {"destroy_queue", destroy_queue},
+ {"set_mode", set_mode},
+
+
+
{"get_payload", get_payload},
{NULL, NULL}
};