From 0da5aa7d09f8ea737aacf6c906cfdb2e4cefe5da Mon Sep 17 00:00:00 2001 From: Neale Pickett Date: Mon, 23 Jul 2018 09:58:31 -0600 Subject: [PATCH] Start trying to make it a library --- examples/simple/simple.go | 26 +++++++++++ netshovel.go | 52 ++++++++++++++++++++++ packet.go | 72 ++++++++++++++++++++++++++++++ dumbdecode.go => stream.go | 91 +++++--------------------------------- 4 files changed, 162 insertions(+), 79 deletions(-) create mode 100644 examples/simple/simple.go create mode 100644 netshovel.go create mode 100644 packet.go rename dumbdecode.go => stream.go (57%) diff --git a/examples/simple/simple.go b/examples/simple/simple.go new file mode 100644 index 0000000..b08ffb2 --- /dev/null +++ b/examples/simple/simple.go @@ -0,0 +1,26 @@ +package main + +import ( + "github.com/dirtbags/netshovel" +) + +struct SimpleStreamFactory { + netshovel.Factory +} + +struct SimpleStream { + netshovel.Stream +} + +func (f *SimpleStreamFactory) New(net, transport gopacket.Flow) tcpassembly.Stream { + ret = SimpleStream{} + ret.Stream = f.Factory.New(net, transport) +} + +struct SimplePacket { + netshovel.Packet +} + +func main() { + netshovel.Shovel(SimpleFactory) +} diff --git a/netshovel.go b/netshovel.go new file mode 100644 index 0000000..8b136bf --- /dev/null +++ b/netshovel.go @@ -0,0 +1,52 @@ +package main + +import ( + "flag" + "fmt" + "io" + "log" + "sort" + "strings" + "sync" + "time" + "github.com/dirtbags/netshovel/gapstring" + "github.com/google/gopacket" + "github.com/google/gopacket/layers" + "github.com/google/gopacket/pcap" + "github.com/google/gopacket/tcpassembly" +) + + +func Shovel(factory tcpassembly.StreamFactory) { + verbose := flag.Bool("verbose", false, "Write lots of information out") + flag.Parse() + + streamPool := tcpassembly.NewStreamPool(factory) + assembler := tcpassembly.NewAssembler(streamPool) + + for _, fn := range flag.Args() { + handle, err := pcap.OpenOffline(fn) + if err != nil { + log.Fatal(err) + } + + packetSource := gopacket.NewPacketSource(handle, handle.LinkType()) + packets := packetSource.Packets() + npackets := 0 + for packet := range packets { + if packet == nil { + break + } + if packet.NetworkLayer() == nil || packet.TransportLayer() == nil || packet.TransportLayer().LayerType() != layers.LayerTypeTCP { + log.Println("Unusable packet") + continue + } + tcp := packet.TransportLayer().(*layers.TCP) + assembler.AssembleWithTimestamp(packet.NetworkLayer().NetworkFlow(), tcp, packet.Metadata().Timestamp) + npackets += 1 + } + log.Println("npackets", npackets) + } + assembler.FlushAll() + goRoutines.Wait() +} diff --git a/packet.go b/packet.go new file mode 100644 index 0000000..6398940 --- /dev/null +++ b/packet.go @@ -0,0 +1,72 @@ +package main + +import ( + "flag" + "fmt" + "io" + "log" + "sort" + "strings" + "sync" + "time" + "github.com/dirtbags/netshovel/gapstring" + "github.com/google/gopacket" + "github.com/google/gopacket/layers" + "github.com/google/gopacket/pcap" + "github.com/google/gopacket/tcpassembly" +) + +type Packet struct { + Opcode int + Description string + When time.Time + Payload gapstring.GapString + Fields map[string]string +} + +var never = time.Unix(0, 0) + +func NewPacket() Packet { + return Packet{ + Opcode: -1, + Description: "Undefined", + When: never, + Payload: gapstring.GapString{}, + Fields: map[string]string{}, + } +} + +func (pkt *Packet) Name() string { + return "Generic" +} + +func (pkt *Packet) Describe() string { + out := new(strings.Builder) + + fmt.Fprintf(out, "%s %s %d: %s\n", + pkt.When.UTC().Format(tim.RFC3339Nano), + pkt.Name(), + pkt.Opcode, + pkt.Description, + ) + for _, k := range pkt.Keys() { + fmt.Fprintf(out, " %s: %s\n", k, pkt.Fields[k]) + } + fmt.Fprint(out, pkt.Payload.Hexdump()) + return out.String() +} + +func (pkt *Packet) Set(key, value string) { + pkt.Fileds[key] = value +} + +func (pkt *Packet) Keys() { + keys := make([]string, len(pkt.Fields)) + i := 0 + for k := range(pkt.Fields) { + keys[i] = k + i += 1 + } + sort.Strings(keys) + return keys +} diff --git a/dumbdecode.go b/stream.go similarity index 57% rename from dumbdecode.go rename to stream.go index 6ecbaf6..96363a1 100644 --- a/dumbdecode.go +++ b/stream.go @@ -16,9 +16,7 @@ import ( "github.com/google/gopacket/tcpassembly" ) -var verbose = flag.Bool("verbose", false, "Write lots of information out") - -var goRoutines sync.WaitGroup +var StreamWG sync.WaitGroup type WriteAtCloser interface { io.WriterAt @@ -39,34 +37,14 @@ type Stream struct { pending Utterance } -type Packet struct { - Opcode int - Description string - When time.Time - Payload gapstring.GapString - Fields map[string]string -} - -var noTime = time.Unix(0, 0) - -func NewPacket() Packet { - return Packet{ - Opcode: -1, - Description: "Undefined", - When: noTime, - Payload: gapstring.GapString{}, - Fields: map[string]string{}, - } -} - func (f *StreamFactory) New(net, transport gopacket.Flow) tcpassembly.Stream { stream := &Stream{ Net: net, Transport: transport, conversation: make(chan Utterance, 100), } - goRoutines.Add(1) - go stream.run() + StreamWG.Add(1) + go stream.Run(StreamWG) return stream } @@ -140,29 +118,18 @@ func (stream *Stream) Read(length int) (Utterance, error) { func (stream *Stream) Describe(pkt Packet) string { out := new(strings.Builder) - fmt.Fprintf(out, "Opcode %d: %s\n", pkt.Opcode, pkt.Description) - fmt.Fprintf(out, " %v:%v → %v:%v (%s)\n", - stream.Net.Src().String(), stream.Transport.Src().String(), - stream.Net.Dst().String(), stream.Transport.Dst().String(), - pkt.When.UTC().Format(time.RFC3339Nano)) - keys := make([]string, len(pkt.Fields)) - i := 0 - for k := range(pkt.Fields) { - keys[i] = k - i += 1 - } - sort.Strings(keys) - for _, k := range keys { - fmt.Fprintf(out, " %s: %s\n", k, pkt.Fields[k]) - } - fmt.Fprint(out, pkt.Payload.Hexdump()) + fmt.Fprintf(out, "%v:%v → %v:%v\n", + stream.Net.Src().String(), stream.Transport.Src().String(), + stream.Net.Dst().String(), stream.Transport.Dst().String() + ) + out.writeString(pkt.Describe()) return out.String() } -func (stream *Stream) run() { - defer goRoutines.Done() +func (stream *Stream) Run(wg sync.WaitGroup) { + defer wg.Done() for { - pkt, err := stream.buildPacket() + pkt, err := stream.BuildPacket() if err == io.EOF { return } else if err != nil { @@ -174,7 +141,7 @@ func (stream *Stream) run() { } } -func (stream *Stream) buildPacket() (Packet, error) { +func (stream *Stream) BuildPacket() (Packet, error) { pkt := NewPacket() utterance, err := stream.Read(-1) @@ -186,37 +153,3 @@ func (stream *Stream) buildPacket() (Packet, error) { pkt.When = utterance.When return pkt, nil } - -func main() { - flag.Parse() - - streamFactory := &StreamFactory{} - streamPool := tcpassembly.NewStreamPool(streamFactory) - assembler := tcpassembly.NewAssembler(streamPool) - - for _, fn := range flag.Args() { - handle, err := pcap.OpenOffline(fn) - if err != nil { - log.Fatal(err) - } - - packetSource := gopacket.NewPacketSource(handle, handle.LinkType()) - packets := packetSource.Packets() - npackets := 0 - for packet := range packets { - if packet == nil { - break - } - if packet.NetworkLayer() == nil || packet.TransportLayer() == nil || packet.TransportLayer().LayerType() != layers.LayerTypeTCP { - log.Println("Unusable packet") - continue - } - tcp := packet.TransportLayer().(*layers.TCP) - assembler.AssembleWithTimestamp(packet.NetworkLayer().NetworkFlow(), tcp, packet.Metadata().Timestamp) - npackets += 1 - } - log.Println("npackets", npackets) - } - assembler.FlushAll() - goRoutines.Wait() -}