diff --git a/gapstring/gapstring.go b/gapstring/gapstring.go index 3140b9e..fdd339c 100644 --- a/gapstring/gapstring.go +++ b/gapstring/gapstring.go @@ -14,8 +14,8 @@ package gapstring import ( "bytes" - "fmt" "encoding/binary" + "fmt" "strings" "unicode/utf16" ) @@ -25,7 +25,7 @@ import ( // XXX: I'll have to fix it later; it doesn't matter much for performance type chunk struct { - gap int // This takes precedence over data + gap int // This takes precedence over data data []byte } @@ -135,11 +135,11 @@ func (g GapString) AppendString(s string) GapString { // if g were a string or byte slice. func (g GapString) Slice(start, end int) GapString { outchunks := make([]chunk, 0, len(g.chunks)) - + if end > g.Length() { panic("runtime error: slice bounds out of range") } - + for _, c := range g.chunks { chunklen := c.length() @@ -160,12 +160,12 @@ func (g GapString) Slice(start, end int) GapString { } start = 0 end -= cend - + if end == 0 { break } } - + return GapString{chunks: outchunks} } @@ -177,7 +177,7 @@ func (g GapString) Xor(mask ...byte) GapString { pos := 0 for _, c := range g.chunks { ret = ret.AppendGap(c.gap) - + out := make([]byte, len(c.data)) for i, b := range c.data { m := mask[(pos+i)%len(mask)] @@ -198,7 +198,7 @@ func (g GapString) Bytes(fill ...byte) []byte { // Fill in gap if len(fill) > 0 { for i := 0; i < c.gap; i += 1 { - ret[pos] = fill[pos % len(fill)] + ret[pos] = fill[pos%len(fill)] pos += 1 } } @@ -243,9 +243,9 @@ func (g GapString) HexString() string { // There's probably a faster way to do this. Do we care? fmt.Fprintf(out, "%02x", c) } - if i + 1 < glen { + if i+1 < glen { out.WriteRune(' ') - if i % 8 == 7 { + if i%8 == 7 { out.WriteRune(' ') } } @@ -254,7 +254,7 @@ func (g GapString) HexString() string { } var fluffych = []rune{ - '·', '☺', '☻', '♥', '♦', '♣', '♠', '•', '◘', '○', '◙', '♂', '♀', '♪', '♫', '☼', + '·', '☺', '☻', '♥', '♦', '♣', '♠', '•', '◘', '○', '◙', '♂', '♀', '♪', '♫', '☼', '►', '◄', '↕', '‼', '¶', '§', '▬', '↨', '↑', '↓', '→', '←', '∟', '↔', '▲', '▼', ' ', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', @@ -298,7 +298,7 @@ func (g GapString) Hexdump() string { glen := g.Length() pos := 0 prev := []byte{} - for ; pos < glen; { + for pos < glen { // Check for repeats end := pos + 16 if end > glen { @@ -307,7 +307,7 @@ func (g GapString) Hexdump() string { cur := g.Slice(pos, end) curBytes := cur.Bytes() if 0 == bytes.Compare(prev, curBytes) { - if ! skipping { + if !skipping { fmt.Fprintln(out, "*") skipping = true } @@ -321,7 +321,7 @@ func (g GapString) Hexdump() string { pos += cur.Length() } fmt.Fprintf(out, "%08x\n", pos) - + return out.String() } @@ -343,7 +343,7 @@ func (g GapString) Uint16LE() (uint16, GapString) { func (g GapString) Utf16(order binary.ByteOrder, fill string) string { in := g.Bytes([]byte(fill)...) ints := make([]uint16, len(in)/2) - + for i := 0; i < len(in); i += 2 { ints[i/2] = order.Uint16(in[i:]) } @@ -361,4 +361,3 @@ func (g GapString) Utf16LE(gap string) string { func (g GapString) Utf16BE(gap string) string { return g.Utf16(binary.BigEndian, gap) } - diff --git a/gapstring/gapstring_test.go b/gapstring/gapstring_test.go index d9c0bf2..0cd018f 100644 --- a/gapstring/gapstring_test.go +++ b/gapstring/gapstring_test.go @@ -13,13 +13,13 @@ func assertEqual(t *testing.T, name string, a, b interface{}) { func TestChunk(t *testing.T) { var c chunk - + c = chunk{gap: 2} assertEqual(t, "gap chunk", c.length(), 2) - + c = chunk{data: []byte("moo")} assertEqual(t, "byte chunk", c.length(), 3) - assertEqual(t, "byte slice", string(c.slice(1,3).data), "oo") + assertEqual(t, "byte slice", string(c.slice(1, 3).data), "oo") } func TestGapString(t *testing.T) { @@ -36,12 +36,12 @@ func TestGapString(t *testing.T) { if g.Length() != 0 { t.Errorf("Appending two emtpy gapstrings") } - + g = g.AppendString("moo") if 0 != bytes.Compare(g.Bytes(), []byte("moo")) { t.Errorf("Simple string") } - + g = g.AppendString("bar") if g.String("") != "moobar" { t.Errorf("Append") @@ -49,7 +49,7 @@ func TestGapString(t *testing.T) { if g.Missing() != 0 { t.Errorf("Missing when there shouldn't be any missing") } - + g = g.AppendGap(8) if g.Length() != 3+3+8 { t.Errorf("Length after gap append") @@ -57,20 +57,20 @@ func TestGapString(t *testing.T) { if g.Missing() != 8 { t.Errorf("Gap miscounted") } - + g = g.AppendString("baz") assertEqual(t, "string", g.String(""), "moobarbaz") assertEqual(t, "string drop", g.String("DROP"), "moobarOPDROPDRbaz") assertEqual(t, "xor", g.Xor(1).String(""), "lnnc`sc`{") assertEqual(t, "xor drop", g.Xor(1).String("DROP"), "lnnc`sOPDROPDRc`{") - + assertEqual(t, "slice", g.Slice(2, 5).String(""), "oba") assertEqual(t, "slice+xor", g.Slice(2, 5).Xor(1).String(""), "nc`") hexdump := "00000000 6d 6f 6f 62 61 72 -- -- -- -- -- -- -- -- 62 61 moobar��������ba\n" + - "00000010 7a z\n" + - "00000011\n" + "00000010 7a z\n" + + "00000011\n" assertEqual(t, "hexdump", g.Hexdump(), hexdump) } diff --git a/netshovel.go b/netshovel.go index c9b01ff..5a74993 100644 --- a/netshovel.go +++ b/netshovel.go @@ -10,11 +10,11 @@ package netshovel import ( "flag" - "log" "github.com/google/gopacket" "github.com/google/gopacket/layers" "github.com/google/gopacket/pcap" "github.com/google/gopacket/tcpassembly" + "log" ) // Mainloop to handle dispatching of PCAP files from command line @@ -25,16 +25,16 @@ import ( 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() for packet := range packets { diff --git a/packet.go b/packet.go index b5e1622..084207c 100644 --- a/packet.go +++ b/packet.go @@ -4,16 +4,17 @@ import ( "encoding/binary" "encoding/hex" "fmt" + "github.com/dirtbags/netshovel/gapstring" "strings" "time" - "github.com/dirtbags/netshovel/gapstring" ) // Error returned by convenience methods that are unable to get enough data type ShortError struct { - Wanted int // How many bytes you needed + Wanted int // How many bytes you needed Available int // How many bytes were available } + func (e *ShortError) Error() string { return fmt.Sprintf("Short read: wanted %d of %d available", e.wanted, e.available) } @@ -21,6 +22,7 @@ func (e *ShortError) Error() string { // Error returned by convenience methods that are unable to operate on gaps in data type MissingError struct { } + func (e *MissingError) Error() string { return "Operation on missing bytes" } @@ -32,8 +34,8 @@ type namedField struct { // An application protocol header field type headerField struct { - name string - bits int + name string + bits int value interface{} order binary.ByteOrder } @@ -46,12 +48,12 @@ type headerField struct { // and // documenting header structure. type Packet struct { - Opcode int + Opcode int Description string - When time.Time - Payload gapstring.GapString - header []headerField - fields []namedField + When time.Time + Payload gapstring.GapString + header []headerField + fields []namedField } var never = time.Unix(0, 0) @@ -59,12 +61,12 @@ var never = time.Unix(0, 0) // Return a new packet func NewPacket() Packet { return Packet{ - Opcode: -1, + Opcode: -1, Description: "Undefined", - When: never, - Payload: gapstring.GapString{}, - header: []headerField{}, - fields: []namedField{}, + When: never, + Payload: gapstring.GapString{}, + header: []headerField{}, + fields: []namedField{}, } } @@ -76,12 +78,12 @@ func (pkt *Packet) Describe() string { out := new(strings.Builder) fmt.Fprintf(out, " %s Opcode %d: %s\n", - pkt.When.UTC().Format(time.RFC3339Nano), + pkt.When.UTC().Format(time.RFC3339Nano), pkt.Opcode, pkt.Description, ) - - for _, f := range(pkt.Fields) { + + for _, f := range pkt.Fields { fmt.Fprintf(out, " %s: %s\n", f.key, f.value) } fmt.Fprint(out, pkt.Payload.Hexdump()) @@ -145,8 +147,8 @@ func (pkt *Packet) Peel(octets int) ([]byte, error) { // Add a field to the header field description func (pkt *Packet) AddHeaderField(order binary.ByteOrder, name string, bits int, value interface{}) { h := headerField{ - name: name, - bits: bits, + name: name, + bits: bits, value: value, order: order, } @@ -161,28 +163,28 @@ func (pkt *Packet) readUint(order binary.ByteOrder, bits int, name string) (inte case 32: case 64: default: - return 0, fmt.Errorf("Weird number of bits: %d", bits) + return 0, fmt.Errorf("Weird number of bits: %d", bits) } - + octets := bits >> 3 b, err := pkt.Peel(octets) if err != nil { return 0, err } - + var value interface{} switch bits { case 8: - value = b[0] + value = b[0] case 16: value = order.Uint16(b) case 32: - value = order.Uint32(b) + value = order.Uint32(b) case 64: - value = order.Uint64(b) + value = order.Uint64(b) } pkt.AddheaderField(order, name, bits, value) - + return value, nil } @@ -248,4 +250,3 @@ func (pkt *Packet) Uint8(name string) (uint8, error) { } return value.(uint8), err } - diff --git a/stream.go b/stream.go index 5e736b1..52e32ec 100644 --- a/stream.go +++ b/stream.go @@ -2,14 +2,14 @@ package netshovel import ( "fmt" - "io" - "os" - "net/url" - "strings" - "time" "github.com/dirtbags/netshovel/gapstring" "github.com/google/gopacket" "github.com/google/gopacket/tcpassembly" + "io" + "net/url" + "os" + "strings" + "time" ) // A File and the path where it lives @@ -34,8 +34,8 @@ type Utterance struct { // A Stream is one half of a two-way conversation type Stream struct { Net, Transport gopacket.Flow - conversation chan Utterance - pending Utterance + conversation chan Utterance + pending Utterance } // Return a newly-built Stream @@ -44,8 +44,8 @@ type Stream struct { // Use this to initialize the internal stuff netshovel needs. func NewStream(net, transport gopacket.Flow) Stream { return Stream{ - Net: net, - Transport: transport, + Net: net, + Transport: transport, conversation: make(chan Utterance, 100), } } @@ -61,7 +61,7 @@ func (stream *Stream) Reassembled(rs []tcpassembly.Reassembly) { } ret.Data = ret.Data.AppendBytes(r.Bytes) } - + // Throw away utterances with no data (SYN, ACK, FIN, &c) if ret.Data.Length() > 0 { stream.conversation <- ret @@ -90,7 +90,7 @@ func (stream *Stream) Read(length int) (Utterance, error) { if length == 0 { return Utterance{}, nil } - + // Special case: length=-1 means "give me the next utterance" if length == -1 { var ret Utterance @@ -99,8 +99,8 @@ func (stream *Stream) Read(length int) (Utterance, error) { ret = stream.pending stream.pending.Data = gapstring.GapString{} } else { - r, more := <- stream.conversation - if ! more { + r, more := <-stream.conversation + if !more { err = io.EOF } ret = r @@ -111,8 +111,8 @@ func (stream *Stream) Read(length int) (Utterance, error) { // Pull in utterances until we have enough data. // .When will always be the timestamp on the last received utterance for stream.pending.Data.Length() < length { - u, more := <- stream.conversation - if ! more { + u, more := <-stream.conversation + if !more { break } stream.pending.Data = stream.pending.Data.Append(u.Data) @@ -124,7 +124,7 @@ func (stream *Stream) Read(length int) (Utterance, error) { if pendingLen == 0 { return Utterance{}, io.EOF } - + sliceLen := length if sliceLen > pendingLen { sliceLen = pendingLen @@ -145,9 +145,9 @@ func (stream *Stream) Describe(pkt Packet) string { 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()) + stream.Net.Dst().String(), stream.Transport.Dst().String(), + ) + out.WriteString(pkt.Describe()) return out.String() } @@ -160,17 +160,17 @@ func (stream *Stream) Describe(pkt Packet) string { // Best practice is to pass in as full a path as you can find, // including drive letters and all parent directories. func (stream *Stream) CreateFile(when time.Time, path string) (NamedFile, error) { - name := fmt.Sprintf( + name := fmt.Sprintf( "xfer/%s,%sp%s,%sp%s,%s", when.UTC().Format(time.RFC3339Nano), stream.Net.Src().String(), stream.Transport.Src().String(), - stream.Net.Dst().String(), stream.Transport.Dst().String(), + stream.Net.Dst().String(), stream.Transport.Dst().String(), url.PathEscape(path), ) - f, err := os.Create(name) - outf := NamedFile{ - File: f, - Name: name, - } - return outf, err + f, err := os.Create(name) + outf := NamedFile{ + File: f, + Name: name, + } + return outf, err }