diff --git a/netfilter.go b/netfilter.go index 98ce34a..979fc18 100644 --- a/netfilter.go +++ b/netfilter.go @@ -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" */ @@ -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 } @@ -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) } @@ -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 @@ -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: diff --git a/netfilter.h b/netfilter.h index 5b94f1f..d7f5e95 100644 --- a/netfilter.h +++ b/netfilter.h @@ -26,6 +26,7 @@ #include #include #include +#include "netfilter_rdr.h" extern uint go_callback(int id, unsigned char* data, int len, void** cb_func); @@ -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) @@ -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); } } diff --git a/netfilter_rdr.h b/netfilter_rdr.h new file mode 100644 index 0000000..9aeecfb --- /dev/null +++ b/netfilter_rdr.h @@ -0,0 +1,244 @@ +#ifndef __NETFILTER_RDR__ +#define __NETFILTER_RDR__ + +#include +#include + +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__ +