commit 2891cccd2f9ecaaa53bd3897d5962e96980324a1
parent 707e234349846c8aa9f5ace53518e88033627e31
Author: Oliver Lowe <o@olowe.co>
Date: Sun, 4 Aug 2024 19:17:10 +1000
pcap: store packet timestamp as a time.Time
Easier to work with.
Diffstat:
2 files changed, 49 insertions(+), 19 deletions(-)
diff --git a/pcap/parser.go b/pcap/parser.go
@@ -5,6 +5,7 @@ import (
"encoding/binary"
"fmt"
"io"
+ "time"
)
const (
@@ -22,12 +23,18 @@ type GlobalHeader struct {
}
type Header struct {
- TsSec uint32
- TsUsec uint32
+ Time time.Time
InclLen uint32
OrigLen uint32
}
+type header struct {
+ Seconds uint32
+ SubSeconds uint32 // micro or nanoseconds
+ InclLen uint32
+ OrigLen uint32
+}
+
type Packet struct {
Header Header
Data []byte
@@ -48,56 +55,68 @@ func decode(reader io.Reader) (*File, error) {
return nil, fmt.Errorf("unknown magic number %#x", magic)
}
- var header GlobalHeader
- if err := binary.Read(reader, binary.LittleEndian, &header); err != nil {
+ var gheader GlobalHeader
+ if err := binary.Read(reader, binary.LittleEndian, &gheader); err != nil {
return nil, fmt.Errorf("read global header: %w", err)
}
var packets []Packet
for i := 1; ; i++ {
- var header Header
- err := binary.Read(reader, binary.LittleEndian, &header)
+ var h header
+ err := binary.Read(reader, binary.LittleEndian, &h)
if err == io.EOF {
break
} else if err != nil {
return nil, fmt.Errorf("packet %d: read header: %w", i, err)
}
+ hh := Header{
+ Time: time.Unix(int64(h.Seconds), int64(h.SubSeconds)*1000),
+ InclLen: h.InclLen,
+ OrigLen: h.OrigLen,
+ }
- data := make([]byte, header.InclLen)
+ data := make([]byte, h.InclLen)
if _, err = io.ReadFull(reader, data); err != nil {
return nil, fmt.Errorf("packet %d: read data: %w", i, err)
}
packets = append(packets, Packet{
- Header: header,
+ Header: hh,
Data: data,
})
}
return &File{
- Header: header,
+ Header: gheader,
Packets: packets,
}, nil
}
func encode(file *File) ([]byte, error) {
- buf := new(bytes.Buffer)
- if err := binary.Write(buf, binary.NativeEndian, magicLittleEndian); err != nil {
- return nil, fmt.Errorf("write magic number: %w", err)
- }
-
+ b := make([]byte, 4)
+ binary.NativeEndian.PutUint32(b, magicLittleEndian)
+ buf := bytes.NewBuffer(b)
if err := binary.Write(buf, binary.LittleEndian, &file.Header); err != nil {
return nil, fmt.Errorf("global header: %v", err)
}
- for _, packet := range file.Packets {
- if err := binary.Write(buf, binary.LittleEndian, &packet.Header); err != nil {
- return nil, fmt.Errorf("Packet Header: %v", err)
+ for _, p := range file.Packets {
+ sec, nsec := timestamp(p.Header.Time)
+ usec := nsec / 1000
+ h := header{sec, usec, p.Header.InclLen, p.Header.OrigLen}
+ if err := binary.Write(buf, binary.LittleEndian, &h); err != nil {
+ return nil, fmt.Errorf("packet header: %v", err)
}
- if err := binary.Write(buf, binary.LittleEndian, &packet.Data); err != nil {
- return nil, fmt.Errorf("Packet Data: %v", err)
+ if err := binary.Write(buf, binary.LittleEndian, &p.Data); err != nil {
+ return nil, fmt.Errorf("packet data: %v", err)
}
}
return buf.Bytes(), nil
}
+
+func timestamp(t time.Time) (seconds, nanoSeconds uint32) {
+ seconds = uint32(t.Unix())
+ nanoSeconds = uint32(t.UnixNano() - t.Unix()*1e9)
+ return
+}
diff --git a/pcap/parser_test.go b/pcap/parser_test.go
@@ -4,6 +4,7 @@ import (
"fmt"
"os"
"testing"
+ "time"
)
func TestReadFile(t *testing.T) {
@@ -77,3 +78,13 @@ func TestReadFile(t *testing.T) {
}
}
+
+func TestTimestamp(t *testing.T) {
+ want := [2]uint32{1, 100}
+ when := time.Unix(1, 100)
+ sec, nsec := timestamp(when)
+ got := [2]uint32{sec, nsec}
+ if got != want {
+ t.Errorf("timestamp(%s) = %v, want %v", when, got, want)
+ }
+}