forked from Lukasa/gopcap
-
Notifications
You must be signed in to change notification settings - Fork 0
/
internet.go
214 lines (173 loc) · 5.97 KB
/
internet.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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
package gopcap
import (
"net"
)
//-------------------------------------------------------------------------------------------
// UnknownINet
//-------------------------------------------------------------------------------------------
// UnknownINet represents the data for an internet-layer packet that gopcap doesn't understand.
// It simply provides uninterpreted data representing the entire internet-layer packet.
type UnknownINet struct {
data TransportLayer
}
func (u *UnknownINet) InternetData() TransportLayer {
return u.data
}
func (u *UnknownINet) FromBytes(data []byte) error {
u.data = new(UnknownTransport)
u.data.FromBytes(data)
return nil
}
//-------------------------------------------------------------------------------------------
// IPv4
//-------------------------------------------------------------------------------------------
// IPv4Packet represents an unpacked IPv4 packet. This method of storing the IPv4 packet data
// is less efficient than the byte-packed form used on the wire.
type IPv4Packet struct {
IHL uint8
DSCP uint8
ECN uint8
TotalLength uint16
ID uint16
DontFragment bool
MoreFragments bool
FragmentOffset uint16
TTL uint8
Protocol IPProtocol
Checksum uint16
SourceAddress net.IP
DestAddress net.IP
Options []byte
data TransportLayer
}
func (p *IPv4Packet) InternetData() TransportLayer {
return p.data
}
func (p *IPv4Packet) FromBytes(data []byte) error {
// The IPv4 header is full of crazy non-aligned fields that I've expanded in the structure.
// This makes this function a total nightmare. My apologies in advance.
// Check that we have enough data for the header, at the very least.
if len(data) < 20 {
return InsufficientLength
}
// Check that this actually is an IPv4 packet.
if ((uint8(data[0]) & 0xF0) >> 4) != uint8(4) {
return IncorrectPacket
}
// The header length is the low four bits of the first byte.
p.IHL = uint8(data[0]) & 0x0F
// The DSCP is the high six(!) bits of the second byte.
p.DSCP = (uint8(data[1]) & 0xFC) >> 2
// Congestion notification is the low two bits of the second byte.
p.ECN = uint8(data[1]) & 0x03
// Total length is saner: 16-bit integer.
p.TotalLength = getUint16(data[2:4], false)
// Same with the ID.
p.ID = getUint16(data[4:6], false)
// Back to the crazy with the flags: the top three bits of the 7th byte. We only care
// about bits two and three. It hurt me to write that sentence.
if (uint8(data[6]) & 0x40) != 0 {
p.DontFragment = true
} else if (uint8(data[6]) & 0x20) != 0 {
p.MoreFragments = true
}
// Following from the flag crazy, the fragment offset is the low 13 bits of the 7th
// and 8th bytes.
p.FragmentOffset = getUint16(data[6:8], false) & 0x1FFF
// The remaining fields are fairly sensible. TTL is the 9th byte.
p.TTL = uint8(data[8])
// Protocol is the tenth.
p.Protocol = IPProtocol(data[9])
// Header checksum is eleven and twelve.
p.Checksum = getUint16(data[10:12], false)
// Then the source IP and destination IP.
p.SourceAddress = data[12:16]
p.DestAddress = data[16:20]
// If IHL is more than 5, we have (IHL - 5) * 4 bytes of options.
if p.IHL > 5 {
optionLength := uint16(p.IHL-5) * 4
p.Options = data[20 : 20+optionLength]
// Reslice data so that the actual packet contents still start at offset 20.
data = data[optionLength:]
}
// The data length is the total length, minus the headers. The headers are, for no good
// reason, measured in 32-bit words, so the data length is actually:
dataLen := p.TotalLength - (uint16(p.IHL) * 4)
if dataLen > uint16(len(data[20:])) {
return IncorrectPacket
}
// Build the transport layer data.
p.buildTransportLayer(data[20 : 20+dataLen])
return nil
}
func (p *IPv4Packet) buildTransportLayer(data []byte) {
switch p.Protocol {
case IPP_TCP:
p.data = new(TCPSegment)
case IPP_UDP:
p.data = new(UDPDatagram)
default:
p.data = new(UnknownTransport)
}
p.data.FromBytes(data)
}
//-------------------------------------------------------------------------------------------
// IPv6
//-------------------------------------------------------------------------------------------
type IPv6Packet struct {
TrafficClass uint8
FlowLabel uint32 // This is a huge waste of space for a 20-bit field. Rethink?
Length uint16
NextHeader IPProtocol
HopLimit uint8
SourceAddress []byte
DestinationAddress []byte
data TransportLayer
}
func (p *IPv6Packet) InternetData() TransportLayer {
return p.data
}
func (p *IPv6Packet) FromBytes(data []byte) error {
// Confirm that we have enough data for the smallest possible header.
if len(data) < 40 {
return InsufficientLength
}
// Check that this actually is an IPv6 packet.
if ((uint8(data[0]) & 0xF0) >> 4) != uint8(6) {
return IncorrectPacket
}
// The traffic class is the octet following the version.
p.TrafficClass = (uint8(data[0]) & 0x0F) << 4
p.TrafficClass += (uint8(data[1]) * 0xF0) >> 4
// The flow label is the next 20 bits.
p.FlowLabel = (uint32(data[1]) & 0x0F) << 16
p.FlowLabel += uint32(data[2]) << 8
p.FlowLabel += uint32(data[3])
// The remaining fields are simply aligned.
p.Length = getUint16(data[4:6], false)
p.NextHeader = IPProtocol(data[6])
p.HopLimit = uint8(data[7])
p.SourceAddress = data[8:24]
p.DestinationAddress = data[24:40]
if p.Length > uint16(len(data[40:])) {
return IncorrectPacket
}
// Following the fixed headers are a sequence of extension headers
// terminating in the transport data.
p.parseRemainingHeaders(data[40 : 40+p.Length])
return nil
}
func (p *IPv6Packet) parseRemainingHeaders(data []byte) {
// Currently we don't support any extension headers so if the next header
// isn't the transport data then give up and interpret it as an unknown
// transport type.
switch p.NextHeader {
case IPP_TCP:
p.data = new(TCPSegment)
case IPP_UDP:
p.data = new(UDPDatagram)
default:
p.data = new(UnknownTransport)
}
p.data.FromBytes(data)
}