Skip to content

Commit e519719

Browse files
committed
Extended to support real-world use cases.
Features include nonblocking, attributes in presentation format and host numeric order, and some general bug-fixing. order
1 parent 0781c34 commit e519719

File tree

3 files changed

+191
-78
lines changed

3 files changed

+191
-78
lines changed

nfct.c

Lines changed: 143 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -34,49 +34,29 @@ I make full userdata out of one or both of them, thats what it has to be. Don't
3434
confuse them, or you will segfault!
3535
*/
3636

37-
38-
#include "lua.h"
39-
#include "lauxlib.h"
40-
#include "lualib.h"
41-
42-
#include <assert.h>
43-
#include <errno.h>
44-
#include <stdio.h>
45-
#include <stdlib.h>
46-
#include <string.h>
47-
#include <unistd.h>
48-
49-
#include <netinet/in.h>
50-
#include <netinet/ip.h>
51-
#include <netinet/tcp.h>
52-
#include <netinet/udp.h>
53-
54-
#include <linux/netfilter.h>
55-
#include <linux/types.h>
37+
#include "nflua.h"
5638

5739
#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
5840

59-
#include "nflua.h"
60-
6141
#define NFCT_REGID "wt.nfct"
6242

6343

64-
static struct nf_conntrack* check_ct(lua_State*L)
44+
static struct nfct_handle* check_cthandle(lua_State*L)
6545
{
66-
struct nf_conntrack* ct = lua_touserdata(L, 1);
46+
struct nfct_handle* cth = lua_touserdata(L, 1);
6747

68-
luaL_argcheck(L, ct, 1, "conntrack not provided");
48+
luaL_argcheck(L, cth, 1, "conntrack handle not provided");
6949

70-
return ct;
50+
return cth;
7151
}
7252

73-
static struct nfct_handle* check_cthandle(lua_State*L)
53+
static struct nf_conntrack* check_ct(lua_State*L)
7454
{
75-
struct nfct_handle* cth = lua_touserdata(L, 1);
55+
struct nf_conntrack* ct = lua_touserdata(L, 1);
7656

77-
luaL_argcheck(L, cth, 1, "conntrack handle not provided");
57+
luaL_argcheck(L, ct, 1, "conntrack not provided");
7858

79-
return cth;
59+
return ct;
8060
}
8161

