-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnetfilter.go
132 lines (119 loc) · 3.65 KB
/
netfilter.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package goaway2
import (
"log"
"os"
"os/signal"
"sync"
"syscall"
netfilter "github.com/AkihiroSuda/go-netfilter-queue"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
)
/***Variables***/
type NetfilterQueue struct {
// Set Variables
Handler func(*RBKV, *PacketData) netfilter.Verdict
QueueNum uint16
MaxWorkers int
// queue handler objects
nfq *netfilter.NFQueue
pktQueue <-chan netfilter.NFPacket
// worker/class handler objects
started bool
wg sync.WaitGroup
}
/***Methods***/
//(*NetfilterQueue).Start : spawn nfq instance and start collecting packets
func (queue *NetfilterQueue) Start() {
// check if already started
if queue.started {
log.Fatalf("NFQueue %d ALREADY STARTED!\n", queue.QueueNum)
}
// spawn netfilter queue instance and start collecting packets
var err error
queue.nfq, err = netfilter.NewNFQueue(queue.QueueNum, 100, netfilter.NF_DEFAULT_PACKET_SIZE)
if err != nil {
log.Fatalf("NFQueue %d Error: %s\n", queue.QueueNum, err.Error())
}
log.Printf("NFQueue: %d Initialized! Starting Workers...\n", queue.QueueNum)
// set packet queue and started boolean
queue.pktQueue = queue.nfq.GetPackets()
queue.started = true
// start max number of workers
for i := 0; i < queue.MaxWorkers; i++ {
go queue.worker()
queue.wg.Add(1)
}
log.Println("Workers Started!")
}
//(*NetfilterQueue).Wait : wait for threads to finish FOREVER!!! (A really long time)
func (queue *NetfilterQueue) Wait() {
queue.wg.Wait()
}
//(*NetfilterQueue).Stop : close nfq instance and stop collecting packets
func (queue *NetfilterQueue) Stop() {
// check if not started
if !queue.started {
log.Fatalf("NFQueue %d NEVER STARTED!\n", queue.QueueNum)
}
// close queue instance
queue.nfq.Close()
// close packet queue and set started boolean
queue.pktQueue = nil
queue.started = false
}
func (queue *NetfilterQueue) Run() {
// start netfilter queue instance
queue.Start()
// handle interupts
c := make(chan os.Signal, 2)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
go func() {
for sig := range c {
log.Fatalf("Captured Signal: %v! Cleaning up...", sig)
queue.Stop()
}
}()
// wait possibly forever
queue.Wait()
}
//(*NetfilterQueue).parsePacket : parse gopacket and return collected packet data
func (queue *NetfilterQueue) parsePacket(packetin gopacket.Packet, packetout *PacketData) {
//get src and dst ip from ipv4
ipLayer := packetin.Layer(layers.LayerTypeIPv4)
if ipLayer != nil {
ip, _ := ipLayer.(*layers.IPv4)
packetout.SrcIP = ip.SrcIP.String()
packetout.DstIP = ip.DstIP.String()
packetout.Protocol = ip.Protocol.String()
}
//get src and dst from tcp ports
tcpLayer := packetin.Layer(layers.LayerTypeTCP)
if tcpLayer != nil {
tcp, _ := tcpLayer.(*layers.TCP)
packetout.SrcPort = int64(tcp.SrcPort)
packetout.DstPort = int64(tcp.DstPort)
}
}
//(*NetfilterQueue).worker : worker instance used to set the verdict for queued packets
func (queue *NetfilterQueue) worker() {
// defer waitgroup completion
defer queue.wg.Done()
// init variables for packet handling
var (
nfqPacket netfilter.NFPacket //Reused netfilter packet object
dataPacket PacketData //Reused parsed packet data as struct
redblackkv *RBKV = NewRedBlackKV() //Reused key/value pair for red black tree caches
)
// loop while running forever
for queue.started {
// collect verdict packet from netfilerqueu
nfqPacket = <-queue.pktQueue
// parse packet for required information
queue.parsePacket(nfqPacket.Packet, &dataPacket)
// complete logic go get verfict on packet and set verdict
nfqPacket.SetVerdict(
queue.Handler(redblackkv, &dataPacket),
)
}
}