-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpcap.go
161 lines (130 loc) · 2.89 KB
/
pcap.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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
package pcap
import (
"time"
"io"
"encoding/binary"
"fmt"
)
const MAXFRAME = 9000
const MAGIC_BE = "\xa1\xb2\xc3\xd4"
const MAGIC_LE = "\xd4\xc3\xb2\xa1"
const VERSION_MAJ = 2
const VERSION_MIN = 4
const LINKTYPE_ETHERNET = 1
const LINKTYPE_RAW = 101
type FileHeader struct {
VersionMajor uint16
VersionMinor uint16
ThisZone int32
SigFigs uint32
SnapLen uint32
LinkType uint32
}
type PcapFile struct {
order binary.ByteOrder
Header FileHeader
}
type FrameHeader struct {
Sec uint32
Usec uint32
Caplen uint32
Framelen uint32
}
func (h *FrameHeader) Time() time.Time {
return time.Unix(int64(h.Sec), int64(h.Usec) * 1000)
}
type Frame struct {
Header FrameHeader
Payload string
}
func (f *Frame) Time() time.Time {
return f.Header.Time()
}
type Reader struct {
PcapFile
r io.Reader
}
type Writer struct {
PcapFile
w io.Writer
}
func NewReader(r io.Reader) (*Reader, error) {
var h FileHeader
var order binary.ByteOrder
magic := make([]byte, 4)
n, err := r.Read(magic)
if err != nil {
return nil, err
}
if (n < 4) {
return nil, fmt.Errorf("Cannot read pcap header")
}
switch (string(magic)) {
case MAGIC_BE:
order = binary.BigEndian
case MAGIC_LE:
order = binary.LittleEndian
default:
return nil, fmt.Errorf("Cannot determine endianness")
}
if err := binary.Read(r, order, &h); err != nil {
return nil, err
}
if (h.VersionMajor != VERSION_MAJ) || (h.VersionMinor != VERSION_MIN) {
return nil, fmt.Errorf("Cannot handle pcap file version %d.%d", h.VersionMajor, h.VersionMinor)
}
ret := &Reader{PcapFile{order, h}, r}
return ret, nil
}
func (r *Reader) ReadFrame() (*Frame, error) {
var h FrameHeader
err := binary.Read(r.r, r.order, &h)
if err != nil {
return nil, err
}
payload := make([]byte, h.Caplen)
l, err := r.r.Read(payload)
if err != nil {
return nil, err
}
if uint32(l) < h.Caplen {
return nil, fmt.Errorf("Short read: %d (wanted %d)", l, h.Caplen)
}
ret := &Frame{h, string(payload)}
return ret, nil
}
func NewWriterLinkType(w io.Writer, linkType uint32) (*Writer, error) {
order := binary.BigEndian
h := &FileHeader{VERSION_MAJ, VERSION_MIN, 0, 0, 9000, linkType}
n, err := w.Write([]byte(MAGIC_BE))
if err != nil {
return nil, err
}
if n != len(MAGIC_BE) {
return nil, fmt.Errorf("Short write outputting header")
}
if err := binary.Write(w, order, h); err != nil {
return nil, err
}
ret := &Writer{PcapFile{order, *h}, w}
return ret, nil
}
func NewWriter(w io.Writer) (*Writer, error) {
return NewWriterLinkType(w, 1)
}
func (w *Writer) WriteFrame(frame Frame) (error) {
if frame.Header.Caplen != uint32(len(frame.Payload)) {
return fmt.Errorf("Caplen != len(Payload)")
}
if err := binary.Write(w.w, w.order, frame.Header); err != nil {
return err
}
n, err := w.w.Write([]byte(frame.Payload))
if err != nil {
return err
}
if n < len(frame.Payload) {
return fmt.Errorf("Short write")
}
return nil
}