Skip to content

Make netfilter dynamically loadable. #6

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 23 additions & 20 deletions netfilter.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,8 @@ The libnetfilter_queue library is part of the http://netfilter.org/projects/libn
package netfilter

/*
#cgo pkg-config: libnetfilter_queue
#cgo CFLAGS: -Wall -Werror -I/usr/include
#cgo LDFLAGS: -L/usr/lib64/
#cgo LDFLAGS: -L/usr/lib64/ -ldl

#include "netfilter.h"
*/
Expand Down Expand Up @@ -57,8 +56,8 @@ func (p *NFPacket) SetRequeueVerdict(newQueueId uint16) {
}

type NFQueue struct {
h *[0]byte
qh *[0]byte
h *C.struct_nfq_handle
qh *C.struct_nfq_q_handle
fd C.int
packets chan NFPacket
}
Expand All @@ -85,39 +84,43 @@ func NewNFQueue(queueId uint16, maxPacketsInQueue uint32, packetSize uint32) (*N
var err error
var ret C.int

if nfq.h, err = C.nfq_open(); err != nil {
if ret = C.InitNF(); ret != 0 {
return nil, fmt.Errorf("Unable to initialize Netfilter bindings")
}

if nfq.h, err = C.nfq_open_rdr(); err != nil {
return nil, fmt.Errorf("Error opening NFQueue handle: %v\n", err)
}

if ret, err = C.nfq_unbind_pf(nfq.h, AF_INET); err != nil || ret < 0 {
if ret, err = C.nfq_unbind_pf_rdr(nfq.h, AF_INET); err != nil || ret < 0 {
return nil, fmt.Errorf("Error unbinding existing NFQ handler from AF_INET protocol family: %v\n", err)
}

if ret, err := C.nfq_bind_pf(nfq.h, AF_INET); err != nil || ret < 0 {
if ret, err := C.nfq_bind_pf_rdr(nfq.h, AF_INET); err != nil || ret < 0 {
return nil, fmt.Errorf("Error binding to AF_INET protocol family: %v\n", err)
}

nfq.packets = make(chan NFPacket)
if nfq.qh, err = C.CreateQueue(nfq.h, C.u_int16_t(queueId), unsafe.Pointer(&nfq.packets)); err != nil || nfq.qh == nil {
C.nfq_close(nfq.h)
C.nfq_close_rdr(nfq.h)
return nil, fmt.Errorf("Error binding to queue: %v\n", err)
}

if ret, err = C.nfq_set_queue_maxlen(nfq.qh, C.u_int32_t(maxPacketsInQueue)); err != nil || ret < 0 {
C.nfq_destroy_queue(nfq.qh)
C.nfq_close(nfq.h)
if ret, err = C.nfq_set_queue_maxlen_rdr(nfq.qh, C.u_int32_t(maxPacketsInQueue)); err != nil || ret < 0 {
C.nfq_destroy_queue_rdr(nfq.qh)
C.nfq_close_rdr(nfq.h)
return nil, fmt.Errorf("Unable to set max packets in queue: %v\n", err)
}

if C.nfq_set_mode(nfq.qh, C.u_int8_t(2), C.uint(packetSize)) < 0 {
C.nfq_destroy_queue(nfq.qh)
C.nfq_close(nfq.h)
if C.nfq_set_mode_rdr(nfq.qh, C.u_int8_t(2), C.u_int32_t(packetSize)) < 0 {
C.nfq_destroy_queue_rdr(nfq.qh)
C.nfq_close_rdr(nfq.h)
return nil, fmt.Errorf("Unable to set packets copy mode: %v\n", err)
}

if nfq.fd, err = C.nfq_fd(nfq.h); err != nil {
C.nfq_destroy_queue(nfq.qh)
C.nfq_close(nfq.h)
if nfq.fd, err = C.nfq_fd_rdr(nfq.h); err != nil {
C.nfq_destroy_queue_rdr(nfq.qh)
C.nfq_close_rdr(nfq.h)
return nil, fmt.Errorf("Unable to get queue file-descriptor. %v", err)
}

Expand All @@ -128,8 +131,8 @@ func NewNFQueue(queueId uint16, maxPacketsInQueue uint32, packetSize uint32) (*N

//Unbind and close the queue
func (nfq *NFQueue) Close() {
C.nfq_destroy_queue(nfq.qh)
C.nfq_close(nfq.h)
C.nfq_destroy_queue_rdr(nfq.qh)
C.nfq_close_rdr(nfq.h)
}

//Get the channel for packets
Expand All @@ -144,7 +147,7 @@ func (nfq *NFQueue) run() {
//export go_callback
func go_callback(queueId C.int, data *C.uchar, len C.int, cb *chan NFPacket) Verdict {
xdata := C.GoBytes(unsafe.Pointer(data), len)
packet := gopacket.NewPacket(xdata, layers.LayerTypeIPv4, gopacket.DecodeOptions{true, true})
packet := gopacket.NewPacket(xdata, layers.LayerTypeIPv4, gopacket.DecodeOptions{Lazy:true, NoCopy:true})
p := NFPacket{verdictChannel: make(chan Verdict), Packet: packet}
select {
case (*cb) <- p:
Expand Down
11 changes: 6 additions & 5 deletions netfilter.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <linux/socket.h>
#include <linux/netfilter.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
#include "netfilter_rdr.h"

extern uint go_callback(int id, unsigned char* data, int len, void** cb_func);

Expand All @@ -36,18 +37,18 @@ static int nf_callback(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct n
int ret = 0;
int verdict = 0;

ph = nfq_get_msg_packet_hdr(nfa);
ph = nfq_get_msg_packet_hdr_rdr(nfa);
id = ntohl(ph->packet_id);

ret = nfq_get_payload(nfa, &buffer);
ret = nfq_get_payload_rdr(nfa, (char**)&buffer);
verdict = go_callback(id, buffer, ret, cb_func);

return nfq_set_verdict(qh, id, verdict, 0, NULL);
return nfq_set_verdict_rdr(qh, id, verdict, 0, NULL);
}

static inline struct nfq_q_handle* CreateQueue(struct nfq_handle *h, u_int16_t queue, void* cb_func)
{
return nfq_create_queue(h, queue, &nf_callback, cb_func);
return nfq_create_queue_rdr(h, queue, &nf_callback, cb_func);
}

static inline void Run(struct nfq_handle *h, int fd)
Expand All @@ -56,7 +57,7 @@ static inline void Run(struct nfq_handle *h, int fd)
int rv;

while ((rv = recv(fd, buf, sizeof(buf), 0)) && rv >= 0) {
nfq_handle_packet(h, buf, rv);
nfq_handle_packet_rdr(h, buf, rv);
}
}

Expand Down
244 changes: 244 additions & 0 deletions netfilter_rdr.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
#ifndef __NETFILTER_RDR__
#define __NETFILTER_RDR__

#include <dlfcn.h>
#include <assert.h>

static void *nfHandle = NULL;

static inline int InitNF(void)
{
nfHandle = dlopen("libnetfilter_queue.so", RTLD_NOW);
if (!nfHandle) {
return -1;
}

return 0;
}

static inline struct nfqnl_msg_packet_hdr* nfq_get_msg_packet_hdr_rdr(struct nfq_data* nfad)
{
assert(nfHandle);

static struct nfqnl_msg_packet_hdr* (*nfq_get_msg_packet_hdr_sym)(struct nfq_data*) = NULL;

if (!nfq_get_msg_packet_hdr_sym) {
nfq_get_msg_packet_hdr_sym = dlsym(nfHandle, "nfq_get_msg_packet_hdr");
assert(nfq_get_msg_packet_hdr_sym);
}

return nfq_get_msg_packet_hdr_sym(nfad);
}

static inline u_int32_t nfq_get_indev_rdr(struct nfq_data* nfad)
{
assert(nfHandle);

static u_int32_t (*nfq_get_indev_sym)(struct nfq_data*) = NULL;

if (!nfq_get_indev_sym) {
nfq_get_indev_sym = dlsym(nfHandle, "nfq_get_indev");
assert(nfq_get_indev_sym);
}

return nfq_get_indev_sym(nfad);
}

static inline int nfq_get_timestamp_rdr(struct nfq_data* nfad, struct timeval* tv)
{
assert(nfHandle);

static int (*nfq_get_timestamp_sym)(struct nfq_data*, struct timeval*) = NULL;

if (!nfq_get_timestamp_sym) {
nfq_get_timestamp_sym = dlsym(nfHandle, "nfq_get_timestamp");
assert(nfq_get_timestamp_sym);
}

return nfq_get_timestamp_sym(nfad, tv);
}

static inline int nfq_get_payload_rdr(struct nfq_data* nfad, char** data)
{
assert(nfHandle);

static int (*nfq_get_payload_sym)(struct nfq_data*, char**) = NULL;

if (!nfq_get_payload_sym) {
nfq_get_payload_sym = dlsym(nfHandle, "nfq_get_payload");
assert(nfq_get_payload_sym);
}

return nfq_get_payload_sym(nfad, data);
}

static inline struct nfq_q_handle* nfq_create_queue_rdr(struct nfq_handle* h, u_int16_t num, nfq_callback* cb, void* data)
{
assert(nfHandle);

static struct nfq_q_handle* (*nfq_create_queue_sym)(struct nfq_handle*, u_int16_t, nfq_callback*, void*) = NULL;

if (!nfq_create_queue_sym) {
nfq_create_queue_sym = dlsym(nfHandle, "nfq_create_queue");
assert(nfq_create_queue_sym);
}

return nfq_create_queue_sym(h, num, cb, data);
}

static inline int nfq_handle_packet_rdr(struct nfq_handle* h, char* buf, int len)
{
assert(nfHandle);

static int (*nfq_handle_packet_sym)(struct nfq_handle*, char*, int) = NULL;

if (!nfq_handle_packet_sym) {
nfq_handle_packet_sym = dlsym(nfHandle, "nfq_handle_packet");
assert(nfq_handle_packet_sym);
}

return nfq_handle_packet_sym(h, buf, len);
}

static inline int nfq_bind_pf_rdr(struct nfq_handle* h, u_int16_t pf)
{
assert(nfHandle);

static int (*nfq_bind_pf_sym)(struct nfq_handle*, u_int16_t) = NULL;

if (!nfq_bind_pf_sym) {
nfq_bind_pf_sym = dlsym(nfHandle, "nfq_bind_pf");
assert(nfq_bind_pf_sym);
}

return nfq_bind_pf_sym(h, pf);
}

static inline int nfq_fd_rdr(struct nfq_handle* h)
{
assert(nfHandle);

static int (*nfq_fd_sym)(struct nfq_handle*) = NULL;

if (!nfq_fd_sym) {
nfq_fd_sym = dlsym(nfHandle, "nfq_fd");
assert(nfq_fd_sym);
}

return nfq_fd_sym(h);
}

static inline struct nfq_handle* nfq_open_rdr(void)
{
assert(nfHandle);

static struct nfq_handle* (*nfq_open_sym)(void) = NULL;

if (!nfq_open_sym) {
nfq_open_sym = dlsym(nfHandle, "nfq_open");
assert(nfq_open_sym);
}

return nfq_open_sym();
}

static inline int nfq_set_queue_maxlen_rdr(struct nfq_q_handle* qh, u_int32_t queuelen)
{
assert(nfHandle);

static int (*nfq_set_queue_maxlen_sym)(struct nfq_q_handle*, u_int32_t) = NULL;

if (!nfq_set_queue_maxlen_sym) {
nfq_set_queue_maxlen_sym = dlsym(nfHandle, "nfq_set_queue_maxlen");
assert(nfq_set_queue_maxlen_sym);
}

return nfq_set_queue_maxlen_sym(qh, queuelen);
}

static inline int nfq_unbind_pf_rdr(struct nfq_handle* h, u_int16_t pf)
{
assert(nfHandle);

static int (*nfq_unbind_pf_sym)(struct nfq_handle*, u_int16_t) = NULL;

if (!nfq_unbind_pf_sym) {
nfq_unbind_pf_sym = dlsym(nfHandle, "nfq_unbind_pf");
assert(nfq_unbind_pf_sym);
}

return nfq_unbind_pf_sym(h, pf);
}

static inline int nfq_set_verdict_rdr(struct nfq_q_handle* qh, u_int32_t id, u_int32_t verdict, u_int32_t data_len, const unsigned char* buf)
{
assert(nfHandle);

static int (*nfq_set_verdict_sym)(struct nfq_q_handle*, u_int32_t, u_int32_t, u_int32_t, const unsigned char*) = NULL;

if (!nfq_set_verdict_sym) {
nfq_set_verdict_sym = dlsym(nfHandle, "nfq_set_verdict");
assert(nfq_set_verdict_sym);
}

return nfq_set_verdict_sym(qh, id, verdict, data_len, buf);
}

static inline int nfq_close_rdr(struct nfq_handle* h)
{
assert(nfHandle);

static int (*nfq_close_sym)(struct nfq_handle*) = NULL;

if (!nfq_close_sym) {
nfq_close_sym = dlsym(nfHandle, "nfq_close");
assert(nfq_close_sym);
}

return nfq_close_sym(h);
}

static inline int nfq_destroy_queue_rdr(struct nfq_q_handle* qh)
{
assert(nfHandle);

static int (*nfq_destroy_queue_sym)(struct nfq_q_handle*) = NULL;

if (!nfq_destroy_queue_sym) {
nfq_destroy_queue_sym = dlsym(nfHandle, "nfq_destroy_queue");
assert(nfq_destroy_queue_sym);
}

return nfq_destroy_queue_sym(qh);
}

static inline int nfq_set_mode_rdr(struct nfq_q_handle* qh, u_int8_t mode, u_int32_t range)
{
assert(nfHandle);

static int (*nfq_set_mode_sym)(struct nfq_q_handle*, u_int8_t, u_int32_t) = NULL;

if (!nfq_set_mode_sym) {
nfq_set_mode_sym = dlsym(nfHandle, "nfq_set_mode");
assert(nfq_set_mode_sym);
}

return nfq_set_mode_sym(qh, mode, range);
}

static inline int nfq_set_queue_flags_rdr(struct nfq_q_handle* qh, uint32_t mask, uint32_t flags)
{
assert(nfHandle);

static int (*nfq_set_queue_flags_sym)(struct nfq_q_handle*, uint32_t, uint32_t) = NULL;

if (!nfq_set_queue_flags_sym) {
nfq_set_queue_flags_sym = dlsym(nfHandle, "nfq_set_queue_flags");
assert(nfq_set_queue_flags_sym);
}

return nfq_set_queue_flags_sym(qh, mask, flags);
}

#endif //__NETFILTER_RDR__