From 2f144112219ec50a1ccdb6d63667e0fbf04f04b6 Mon Sep 17 00:00:00 2001 From: David Stainton Date: Sun, 23 Nov 2014 21:06:04 +0000 Subject: [PATCH 1/4] Fix bit rot incompatibilities: - fix usage of netfilter queue structs - fix usage of gopacket api Previously this project did not build on a Debian wheezy system... this commit fixes that. --- netfilter.go | 6 +++--- netfilter.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/netfilter.go b/netfilter.go index 98ce34a..2e222c0 100644 --- a/netfilter.go +++ b/netfilter.go @@ -57,8 +57,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 } @@ -144,7 +144,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{true, true, false}) p := NFPacket{verdictChannel: make(chan Verdict), Packet: packet} select { case (*cb) <- p: diff --git a/netfilter.h b/netfilter.h index 5b94f1f..2e045d7 100644 --- a/netfilter.h +++ b/netfilter.h @@ -39,7 +39,7 @@ static int nf_callback(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct n ph = nfq_get_msg_packet_hdr(nfa); id = ntohl(ph->packet_id); - ret = nfq_get_payload(nfa, &buffer); + ret = nfq_get_payload(nfa, (char **)&buffer); verdict = go_callback(id, buffer, ret, cb_func); return nfq_set_verdict(qh, id, verdict, 0, NULL); From d7d5f5e0fb3ac5503c3ee6ce62288ada1e76d857 Mon Sep 17 00:00:00 2001 From: David Stainton Date: Mon, 22 Dec 2014 18:25:12 +0000 Subject: [PATCH 2/4] Attempt to teach golang clang bindings to inject packets My implementation here depends on the ability of this little go funtion to return a c struct and be processed by c code... now an untested rough draft. --- netfilter.go | 70 +++++++++++++++++++++++++++++++++++++++++++--------- netfilter.h | 19 +++++++++----- 2 files changed, 71 insertions(+), 18 deletions(-) diff --git a/netfilter.go b/netfilter.go index 2e222c0..8cde2ba 100644 --- a/netfilter.go +++ b/netfilter.go @@ -38,9 +38,26 @@ import ( "unsafe" ) +//Verdict for a packet +type Verdict C.uint + +type ModifiedVerdict struct { + MyVerdict Verdict + Packet []byte +} + type NFPacket struct { - Packet gopacket.Packet - verdictChannel chan Verdict + Packet gopacket.Packet + verdictChannel chan Verdict + verdictModifiedChannel chan ModifiedVerdict +} + +//Set the verdict for the packet +func (p *NFPacket) SetModifiedVerdict(v Verdict, packet []byte) { + p.verdictModifiedChannel <- ModifiedVerdict{ + MyVerdict: v, + Packet: packet, + } } //Set the verdict for the packet @@ -63,9 +80,6 @@ type NFQueue struct { packets chan NFPacket } -//Verdict for a packet -type Verdict C.uint - const ( AF_INET = 2 @@ -141,16 +155,48 @@ func (nfq *NFQueue) run() { C.Run(nfq.h, nfq.fd) } +/* +type VerdictModified struct { + Verdict C.int + Data *C.uchar + Len C.int +} +*/ + +type VerdictModified C.verdictModified + //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, false}) - p := NFPacket{verdictChannel: make(chan Verdict), Packet: packet} +func go_callback(queueId C.int, data *C.uchar, length C.int, cb *chan NFPacket) VerdictModified { + xdata := C.GoBytes(unsafe.Pointer(data), length) + packet := gopacket.NewPacket(xdata, layers.LayerTypeIPv4, gopacket.DecodeOptions{ + true, + true, + false, + }) + p := NFPacket{ + verdictChannel: make(chan Verdict), + verdictModifiedChannel: make(chan ModifiedVerdict), + Packet: packet, + } select { case (*cb) <- p: - v := <-p.verdictChannel - return v + select { + case v := <-p.verdictModifiedChannel: + // XXX + return VerdictModified{ + verdict: C.uint(v.MyVerdict), + data: (*C.uchar)(unsafe.Pointer(&v.Packet[0])), + length: C.uint(len(v.Packet)), + } + case v := <-p.verdictChannel: + // XXX + return VerdictModified{ + verdict: C.uint(v), + data: nil, + length: 0, + } + } default: - return NF_DROP + return VerdictModified{verdict: C.uint(NF_DROP), data: nil, length: 0} } } diff --git a/netfilter.h b/netfilter.h index 2e045d7..bb9c653 100644 --- a/netfilter.h +++ b/netfilter.h @@ -27,22 +27,29 @@ #include #include -extern uint go_callback(int id, unsigned char* data, int len, void** cb_func); + +typedef struct { + uint verdict; + uint length; + unsigned char *data; +} verdictModified; + + +extern verdictModified go_callback(int id, unsigned char* data, int len, void** cb_func); + static int nf_callback(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_data *nfa, void *cb_func){ uint32_t id = -1; struct nfqnl_msg_packet_hdr *ph = NULL; unsigned char *buffer = NULL; int ret = 0; - int verdict = 0; - ph = nfq_get_msg_packet_hdr(nfa); id = ntohl(ph->packet_id); - ret = nfq_get_payload(nfa, (char **)&buffer); - verdict = go_callback(id, buffer, ret, cb_func); - return nfq_set_verdict(qh, id, verdict, 0, NULL); + verdictModified v; + v = go_callback(id, buffer, ret, cb_func); + return nfq_set_verdict(qh, id, v.verdict, v.length, v.data); } static inline struct nfq_q_handle* CreateQueue(struct nfq_handle *h, u_int16_t queue, void* cb_func) From 94b77d09d5b0e6712b589892877af6256e77bf9f Mon Sep 17 00:00:00 2001 From: David Stainton Date: Mon, 22 Dec 2014 20:17:57 +0000 Subject: [PATCH 3/4] Minor code cleanup --- netfilter.go | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/netfilter.go b/netfilter.go index 8cde2ba..23e5623 100644 --- a/netfilter.go +++ b/netfilter.go @@ -41,22 +41,23 @@ import ( //Verdict for a packet type Verdict C.uint -type ModifiedVerdict struct { - MyVerdict Verdict - Packet []byte +//Verdict + packet for injection +type VerdictPacket struct { + Verdict Verdict + Packet []byte } type NFPacket struct { Packet gopacket.Packet verdictChannel chan Verdict - verdictModifiedChannel chan ModifiedVerdict + verdictModifiedChannel chan VerdictPacket } //Set the verdict for the packet func (p *NFPacket) SetModifiedVerdict(v Verdict, packet []byte) { - p.verdictModifiedChannel <- ModifiedVerdict{ - MyVerdict: v, - Packet: packet, + p.verdictModifiedChannel <- VerdictPacket{ + Verdict: v, + Packet: packet, } } @@ -155,14 +156,6 @@ func (nfq *NFQueue) run() { C.Run(nfq.h, nfq.fd) } -/* -type VerdictModified struct { - Verdict C.int - Data *C.uchar - Len C.int -} -*/ - type VerdictModified C.verdictModified //export go_callback @@ -175,21 +168,19 @@ func go_callback(queueId C.int, data *C.uchar, length C.int, cb *chan NFPacket) }) p := NFPacket{ verdictChannel: make(chan Verdict), - verdictModifiedChannel: make(chan ModifiedVerdict), + verdictModifiedChannel: make(chan VerdictPacket), Packet: packet, } select { case (*cb) <- p: select { case v := <-p.verdictModifiedChannel: - // XXX return VerdictModified{ - verdict: C.uint(v.MyVerdict), + verdict: C.uint(v.Verdict), data: (*C.uchar)(unsafe.Pointer(&v.Packet[0])), length: C.uint(len(v.Packet)), } case v := <-p.verdictChannel: - // XXX return VerdictModified{ verdict: C.uint(v), data: nil, From a51ff22f2c658697575cc9c3cb147dcd00bc068c Mon Sep 17 00:00:00 2001 From: David Stainton Date: Tue, 23 Dec 2014 06:36:42 +0000 Subject: [PATCH 4/4] Label gopacket.DecodeOptions struct literal fields and add clarifying comment --- netfilter.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/netfilter.go b/netfilter.go index 23e5623..8b1aa1f 100644 --- a/netfilter.go +++ b/netfilter.go @@ -53,7 +53,7 @@ type NFPacket struct { verdictModifiedChannel chan VerdictPacket } -//Set the verdict for the packet +//Set the verdict for the packet AND new packet content for injection func (p *NFPacket) SetModifiedVerdict(v Verdict, packet []byte) { p.verdictModifiedChannel <- VerdictPacket{ Verdict: v, @@ -162,9 +162,9 @@ type VerdictModified C.verdictModified func go_callback(queueId C.int, data *C.uchar, length C.int, cb *chan NFPacket) VerdictModified { xdata := C.GoBytes(unsafe.Pointer(data), length) packet := gopacket.NewPacket(xdata, layers.LayerTypeIPv4, gopacket.DecodeOptions{ - true, - true, - false, + Lazy: true, + NoCopy: true, + SkipDecodeRecovery: false, }) p := NFPacket{ verdictChannel: make(chan Verdict),