Skip to content

Commit a6397e9

Browse files
committed
Version 0.1
1 parent f452da2 commit a6397e9

File tree

4 files changed

+273
-0
lines changed

4 files changed

+273
-0
lines changed

README.md

+44
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,47 @@ go-netfilter-queue
22
==================
33

44
Go bindings for libnetfilter_queue
5+
6+
This library provides access to packets in the IPTables netfilter queue (NFQUEUE).
7+
The libnetfilter_queue library is part of the [Netfilter project| http://netfilter.org/projects/libnetfilter_queue/].
8+
9+
Example
10+
=======
11+
12+
use IPTables to direct all outgoing Ping/ICMP requests to the queue 0:
13+
14+
iptables -A OUTPUT -p icmp -j NFQUEUE --queue-num 0
15+
16+
You can then use go-netfilter-queue to inspect the packets:
17+
18+
package main
19+
20+
import (
21+
"fmt"
22+
"github.com/kraman/go-netfilter-queue"
23+
"os"
24+
)
25+
26+
func main() {
27+
var err error
28+
29+
nfq, err := netfilter.NewNFQueue(0, 100, netfilter.NF_DEFAULT_PACKET_SIZE)
30+
if err != nil {
31+
fmt.Println(err)
32+
os.Exit(1)
33+
}
34+
defer nfq.Close()
35+
packets := nfq.GetPackets()
36+
37+
for true {
38+
select {
39+
case p := <-packets:
40+
fmt.Println(p.Packet)
41+
p.SetVerdict(netfilter.NF_ACCEPT)
42+
}
43+
}
44+
}
45+
46+
To undo the IPTables redirect. Run:
47+
48+
iptables -D OUTPUT -p icmp -j NFQUEUE --queue-num 0

netfilter.c

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/*
2+
Copyright 2014 Krishna Raman <[email protected]>
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
#include "netfilter.h"
18+

netfilter.go

+146
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
/*
2+
Copyright 2014 Krishna Raman <[email protected]>
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
/*
18+
Go bindings for libnetfilter_queue
19+
20+
This library provides access to packets in the IPTables netfilter queue (NFQUEUE).
21+
The libnetfilter_queue library is part of the http://netfilter.org/projects/libnetfilter_queue/ project.
22+
*/
23+
package netfilter
24+
25+
/*
26+
#cgo pkg-config: libnetfilter_queue
27+
#cgo CFLAGS: -Wall -Werror -I/usr/include
28+
#cgo LDFLAGS: -L/usr/lib64/
29+
30+
#include "netfilter.h"
31+
*/
32+
import "C"
33+
34+
import (
35+
"code.google.com/p/gopacket"
36+
"code.google.com/p/gopacket/layers"
37+
"fmt"
38+
"unsafe"
39+
)
40+
41+
type NFPacket struct {
42+
Packet gopacket.Packet
43+
verdictChannel chan Verdict
44+
}
45+
46+
//Set the verdict for the packet
47+
func (p *NFPacket) SetVerdict(v Verdict) {
48+
p.verdictChannel <- v
49+
}
50+
51+
type NFQueue struct {
52+
h *[0]byte
53+
qh *[0]byte
54+
fd C.int
55+
packets chan NFPacket
56+
}
57+
58+
//Verdict for a packet
59+
type Verdict C.int
60+
61+
const (
62+
AF_INET = 2
63+
64+
//Discarded the packet
65+
NF_DROP Verdict = 0
66+
67+
//The packet passes, continue iterations
68+
NF_ACCEPT Verdict = 1
69+
70+
NF_DEFAULT_PACKET_SIZE uint32 = 0xffff
71+
)
72+
73+
//Create and bind to queue specified by queueId
74+
func NewNFQueue(queueId int, maxPacketsInQueue uint32, packetSize uint32) (*NFQueue, error) {
75+
var nfq = NFQueue{}
76+
var err error
77+
var ret C.int
78+
79+
if nfq.h, err = C.nfq_open(); err != nil {
80+
return nil, fmt.Errorf("Error opening NFQueue handle: %v\n", err)
81+
}
82+
83+
if ret, err = C.nfq_unbind_pf(nfq.h, AF_INET); err != nil || ret < 0 {
84+
return nil, fmt.Errorf("Error unbinding existing NFQ handler from AF_INET protocol family: %v\n", err)
85+
}
86+
87+
if ret, err := C.nfq_bind_pf(nfq.h, AF_INET); err != nil || ret < 0 {
88+
return nil, fmt.Errorf("Error binding to AF_INET protocol family: %v\n", err)
89+
}
90+
91+
nfq.packets = make(chan NFPacket)
92+
if nfq.qh, err = C.CreateQueue(nfq.h, C.int(queueId), unsafe.Pointer(&nfq.packets)); err != nil || nfq.qh == nil {
93+
C.nfq_close(nfq.h)
94+
return nil, fmt.Errorf("Error binding to queue: %v\n", err)
95+
}
96+
97+
if ret, err = C.nfq_set_queue_maxlen(nfq.qh, C.u_int32_t(maxPacketsInQueue)); err != nil || ret < 0 {
98+
C.nfq_destroy_queue(nfq.qh)
99+
C.nfq_close(nfq.h)
100+
return nil, fmt.Errorf("Unable to set max packets in queue: %v\n", err)
101+
}
102+
103+
if C.nfq_set_mode(nfq.qh, C.u_int8_t(2), C.uint(packetSize)) < 0 {
104+
C.nfq_destroy_queue(nfq.qh)
105+
C.nfq_close(nfq.h)
106+
return nil, fmt.Errorf("Unable to set packets copy mode: %v\n", err)
107+
}
108+
109+
if nfq.fd, err = C.nfq_fd(nfq.h); err != nil {
110+
C.nfq_destroy_queue(nfq.qh)
111+
C.nfq_close(nfq.h)
112+
return nil, fmt.Errorf("Unable to get queue file-descriptor. %v", err)
113+
}
114+
115+
go nfq.run()
116+
117+
return &nfq, nil
118+
}
119+
120+
//Unbind and close the queue
121+
func (nfq *NFQueue) Close() {
122+
C.nfq_destroy_queue(nfq.qh)
123+
C.nfq_close(nfq.h)
124+
}
125+
126+
//Get the channel for packets
127+
func (nfq *NFQueue) GetPackets() <-chan NFPacket {
128+
return nfq.packets
129+
}
130+
131+
func (nfq *NFQueue) run() {
132+
C.Run(nfq.h, nfq.fd)
133+
}
134+
135+
//export go_callback
136+
func go_callback(queueId C.int, data *C.uchar, len C.int, cb *chan NFPacket) Verdict {
137+
xdata := C.GoBytes(unsafe.Pointer(data), len)
138+
packet := gopacket.NewPacket(xdata, layers.LayerTypeIPv4, gopacket.DecodeOptions{true, true})
139+
p := NFPacket{verdictChannel: make(chan Verdict), Packet: packet}
140+
select {
141+
case (*cb) <- p:
142+
return <-p.verdictChannel
143+
default:
144+
return NF_DROP
145+
}
146+
}

netfilter.h

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
Copyright 2014 Krishna Raman <[email protected]>
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
#ifndef _NETFILTER_H
18+
#define _NETFILTER_H
19+
20+
#include <stdio.h>
21+
#include <stdlib.h>
22+
#include <math.h>
23+
#include <unistd.h>
24+
#include <netinet/in.h>
25+
#include <linux/types.h>
26+
#include <linux/socket.h>
27+
#include <linux/netfilter.h>
28+
#include <libnetfilter_queue/libnetfilter_queue.h>
29+
30+
extern int go_callback(int id, unsigned char* data, int len, void** cb_func);
31+
32+
static int nf_callback(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_data *nfa, void *cb_func){
33+
uint32_t id = -1;
34+
struct nfqnl_msg_packet_hdr *ph = NULL;
35+
unsigned char *buffer = NULL;
36+
int ret = 0;
37+
int verdict = 0;
38+
39+
ph = nfq_get_msg_packet_hdr(nfa);
40+
id = ntohl(ph->packet_id);
41+
42+
ret = nfq_get_payload(nfa, &buffer);
43+
verdict = go_callback(id, buffer, ret, cb_func);
44+
45+
return nfq_set_verdict(qh, id, verdict, 0, NULL);
46+
}
47+
48+
static inline struct nfq_q_handle* CreateQueue(struct nfq_handle *h, int queue, void* cb_func)
49+
{
50+
return nfq_create_queue(h, queue, &nf_callback, cb_func);
51+
}
52+
53+
static inline void Run(struct nfq_handle *h, int fd)
54+
{
55+
char buf[4096] __attribute__ ((aligned));
56+
int rv;
57+
58+
while ((rv = recv(fd, buf, sizeof(buf), 0)) && rv >= 0) {
59+
nfq_handle_packet(h, buf, rv);
60+
}
61+
}
62+
63+
#endif
64+
65+

0 commit comments

Comments
 (0)