forked from danmia/pcapdaemon
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcapture.go
335 lines (282 loc) · 12.6 KB
/
capture.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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
package main
import (
"fmt"
"log"
"time"
"bytes"
"regexp"
"strconv"
"io/ioutil"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcap"
"github.com/google/gopacket/pcapgo"
)
func captureToBuffer(req Capmsg, iface string) {
var (
snapshotLen int32 = 1500
promiscuous bool = true
err error
rerr error
timeout time.Duration = 3 * time.Second
handle *pcap.Handle
packetCount int = 0
fileName string
tagstr string
matchNode bool = false
captimeout time.Duration
capduration time.Duration
capbytes int
)
// Do sanity checking on max number of packets
if(req.Packets == 0) {
fmt.Println("Invalid Capture size. packets must be set to between 1 and " + strconv.Itoa(config.Gen.Maxpackets))
log.Println("Invalid Capture size. packets must be set to between 1 and " + strconv.Itoa(config.Gen.Maxpackets))
return
}
if(req.Packets > config.Gen.Maxpackets) {
fmt.Println("Invalid Capture size. packets cannot be > than maxpackets which is " + strconv.Itoa(config.Gen.Maxpackets))
log.Println("Invalid Capture size. packets cannot be > than maxpackets which is " + strconv.Itoa(config.Gen.Maxpackets))
return
}
// Check the node against the message to see if we match either node or nodere
if(req.Node != "" && req.Nodere != "") {
fmt.Println("Invalid msg: both node and nodere are set. Use one or the other")
log.Println("Invalid msg: both node and nodere are set. Use one or the other")
return
}
if(req.Node == "" && req.Nodere == "") {
fmt.Println("Invalid msg: both node and nodere are missing. Use one or the other")
log.Println("Invalid msg: both node and nodere are missing. Use one or the other")
return
}
if(req.Node != "") {
if(req.Node == hostname) {
fmt.Println("Matched node: " + req.Node)
log.Println("Matched node: " + req.Node)
matchNode = true
} else if(req.Node == "any") {
fmt.Println("Matched node: any")
log.Println("Matched node: any")
matchNode = true
}
} else if(req.Nodere != "") {
matchNode, rerr = regexp.MatchString(req.Nodere, hostname)
if(rerr != nil) {
fmt.Printf("Error applying regex: %s\n", rerr)
log.Printf("Error applying regex: %s\n", rerr)
}
if(matchNode) {
fmt.Println("Node regex match: " + req.Nodere + " against " + hostname)
log.Println("Node regex match: " + req.Nodere + " against " + hostname)
}
}
if(matchNode == false) {
fmt.Println("We didn't match via node or nodere " + hostname)
log.Println("We didn't match via node or nodere " + hostname)
return
}
// END OF NODE MATCHING
// Timeout management is to break out of a capture if long periods of time pass
// without capturing any packets
if(req.Timeout != 0) {
if(req.Timeout > config.Gen.Maxtimeout) {
log.Printf("Error: message timeout %d is greater than max allowable timeout %d\n", req.Timeout, config.Gen.Maxtimeout)
fmt.Printf("Error: message timeout %d is greater than max allowable timeout %d\n", req.Timeout, config.Gen.Maxtimeout)
return
}
captimeout = req.Timeout * time.Second
} else {
captimeout = config.Gen.Deftimeout * time.Second
}
// Duration managment is to put a cap on how long to capture for no matter what is going on
if(req.Duration != 0) {
if(req.Duration > config.Gen.Maxduration) {
log.Printf("Error: message duration %d is greater than max allowable duration %d\n", req.Duration, config.Gen.Maxduration)
fmt.Printf("Error: message duration %d is greater than max allowable duration %d\n", req.Duration, config.Gen.Maxduration)
return
}
capduration = req.Duration * time.Second
} else {
capduration = config.Gen.Maxduration * time.Second
}
// Byte management is to break out after a certain number of bytes
if(req.Bytes != 0) {
if(req.Bytes > config.Gen.Maxbytes) {
log.Printf("Error: message bytes %d is greater than max allowable bytes %d\n", req.Bytes, config.Gen.Maxbytes)
fmt.Printf("Error: message bytes %d is greater than max allowable bytes %d\n", req.Bytes, config.Gen.Maxbytes)
return
}
capbytes = req.Bytes
} else {
capbytes = config.Gen.Maxbytes
}
// If snaplength is not overridden in the message then use the system default
if(req.Snap == 0) {
req.Snap = config.Gen.Snap
}
log.Println("Capturing " + strconv.Itoa(req.Packets) + " packets on interface " + iface + " with a snaplength of " + strconv.Itoa(req.Snap))
fmt.Println("Capturing " + strconv.Itoa(req.Packets) + " packets on interface " + iface + " with a snaplength of " + strconv.Itoa(req.Snap))
fileName = hostname + "-" + iface + "-" + strconv.FormatInt(time.Now().Unix(), 10) + ".pcap"
var f bytes.Buffer
w := pcapgo.NewWriter(&f)
w.WriteFileHeader(uint32(snapshotLen), layers.LinkTypeEthernet)
// Open the device for capturing
handle, err = pcap.OpenLive(iface, int32(req.Snap), promiscuous, timeout)
if err != nil {
fmt.Printf("Error opening device %s: %v", iface, err)
log.Printf("Error opening device %s: %v", iface, err)
}
if(req.Bpf != "") {
err := handle.SetBPFFilter(req.Bpf);
if(err != nil) {
fmt.Printf("Error compiling BPF Filter:[%s] %s\n", req.Bpf, err)
log.Printf("Error compiling BPF Filter:[%s] %s\n", req.Bpf, err)
return
} else {
fmt.Printf("Successfully compiled BPF Filter: [%s]\n", req.Bpf)
log.Printf("Successfully compiled BPF Filter: [%s]\n", req.Bpf)
}
}
defer handle.Close()
// Start processing packets
packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
packetSource.DecodeOptions = gopacket.DecodeOptions{Lazy: false, NoCopy: false, SkipDecodeRecovery: *panicPtr}
packetchan := packetSource.Packets()
captimer := time.NewTimer(capduration)
C:
for {
select {
case packet := <-packetchan:
// Process packet here
// Global packet debug
if(config.Gen.PacketDebug || req.PacketDebug) {
fmt.Println(packet)
log.Println(packet)
}
w.WritePacket(packet.Metadata().CaptureInfo, packet.Data())
packetCount++
// Only capture a fixed amount of packets
if packetCount >= req.Packets {
fmt.Printf("Packet count %d hit for capture %s, size: %d bytes\n", req.Packets, fileName, f.Len())
log.Printf("Packet count %d hit for capture %s, size: %d bytes\n", req.Packets, fileName, f.Len())
break C
}
// Only capture a fixed amount of packets
if capbytes <= f.Len() {
fmt.Printf("Size limit %d bytes hit for capture %s, size: %d bytes\n", capbytes, fileName, f.Len())
log.Printf("Size limit %d bytes hit for capture %s, size: %d bytes\n", capbytes, fileName, f.Len())
break C
}
case <-time.After(captimeout):
fmt.Printf("Packet timeout %s hit for capture %s, captured %d packets, size: %d\n", captimeout.String(), fileName, packetCount, f.Len())
log.Printf("Packet timeout %s hit for capture %s, captured %d packets, size: %d\n", captimeout.String(), fileName, packetCount, f.Len())
// If there are no packets before the timeout then return without uploading
if(packetCount == 0) {
log.Printf("Packet timeout %s hit for capture %s and packet count is 0 so returning without uploading\n", captimeout.String(), fileName)
fmt.Printf("Packet timeout %s hit for capture %s and packet count is 0 so returning without uploading\n", captimeout.String(), fileName)
return
}
break C
case <- captimer.C:
fmt.Printf("Capture duration %s hit for capture %s, captured %d packets, size: %d\n", capduration.String(), fileName, packetCount, f.Len())
log.Printf("Capture duration %s hit for capture %s, captured %d packets, size: %d\n", capduration.String(), fileName, packetCount, f.Len())
// If there are no packets before the total duration hits then return without uploading
if(packetCount == 0) {
log.Printf("Capture duration %s hit for capture %s and packet count is 0 so returning without uploading\n", capduration.String(), fileName)
fmt.Printf("Capture duration %s hit for capture %s and packet count is 0 so returning without uploading\n", capduration.String(), fileName)
return
}
break C
}
}
// Handle Tags
// First tim I'm touching tagstr which is why I don't check for empty
if(req.Customer != "") {
tagstr = "customer:" + req.Customer
}
if(req.Alertid != 0 && tagstr == "") {
tagstr = "alertid:" + strconv.Itoa(req.Alertid)
} else if(req.Alertid != 0 && tagstr != "") {
tagstr = tagstr + ",alertid:" + strconv.Itoa(req.Alertid)
}
if(req.Tags != "" && tagstr == "") {
tagstr = req.Tags
} else if(req.Tags != "" && tagstr != "") {
tagstr = tagstr + "," + req.Tags
}
if(req.AliasMatched != "" && tagstr == "") {
tagstr = "alias:" + req.AliasMatched
} else if(req.AliasMatched != "" && tagstr != "") {
tagstr = tagstr + ",alias:" + req.AliasMatched
}
if(tagstr == "") {
tagstr = "node:" + hostname + ",interface:" + iface + ",snaplength:" + strconv.Itoa(req.Snap)
} else {
tagstr = tagstr + ",node:" + hostname + ",interface:" + iface + ",snaplength:" + strconv.Itoa(req.Snap)
}
if(config.Gen.Writelocal) {
ferr := ioutil.WriteFile(config.Gen.Localdir + "/" + fileName, f.Bytes(), 0644)
if(ferr != nil) {
fmt.Printf("Error writing file: %s", ferr)
log.Printf("Error writing file: %s", ferr)
} else {
log.Printf("Written locally file: %s", config.Gen.Localdir + "/" + fileName)
fmt.Printf("Written locally file: %s", config.Gen.Localdir + "/" + fileName)
}
}
if(config.Cs.Upload) {
log.Printf("Uploading to Cloudshark file: %s\n", fileName)
fmt.Printf("Uploading to Cloudshark file: %s\n", fileName)
postBufferCloudshark(config.Cs.Scheme, config.Cs.Host, config.Cs.Port, config.Cs.Token, config.Cs.Timeout, f, fileName, tagstr)
}
if(config.Aws.Upload) {
log.Printf("Uploading to S3 file: %s\n", fileName)
fmt.Printf("Uploading to S3 file: %s\n", fileName)
var msgfolder string
var msgbucket string
var msgacl string
var msgregion string
var msgep string
var msgenc bool
if(req.Bucket != "") {
msgbucket = req.Bucket
} else {
msgbucket = *config.Aws.Bucket
}
if(req.Folder != "") {
msgfolder = req.Folder
} else {
msgfolder = *config.Aws.Folder
}
if(req.Acl != "") {
msgacl = req.Acl
} else {
msgacl = *config.Aws.Acl
}
if(req.Region != "") {
msgregion = req.Region
} else {
msgregion = *config.Aws.Region
}
if(req.Endpoint != "") {
msgep = req.Endpoint
} else {
msgep = *config.Aws.Endpoint
}
fmt.Println("Enc: ", req.Encryption)
if(req.Encryption) {
msgenc = req.Encryption
} else {
msgenc = *config.Aws.Encryption
}
msgconfig := awsconfig
msgconfig.Region = &msgregion
msgconfig.Endpoint = &msgep
log.Printf("Uploading to S3 file: %s", msgbucket + ":" + msgfolder + "/" + fileName)
fmt.Printf("Uploading to S3 file: %s", msgbucket + ":" + msgfolder + "/" + fileName)
postS3(*msgconfig, msgbucket, f, fileName, tagstr, msgfolder, msgacl, msgenc)
}
fmt.Println("Returning from capture")
return
}