-
Notifications
You must be signed in to change notification settings - Fork 156
/
vlan.go
168 lines (148 loc) · 5.57 KB
/
vlan.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
// Copyright 2017 Intel Corporation.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package packet
import (
"fmt"
"unsafe"
. "github.com/intel-go/nff-go/common"
)
// VLANHdr 802.1Q VLAN header. We interpret it as an addition after
// EtherHdr structure, so it contains actual frame EtherType after TCI
// while TPID=0x8100 is present in EtherHdr.
type VLANHdr struct {
TCI uint16 // Tag control information. Contains PCP, DEI and VID bit-fields
EtherType uint16 // Real EtherType instead of VLANNumber in EtherHdr.EtherType
}
func (hdr *VLANHdr) String() string {
return fmt.Sprintf(`L2 VLAN:
TCI: 0x%02x (priority: %d, drop %d, ID: %d)
EtherType: 0x%02x`, SwapBytesUint16(hdr.TCI), byte(SwapBytesUint16(hdr.TCI)>>13),
(SwapBytesUint16(hdr.TCI)>>12)&1, SwapBytesUint16(hdr.TCI)&0xfff, SwapBytesUint16(hdr.EtherType))
}
// GetVLANTagIdentifier returns VID (12 bits of VLAN tag from VLAN header).
func (hdr *VLANHdr) GetVLANTagIdentifier() uint16 {
return SwapBytesUint16(hdr.TCI) & 0x0fff
}
// SetVLANTagIdentifier sets VID (12 bits of VLAN tag to specified value).
func (hdr *VLANHdr) SetVLANTagIdentifier(tag uint16) {
hdr.TCI = SwapBytesUint16((SwapBytesUint16(hdr.TCI) & 0xf000) | (tag & 0x0fff))
}
// GetVLAN returns VLAN header pointer if it is present in the packet.
func (packet *Packet) GetVLAN() *VLANHdr {
if packet.Ether.EtherType == SwapBytesUint16(VLANNumber) {
return (*VLANHdr)(unsafe.Pointer(packet.unparsed()))
}
return nil
}
// GetVLANNoCheck casts pointer to memory right after Ethernet header
// to VLANHdr type.
func (packet *Packet) GetVLANNoCheck() *VLANHdr {
return (*VLANHdr)(unsafe.Pointer(packet.unparsed()))
}
// GetEtherType correctly returns EtherType from Ethernet header or
// VLAN header.
func (packet *Packet) GetEtherType() uint16 {
if packet.Ether.EtherType == SwapBytesUint16(VLANNumber) {
vptr := packet.unparsed()
vhdr := (*VLANHdr)(unsafe.Pointer(vptr))
return SwapBytesUint16(vhdr.EtherType)
}
return SwapBytesUint16(packet.Ether.EtherType)
}
// ParseL3CheckVLAN set pointer to start of L3 header taking possible
// presence of VLAN header into account.
func (packet *Packet) ParseL3CheckVLAN() *VLANHdr {
ptr := packet.unparsed()
if packet.Ether.EtherType == SwapBytesUint16(VLANNumber) {
packet.L3 = unsafe.Pointer(uintptr(ptr) + VLANLen)
return (*VLANHdr)(ptr)
}
packet.L3 = ptr
return nil
}
// GetIPv4CheckVLAN ensures if EtherType is IPv4 and casts L3 pointer
// to IPv4Hdr type. VLAN presence is checked if necessary.
func (packet *Packet) GetIPv4CheckVLAN() *IPv4Hdr {
if packet.GetEtherType() == IPV4Number {
return (*IPv4Hdr)(packet.L3)
}
return nil
}
// GetARPCheckVLAN ensures if EtherType is ARP and casts L3 pointer to
// ARPHdr type. VLAN presence is checked if necessary.
func (packet *Packet) GetARPCheckVLAN() *ARPHdr {
if packet.GetEtherType() == ARPNumber {
return (*ARPHdr)(packet.L3)
}
return nil
}
// GetIPv6CheckVLAN ensures if EtherType is IPv6 and cast L3 pointer
// to IPv6Hdr type. VLAN presence is checked if necessary.
func (packet *Packet) GetIPv6CheckVLAN() *IPv6Hdr {
if packet.GetEtherType() == IPV6Number {
return (*IPv6Hdr)(packet.L3)
}
return nil
}
// ParseAllKnownL3CheckVLAN parses L3 field and returns pointers to parsed
// headers taking possible presence of VLAN header into account.
func (packet *Packet) ParseAllKnownL3CheckVLAN() (*IPv4Hdr, *IPv6Hdr, *ARPHdr) {
packet.ParseL3CheckVLAN()
if packet.GetIPv4CheckVLAN() != nil {
return packet.GetIPv4NoCheck(), nil, nil
} else if packet.GetIPv6CheckVLAN() != nil {
return nil, packet.GetIPv6NoCheck(), nil
} else if packet.GetARPCheckVLAN() != nil {
return nil, nil, packet.GetARPNoCheck()
}
return nil, nil, nil
}
// AddVLANTag increases size of packet on VLANLen and adds 802.1Q VLAN header
// after Ether header, tag is a tag control information. Returns false if error.
func (packet *Packet) AddVLANTag(tag uint16) bool {
// We add vlanTag place two bytes before ending of ethernet.
// VLANhdr.EtherType will automatically be correct and equal to previous ether.etherType
if !packet.EncapsulateHead(EtherLen-2, VLANLen) {
return false
}
vhdr := (*VLANHdr)(unsafe.Pointer(packet.unparsed()))
// EncapsulateHead function has moved pointer to EtherType,
// so the following line is correct. L3 stayed at the same place.
packet.Ether.EtherType = SwapBytesUint16(VLANNumber)
vhdr.TCI = SwapBytesUint16(tag)
return true
}
// RemoveVLANTag decreases size of packet on VLANLen
func (packet *Packet) RemoveVLANTag() bool {
// We want to remove 8100 etherType and remain actual "next" Exther type
// so we need to remove 4 bytes starting 2 bytes earlier than VLANtag
if !packet.DecapsulateHead(EtherLen-2, VLANLen) {
return false
}
return true
}
// ParseDataCheckVLAN parses L3, L4 and fills the field packet.Data.
// returns 0 in case of success and -1 in case of
// failure to parse L3 or L4. VLAN presence is checked.
func (packet *Packet) ParseDataCheckVLAN() int {
var pktTCP *TCPHdr
var pktUDP *UDPHdr
var pktICMP *ICMPHdr
pktIPv4, pktIPv6, _ := packet.ParseAllKnownL3CheckVLAN()
if pktIPv4 != nil {
pktTCP, pktUDP, pktICMP = packet.ParseAllKnownL4ForIPv4()
} else if pktIPv6 != nil {
pktTCP, pktUDP, pktICMP = packet.ParseAllKnownL4ForIPv6()
}
if pktTCP != nil {
packet.Data = unsafe.Pointer(uintptr(packet.L4) + uintptr(((*TCPHdr)(packet.L4)).DataOff&0xf0)>>2)
} else if pktUDP != nil {
packet.Data = unsafe.Pointer(uintptr(packet.L4) + uintptr(UDPLen))
} else if pktICMP != nil {
packet.Data = unsafe.Pointer(uintptr(packet.L4) + uintptr(ICMPLen))
} else {
return -1
}
return 0
}