-
Notifications
You must be signed in to change notification settings - Fork 4
/
capture.go
131 lines (115 loc) · 3.31 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
package main
import (
"bytes"
"os"
"time"
"github.com/rs/zerolog/log"
"github.com/gopacket/gopacket"
"github.com/gopacket/gopacket/layers"
"github.com/gopacket/gopacket/pcap"
"github.com/gopacket/gopacket/pcapgo"
"github.com/lunixbochs/struc"
)
type packetMetaDataKey struct {
LocalPort, RemotePort uint16
}
type packetMetaData struct {
Magic uint32 `struc:"int32"`
Pid uint32 `struc:"uint32"`
CmdLen uint8 `struc:"uint8,sizeof=Cmd"` // max Cmd is 255 chars
Cmd string
ArgsLen uint16 `struc:"uint16,sizeof=Args"` // max args is 65535 chars
Args string
}
func initializeLivePcap(devName, filter string) *pcap.Handle {
// Open device
handle, err := pcap.OpenLive(devName, 65536, true, pcap.BlockForever)
if err != nil {
log.Fatal().Msg(err.Error())
}
// Set Filter
log.Info().Msgf("Using Device: %s", devName)
log.Info().Msgf("Filter: %s", filter)
err = handle.SetBPFFilter(filter)
if err != nil {
log.Fatal().Msg(err.Error())
}
return handle
}
// blocking function to grab packets
func capture() {
// set up inpput handle
var outputHandle *pcapgo.NgWriter
if generalOptions.OutFile == "-" {
var err error
outputHandle, err = pcapgo.NewNgWriter(os.Stdout, 1)
if err != nil {
panic(err)
}
} else {
f, err := os.OpenFile(string(generalOptions.OutFile), os.O_RDWR|os.O_CREATE, 0o755)
if err != nil {
log.Warn().Msg(err.Error())
}
defer f.Close()
outputHandle, err = pcapgo.NewNgWriter(f, 1)
if err != nil {
panic(err)
}
// generate a packet
}
inputHandle := initializeLivePcap(generalOptions.Interface, generalOptions.Bpf)
for {
packet, _, err := inputHandle.ReadPacketData()
if err != nil {
log.Fatal().Msg(err.Error())
}
ethPacket := gopacket.NewPacket(
packet,
layers.LayerTypeEthernet,
gopacket.Default,
)
oldEthLayer := ethPacket.Layers()[0].(*layers.Ethernet)
// subtract oldethelayer from the begining of ethpacket
restOfLayers := ethPacket.Layers()[1:]
remainder := []byte{}
metadata := packetMetaData{}
for _, layer := range restOfLayers {
// we can correlate metadata only in TCP or UDP for now
remainder = append(remainder, layer.LayerContents()...)
if layer.LayerType() == layers.LayerTypeTCP {
tcpLayer := layer.(*layers.TCP)
metadata = lookupProcess(generalOptions.Verbosity, uint16(tcpLayer.SrcPort), uint16(tcpLayer.DstPort))
}
if layer.LayerType() == layers.LayerTypeUDP {
udpLayer := layer.(*layers.UDP)
metadata = lookupProcess(generalOptions.Verbosity, uint16(udpLayer.SrcPort), uint16(udpLayer.DstPort))
}
}
var packetTrailer bytes.Buffer
err = struc.Pack(&packetTrailer, &metadata)
if err != nil {
log.Warn().Msg(err.Error())
}
newEtherLayer := &EthernetWithTrailer{
SrcMAC: oldEthLayer.SrcMAC,
DstMAC: oldEthLayer.DstMAC,
EthernetType: oldEthLayer.EthernetType,
Trailer: packetTrailer.Bytes(),
}
buffer := gopacket.NewSerializeBuffer()
err = gopacket.SerializeLayers(buffer, gopacket.SerializeOptions{}, newEtherLayer, gopacket.Payload(remainder))
if err != nil {
log.Warn().Msg(err.Error())
}
err = outputHandle.WritePacket(gopacket.CaptureInfo{
Timestamp: time.Now(),
Length: len(buffer.Bytes()),
CaptureLength: len(buffer.Bytes()),
}, buffer.Bytes())
if err != nil {
panic(err)
}
outputHandle.Flush()
}
}