Neale Pickett
·
2020-09-24
hk_test.go
1// hk_test is a start at a decoder I was writing, which exhibited some problems.
2// It also illustrates what a real decoder might look like.
3
4package netshovel
5
6import (
7 "fmt"
8 "io"
9 "log"
10 "strings"
11 "sync"
12 "testing"
13
14 "github.com/google/gopacket"
15 "github.com/google/gopacket/tcpassembly"
16)
17
18var wg sync.WaitGroup
19
20// HKStreamFactory generates HKStreams.
21type HKStreamFactory struct {
22 err *error
23}
24
25// New returns a new HKStream.
26func (f *HKStreamFactory) New(net, transport gopacket.Flow) tcpassembly.Stream {
27 stream := &HKStream{
28 Stream: NewStream(net, transport),
29 err: f.err,
30 }
31 wg.Add(1)
32 go stream.Decode(&wg)
33
34 return stream
35}
36
37// HKStream represents half of a TCP Stream.
38type HKStream struct {
39 *Stream
40 err *error
41}
42
43func (stream HKStream) Read(length int) (Utterance, error) {
44 u, err := stream.Stream.Read(length)
45 return u, err
46}
47
48// DisplayUtterance prints an unparsed TCP utterance
49func (stream HKStream) DisplayUtterance(u Utterance) {
50 fmt.Printf("Unparsed %v:%v → %v:%v\n",
51 stream.Net.Src().String(), stream.Transport.Src().String(),
52 stream.Net.Dst().String(), stream.Transport.Dst().String(),
53 )
54 fmt.Println(u.Data.Hexdump())
55}
56
57// Display prints as much about an HKPacket as we are able to determine.
58func (stream HKStream) Display(pkt HKPacket) {
59 out := new(strings.Builder)
60
61 fmt.Fprintf(out, "HK %v:%v → %v:%v\n",
62 stream.Net.Src().String(), stream.Transport.Src().String(),
63 stream.Net.Dst().String(), stream.Transport.Dst().String(),
64 )
65 out.WriteString(pkt.Describe())
66 fmt.Println(out.String())
67}
68
69// Decode decodes all data from the stream.
70func (stream HKStream) Decode(wg *sync.WaitGroup) {
71 defer wg.Done()
72 for {
73 utterance, err := stream.Read(2)
74 if err == io.EOF {
75 return
76 } else if err != nil {
77 log.Println(err)
78 return
79 }
80
81 // Was it actually HK?
82 if utterance.Data.String("DROP") != "HK" {
83 u, err := stream.Read(-1)
84 if err != nil {
85 log.Println(err)
86 return
87 }
88
89 if utterance.When != u.When {
90 stream.DisplayUtterance(utterance)
91 utterance = u
92 *stream.err = fmt.Errorf("Short length on non-HK packet, and a different utterance was returned")
93 } else {
94 utterance.Data = utterance.Data.Append(u.Data)
95 }
96 if utterance.Data.Length() < 10 {
97 *stream.err = fmt.Errorf("Short length on non-HK packet")
98 return
99 }
100 stream.DisplayUtterance(utterance)
101 continue
102 }
103
104 pkt := NewHKPacket(utterance)
105 if err := pkt.Decode(stream); err != nil {
106 log.Println(err)
107 return
108 }
109 stream.Display(pkt)
110 }
111}
112
113// NewHKPacket returns a shiny new HKPacket.
114func NewHKPacket(u Utterance) HKPacket {
115 pkt := HKPacket{
116 Packet: NewPacket(),
117 }
118 pkt.Payload = u.Data
119 pkt.When = u.When
120 return pkt
121}
122
123// HKPacket is a single HK packet.
124type HKPacket struct {
125 Packet
126}
127
128// Decode from a readable
129func (pkt *HKPacket) Decode(stream HKStream) error {
130 header, err := stream.Read(9)
131 if err != nil {
132 return err
133 }
134 pkt.Payload = header.Data
135
136 unknown, _ := pkt.Uint32BE("unknown")
137 length, _ := pkt.Uint32BE("length")
138 opcode, _ := pkt.Uint8("opcode")
139 pkt.Opcode = int(opcode)
140
141 if unknown != 0 {
142 return fmt.Errorf("unknown header was actually %d", unknown)
143 }
144 if length > 100 {
145 return fmt.Errorf("Length too big: %d", length)
146 }
147
148 body, err := stream.Read(int(length - 9 - 2))
149 if err != nil {
150 return err
151 }
152 pkt.Payload = body.Data
153
154 subcode, _ := pkt.Uint8("subcode")
155 if subcode != 0 {
156 return fmt.Errorf("Subcode not zero: %d", subcode)
157 }
158 pkt.SetString("Payload", pkt.Payload.String("DROP"))
159
160 switch pkt.Opcode {
161 case 7:
162 pkt.Description = "Keepalive"
163 }
164
165 return nil
166}
167
168func TestHK(t *testing.T) {
169 factory := HKStreamFactory{err: new(error)}
170 streamPool := tcpassembly.NewStreamPool(&factory)
171 assembler := tcpassembly.NewAssembler(streamPool)
172 ShovelFile("testdata/hk.pcap", assembler)
173 assembler.FlushAll()
174 wg.Wait()
175
176 if *factory.err != nil {
177 t.Error(*factory.err)
178 }
179}