forked from Lukasa/gopcap
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathparse.go
131 lines (102 loc) · 3.66 KB
/
parse.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
package gopcap
import (
"bytes"
"io"
"time"
)
// checkMagicNum checks the first four bytes of a pcap file, searching for the magic number
// and checking the byte order. Returns three values: whether the file is a pcap file, whether
// the byte order needs flipping, and any error that was encountered. If error is returned,
// the other values are invalid.
func checkMagicNum(src io.Reader) (bool, bool, error) {
// These magic numbers form the header of a pcap file.
magic := []byte{0xa1, 0xb2, 0xc3, 0xd4}
magic_reverse := []byte{0xd4, 0xc3, 0xb2, 0xa1}
buffer := make([]byte, 4)
read_count, err := src.Read(buffer)
if read_count != 4 {
return false, false, InsufficientLength
}
if (err != nil) && (err != io.EOF) {
return false, false, err
}
if bytes.Compare(buffer, magic) == 0 {
return true, false, nil
} else if bytes.Compare(buffer, magic_reverse) == 0 {
return true, true, nil
}
return false, false, NotAPcapFile
}
// parsePacket parses a full packet out of the pcap file. It returns an error if any problems were
// encountered.
func parsePacket(pkt *Packet, src io.Reader, flipped bool, linkType Link) error {
err := populatePacketHeader(pkt, src, flipped)
if err != nil {
return err
}
data := make([]byte, pkt.IncludedLen)
readlen, err := src.Read(data)
if uint32(readlen) != pkt.IncludedLen {
return UnexpectedEOF
}
pkt.Data, err = parseLinkData(data, linkType)
return err
}
// populateFileHeader reads the next 20 bytes out of the .pcap file and uses it to populate the
// PcapFile structure.
func populateFileHeader(file *PcapFile, src io.Reader, flipped bool) error {
buffer := make([]byte, 20)
read_count, err := src.Read(buffer)
if err != nil {
return err
} else if read_count != 20 {
return InsufficientLength
}
// First two bytes are the major version number.
file.MajorVersion = getUint16(buffer[0:2], flipped)
// Next two are the minor version number.
file.MinorVersion = getUint16(buffer[2:4], flipped)
// GMT to local correction, in seconds east of UTC.
file.TZCorrection = getInt32(buffer[4:8], flipped)
// Next is the number of significant figures in the timestamps. Almost always zero.
file.SigFigs = getUint32(buffer[8:12], flipped)
// Now the maximum length of the captured packet data.
file.MaxLen = getUint32(buffer[12:16], flipped)
// And the link type.
file.LinkType = Link(getUint32(buffer[16:20], flipped))
return nil
}
// populatePacketHeader reads the next 16 bytes out of the file and builds it into a
// packet header.
func populatePacketHeader(packet *Packet, src io.Reader, flipped bool) error {
buffer := make([]byte, 16)
read_count, err := src.Read(buffer)
if err != nil {
return err
} else if read_count != 16 {
return InsufficientLength
}
// First is a pair of fields that build up the timestamp.
ts_seconds := getUint32(buffer[0:4], flipped)
ts_micros := getUint32(buffer[4:8], flipped)
//packet.Timestamp = (time.Duration(ts_seconds) * time.Second) + (time.Duration(ts_micros) * time.Microsecond)
packet.Timestamp = time.Unix(int64(ts_seconds), int64(ts_micros)*int64(time.Microsecond))
// Next is the length of the data segment.
packet.IncludedLen = getUint32(buffer[8:12], flipped)
// Then the original length of the packet.
packet.ActualLen = getUint32(buffer[12:16], flipped)
return err
}
// parseLinkData takes the data buffer containing the full link-layer packet (or equivalent, e.g.
// Ethernet frame) and builds an appropriate in-memory representation.
func parseLinkData(data []byte, linkType Link) (LinkLayer, error) {
var pkt LinkLayer
switch linkType {
case ETHERNET:
pkt = new(EthernetFrame)
default:
pkt = new(UnknownLink)
}
err := pkt.FromBytes(data)
return pkt, err
}