-
Notifications
You must be signed in to change notification settings - Fork 6
/
sensor.go
149 lines (136 loc) · 3.43 KB
/
sensor.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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
package gourmet
import (
"errors"
"fmt"
"log"
"time"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
)
type interfaceType byte
const (
afpacketType interfaceType = 1
libpcapType interfaceType = 3
)
type sensorMetadata struct {
// The network interface that the sensor is capturing traffic
NetworkInterface string
// The IP address of the capturing network interface
NetworkAddress []string
}
func getSensorMetadata(interfaceName string) *sensorMetadata {
return &sensorMetadata{
NetworkInterface: interfaceName,
NetworkAddress: getInterfaceAddresses(interfaceName),
}
}
type sensor struct {
source gopacket.ZeroCopyPacketDataSource
streamFactory *tcpStreamFactory
connections chan *Connection
}
// Start is the entry point for Gourmet
func Start(config *Config) {
var err error
var workingGraph analyzerGraph
for k, v := range config.Analyzers {
analyzerNode, err := createAnalyzerNode(k, v)
if err != nil {
log.Fatal(fmt.Errorf("unable to process analyzer config: %s", err))
}
workingGraph = append(workingGraph, analyzerNode)
}
err = resolveGraph(workingGraph)
if err != nil {
log.Fatal(fmt.Errorf("failed to build dependency graph for analyzers: %s", err))
}
err = newAnalyzers(config.Analyzers, config.SkipUpdate)
if err != nil {
log.Fatal(err)
}
err = initLogger(config.LogFile, config.Interface)
if err != nil {
log.Fatal(err)
}
c := make(chan *Connection)
s := &sensor{
connections: c,
streamFactory: &tcpStreamFactory{
connections: c,
connTimeout: config.ConnTimeout,
},
}
err = s.getPacketSource(config)
if err != nil {
log.Fatal(err)
}
go s.processConnections()
fmt.Printf("Gourmet is running and logging to %s. Press CTL+C to stop...", gLogger.fileName)
fmt.Println()
s.run()
}
func convertIfaceType(ifaceType string) (interfaceType, error) {
if ifaceType == "libpcap" {
return libpcapType, nil
} else if ifaceType == "afpacket" {
return afpacketType, nil
} else {
return 0, errors.New("invalid interface type. Must be libpcap or afpacket")
}
}
func (s *sensor) getPacketSource(c *Config) (err error) {
ifaceType, err := convertIfaceType(c.InterfaceType)
if err != nil {
return err
}
if ifaceType == afpacketType {
s.source, err = newAfpacketSensor(c)
if err != nil {
return err
}
} else if ifaceType == libpcapType {
s.source, err = newLibpcapSensor(c)
if err != nil {
return err
}
} else {
return errors.New("interface type is not set")
}
return nil
}
func (s *sensor) run() {
s.streamFactory.createAssembler()
s.streamFactory.ticker = time.NewTicker(time.Second * 10)
for {
p, ci, err := s.source.ZeroCopyReadPacketData()
if err != nil {
log.Println(err)
continue
}
packet := gopacket.NewPacket(p, layers.LayerTypeEthernet, gopacket.DecodeStreamsAsDatagrams)
go s.processNewPacket(packet, ci)
}
}
func (s *sensor) processNewPacket(packet gopacket.Packet, ci gopacket.CaptureInfo) {
if packet.TransportLayer() != nil {
layer := packet.TransportLayer()
switch layer.LayerType() {
case layers.LayerTypeTCP:
s.streamFactory.newPacket(packet.NetworkLayer().NetworkFlow(), packet.TransportLayer().(*layers.TCP))
return
case layers.LayerTypeUDP:
udp := processUDPPacket(packet, ci)
s.connections <- udp
return
}
}
}
func (s *sensor) processConnections() {
for connection := range s.connections {
err := connection.analyze()
if err != nil {
log.Println(err)
}
gLogger.log(*connection)
}
}