Seems to be working now
This commit is contained in:
parent
089627a480
commit
899e425e76
|
@ -0,0 +1,13 @@
|
||||||
|
This software has been authored by an employee or employees of Los
|
||||||
|
Alamos National Security, LLC, operator of the Los Alamos National
|
||||||
|
Laboratory (LANL) under Contract No. DE-AC52-06NA25396 with the
|
||||||
|
U.S. Department of Energy. The U.S. Government has rights to use,
|
||||||
|
reproduce, and distribute this software. The public may copy,
|
||||||
|
distribute, prepare derivative works and publicly display this
|
||||||
|
software without charge, provided that this Notice and any
|
||||||
|
statement of authorship are reproduced on all copies. Neither the
|
||||||
|
Government nor LANS makes any warranty, express or implied, or
|
||||||
|
assumes any liability or responsibility for the use of this
|
||||||
|
software. If software is modified to produce derivative works,
|
||||||
|
such modified software should be clearly marked, so as not to
|
||||||
|
confuse it with the version available from LANL.
|
|
@ -0,0 +1,28 @@
|
||||||
|
Dirtbags Netshovel Library
|
||||||
|
==========================
|
||||||
|
|
||||||
|
This is a library for advanced
|
||||||
|
[network archaeology](https://sites.google.com/view/cyberfire/foundry/classes/network-archaeology).
|
||||||
|
|
||||||
|
It provides a field-tested framework for
|
||||||
|
exploring unknown TCP-based protocols,
|
||||||
|
and room to grow these explorations into full-blown decoders.
|
||||||
|
|
||||||
|
|
||||||
|
Get going
|
||||||
|
=========
|
||||||
|
|
||||||
|
Documentation sucks, sorry.
|
||||||
|
Start with `examples/simple` and build it up into whatever you want.
|
||||||
|
|
||||||
|
|
||||||
|
The Future
|
||||||
|
==========
|
||||||
|
|
||||||
|
This is my first real Go program,
|
||||||
|
so it is likely to change drastically
|
||||||
|
as I figure out how to better architect Go libraries.
|
||||||
|
|
||||||
|
We strongly encourage you to bring in whatever version of this you're using
|
||||||
|
under a [vendor folder](https://blog.gopheracademy.com/advent-2015/vendor-folder/)
|
||||||
|
and check it in.
|
|
@ -1,26 +1,77 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"github.com/google/gopacket"
|
||||||
|
"github.com/google/gopacket/tcpassembly"
|
||||||
"github.com/dirtbags/netshovel"
|
"github.com/dirtbags/netshovel"
|
||||||
)
|
)
|
||||||
|
|
||||||
struct SimpleStreamFactory {
|
var wg sync.WaitGroup
|
||||||
netshovel.Factory
|
|
||||||
|
type SimpleStreamFactory struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SimpleStream {
|
type SimpleStream struct {
|
||||||
netshovel.Stream
|
netshovel.Stream
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *SimpleStreamFactory) New(net, transport gopacket.Flow) tcpassembly.Stream {
|
type SimplePacket struct {
|
||||||
ret = SimpleStream{}
|
|
||||||
ret.Stream = f.Factory.New(net, transport)
|
|
||||||
}
|
|
||||||
|
|
||||||
struct SimplePacket {
|
|
||||||
netshovel.Packet
|
netshovel.Packet
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func NewSimplePacket() SimplePacket {
|
||||||
netshovel.Shovel(SimpleFactory)
|
return SimplePacket{
|
||||||
|
Packet: netshovel.NewPacket(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *SimpleStreamFactory) New(net, transport gopacket.Flow) tcpassembly.Stream {
|
||||||
|
stream := &SimpleStream{
|
||||||
|
Stream: netshovel.NewStream(net, transport),
|
||||||
|
}
|
||||||
|
wg.Add(1)
|
||||||
|
go stream.Decode(wg)
|
||||||
|
|
||||||
|
return stream
|
||||||
|
}
|
||||||
|
|
||||||
|
func (stream SimpleStream) Display(pkt SimplePacket) {
|
||||||
|
out := new(strings.Builder)
|
||||||
|
|
||||||
|
fmt.Fprintf(out, "Simple %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())
|
||||||
|
fmt.Println(out.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (stream SimpleStream) Decode(wg sync.WaitGroup) {
|
||||||
|
defer wg.Done()
|
||||||
|
for {
|
||||||
|
pkt := NewSimplePacket()
|
||||||
|
|
||||||
|
|
||||||
|
utterance, err := stream.Read(-1)
|
||||||
|
if err != nil {
|
||||||
|
if err != io.EOF {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
pkt.Payload = utterance.Data
|
||||||
|
pkt.When = utterance.When
|
||||||
|
stream.Display(pkt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
netshovel.Shovel(&SimpleStreamFactory{})
|
||||||
|
wg.Wait()
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package gapstring
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"encoding/hex"
|
||||||
"strings"
|
"strings"
|
||||||
"unicode/utf16"
|
"unicode/utf16"
|
||||||
)
|
)
|
||||||
|
@ -193,6 +194,10 @@ func (g GapString) String(fill string) string {
|
||||||
return string(g.Bytes([]byte(fill)...))
|
return string(g.Bytes([]byte(fill)...))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (g GapString) HexString(fill ...byte) string {
|
||||||
|
return hex.EncodeToString(g.Bytes(fill...))
|
||||||
|
}
|
||||||
|
|
||||||
var fluffych = []rune{
|
var fluffych = []rune{
|
||||||
'·', '☺', '☻', '♥', '♦', '♣', '♠', '•', '◘', '○', '◙', '♂', '♀', '♪', '♫', '☼',
|
'·', '☺', '☻', '♥', '♦', '♣', '♠', '•', '◘', '○', '◙', '♂', '♀', '♪', '♫', '☼',
|
||||||
'►', '◄', '↕', '‼', '¶', '§', '▬', '↨', '↑', '↓', '→', '←', '∟', '↔', '▲', '▼',
|
'►', '◄', '↕', '‼', '¶', '§', '▬', '↨', '↑', '↓', '→', '←', '∟', '↔', '▲', '▼',
|
||||||
|
@ -212,7 +217,7 @@ var fluffych = []rune{
|
||||||
'≡', '±', '≥', '≤', '⌠', '⌡', '÷', '≈', '°', '∀', '∃', '√', 'ⁿ', '²', '■', '¤',
|
'≡', '±', '≥', '≤', '⌠', '⌡', '÷', '≈', '°', '∀', '∃', '√', 'ⁿ', '²', '■', '¤',
|
||||||
}
|
}
|
||||||
func (g GapString) Hexdump() string {
|
func (g GapString) Hexdump() string {
|
||||||
var out strings.Builder
|
out := new(strings.Builder)
|
||||||
skipping := false
|
skipping := false
|
||||||
glen := g.Length()
|
glen := g.Length()
|
||||||
pos := 0
|
pos := 0
|
||||||
|
@ -228,7 +233,7 @@ func (g GapString) Hexdump() string {
|
||||||
}
|
}
|
||||||
if repeated {
|
if repeated {
|
||||||
if ! skipping {
|
if ! skipping {
|
||||||
fmt.Fprintln(&out, "*")
|
fmt.Fprintln(out, "*")
|
||||||
skipping = true
|
skipping = true
|
||||||
}
|
}
|
||||||
pos += 16
|
pos += 16
|
||||||
|
@ -239,44 +244,44 @@ func (g GapString) Hexdump() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Output offset
|
// Output offset
|
||||||
fmt.Fprintf(&out, "%08x ", pos)
|
fmt.Fprintf(out, "%08x ", pos)
|
||||||
|
|
||||||
// Output octet values
|
// Output octet values
|
||||||
for i := 0; i < 16; i += 1 {
|
for i := 0; i < 16; i += 1 {
|
||||||
if pos+i < glen {
|
if pos+i < glen {
|
||||||
c := g.ValueAt(pos+i)
|
c := g.ValueAt(pos+i)
|
||||||
if c == -1 {
|
if c == -1 {
|
||||||
fmt.Fprintf(&out, "-- ")
|
fmt.Fprintf(out, "-- ")
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(&out, "%02x ", c)
|
fmt.Fprintf(out, "%02x ", c)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(&out, " ")
|
fmt.Fprintf(out, " ")
|
||||||
}
|
}
|
||||||
if i == 7 {
|
if i == 7 {
|
||||||
fmt.Fprintf(&out, " ")
|
fmt.Fprintf(out, " ")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintf(&out, " ")
|
fmt.Fprintf(out, " ")
|
||||||
|
|
||||||
|
|
||||||
// Output octet glyphs
|
// Output octet glyphs
|
||||||
for i := 0; (i < 16) && (pos < glen); {
|
for i := 0; (i < 16) && (pos < glen); {
|
||||||
c := g.ValueAt(pos)
|
c := g.ValueAt(pos)
|
||||||
if c == -1 {
|
if c == -1 {
|
||||||
fmt.Fprintf(&out, "<22>")
|
fmt.Fprintf(out, "<22>")
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(&out, "%c", fluffych[c])
|
fmt.Fprintf(out, "%c", fluffych[c])
|
||||||
}
|
}
|
||||||
i += 1
|
i += 1
|
||||||
pos += 1
|
pos += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
// Output newline
|
// Output newline
|
||||||
fmt.Fprintln(&out, "")
|
fmt.Fprintln(out, "")
|
||||||
}
|
}
|
||||||
fmt.Fprintf(&out, "%08x\n", pos)
|
fmt.Fprintf(out, "%08x\n", pos)
|
||||||
|
|
||||||
return out.String()
|
return out.String()
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,6 @@ func Shovel(factory tcpassembly.StreamFactory) {
|
||||||
|
|
||||||
packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
|
packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
|
||||||
packets := packetSource.Packets()
|
packets := packetSource.Packets()
|
||||||
npackets := 0
|
|
||||||
for packet := range packets {
|
for packet := range packets {
|
||||||
if packet == nil {
|
if packet == nil {
|
||||||
break
|
break
|
||||||
|
@ -35,10 +34,7 @@ func Shovel(factory tcpassembly.StreamFactory) {
|
||||||
}
|
}
|
||||||
tcp := packet.TransportLayer().(*layers.TCP)
|
tcp := packet.TransportLayer().(*layers.TCP)
|
||||||
assembler.AssembleWithTimestamp(packet.NetworkLayer().NetworkFlow(), tcp, packet.Metadata().Timestamp)
|
assembler.AssembleWithTimestamp(packet.NetworkLayer().NetworkFlow(), tcp, packet.Metadata().Timestamp)
|
||||||
npackets += 1
|
|
||||||
}
|
}
|
||||||
log.Println("npackets", npackets)
|
|
||||||
}
|
}
|
||||||
assembler.FlushAll()
|
assembler.FlushAll()
|
||||||
StreamWG.Wait()
|
|
||||||
}
|
}
|
||||||
|
|
32
packet.go
32
packet.go
|
@ -8,7 +8,10 @@ import (
|
||||||
"github.com/dirtbags/netshovel/gapstring"
|
"github.com/dirtbags/netshovel/gapstring"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type PacketFactory func()Packet
|
||||||
|
|
||||||
type Packet struct {
|
type Packet struct {
|
||||||
|
Name string
|
||||||
Opcode int
|
Opcode int
|
||||||
Description string
|
Description string
|
||||||
When time.Time
|
When time.Time
|
||||||
|
@ -20,6 +23,7 @@ var never = time.Unix(0, 0)
|
||||||
|
|
||||||
func NewPacket() Packet {
|
func NewPacket() Packet {
|
||||||
return Packet{
|
return Packet{
|
||||||
|
Name: "Generic",
|
||||||
Opcode: -1,
|
Opcode: -1,
|
||||||
Description: "Undefined",
|
Description: "Undefined",
|
||||||
When: never,
|
When: never,
|
||||||
|
@ -28,20 +32,23 @@ func NewPacket() Packet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pkt *Packet) Name() string {
|
|
||||||
return "Generic"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pkt *Packet) Describe() string {
|
func (pkt *Packet) Describe() string {
|
||||||
out := new(strings.Builder)
|
out := new(strings.Builder)
|
||||||
|
|
||||||
fmt.Fprintf(out, "%s %s %d: %s\n",
|
fmt.Fprintf(out, " %s %s %d: %s\n",
|
||||||
pkt.When.UTC().Format(time.RFC3339Nano),
|
pkt.When.UTC().Format(time.RFC3339Nano),
|
||||||
pkt.Name(),
|
pkt.Name,
|
||||||
pkt.Opcode,
|
pkt.Opcode,
|
||||||
pkt.Description,
|
pkt.Description,
|
||||||
)
|
)
|
||||||
for _, k := range pkt.Keys() {
|
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.Fprintf(out, " %s: %s\n", k, pkt.Fields[k])
|
||||||
}
|
}
|
||||||
fmt.Fprint(out, pkt.Payload.Hexdump())
|
fmt.Fprint(out, pkt.Payload.Hexdump())
|
||||||
|
@ -51,14 +58,3 @@ func (pkt *Packet) Describe() string {
|
||||||
func (pkt *Packet) Set(key, value string) {
|
func (pkt *Packet) Set(key, value string) {
|
||||||
pkt.Fields[key] = value
|
pkt.Fields[key] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pkt *Packet) Keys() []string{
|
|
||||||
keys := make([]string, len(pkt.Fields))
|
|
||||||
i := 0
|
|
||||||
for k := range(pkt.Fields) {
|
|
||||||
keys[i] = k
|
|
||||||
i += 1
|
|
||||||
}
|
|
||||||
sort.Strings(keys)
|
|
||||||
return keys
|
|
||||||
}
|
|
||||||
|
|
42
stream.go
42
stream.go
|
@ -5,15 +5,12 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
"github.com/dirtbags/netshovel/gapstring"
|
"github.com/dirtbags/netshovel/gapstring"
|
||||||
"github.com/google/gopacket"
|
"github.com/google/gopacket"
|
||||||
"github.com/google/gopacket/tcpassembly"
|
"github.com/google/gopacket/tcpassembly"
|
||||||
)
|
)
|
||||||
|
|
||||||
var StreamWG sync.WaitGroup
|
|
||||||
|
|
||||||
type WriteAtCloser interface {
|
type WriteAtCloser interface {
|
||||||
io.WriterAt
|
io.WriterAt
|
||||||
io.WriteCloser
|
io.WriteCloser
|
||||||
|
@ -24,25 +21,18 @@ type Utterance struct {
|
||||||
Data gapstring.GapString
|
Data gapstring.GapString
|
||||||
}
|
}
|
||||||
|
|
||||||
type StreamFactory struct {}
|
|
||||||
|
|
||||||
type Stream struct {
|
type Stream struct {
|
||||||
Net, Transport gopacket.Flow
|
Net, Transport gopacket.Flow
|
||||||
conversation chan Utterance
|
conversation chan Utterance
|
||||||
done chan bool
|
|
||||||
pending Utterance
|
pending Utterance
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *StreamFactory) New(net, transport gopacket.Flow) tcpassembly.Stream {
|
func NewStream(net, transport gopacket.Flow) Stream {
|
||||||
stream := &Stream{
|
return Stream{
|
||||||
Net: net,
|
Net: net,
|
||||||
Transport: transport,
|
Transport: transport,
|
||||||
conversation: make(chan Utterance, 100),
|
conversation: make(chan Utterance, 100),
|
||||||
}
|
}
|
||||||
StreamWG.Add(1)
|
|
||||||
go stream.Run(StreamWG)
|
|
||||||
|
|
||||||
return stream
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (stream *Stream) Reassembled(rs []tcpassembly.Reassembly) {
|
func (stream *Stream) Reassembled(rs []tcpassembly.Reassembly) {
|
||||||
|
@ -121,31 +111,3 @@ func (stream *Stream) Describe(pkt Packet) string {
|
||||||
out.WriteString(pkt.Describe())
|
out.WriteString(pkt.Describe())
|
||||||
return out.String()
|
return out.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (stream *Stream) Run(wg sync.WaitGroup) {
|
|
||||||
defer wg.Done()
|
|
||||||
for {
|
|
||||||
pkt, err := stream.BuildPacket()
|
|
||||||
if err == io.EOF {
|
|
||||||
return
|
|
||||||
} else if err != nil {
|
|
||||||
log.Println(err) // XXX: Print out 4-tuple identifying this stream
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println(stream.Describe(pkt))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (stream *Stream) BuildPacket() (Packet, error) {
|
|
||||||
pkt := NewPacket()
|
|
||||||
|
|
||||||
utterance, err := stream.Read(-1)
|
|
||||||
if err != nil {
|
|
||||||
return pkt, err
|
|
||||||
}
|
|
||||||
|
|
||||||
pkt.Payload = utterance.Data
|
|
||||||
pkt.When = utterance.When
|
|
||||||
return pkt, nil
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue