Skip to content

Commit 79778f2

Browse files
vista-ggidofalvy-tc
authored andcommitted
Add unit tests for Ethernet and VLAN manipulation functions
1 parent 6aab800 commit 79778f2

File tree

1 file changed

+176
-0
lines changed

1 file changed

+176
-0
lines changed

dhcpv4/nclient4/ethernet_test.go

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
//go:build go1.12
2+
// +build go1.12
3+
4+
package nclient4
5+
6+
import (
7+
"bytes"
8+
"net"
9+
"testing"
10+
11+
"github.com/google/gopacket"
12+
"github.com/google/gopacket/layers"
13+
"github.com/u-root/uio/uio"
14+
)
15+
16+
var (
17+
testMac = net.HardwareAddr{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}
18+
// Test payload 123456789abcdefghijklmnopqrstvwxyz
19+
// This length is required to avoid zero-padding the Ethernet frame from the right side
20+
testPayload = gopacket.Payload{0x54, 0x65, 0x73, 0x74, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x76, 0x77, 0x78, 0x79, 0x7a}
21+
22+
ethHdrIPv4 = &layers.Ethernet{
23+
DstMAC: BroadcastMac,
24+
SrcMAC: testMac,
25+
EthernetType: layers.EthernetTypeIPv4,
26+
}
27+
ethHdrVLAN = &layers.Ethernet{
28+
DstMAC: BroadcastMac,
29+
SrcMAC: testMac,
30+
EthernetType: layers.EthernetTypeDot1Q,
31+
}
32+
ethHdrARP = &layers.Ethernet{
33+
DstMAC: BroadcastMac,
34+
SrcMAC: testMac,
35+
EthernetType: layers.EthernetTypeARP,
36+
}
37+
vlanTagOuter = &layers.Dot1Q{
38+
Priority: 0,
39+
DropEligible: false,
40+
VLANIdentifier: 100,
41+
Type: layers.EthernetTypeDot1Q,
42+
}
43+
vlanTagInner = &layers.Dot1Q{
44+
Priority: 0,
45+
DropEligible: false,
46+
VLANIdentifier: 200,
47+
Type: layers.EthernetTypeIPv4,
48+
}
49+
ipv4Hdr = &layers.IPv4{
50+
SrcIP: net.IP{1, 2, 3, 4},
51+
DstIP: net.IP{5, 6, 7, 8},
52+
}
53+
opts = gopacket.SerializeOptions{}
54+
)
55+
56+
func TestProcessVLANStack(t *testing.T) {
57+
for _, tt := range []struct {
58+
name string
59+
inputBytes []byte
60+
vlanConfig []uint16
61+
wantSuccess bool
62+
}{
63+
{"no VLANs + no VLANs configured", []byte{0x08, 0x00}, []uint16{}, true},
64+
{"no VLANs + VLAN configured", []byte{0x08, 0x00}, []uint16{100}, false},
65+
{"valid VLAN stack (single)", []byte{0x81, 0x00, 0x01, 0x00, 0x08, 0x00}, []uint16{0x100}, true},
66+
{"invalid VLAN stack (single)", []byte{0x81, 0x00, 0x01, 0xFF, 0x08, 0x00}, []uint16{0x100}, false},
67+
{"valid VLAN stack (double)", []byte{0x81, 0x00, 0x01, 0x00, 0x81, 0x00, 0x02, 0x00, 0x08, 0x00}, []uint16{0x100, 0x200}, true},
68+
{"invalid VLAN stack (double)", []byte{0x81, 0x00, 0x01, 0x00, 0x81, 0x00, 0x02, 0xFF, 0x08, 0x00}, []uint16{0x100, 0x200}, false},
69+
{"invalid VLAN stack (too short)", []byte{0x81, 0x00, 0x01, 0x00, 0x08, 0x00}, []uint16{0x100, 0x200}, false},
70+
{"invalid VLAN stack (too long)", []byte{0x81, 0x00, 0x01, 0x00, 0x81, 0x00, 0x02, 0x00, 0x08, 0x00}, []uint16{0x100}, false},
71+
{"invalid packet (ARP)", []byte{0x08, 0x06}, []uint16{}, false},
72+
} {
73+
t.Run(tt.name, func(t *testing.T) {
74+
testBuf := uio.NewBigEndianBuffer(tt.inputBytes)
75+
testSuccess := processVLANStack(testBuf, tt.vlanConfig)
76+
77+
if testSuccess != tt.wantSuccess {
78+
t.Errorf("got %v, want %v", testSuccess, tt.wantSuccess)
79+
}
80+
})
81+
}
82+
}
83+
84+
func TestCreateVLANTag(t *testing.T) {
85+
// Gopacket builds VLAN tags the other way around: first VLAN ID/TCI, then TPID, due to their different layered approach
86+
// Since a VLAN tag is only 4 bytes, and the value is well-known, it makes sense to just construct the packet by hand.
87+
want := []byte{0x81, 0x00, 0x01, 0x23}
88+
89+
test := createVLANTag(0x0123)
90+
91+
if !bytes.Equal(test, want) {
92+
t.Errorf("got %v, want %v", test, want)
93+
}
94+
}
95+
96+
func TestGetEthernetPayload(t *testing.T) {
97+
for _, tt := range []struct {
98+
name string
99+
testLayers []gopacket.SerializableLayer
100+
wantLayers []gopacket.SerializableLayer
101+
vlanConfig []uint16
102+
}{
103+
{"no VLAN", []gopacket.SerializableLayer{ethHdrIPv4, ipv4Hdr, testPayload}, []gopacket.SerializableLayer{ipv4Hdr, testPayload}, []uint16{}},
104+
{"single VLAN", []gopacket.SerializableLayer{ethHdrVLAN, vlanTagInner, ipv4Hdr, testPayload}, []gopacket.SerializableLayer{ipv4Hdr, testPayload}, []uint16{200}},
105+
{"QinQ", []gopacket.SerializableLayer{ethHdrVLAN, vlanTagOuter, vlanTagInner, ipv4Hdr, testPayload}, []gopacket.SerializableLayer{ipv4Hdr, testPayload}, []uint16{100, 200}},
106+
{"invalid VLAN", []gopacket.SerializableLayer{ethHdrVLAN, vlanTagInner, ipv4Hdr, testPayload}, nil, []uint16{300}},
107+
{"invalid packet (ARP)", []gopacket.SerializableLayer{ethHdrARP}, nil, []uint16{}},
108+
} {
109+
t.Run(tt.name, func(t *testing.T) {
110+
testBuf := gopacket.NewSerializeBuffer()
111+
err := gopacket.SerializeLayers(testBuf, opts, tt.testLayers...)
112+
if err != nil {
113+
t.Errorf("error serializing in gopacket (not our bug!)")
114+
}
115+
116+
var want []byte
117+
if tt.wantLayers == nil {
118+
want = nil
119+
} else {
120+
wantBuf := gopacket.NewSerializeBuffer()
121+
err := gopacket.SerializeLayers(wantBuf, opts, tt.wantLayers...)
122+
if err != nil {
123+
t.Errorf("error serializing in gopacket (not our bug!)")
124+
}
125+
want = wantBuf.Bytes()
126+
}
127+
128+
testBytes := testBuf.Bytes()
129+
test := getEthernetPayload(testBytes, tt.vlanConfig)
130+
131+
if !bytes.Equal(test, want) {
132+
t.Errorf("got %v, want %v", test, want)
133+
}
134+
})
135+
}
136+
}
137+
138+
func TestAddEthernetHdrTwo(t *testing.T) {
139+
for _, tt := range []struct {
140+
name string
141+
testLayers []gopacket.SerializableLayer
142+
wantLayers []gopacket.SerializableLayer
143+
vlanConfig []uint16
144+
}{
145+
{"no VLAN", []gopacket.SerializableLayer{ipv4Hdr, testPayload}, []gopacket.SerializableLayer{ethHdrIPv4, ipv4Hdr, testPayload}, []uint16{}},
146+
{"single VLAN", []gopacket.SerializableLayer{ipv4Hdr, testPayload}, []gopacket.SerializableLayer{ethHdrVLAN, vlanTagInner, ipv4Hdr, testPayload}, []uint16{200}},
147+
{"QinQ", []gopacket.SerializableLayer{ipv4Hdr, testPayload}, []gopacket.SerializableLayer{ethHdrVLAN, vlanTagOuter, vlanTagInner, ipv4Hdr, testPayload}, []uint16{100, 200}},
148+
} {
149+
t.Run(tt.name, func(t *testing.T) {
150+
testBuf := gopacket.NewSerializeBuffer()
151+
err := gopacket.SerializeLayers(testBuf, opts, tt.testLayers...)
152+
if err != nil {
153+
t.Errorf("error serializing in gopacket (not our bug!)")
154+
}
155+
156+
var want []byte
157+
if tt.wantLayers == nil {
158+
want = nil
159+
} else {
160+
wantBuf := gopacket.NewSerializeBuffer()
161+
err := gopacket.SerializeLayers(wantBuf, opts, tt.wantLayers...)
162+
if err != nil {
163+
t.Errorf("error serializing in gopacket (not our bug!)")
164+
}
165+
want = wantBuf.Bytes()
166+
}
167+
168+
testBytes := testBuf.Bytes()
169+
test := addEthernetHdr(testBytes, BroadcastMac, testMac, etherIPv4Proto, tt.vlanConfig)
170+
171+
if !bytes.Equal(test, want) {
172+
t.Errorf("got %v, want %v", test, want)
173+
}
174+
})
175+
}
176+
}

0 commit comments

Comments
 (0)