netshovel

Network Archaeology library for Go
git clone https://git.woozle.org/neale/netshovel.git

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