From 620e16bbd0f40a1089767a784d4e279e8a0a934a Mon Sep 17 00:00:00 2001 From: Neale Pickett Date: Mon, 23 Jul 2018 23:48:14 +0000 Subject: [PATCH] Start adding convenience --- gapstring/gapstring.go | 106 +++++++++++++++++++---------------------- packet.go | 53 ++++++++++++++------- stream.go | 29 +++++++---- 3 files changed, 108 insertions(+), 80 deletions(-) diff --git a/gapstring/gapstring.go b/gapstring/gapstring.go index 7f24df4..0dca1c4 100644 --- a/gapstring/gapstring.go +++ b/gapstring/gapstring.go @@ -1,9 +1,9 @@ package gapstring import ( + "bytes" "fmt" "encoding/binary" - "encoding/hex" "strings" "unicode/utf16" ) @@ -194,8 +194,25 @@ func (g GapString) String(fill string) string { return string(g.Bytes([]byte(fill)...)) } -func (g GapString) HexString(fill ...byte) string { - return hex.EncodeToString(g.Bytes(fill...)) +func (g GapString) HexString() string { + out := new(strings.Builder) + glen := g.Length() + for i := 0; i < glen; i += 1 { + c := g.ValueAt(i) + if c == -1 { + out.WriteString("--") + } else { + // There's probably a faster way to do this. Do we care? + fmt.Fprintf(out, "%02x", c) + } + if i + 1 < glen { + out.WriteRune(' ') + if i % 8 == 7 { + out.WriteRune(' ') + } + } + } + return out.String() } var fluffych = []rune{ @@ -216,70 +233,47 @@ var fluffych = []rune{ 'α', 'ß', 'Γ', 'π', 'Σ', 'σ', 'µ', 'τ', 'Φ', 'Θ', 'Ω', 'δ', '∞', 'φ', 'ε', '∩', '≡', '±', '≥', '≤', '⌠', '⌡', '÷', '≈', '°', '∀', '∃', '√', 'ⁿ', '²', '■', '¤', } +func (g GapString) Runes() string { + out := new(strings.Builder) + glen := g.Length() + for i := 0; i < glen; i += 1 { + c := g.ValueAt(i) + if c == -1 { + out.WriteRune('�') + } else { + out.WriteRune(fluffych[c]) + } + } + return out.String() +} + func (g GapString) Hexdump() string { out := new(strings.Builder) skipping := false glen := g.Length() pos := 0 + prev := []byte{} for ; pos < glen; { // Check for repeats - repeated := true - if (pos > 0) { - for i := 0; (i < 16) && (pos+i < glen); i += 1 { - if g.ValueAt(pos+i) != g.ValueAt(pos+i-16) { - repeated = false - break - } - } - if repeated { - if ! skipping { - fmt.Fprintln(out, "*") - skipping = true - } - pos += 16 - continue - } else { - skipping = false + end := pos + 16 + if end > glen { + end = glen + } + cur := g.Slice(pos, end) + curBytes := cur.Bytes() + if 0 == bytes.Compare(prev, curBytes) { + if ! skipping { + fmt.Fprintln(out, "*") + skipping = true } + continue } - // Output offset fmt.Fprintf(out, "%08x ", pos) - - // Output octet values - for i := 0; i < 16; i += 1 { - if pos+i < glen { - c := g.ValueAt(pos+i) - if c == -1 { - fmt.Fprintf(out, "-- ") - } else { - fmt.Fprintf(out, "%02x ", c) - } - } else { - fmt.Fprintf(out, " ") - } - if i == 7 { - fmt.Fprintf(out, " ") - } - } - - fmt.Fprintf(out, " ") - - - // Output octet glyphs - for i := 0; (i < 16) && (pos < glen); { - c := g.ValueAt(pos) - if c == -1 { - fmt.Fprintf(out, "�") - } else { - fmt.Fprintf(out, "%c", fluffych[c]) - } - i += 1 - pos += 1 - } - - // Output newline - fmt.Fprintln(out, "") + fmt.Fprintf(out, "%-50s", cur.HexString()) + fmt.Fprintln(out, cur.Runes()) + + pos += cur.Length() } fmt.Fprintf(out, "%08x\n", pos) diff --git a/packet.go b/packet.go index e723cd6..8eea74b 100644 --- a/packet.go +++ b/packet.go @@ -1,8 +1,8 @@ package netshovel import ( + "encoding/hex" "fmt" - "sort" "strings" "time" "github.com/dirtbags/netshovel/gapstring" @@ -10,51 +10,72 @@ import ( type PacketFactory func()Packet +type Field struct { + key, value string +} + type Packet struct { Name string Opcode int Description string When time.Time Payload gapstring.GapString - Fields map[string]string + Fields []Field } var never = time.Unix(0, 0) func NewPacket() Packet { return Packet{ - Name: "Generic", Opcode: -1, Description: "Undefined", When: never, Payload: gapstring.GapString{}, - Fields: map[string]string{}, + Fields: []Field{}, } } func (pkt *Packet) Describe() string { out := new(strings.Builder) - fmt.Fprintf(out, " %s %s %d: %s\n", + fmt.Fprintf(out, " %s Opcode %d: %s\n", pkt.When.UTC().Format(time.RFC3339Nano), - pkt.Name, pkt.Opcode, pkt.Description, ) - 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]) + + for _, f := range(pkt.Fields) { + fmt.Fprintf(out, " %s: %s\n", f.key, f.value) } fmt.Fprint(out, pkt.Payload.Hexdump()) return out.String() } + func (pkt *Packet) Set(key, value string) { - pkt.Fields[key] = value + pkt.Fields = append(pkt.Fields, Field{key, value}) +} + +func (pkt *Packet) SetString(key, value string) { + pkt.Set(key, fmt.Sprintf("%#v", value)) +} + +func (pkt *Packet) SetInt(key string, value int) { + pkt.Set(key, fmt.Sprintf("%d == 0x%x", value, value)) +} + +func (pkt *Packet) SetUint(key string, value uint) { + pkt.Set(key, fmt.Sprintf("%d == 0x%x", value, value)) +} + +func (pkt *Packet) SetUint32(key string, value uint32) { + pkt.Set(key, fmt.Sprintf("%d == 0x%04x", value, value)) +} + +func (pkt *Packet) SetBytes(key string, value []byte) { + pkt.Set(key, hex.EncodeToString(value)) +} + +func (pkt *Packet) SetGapString(key string, value gapstring.GapString) { + pkt.Set(key, fmt.Sprintf("%s %s", value.HexString(), value.Runes())) } diff --git a/stream.go b/stream.go index 72a3d36..12c418e 100644 --- a/stream.go +++ b/stream.go @@ -3,7 +3,8 @@ package netshovel import ( "fmt" "io" - "log" + "os" + "net/url" "strings" "time" "github.com/dirtbags/netshovel/gapstring" @@ -11,9 +12,9 @@ import ( "github.com/google/gopacket/tcpassembly" ) -type WriteAtCloser interface { - io.WriterAt - io.WriteCloser +type NamedFile struct { + *os.File + Name string } type Utterance struct { @@ -58,10 +59,6 @@ func (stream *Stream) ReassemblyComplete() { } func (stream *Stream) Read(length int) (Utterance, error) { - if length > 0x100000 { - log.Fatalf("FATAL: Trying to read 0x%x octets", length) - } - // Special case: length=-1 means "give me the next utterance" if length == -1 { if stream.pending.Data.Length() > 0 { @@ -111,3 +108,19 @@ func (stream *Stream) Describe(pkt Packet) string { out.WriteString(pkt.Describe()) return out.String() } + +func (stream *Stream) CreateFile(when time.Time, path string) (NamedFile, error) { + 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(), + url.PathEscape(path), + ) + f, err := os.Create(name) + outf := NamedFile{ + File: f, + Name: name, + } + return outf, err +}