diff --git a/netfilter.go b/netfilter.go index 98ce34a..8b1aa1f 100644 --- a/netfilter.go +++ b/netfilter.go @@ -38,9 +38,27 @@ import ( "unsafe" ) +//Verdict for a packet +type Verdict C.uint + +//Verdict + packet for injection +type VerdictPacket struct { + Verdict Verdict + Packet []byte +} + type NFPacket struct { - Packet gopacket.Packet - verdictChannel chan Verdict + Packet gopacket.Packet + verdictChannel chan Verdict + verdictModifiedChannel chan VerdictPacket +} + +//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, + Packet: packet, + } } //Set the verdict for the packet @@ -57,15 +75,12 @@ 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 } -//Verdict for a packet -type Verdict C.uint - const ( AF_INET = 2 @@ -141,16 +156,38 @@ func (nfq *NFQueue) run() { C.Run(nfq.h, nfq.fd) } +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}) - 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{ + Lazy: true, + NoCopy: true, + SkipDecodeRecovery: false, + }) + p := NFPacket{ + verdictChannel: make(chan Verdict), + verdictModifiedChannel: make(chan VerdictPacket), + Packet: packet, + } select { case (*cb) <- p: - v := <-p.verdictChannel - return v + select { + case v := <-p.verdictModifiedChannel: + return VerdictModified{ + verdict: C.uint(v.Verdict), + data: (*C.uchar)(unsafe.Pointer(&v.Packet[0])), + length: C.uint(len(v.Packet)), + } + case v := <-p.verdictChannel: + 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 5b94f1f..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); - ret = nfq_get_payload(nfa, &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)