8262
static const char* ctmsg_type_string(enum nf_conntrack_msg_type type)
@@ -104,7 +84,7 @@ Returns a conntrack handle on success, or nil,emsg,errno on failure.
10484
There is no garbage collection, nfct.fini() must be called on the handle to
10585
release it's resources.
10686
*/
107-
static int open(lua_State *L)
87+
static int hopen(lua_State *L)
10888
{
10989
static const char* subsys_opts[] = {
11090
"track", "expect", NULL
@@ -145,7 +125,7 @@ static int open(lua_State *L)
145125
assert(subsys_opt == 0 || subsys_opt == 1);
146126

147127
for(narg = 2; narg <= lua_gettop(L); narg++) {
148-
int subscription_opt = luaL_checkoption(L, 1, "none", subscription_opts);
128+
int subscription_opt = luaL_checkoption(L, narg, "none", subscription_opts);
149129
subscription_val |= subscription_vals[subsys_opt][subscription_opt];
150130
}
151131

@@ -186,6 +166,18 @@ static int fd(lua_State* L)
186166
return 1;
187167
}
188168

169+
/*-
170+
-- cthandle = nfct.setblocking(cthandle, [blocking])
171+
172+
blocking is true to set blocking, and false to set non-blocking (default is false)
173+
174+
Return is cthandle on success, or nil,emsg,errno on failure.
175+
*/
176+
static int setblocking(lua_State* L)
177+
{
178+
return nfsetblocking(L, nfct_fd(check_cthandle(L)));
179+
}
180+
189181
static int cb(
190182
enum nf_conntrack_msg_type type,
191183
struct nf_conntrack *ct,
@@ -559,10 +551,20 @@ static enum nf_conntrack_attr check_attr(lua_State* L)
559551
return attr_val;
560552
}
561553

554+
/*
555+
TODO
556+
get_attr_ip() -- ip in presentation format
557+
get_attr_port() -- port as a number (cvt to host byte order)
558+
get_attr_l3proto() -- protocol as string (or number if unrecognized)
559+
get_attr_l4proto() -- "" ""
560+
*/
562561
/*-
563562
-- value = nfct.get_attr_u8(ct, attr)
564563
-- value = nfct.get_attr_u16(ct, attr)
565564
-- value = nfct.get_attr_u32(ct, attr)
565+
-- value = nfct.get_attr_n16(ct, attr)
566+
-- value = nfct.get_attr_n32(ct, attr)
567+
-- value = nfct.get_attr_port(ct, attr)
566568
567569
No error checking is done, values of zero will be returned for
568570
attributes that aren't present, and undefined values will be returned
@@ -571,6 +573,11 @@ the attribute value may be in network byte order.
571573
572574
ct is a conntrack context (NOT a conntrack handle, do not mix the two).
573575
576+
get_attr_n#() is like the "u" version, but it converts the number from network
577+
to host byte order.
578+
579+
get_attr_port() is an alias for get_attr_n16(), since TCP and UDP ports are n16.
580+
574581
attr is one of:
575582
"orig-ipv4-src", -- u32 bits
576583
"orig-ipv4-dst", -- u32 bits
@@ -634,24 +641,45 @@ attr is one of:
634641
635642
See enum nf_conntrack_attr (the aliases are not supported)
636643
*/
637-
/* TODO this could have a much better API, but I've no time for this now. */
638-
644+
/* FIXME - I really need the aliases back in, they aren't just for backwards
645+
* compatibility, they are the best names to use, usually.
646+
*/
639647
/*-
640648
-- ct = nfct.set_attr_u8(ct, attr, value)
641649
-- ct = nfct.set_attr_u16(ct, attr, value)
642650
-- ct = nfct.set_attr_u32(ct, attr, value)
651+
-- ct = nfct.set_attr_n16(ct, attr, value)
652+
-- ct = nfct.set_attr_n32(ct, attr, value)
643653
644654
No error checking is done, value will be cast to the necessary type, and who
645655
knows what will happen for values that aren't actually of the correct type for
646656
the attribute. The attribute value may need to be in network byte order.
647657
648658
ct is a conntrack context (NOT a conntrack handle, do not mix the two).
649659
650-
See nfct.get_attr_*() for the supported attr names.
660+
See nfct.get_attr_*() for the supported attr names and types.
651661
652662
Returns the conntrack conntext, so calls can be chained.
653663
*/
654664

665+
/* Pretent nfct implements these, so I can construct setters/getters using my macro. */
666+
static u_int16_t nfct_get_attr_n16(struct nf_conntrack* ct, enum nf_conntrack_attr attr)
667+
{
668+
return ntohs(nfct_get_attr_u16(ct, attr));
669+
}
670+
static u_int32_t nfct_get_attr_n32(struct nf_conntrack* ct, enum nf_conntrack_attr attr)
671+
{
672+
return ntohl(nfct_get_attr_u32(ct, attr));
673+
}
674+
static void nfct_set_attr_n16(struct nf_conntrack* ct, enum nf_conntrack_attr attr, u_int16_t value)
675+
{
676+
nfct_set_attr_u16(ct, attr, htons(value));
677+
}
678+
static void nfct_set_attr_n32(struct nf_conntrack* ct, enum nf_conntrack_attr attr, u_int32_t value)
679+
{
680+
nfct_set_attr_u32(ct, attr, htonl(value));
681+
}
682+
655683
/*
656684
static int get_attr_u8(lua_State* L)
657685
{
@@ -664,11 +692,79 @@ static int get_attr_u8(lua_State* L)
664692
static int get_attr_##ux(lua_State* L) \
665693
{ lua_pushinteger(L, nfct_get_attr_##ux(check_ct(L), check_attr(L))); return 1; } \
666694
static int set_attr_##ux(lua_State* L) \
667-
{ nfct_set_attr_##ux(check_ct(L), check_attr(L), luaL_checklong(L,3)); return 1; }
695+
{ nfct_set_attr_##ux(check_ct(L), check_attr(L), luaL_checklong(L,3)); lua_settop(L, 1); return 1; }
696+
697+
/* should I add checks for existence of the attribute? I doubt performance is
698+
* an issue, so why not return
699+
* nil and emsg when attr isn't present
700+
*/
668701

669702
ATTR_UX(u8)
670703
ATTR_UX(u16)
671704
ATTR_UX(u32)
705+
ATTR_UX(n16)
706+
ATTR_UX(n32)
707+
708+
/*-
709+
-- value = nfct.get_attr_ipv4(ct, attr)
710+
-- value = nfct.get_attr_ipv6(ct, attr)
711+
-- ct = nfct.set_attr_ipv4(ct, attr, value)
712+
713+
Get an attribute as a string, the internet address in presentation format.
714+
715+
See inet_ntop(3) for more information.
716+
717+
Return is the presentation address, or nil,emsg,errno on failure.
718+
*/
719+
static int get_attr_ipvx(lua_State* L, int af, const void* src)
720+
{
721+
char dst[INET6_ADDRSTRLEN];
722+
const char* p = inet_ntop(af, src, dst, sizeof(dst));
723+
if(!p) {
724+
return push_error(L);
725+
}
726+
lua_pushstring(L, p);
727+
return 1;
728+
}
729+
730+
static int get_attr_ipv4(lua_State* L)
731+
{
732+
return get_attr_ipvx(L,
733+
AF_INET,
734+
nfct_get_attr(check_ct(L), check_attr(L)));
735+
}
736+
737+
static int get_attr_ipv6(lua_State* L)
738+
{
739+
return get_attr_ipvx(L,
740+
AF_INET6,
741+
nfct_get_attr(check_ct(L), check_attr(L)));
742+
}
743+
744+
static int set_attr_ipvx(lua_State* L, int af)
745+
{
746+
unsigned char buf[sizeof(struct in6_addr)];
747+
748+
if(!inet_pton(af, luaL_checkstring(L, 3), buf)) {
749+
return push_error(L);
750+
}
751+
752+
nfct_set_attr(check_ct(L), check_attr(L), buf);
753+
754+
lua_settop(L, 1);
755+
756+
return 1;
757+
}
758+
759+
static int set_attr_ipv4(lua_State* L)
760+
{
761+
return set_attr_ipvx(L, AF_INET);
762+
}
763+
764+
static int set_attr_ipv6(lua_State* L)
765+
{
766+
return set_attr_ipvx(L, AF_INET6);
767+
}
672768

673769
/*-
674770
-- h = nfct.ntohs(n)
@@ -692,9 +788,10 @@ static int cthtons(lua_State* L)
692788
static const luaL_reg nfct[] =
693789
{
694790
/* return or operate on cthandle */
695-
{"open", open},
791+
{"open", hopen},
696792
{"close", gc},
697793
{"fd", fd},
794+
{"setblocking", setblocking},
698795
{"callback_register", callback_register},
699796
{"catch", catch},
700797
{"loop", loop},
@@ -706,9 +803,19 @@ static const luaL_reg nfct[] =
706803
{"get_attr_u8", get_attr_u8},
707804
{"get_attr_u16", get_attr_u16},
708805
{"get_attr_u32", get_attr_u32},
806+
{"get_attr_n16", get_attr_n16},
807+
{"get_attr_n32", get_attr_n32},
808+
{"get_attr_ipv4", get_attr_ipv4},
809+
{"get_attr_ipv6", get_attr_ipv6},
810+
{"get_attr_port", get_attr_n16},
709811
{"set_attr_u8", set_attr_u8},
710812
{"set_attr_u16", set_attr_u16},
711813
{"set_attr_u32", set_attr_u32},
814+
{"set_attr_n16", set_attr_n16},
815+
{"set_attr_n32", set_attr_n32},
816+
{"set_attr_ipv4", set_attr_ipv4},
817+
{"set_attr_ipv6", set_attr_ipv6},
818+
{"set_attr_port", set_attr_n16},
712819

713820
/* attr value conversion */
714821
{"ntohs", ctntohs},

nflua.h

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,28 @@ THE POSSIBILITY OF SUCH DAMAGE.
2727

2828
/* Code common to the lua netfilter bindings. */
2929

30+
#include "lua.h"
31+
#include "lauxlib.h"
32+
#include "lualib.h"
33+
34+
#include <assert.h>
35+
#include <errno.h>
36+
#include <fcntl.h>
37+
#include <stdio.h>
38+
#include <stdlib.h>
39+
#include <string.h>
40+
#include <unistd.h>
41+
42+
#include <arpa/inet.h>
43+
44+
#include <netinet/in.h>
45+
#include <netinet/ip.h>
46+
#include <netinet/tcp.h>
47+
#include <netinet/udp.h>
48+
49+
#include <linux/netfilter.h>
50+
#include <linux/types.h>
51+
3052
static const char* nfemsg(int eno)
3153
{
3254
switch(errno) {
@@ -43,4 +65,26 @@ static int push_error(lua_State* L)
4365
return 3;
4466
}
4567

68+
static int nfsetblocking(lua_State* L, int fd)
69+
{
70+
int set = lua_toboolean(L, 2);
71+
long flags = fcntl(fd, F_GETFL, 0);
72+
if(flags < 0) {
73+
return push_error(L);
74+
}
75+
/* to SET blocking, we CLEAR O_NONBLOCK */
76+
if(set) {
77+
flags &= ~O_NONBLOCK;
78+
} else {
79+
flags |= O_NONBLOCK;
80+
81+
}
82+
if(fcntl(fd, F_SETFL, flags) < 0) {
83+
return push_error(L);
84+
}
85+
86+
lua_settop(L, 1);
87+
88+
return 1;
89+
}
4690

0 commit comments

Comments
 (0)