-
Notifications
You must be signed in to change notification settings - Fork 8
/
reassembler.go
86 lines (70 loc) · 2.07 KB
/
reassembler.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
package zanarkand
import (
"bufio"
"encoding/binary"
"fmt"
"github.com/google/gopacket"
"github.com/google/gopacket/tcpassembly"
"github.com/google/gopacket/tcpassembly/tcpreader"
)
// reassembledPacket is a frame payload with TCP metadata
type reassembledPacket struct {
Body []byte
Flow gopacket.Flow
}
// reassembledChan is a byte channel to receive the length of a full frame
var reassembledChan = make(chan reassembledPacket, 200)
// frameStreamFactory implements tcpassembly.StreamFactory
type frameStreamFactory struct{}
// frameStream handles decoding TCP packets
type frameStream struct {
net, transport gopacket.Flow
r tcpreader.ReaderStream
}
// New implements StreamFactory.New(), acting as a Factory for each new Flow.
func (f *frameStreamFactory) New(net, transport gopacket.Flow) tcpassembly.Stream {
fs := &frameStream{
net: net,
transport: transport,
r: tcpreader.NewReaderStream(),
}
// Start the Stream or prepare to clench
go fs.run()
// ReaderStream implements tcpassembly.Stream so return a pointer to it
return &fs.r
}
// Run the stream, quickly
func (f *frameStream) run() {
var reader = bufio.NewReaderSize(&f.r, 128*1024)
for {
// Skip to start of a frame
err := discardUntilValid(reader)
if err != nil {
// #nosec G104
fmt.Errorf("error syncing Frame start position: %w", err)
return
}
// Grab the synced header bytes so we can make sure we have enough data
header, err := reader.Peek(frameHeaderLength)
if err != nil {
// #nosec G104
fmt.Errorf("can't peek into header bytes from buffer: %w", err)
return
}
// Make a buffer for the full Frame size
length := binary.LittleEndian.Uint32(header[24:28])
data := make([]byte, int(length))
count, err := reader.Read(data)
if err != nil {
// #nosec G104
fmt.Errorf("can't read %d bytes from buffer: %w", length, err)
return
}
if count != int(length) {
// #nosec G104
fmt.Errorf("read less data than expected: %d < %d", count, length)
return
}
reassembledChan <- reassembledPacket{Body: data, Flow: f.net}
}
}