forked from google/gopacket
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathread.go
139 lines (127 loc) · 3.94 KB
/
read.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// 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"
"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.
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 []byte
}
const magicNanoseconds = 0xA1B23C4D
const magicMicrosecondsBigendian = 0xD4C3B2A1
const magicNanosecondsBigendian = 0x4D3CB2A1
// 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 {
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 errors.New(fmt.Sprintf("Unknown maigc %x", magic))
}
if r.versionMajor = r.byteOrder.Uint16(buf[4:6]); r.versionMajor != versionMajor {
return errors.New(fmt.Sprintf("Unknown major version %d", r.versionMajor))
}
if r.versionMinor = r.byteOrder.Uint16(buf[6:8]); r.versionMinor != versionMinor {
return errors.New(fmt.Sprintf("Unknown minor version %d", r.versionMinor))
}
// ignore timezone 8:12 and sigfigs 12:16
r.snaplen = r.byteOrder.Uint32(buf[16:20])
r.buf = make([]byte, r.snaplen+16)
r.linkType = layers.LinkType(r.byteOrder.Uint32(buf[20:24]))
return nil
}
// Read next packet from file
func (r *Reader) ReadPacketData() (data []byte, ci gopacket.CaptureInfo, err error) {
if ci, err = r.readPacketHeader(); err != nil {
return
}
var n int
if 16+ci.CaptureLength > len(r.buf) {
err = gopacket.ErrMalformedPacket
return
}
data = r.buf[16 : 16+ci.CaptureLength]
if n, err = io.ReadFull(r.r, data); err != nil {
return
} else if n < ci.CaptureLength {
err = io.ErrUnexpectedEOF
}
return
}
func (r *Reader) readPacketHeader() (ci gopacket.CaptureInfo, err error) {
var n int
if n, err = io.ReadFull(r.r, r.buf[0:16]); err != nil {
return
} else if n < 16 {
err = io.ErrUnexpectedEOF
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
}
// 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)
}