Start trying to make it a library

This commit is contained in:
Neale Pickett 2018-07-23 09:58:31 -06:00
parent 22929176dd
commit 0da5aa7d09
4 changed files with 162 additions and 79 deletions

26
examples/simple/simple.go Normal file
View File

@ -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)
}

52
netshovel.go Normal file
View File

@ -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()
}

72
packet.go Normal file
View File

@ -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
}

View File

@ -16,9 +16,7 @@ import (
"github.com/google/gopacket/tcpassembly" "github.com/google/gopacket/tcpassembly"
) )
var verbose = flag.Bool("verbose", false, "Write lots of information out") var StreamWG sync.WaitGroup
var goRoutines sync.WaitGroup
type WriteAtCloser interface { type WriteAtCloser interface {
io.WriterAt io.WriterAt
@ -39,34 +37,14 @@ type Stream struct {
pending Utterance 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 { func (f *StreamFactory) New(net, transport gopacket.Flow) tcpassembly.Stream {
stream := &Stream{ stream := &Stream{
Net: net, Net: net,
Transport: transport, Transport: transport,
conversation: make(chan Utterance, 100), conversation: make(chan Utterance, 100),
} }
goRoutines.Add(1) StreamWG.Add(1)
go stream.run() go stream.Run(StreamWG)
return stream return stream
} }
@ -140,29 +118,18 @@ func (stream *Stream) Read(length int) (Utterance, error) {
func (stream *Stream) Describe(pkt Packet) string { func (stream *Stream) Describe(pkt Packet) string {
out := new(strings.Builder) out := new(strings.Builder)
fmt.Fprintf(out, "Opcode %d: %s\n", pkt.Opcode, pkt.Description) fmt.Fprintf(out, "%v:%v → %v:%v\n",
fmt.Fprintf(out, " %v:%v → %v:%v (%s)\n", stream.Net.Src().String(), stream.Transport.Src().String(),
stream.Net.Src().String(), stream.Transport.Src().String(), stream.Net.Dst().String(), stream.Transport.Dst().String()
stream.Net.Dst().String(), stream.Transport.Dst().String(), )
pkt.When.UTC().Format(time.RFC3339Nano)) out.writeString(pkt.Describe())
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())
return out.String() return out.String()
} }
func (stream *Stream) run() { func (stream *Stream) Run(wg sync.WaitGroup) {
defer goRoutines.Done() defer wg.Done()
for { for {
pkt, err := stream.buildPacket() pkt, err := stream.BuildPacket()
if err == io.EOF { if err == io.EOF {
return return
} else if err != nil { } 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() pkt := NewPacket()
utterance, err := stream.Read(-1) utterance, err := stream.Read(-1)
@ -186,37 +153,3 @@ func (stream *Stream) buildPacket() (Packet, error) {
pkt.When = utterance.When pkt.When = utterance.When
return pkt, nil 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()
}