added support for string type
[govpp.git] / vendor / github.com / google / gopacket / pcapgo / read.go
1 // Copyright 2014 Damjan Cvetko. All rights reserved.
2 //
3 // Use of this source code is governed by a BSD-style license
4 // that can be found in the LICENSE file in the root of the source
5 // tree.
6
7 package pcapgo
8
9 import (
10         "encoding/binary"
11         "errors"
12         "fmt"
13         "io"
14         "time"
15
16         "bufio"
17         "compress/gzip"
18         "github.com/google/gopacket"
19         "github.com/google/gopacket/layers"
20 )
21
22 // Reader wraps an underlying io.Reader to read packet data in PCAP
23 // format.  See http://wiki.wireshark.org/Development/LibpcapFileFormat
24 // for information on the file format.
25 //
26 // We currenty read v2.4 file format with nanosecond and microsecdond
27 // timestamp resolution in little-endian and big-endian encoding.
28 //
29 // If the PCAP data is gzip compressed it is transparently uncompressed
30 // by wrapping the given io.Reader with a gzip.Reader.
31 type Reader struct {
32         r              io.Reader
33         byteOrder      binary.ByteOrder
34         nanoSecsFactor uint32
35         versionMajor   uint16
36         versionMinor   uint16
37         // timezone
38         // sigfigs
39         snaplen  uint32
40         linkType layers.LinkType
41         // reusable buffer
42         buf [16]byte
43 }
44
45 const magicNanoseconds = 0xA1B23C4D
46 const magicMicrosecondsBigendian = 0xD4C3B2A1
47 const magicNanosecondsBigendian = 0x4D3CB2A1
48
49 const magicGzip1 = 0x1f
50 const magicGzip2 = 0x8b
51
52 // NewReader returns a new reader object, for reading packet data from
53 // the given reader. The reader must be open and header data is
54 // read from it at this point.
55 // If the file format is not supported an error is returned
56 //
57 //  // Create new reader:
58 //  f, _ := os.Open("/tmp/file.pcap")
59 //  defer f.Close()
60 //  r, err := NewReader(f)
61 //  data, ci, err := r.ReadPacketData()
62 func NewReader(r io.Reader) (*Reader, error) {
63         ret := Reader{r: r}
64         if err := ret.readHeader(); err != nil {
65                 return nil, err
66         }
67         return &ret, nil
68 }
69
70 func (r *Reader) readHeader() error {
71         br := bufio.NewReader(r.r)
72         gzipMagic, err := br.Peek(2)
73         if err != nil {
74                 return err
75         }
76
77         if gzipMagic[0] == magicGzip1 && gzipMagic[1] == magicGzip2 {
78                 if r.r, err = gzip.NewReader(br); err != nil {
79                         return err
80                 }
81         } else {
82                 r.r = br
83         }
84
85         buf := make([]byte, 24)
86         if n, err := io.ReadFull(r.r, buf); err != nil {
87                 return err
88         } else if n < 24 {
89                 return errors.New("Not enough data for read")
90         }
91         if magic := binary.LittleEndian.Uint32(buf[0:4]); magic == magicNanoseconds {
92                 r.byteOrder = binary.LittleEndian
93                 r.nanoSecsFactor = 1
94         } else if magic == magicNanosecondsBigendian {
95                 r.byteOrder = binary.BigEndian
96                 r.nanoSecsFactor = 1
97         } else if magic == magicMicroseconds {
98                 r.byteOrder = binary.LittleEndian
99                 r.nanoSecsFactor = 1000
100         } else if magic == magicMicrosecondsBigendian {
101                 r.byteOrder = binary.BigEndian
102                 r.nanoSecsFactor = 1000
103         } else {
104                 return fmt.Errorf("Unknown magic %x", magic)
105         }
106         if r.versionMajor = r.byteOrder.Uint16(buf[4:6]); r.versionMajor != versionMajor {
107                 return fmt.Errorf("Unknown major version %d", r.versionMajor)
108         }
109         if r.versionMinor = r.byteOrder.Uint16(buf[6:8]); r.versionMinor != versionMinor {
110                 return fmt.Errorf("Unknown minor version %d", r.versionMinor)
111         }
112         // ignore timezone 8:12 and sigfigs 12:16
113         r.snaplen = r.byteOrder.Uint32(buf[16:20])
114         r.linkType = layers.LinkType(r.byteOrder.Uint32(buf[20:24]))
115         return nil
116 }
117
118 // ReadPacketData reads next packet from file.
119 func (r *Reader) ReadPacketData() (data []byte, ci gopacket.CaptureInfo, err error) {
120         if ci, err = r.readPacketHeader(); err != nil {
121                 return
122         }
123         if ci.CaptureLength > int(r.snaplen) {
124                 err = fmt.Errorf("capture length exceeds snap length: %d > %d", 16+ci.CaptureLength, r.snaplen)
125                 return
126         }
127         data = make([]byte, ci.CaptureLength)
128         _, err = io.ReadFull(r.r, data)
129         return data, ci, err
130 }
131
132 func (r *Reader) readPacketHeader() (ci gopacket.CaptureInfo, err error) {
133         if _, err = io.ReadFull(r.r, r.buf[:]); err != nil {
134                 return
135         }
136         ci.Timestamp = time.Unix(int64(r.byteOrder.Uint32(r.buf[0:4])), int64(r.byteOrder.Uint32(r.buf[4:8])*r.nanoSecsFactor)).UTC()
137         ci.CaptureLength = int(r.byteOrder.Uint32(r.buf[8:12]))
138         ci.Length = int(r.byteOrder.Uint32(r.buf[12:16]))
139         return
140 }
141
142 // LinkType returns network, as a layers.LinkType.
143 func (r *Reader) LinkType() layers.LinkType {
144         return r.linkType
145 }
146
147 // Snaplen returns the snapshot length of the capture file.
148 func (r *Reader) Snaplen() uint32 {
149         return r.snaplen
150 }
151
152 // Reader formater
153 func (r *Reader) String() string {
154         return fmt.Sprintf("PcapFile  maj: %x min: %x snaplen: %d linktype: %s", r.versionMajor, r.versionMinor, r.snaplen, r.linkType)
155 }