aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/google/gopacket/pcapgo
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/google/gopacket/pcapgo')
-rw-r--r--vendor/github.com/google/gopacket/pcapgo/read.go155
-rw-r--r--vendor/github.com/google/gopacket/pcapgo/read_test.go203
-rw-r--r--vendor/github.com/google/gopacket/pcapgo/write.go103
-rw-r--r--vendor/github.com/google/gopacket/pcapgo/write_test.go71
4 files changed, 532 insertions, 0 deletions
diff --git a/vendor/github.com/google/gopacket/pcapgo/read.go b/vendor/github.com/google/gopacket/pcapgo/read.go
new file mode 100644
index 0000000..5acd06f
--- /dev/null
+++ b/vendor/github.com/google/gopacket/pcapgo/read.go
@@ -0,0 +1,155 @@
+// Copyright 2014 Damjan Cvetko. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the LICENSE file in the root of the source
+// tree.
+
+package pcapgo
+
+import (
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "io"
+ "time"
+
+ "bufio"
+ "compress/gzip"
+ "github.com/google/gopacket"
+ "github.com/google/gopacket/layers"
+)
+
+// Reader wraps an underlying io.Reader to read packet data in PCAP
+// format. See http://wiki.wireshark.org/Development/LibpcapFileFormat
+// for information on the file format.
+//
+// We currenty read v2.4 file format with nanosecond and microsecdond
+// timestamp resolution in little-endian and big-endian encoding.
+//
+// If the PCAP data is gzip compressed it is transparently uncompressed
+// by wrapping the given io.Reader with a gzip.Reader.
+type Reader struct {
+ r io.Reader
+ byteOrder binary.ByteOrder
+ nanoSecsFactor uint32
+ versionMajor uint16
+ versionMinor uint16
+ // timezone
+ // sigfigs
+ snaplen uint32
+ linkType layers.LinkType
+ // reusable buffer
+ buf [16]byte
+}
+
+const magicNanoseconds = 0xA1B23C4D
+const magicMicrosecondsBigendian = 0xD4C3B2A1
+const magicNanosecondsBigendian = 0x4D3CB2A1
+
+const magicGzip1 = 0x1f
+const magicGzip2 = 0x8b
+
+// NewReader returns a new reader object, for reading packet data from
+// the given reader. The reader must be open and header data is
+// read from it at this point.
+// If the file format is not supported an error is returned
+//
+// // Create new reader:
+// f, _ := os.Open("/tmp/file.pcap")
+// defer f.Close()
+// r, err := NewReader(f)
+// data, ci, err := r.ReadPacketData()
+func NewReader(r io.Reader) (*Reader, error) {
+ ret := Reader{r: r}
+ if err := ret.readHeader(); err != nil {
+ return nil, err
+ }
+ return &ret, nil
+}
+
+func (r *Reader) readHeader() error {
+ br := bufio.NewReader(r.r)
+ gzipMagic, err := br.Peek(2)
+ if err != nil {
+ return err
+ }
+
+ if gzipMagic[0] == magicGzip1 && gzipMagic[1] == magicGzip2 {
+ if r.r, err = gzip.NewReader(br); err != nil {
+ return err
+ }
+ } else {
+ r.r = br
+ }
+
+ buf := make([]byte, 24)
+ if n, err := io.ReadFull(r.r, buf); err != nil {
+ return err
+ } else if n < 24 {
+ return errors.New("Not enough data for read")
+ }
+ if magic := binary.LittleEndian.Uint32(buf[0:4]); magic == magicNanoseconds {
+ r.byteOrder = binary.LittleEndian
+ r.nanoSecsFactor = 1
+ } else if magic == magicNanosecondsBigendian {
+ r.byteOrder = binary.BigEndian
+ r.nanoSecsFactor = 1
+ } else if magic == magicMicroseconds {
+ r.byteOrder = binary.LittleEndian
+ r.nanoSecsFactor = 1000
+ } else if magic == magicMicrosecondsBigendian {
+ r.byteOrder = binary.BigEndian
+ r.nanoSecsFactor = 1000
+ } else {
+ return fmt.Errorf("Unknown magic %x", magic)
+ }
+ if r.versionMajor = r.byteOrder.Uint16(buf[4:6]); r.versionMajor != versionMajor {
+ return fmt.Errorf("Unknown major version %d", r.versionMajor)
+ }
+ if r.versionMinor = r.byteOrder.Uint16(buf[6:8]); r.versionMinor != versionMinor {
+ return fmt.Errorf("Unknown minor version %d", r.versionMinor)
+ }
+ // ignore timezone 8:12 and sigfigs 12:16
+ r.snaplen = r.byteOrder.Uint32(buf[16:20])
+ r.linkType = layers.LinkType(r.byteOrder.Uint32(buf[20:24]))
+ return nil
+}
+
+// ReadPacketData reads next packet from file.
+func (r *Reader) ReadPacketData() (data []byte, ci gopacket.CaptureInfo, err error) {
+ if ci, err = r.readPacketHeader(); err != nil {
+ return
+ }
+ if ci.CaptureLength > int(r.snaplen) {
+ err = fmt.Errorf("capture length exceeds snap length: %d > %d", 16+ci.CaptureLength, r.snaplen)
+ return
+ }
+ data = make([]byte, ci.CaptureLength)
+ _, err = io.ReadFull(r.r, data)
+ return data, ci, err
+}
+
+func (r *Reader) readPacketHeader() (ci gopacket.CaptureInfo, err error) {
+ if _, err = io.ReadFull(r.r, r.buf[:]); err != nil {
+ return
+ }
+ ci.Timestamp = time.Unix(int64(r.byteOrder.Uint32(r.buf[0:4])), int64(r.byteOrder.Uint32(r.buf[4:8])*r.nanoSecsFactor)).UTC()
+ ci.CaptureLength = int(r.byteOrder.Uint32(r.buf[8:12]))
+ ci.Length = int(r.byteOrder.Uint32(r.buf[12:16]))
+ return
+}
+
+// LinkType returns network, as a layers.LinkType.
+func (r *Reader) LinkType() layers.LinkType {
+ return r.linkType
+}
+
+// Snaplen returns the snapshot length of the capture file.
+func (r *Reader) Snaplen() uint32 {
+ return r.snaplen
+}
+
+// Reader formater
+func (r *Reader) String() string {
+ return fmt.Sprintf("PcapFile maj: %x min: %x snaplen: %d linktype: %s", r.versionMajor, r.versionMinor, r.snaplen, r.linkType)
+}
diff --git a/vendor/github.com/google/gopacket/pcapgo/read_test.go b/vendor/github.com/google/gopacket/pcapgo/read_test.go
new file mode 100644
index 0000000..87bf7ab
--- /dev/null
+++ b/vendor/github.com/google/gopacket/pcapgo/read_test.go
@@ -0,0 +1,203 @@
+// Copyright 2014 Damjan Cvetko. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the LICENSE file in the root of the source
+// tree.
+package pcapgo
+
+import (
+ "bytes"
+ "testing"
+ "time"
+)
+
+// test header read
+func TestCreatePcapReader(t *testing.T) {
+ test := []byte{
+ 0xd4, 0xc3, 0xb2, 0xa1, 0x02, 0x00, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ }
+ buf := bytes.NewBuffer(test)
+ _, err := NewReader(buf)
+ if err != nil {
+ t.Error(err)
+ t.FailNow()
+ }
+}
+
+// test big endian file read
+func TestCreatePcapReaderBigEndian(t *testing.T) {
+ test := []byte{
+ 0xa1, 0xb2, 0xc3, 0xd4, 0x00, 0x02, 0x00, 0x04,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01,
+ }
+ buf := bytes.NewBuffer(test)
+ _, err := NewReader(buf)
+ if err != nil {
+ t.Error(err)
+ t.FailNow()
+ }
+}
+
+// test opening invalid data
+func TestCreatePcapReaderFail(t *testing.T) {
+ test := []byte{
+ 0xd0, 0xc3, 0xb2, 0xa1, 0x02, 0x00, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ }
+ buf := bytes.NewBuffer(test)
+ _, err := NewReader(buf)
+ if err == nil {
+ t.Error("Should fail but did not")
+ t.FailNow()
+ }
+}
+
+func TestPacket(t *testing.T) {
+ test := []byte{
+ 0xd4, 0xc3, 0xb2, 0xa1, 0x02, 0x00, 0x04, 0x00, // magic, maj, min
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // tz, sigfigs
+ 0xff, 0xff, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // snaplen, linkType
+ 0x5A, 0xCC, 0x1A, 0x54, 0x01, 0x00, 0x00, 0x00, // sec, usec
+ 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, // cap len, full len
+ 0x01, 0x02, 0x03, 0x04, // data
+ }
+
+ buf := bytes.NewBuffer(test)
+ r, err := NewReader(buf)
+
+ data, ci, err := r.ReadPacketData()
+ if err != nil {
+ t.Error(err)
+ t.FailNow()
+ }
+ if !ci.Timestamp.Equal(time.Date(2014, 9, 18, 12, 13, 14, 1000, time.UTC)) {
+ t.Error("Invalid time read")
+ t.FailNow()
+ }
+ if ci.CaptureLength != 4 || ci.Length != 8 {
+ t.Error("Invalid CapLen or Len")
+ }
+ want := []byte{1, 2, 3, 4}
+ if !bytes.Equal(data, want) {
+ t.Errorf("buf mismatch:\nwant: %+v\ngot: %+v", want, data)
+ }
+}
+
+func TestPacketNano(t *testing.T) {
+ test := []byte{
+ 0x4d, 0x3c, 0xb2, 0xa1, 0x02, 0x00, 0x04, 0x00, // magic, maj, min
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // tz, sigfigs
+ 0xff, 0xff, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // snaplen, linkType
+ 0x5A, 0xCC, 0x1A, 0x54, 0x01, 0x00, 0x00, 0x00, // sec, usec
+ 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, // cap len, full len
+ 0x01, 0x02, 0x03, 0x04, // data
+ }
+
+ buf := bytes.NewBuffer(test)
+ r, err := NewReader(buf)
+
+ data, ci, err := r.ReadPacketData()
+ if err != nil {
+ t.Error(err)
+ t.FailNow()
+ }
+ if !ci.Timestamp.Equal(time.Date(2014, 9, 18, 12, 13, 14, 1, time.UTC)) {
+ t.Error("Invalid time read")
+ t.FailNow()
+ }
+ if ci.CaptureLength != 4 || ci.Length != 8 {
+ t.Error("Invalid CapLen or Len")
+ }
+ want := []byte{1, 2, 3, 4}
+ if !bytes.Equal(data, want) {
+ t.Errorf("buf mismatch:\nwant: %+v\ngot: %+v", want, data)
+ }
+}
+
+func TestGzipPacket(t *testing.T) {
+ test := []byte{
+ 0x1f, 0x8b, 0x08, 0x08, 0x92, 0x4d, 0x81, 0x57,
+ 0x00, 0x03, 0x74, 0x65, 0x73, 0x74, 0x00, 0xbb,
+ 0x72, 0x78, 0xd3, 0x42, 0x26, 0x06, 0x16, 0x06,
+ 0x18, 0xf8, 0xff, 0x9f, 0x81, 0x81, 0x11, 0x48,
+ 0x47, 0x9d, 0x91, 0x0a, 0x01, 0xd1, 0x20, 0x19,
+ 0x0e, 0x20, 0x66, 0x64, 0x62, 0x66, 0x01, 0x00,
+ 0xe4, 0x76, 0x9b, 0x75, 0x2c, 0x00, 0x00, 0x00,
+ }
+ buf := bytes.NewBuffer(test)
+ r, err := NewReader(buf)
+ if err != nil {
+ t.Error("Unexpected error returned:", err)
+ t.FailNow()
+ }
+
+ data, ci, err := r.ReadPacketData()
+ if err != nil {
+ t.Error(err)
+ t.FailNow()
+ }
+ if !ci.Timestamp.Equal(time.Date(2014, 9, 18, 12, 13, 14, 1000, time.UTC)) {
+ t.Error("Invalid time read")
+ t.FailNow()
+ }
+ if ci.CaptureLength != 4 || ci.Length != 8 {
+ t.Error("Invalid CapLen or Len")
+ }
+ want := []byte{1, 2, 3, 4}
+ if !bytes.Equal(data, want) {
+ t.Errorf("buf mismatch:\nwant: %+v\ngot: %+v", want, data)
+ }
+}
+
+func TestTruncatedGzipPacket(t *testing.T) {
+ test := []byte{
+ 0x1f, 0x8b, 0x08,
+ }
+ buf := bytes.NewBuffer(test)
+ _, err := NewReader(buf)
+ if err == nil {
+ t.Error("Should fail but did not")
+ t.FailNow()
+ }
+}
+
+func TestPacketBufferReuse(t *testing.T) {
+ test := []byte{
+ 0xd4, 0xc3, 0xb2, 0xa1, 0x02, 0x00, 0x04, 0x00, // magic, maj, min
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // tz, sigfigs
+ 0xff, 0xff, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // snaplen, linkType
+ 0x5A, 0xCC, 0x1A, 0x54, 0x01, 0x00, 0x00, 0x00, // sec, usec
+ 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, // cap len, full len
+ 0x01, 0x02, 0x03, 0x04, // data
+ 0x5A, 0xCC, 0x1A, 0x54, 0x01, 0x00, 0x00, 0x00, // sec, usec
+ 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, // cap len, full len
+ 0x01, 0x02, 0x03, 0x04, // data
+ }
+
+ buf := bytes.NewBuffer(test)
+ r, err := NewReader(buf)
+
+ data1, _, err := r.ReadPacketData()
+ if err != nil {
+ t.Error(err)
+ t.FailNow()
+ }
+ if want := []byte{1, 2, 3, 4}; !bytes.Equal(data1, want) {
+ t.Errorf("buf mismatch:\nwant: %+v\ngot: %+v", want, data1)
+ }
+ data2, _, err := r.ReadPacketData()
+ if err != nil {
+ t.Error(err)
+ t.FailNow()
+ }
+ for i := range data1 {
+ data1[i] = 0xff // modify data1 after getting data2, make sure we don't overlap buffers.
+ }
+ if want := []byte{1, 2, 3, 4}; !bytes.Equal(data2, want) {
+ t.Errorf("buf mismatch:\nwant: %+v\ngot: %+v", want, data2)
+ }
+}
diff --git a/vendor/github.com/google/gopacket/pcapgo/write.go b/vendor/github.com/google/gopacket/pcapgo/write.go
new file mode 100644
index 0000000..bfc312f
--- /dev/null
+++ b/vendor/github.com/google/gopacket/pcapgo/write.go
@@ -0,0 +1,103 @@
+// Copyright 2012 Google, Inc. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the LICENSE file in the root of the source
+// tree.
+
+// Package pcapgo provides some native PCAP support, not requiring
+// C libpcap to be installed.
+package pcapgo
+
+import (
+ "encoding/binary"
+ "fmt"
+ "io"
+ "time"
+
+ "github.com/google/gopacket"
+ "github.com/google/gopacket/layers"
+)
+
+// Writer wraps an underlying io.Writer to write packet data in PCAP
+// format. See http://wiki.wireshark.org/Development/LibpcapFileFormat
+// for information on the file format.
+//
+// For those that care, we currently write v2.4 files with nanosecond
+// timestamp resolution and little-endian encoding.
+type Writer struct {
+ w io.Writer
+}
+
+const magicMicroseconds = 0xA1B2C3D4
+const versionMajor = 2
+const versionMinor = 4
+
+// NewWriter returns a new writer object, for writing packet data out
+// to the given writer. If this is a new empty writer (as opposed to
+// an append), you must call WriteFileHeader before WritePacket.
+//
+// // Write a new file:
+// f, _ := os.Create("/tmp/file.pcap")
+// w := pcapgo.NewWriter(f)
+// w.WriteFileHeader(65536, layers.LinkTypeEthernet) // new file, must do this.
+// w.WritePacket(gopacket.CaptureInfo{...}, data1)
+// f.Close()
+// // Append to existing file (must have same snaplen and linktype)
+// f2, _ := os.OpenFile("/tmp/file.pcap", os.O_APPEND, 0700)
+// w2 := pcapgo.NewWriter(f2)
+// // no need for file header, it's already written.
+// w2.WritePacket(gopacket.CaptureInfo{...}, data2)
+// f2.Close()
+func NewWriter(w io.Writer) *Writer {
+ return &Writer{w: w}
+}
+
+// WriteFileHeader writes a file header out to the writer.
+// This must be called exactly once per output.
+func (w *Writer) WriteFileHeader(snaplen uint32, linktype layers.LinkType) error {
+ var buf [24]byte
+ binary.LittleEndian.PutUint32(buf[0:4], magicMicroseconds)
+ binary.LittleEndian.PutUint16(buf[4:6], versionMajor)
+ binary.LittleEndian.PutUint16(buf[6:8], versionMinor)
+ // bytes 8:12 stay 0 (timezone = UTC)
+ // bytes 12:16 stay 0 (sigfigs is always set to zero, according to
+ // http://wiki.wireshark.org/Development/LibpcapFileFormat
+ binary.LittleEndian.PutUint32(buf[16:20], snaplen)
+ binary.LittleEndian.PutUint32(buf[20:24], uint32(linktype))
+ _, err := w.w.Write(buf[:])
+ return err
+}
+
+const nanosPerMicro = 1000
+
+func (w *Writer) writePacketHeader(ci gopacket.CaptureInfo) error {
+ var buf [16]byte
+
+ t := ci.Timestamp
+ if t.IsZero() {
+ t = time.Now()
+ }
+ secs := t.Unix()
+ usecs := t.Nanosecond() / nanosPerMicro
+ binary.LittleEndian.PutUint32(buf[0:4], uint32(secs))
+ binary.LittleEndian.PutUint32(buf[4:8], uint32(usecs))
+ binary.LittleEndian.PutUint32(buf[8:12], uint32(ci.CaptureLength))
+ binary.LittleEndian.PutUint32(buf[12:16], uint32(ci.Length))
+ _, err := w.w.Write(buf[:])
+ return err
+}
+
+// WritePacket writes the given packet data out to the file.
+func (w *Writer) WritePacket(ci gopacket.CaptureInfo, data []byte) error {
+ if ci.CaptureLength != len(data) {
+ return fmt.Errorf("capture length %d does not match data length %d", ci.CaptureLength, len(data))
+ }
+ if ci.CaptureLength > ci.Length {
+ return fmt.Errorf("invalid capture info %+v: capture length > length", ci)
+ }
+ if err := w.writePacketHeader(ci); err != nil {
+ return fmt.Errorf("error writing packet header: %v", err)
+ }
+ _, err := w.w.Write(data)
+ return err
+}
diff --git a/vendor/github.com/google/gopacket/pcapgo/write_test.go b/vendor/github.com/google/gopacket/pcapgo/write_test.go
new file mode 100644
index 0000000..5b87d6a
--- /dev/null
+++ b/vendor/github.com/google/gopacket/pcapgo/write_test.go
@@ -0,0 +1,71 @@
+// Copyright 2012 Google, Inc. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the LICENSE file in the root of the source
+// tree.
+
+package pcapgo
+
+import (
+ "bytes"
+ "github.com/google/gopacket"
+ "testing"
+ "time"
+)
+
+func TestWriteHeader(t *testing.T) {
+ var buf bytes.Buffer
+ w := NewWriter(&buf)
+ w.WriteFileHeader(0x1234, 0x56)
+ want := []byte{
+ 0xd4, 0xc3, 0xb2, 0xa1, 0x02, 0x00, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x34, 0x12, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00,
+ }
+ if got := buf.Bytes(); !bytes.Equal(got, want) {
+ t.Errorf("buf mismatch:\nwant: %+v\ngot: %+v", want, got)
+ }
+}
+
+func TestWritePacket(t *testing.T) {
+ ci := gopacket.CaptureInfo{
+ Timestamp: time.Unix(0x01020304, 0xAA*1000),
+ Length: 0xABCD,
+ CaptureLength: 10,
+ }
+ data := []byte{9, 8, 7, 6, 5, 4, 3, 2, 1, 0}
+ var buf bytes.Buffer
+ w := NewWriter(&buf)
+ w.WritePacket(ci, data)
+ want := []byte{
+ 0x04, 0x03, 0x02, 0x01, 0xAA, 0x00, 0x00, 0x00,
+ 0x0A, 0x00, 0x00, 0x00, 0xCD, 0xAB, 0x00, 0x00,
+ 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ }
+ if got := buf.Bytes(); !bytes.Equal(got, want) {
+ t.Errorf("buf mismatch:\nwant: %+v\ngot: %+v", want, got)
+ }
+}
+
+func TestCaptureInfoErrors(t *testing.T) {
+ data := []byte{1, 2, 3, 4}
+ ts := time.Unix(0, 0)
+ for _, test := range []gopacket.CaptureInfo{
+ gopacket.CaptureInfo{
+ Timestamp: ts,
+ Length: 5,
+ CaptureLength: 5,
+ },
+ gopacket.CaptureInfo{
+ Timestamp: ts,
+ Length: 3,
+ CaptureLength: 4,
+ },
+ } {
+ var buf bytes.Buffer
+ w := NewWriter(&buf)
+ if err := w.WritePacket(test, data); err == nil {
+ t.Errorf("CaptureInfo %+v should have error", test)
+ }
+ }
+}