Implement a pcap writer.

This commit is contained in:
David Anderson 2016-02-27 20:25:43 -08:00
parent 67755cdc83
commit 7549f62395
5 changed files with 160 additions and 1 deletions

Binary file not shown.

View File

@ -73,7 +73,6 @@ func NewReader(r io.Reader) (*Reader, error) {
return nil, err
}
}
fmt.Printf("%x\n", header.Magic)
switch header.Magic {
case 0xa1b2c3d4:
// Timestamps are (sec, usec)

74
pcap/writer.go Normal file
View File

@ -0,0 +1,74 @@
package pcap
import (
"encoding/binary"
"io"
)
// Writer serializes Packets to an io.Writer.
type Writer struct {
Writer io.Writer
LinkType LinkType
SnapLen uint32
ByteOrder binary.ByteOrder // defaults to binary.LittleEndian
headerWritten bool
}
func (w *Writer) order() binary.ByteOrder {
if w.ByteOrder != nil {
return w.ByteOrder
}
return binary.LittleEndian
}
func (w *Writer) header() error {
hdr := struct {
Magic uint32
Major uint16
Minor uint16
Ignored uint64
Snaplen uint32
Type uint32
}{
Magic: 0xa1b23c4d,
Major: 2,
Minor: 4,
Snaplen: w.SnapLen,
Type: uint32(w.LinkType),
}
if err := binary.Write(w.Writer, w.order(), hdr); err != nil {
return err
}
w.headerWritten = true
return nil
}
// Put serializes pkt to w.Writer.
func (w *Writer) Put(pkt *Packet) error {
if !w.headerWritten {
if err := w.header(); err != nil {
return err
}
}
hdr := struct {
Sec uint32
NSec uint32
Len uint32
OrigLen uint32
}{
Sec: uint32(pkt.Timestamp.Unix()),
NSec: uint32(pkt.Timestamp.Nanosecond()),
Len: uint32(len(pkt.Bytes)),
OrigLen: uint32(pkt.Length),
}
if err := binary.Write(w.Writer, w.order(), hdr); err != nil {
return err
}
if _, err := w.Writer.Write(pkt.Bytes); err != nil {
return err
}
return nil
}

86
pcap/writer_test.go Normal file
View File

@ -0,0 +1,86 @@
package pcap
import (
"bytes"
"encoding/binary"
"io"
"reflect"
"testing"
"time"
"github.com/kr/pretty"
)
func TestReadback(t *testing.T) {
pkts := []*Packet{
{
Timestamp: time.Now(),
Length: 42,
Bytes: []byte{1, 2, 3, 4},
},
{
Timestamp: time.Now(),
Length: 30,
Bytes: []byte{2, 3, 4, 5},
},
{
Timestamp: time.Now(),
Length: 20,
Bytes: []byte{3, 4, 5, 6},
},
{
Timestamp: time.Now(),
Length: 10,
Bytes: []byte{4, 5, 6, 7},
},
}
serializations := map[string]bool{}
for _, order := range []binary.ByteOrder{nil, binary.LittleEndian, binary.BigEndian} {
var b bytes.Buffer
w := &Writer{
Writer: &b,
LinkType: LinkEthernet,
SnapLen: 65535,
ByteOrder: order,
}
for _, pkt := range pkts {
if err := w.Put(pkt); err != nil {
t.Fatalf(pretty.Sprintf("Writing packet %# v: %s", pkt, err))
}
}
// Record the binary form, to check how many different serializations we get.
serializations[b.String()] = true
readBack := []*Packet{}
r, err := NewReader(&b)
if err != nil {
t.Fatalf("Initializing reader for writer read-back: %s", err)
}
if r.LinkType != LinkEthernet {
t.Fatalf("Wrote link type %d, read back %d", LinkEthernet, r.LinkType)
}
ReadLoop:
for {
pkt, err := r.Next()
if err != nil {
if err == io.EOF {
break ReadLoop
}
t.Fatalf("Unexpected error reading packets: %s", err)
}
readBack = append(readBack, pkt)
}
if !reflect.DeepEqual(pkts, readBack) {
t.Fatalf("Packets were mutated by write-then-read")
}
}
if len(serializations) != 2 {
t.Fatalf("Expected 2 distinct serializations due to endianness, got %d", len(serializations))
}
}