Skip to content

Commit 5d09ff9

Browse files
committed
Add TCP unit tests
1 parent c51b417 commit 5d09ff9

File tree

3 files changed

+202
-10
lines changed

3 files changed

+202
-10
lines changed

protocols/tcp.go

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,18 @@ type tcpHeader struct {
1616
destinationPort uint16
1717
sequenceNumber uint32
1818
ackNumber uint32
19-
rawOffset uint8
20-
reserved uint8
21-
flags uint16
19+
rawOffset uint8 // rawOffset is in 4-byte words
20+
flags uint8
2221
windowSize uint16
2322
checksum uint16
2423
urgentPointer uint16
2524
options []byte
2625
}
2726

28-
var errTCPHeaderTooShort = errors.New("TCP header must be at least 20 bytes")
29-
var errTCPHeaderLenMismatch = errors.New("TCP header length less than raw Offset")
27+
var (
28+
errTCPHeaderTooShort = errors.New("TCP header must be at least 20 bytes")
29+
errTCPHeaderLenMismatch = errors.New("TCP header length less than raw Offset")
30+
)
3031

3132
func TCPPacketFromIPPacket(ip IPPacket) (*TCPPacket, error) {
3233
tcpHeader, err := tcpHeaderFromBytes(ip.Payload())
@@ -41,19 +42,20 @@ func tcpHeaderFromBytes(raw []byte) (*tcpHeader, error) {
4142
if len(raw) < 20 {
4243
return nil, errTCPHeaderTooShort
4344
}
44-
offset := (raw[12] >> 4)
45-
hLen := int(offset * 4)
45+
46+
offset := raw[12] >> 4
47+
hLen := int(offset) * 4
4648
if len(raw) < hLen {
4749
return nil, errTCPHeaderLenMismatch
4850
}
51+
4952
return &tcpHeader{
5053
sourcePort: binary.BigEndian.Uint16(raw[0:2]),
5154
destinationPort: binary.BigEndian.Uint16(raw[2:4]),
5255
sequenceNumber: binary.BigEndian.Uint32(raw[4:8]),
5356
ackNumber: binary.BigEndian.Uint32(raw[8:12]),
5457
rawOffset: offset,
55-
reserved: (raw[12] & 0x0E) >> 1,
56-
flags: binary.BigEndian.Uint16(raw[12:14]) & 0x1FF,
58+
flags: raw[13],
5759
windowSize: binary.BigEndian.Uint16(raw[14:16]),
5860
checksum: binary.BigEndian.Uint16(raw[16:18]),
5961
urgentPointer: binary.BigEndian.Uint16(raw[18:20]),

protocols/tcp_test.go

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
package protocols
2+
3+
import (
4+
"reflect"
5+
"testing"
6+
)
7+
8+
func TestTCPPacketFromIPPacket(t *testing.T) {
9+
tests := []struct {
10+
name string
11+
ipPacket IPPacket
12+
expectedErr error
13+
expectedTCPPacket *TCPPacket
14+
}{
15+
{
16+
name: "IPv4 Packet - Valid",
17+
ipPacket: ipv4Packet{
18+
payload: []byte{
19+
0x00, 0x50, 0x01, 0xbb, 0x1c, 0x46, 0x6f, 0x58, 0x00, 0x00, 0x00, 0x00,
20+
0x70, 0x02, 0x20, 0x00, 0xe0, 0x57, 0x00, 0x00,
21+
0x01, 0x01, 0x08, 0x0a, 0x00, 0x00, 0x00, 0x01,
22+
},
23+
},
24+
expectedErr: nil,
25+
expectedTCPPacket: &TCPPacket{
26+
ipPacket: ipv4Packet{
27+
payload: []byte{
28+
0x00, 0x50, 0x01, 0xbb, 0x1c, 0x46, 0x6f, 0x58, 0x00, 0x00, 0x00, 0x00,
29+
0x70, 0x02, 0x20, 0x00, 0xe0, 0x57, 0x00, 0x00,
30+
0x01, 0x01, 0x08, 0x0a, 0x00, 0x00, 0x00, 0x01,
31+
},
32+
},
33+
header: tcpHeader{
34+
sourcePort: 80,
35+
destinationPort: 443,
36+
sequenceNumber: 474378072,
37+
ackNumber: 0,
38+
rawOffset: 7,
39+
flags: 0x2,
40+
windowSize: 8192,
41+
checksum: 0xe057,
42+
urgentPointer: 0,
43+
options: []byte{0x01, 0x01, 0x08, 0x0a, 0x00, 0x00, 0x00, 0x01},
44+
},
45+
},
46+
},
47+
{
48+
name: "IPv6 Packet - Valid",
49+
ipPacket: ipv6Packet{
50+
payload: []byte{
51+
0x00, 0x50, 0x01, 0xbb, 0x1c, 0x46, 0x6f, 0x58, 0x00, 0x00, 0x00, 0x00,
52+
0x70, 0x02, 0x20, 0x00, 0xe0, 0x57, 0x00, 0x00,
53+
0x01, 0x01, 0x08, 0x0a, 0x00, 0x00, 0x00, 0x01,
54+
},
55+
},
56+
expectedErr: nil,
57+
expectedTCPPacket: &TCPPacket{
58+
ipPacket: ipv6Packet{
59+
payload: []byte{
60+
0x00, 0x50, 0x01, 0xbb, 0x1c, 0x46, 0x6f, 0x58, 0x00, 0x00, 0x00, 0x00,
61+
0x70, 0x02, 0x20, 0x00, 0xe0, 0x57, 0x00, 0x00,
62+
0x01, 0x01, 0x08, 0x0a, 0x00, 0x00, 0x00, 0x01,
63+
},
64+
},
65+
header: tcpHeader{
66+
sourcePort: 80,
67+
destinationPort: 443,
68+
sequenceNumber: 474378072,
69+
ackNumber: 0,
70+
rawOffset: 7,
71+
flags: 0x2,
72+
windowSize: 8192,
73+
checksum: 0xe057,
74+
urgentPointer: 0,
75+
options: []byte{0x01, 0x01, 0x08, 0x0a, 0x00, 0x00, 0x00, 0x01},
76+
},
77+
},
78+
},
79+
}
80+
81+
for _, tt := range tests {
82+
t.Run(tt.name, func(t *testing.T) {
83+
tcp, err := TCPPacketFromIPPacket(tt.ipPacket)
84+
if tt.expectedErr != err {
85+
t.Errorf("expected error: %v - got %v", tt.expectedErr, err)
86+
}
87+
if tt.expectedErr == nil && !reflect.DeepEqual(tcp, tt.expectedTCPPacket) {
88+
t.Errorf("expected TCP packet to be %+v - got %+v", tt.expectedTCPPacket, tcp)
89+
}
90+
})
91+
}
92+
}
93+
94+
func TestTCPHeaderFromBytes(t *testing.T) {
95+
tests := []struct {
96+
name string
97+
raw []byte
98+
expectedHeader *tcpHeader
99+
expectedErr error
100+
}{
101+
{
102+
name: "Valid TCP header without options",
103+
raw: []byte{
104+
0x00, 0x50, 0x01, 0xbb, 0x1c, 0x46, 0x6f, 0x58, 0x00, 0x00, 0x00, 0x00,
105+
0x50, 0x02, 0x20, 0x00, 0xe0, 0x57, 0x00, 0x00,
106+
},
107+
expectedHeader: &tcpHeader{
108+
sourcePort: 80,
109+
destinationPort: 443,
110+
sequenceNumber: 474378072,
111+
ackNumber: 0,
112+
rawOffset: 5,
113+
flags: 0x2,
114+
windowSize: 8192,
115+
checksum: 0xe057,
116+
urgentPointer: 0,
117+
options: []byte{},
118+
},
119+
expectedErr: nil,
120+
},
121+
{
122+
name: "Valid TCP header with options",
123+
raw: []byte{
124+
0x00, 0x50, 0x01, 0xbb, 0x1c, 0x46, 0x6f, 0x58, 0x00, 0x00, 0x00, 0x00,
125+
0x70, 0x02, 0x20, 0x00, 0xe0, 0x57, 0x00, 0x00,
126+
0x01, 0x01, 0x08, 0x0a, 0x00, 0x00, 0x00, 0x01,
127+
},
128+
expectedHeader: &tcpHeader{
129+
sourcePort: 80,
130+
destinationPort: 443,
131+
sequenceNumber: 474378072,
132+
ackNumber: 0,
133+
rawOffset: 7,
134+
flags: 0x2,
135+
windowSize: 8192,
136+
checksum: 0xe057,
137+
urgentPointer: 0,
138+
options: []byte{0x01, 0x01, 0x08, 0x0a, 0x00, 0x00, 0x00, 0x01},
139+
},
140+
expectedErr: nil,
141+
},
142+
{
143+
name: "Invalid TCP header (too short)",
144+
raw: []byte{0x00, 0x50},
145+
expectedHeader: nil,
146+
expectedErr: errTCPHeaderTooShort,
147+
},
148+
{
149+
name: "Valid TCP header with minimum length",
150+
raw: []byte{
151+
0x00, 0x50, 0x01, 0xbb, 0x1c, 0x46, 0x6f, 0x58, 0x00, 0x00, 0x00, 0x00,
152+
0x50, 0x02, 0x20, 0x00, 0xe0, 0x57, 0x00, 0x00,
153+
},
154+
expectedHeader: &tcpHeader{
155+
sourcePort: 80,
156+
destinationPort: 443,
157+
sequenceNumber: 474378072,
158+
ackNumber: 0,
159+
rawOffset: 5,
160+
flags: 0x2,
161+
windowSize: 8192,
162+
checksum: 0xe057,
163+
urgentPointer: 0,
164+
options: []byte{},
165+
},
166+
expectedErr: nil,
167+
},
168+
{
169+
name: "Invalid TCP header (length mismatch)",
170+
raw: []byte{
171+
0x00, 0x50, 0x01, 0xbb, 0x1c, 0x46, 0x6f, 0x58, 0x00, 0x00, 0x00, 0x00,
172+
0x80, 0x02, 0x20, 0x00, 0xe0, 0x57, 0x00, 0x00,
173+
},
174+
expectedHeader: nil,
175+
expectedErr: errTCPHeaderLenMismatch,
176+
},
177+
}
178+
179+
for _, tt := range tests {
180+
t.Run(tt.name, func(t *testing.T) {
181+
h, err := tcpHeaderFromBytes(tt.raw)
182+
if tt.expectedErr != err {
183+
t.Errorf("expected error: %v - got %v", tt.expectedErr, err)
184+
}
185+
if tt.expectedErr == nil && !reflect.DeepEqual(h, tt.expectedHeader) {
186+
t.Errorf("expected header to be %+v - got %+v", tt.expectedHeader, h)
187+
}
188+
})
189+
}
190+
}

sockets/raw_socket.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ func (rs *RawSocket) Bind(iface net.Interface) error {
8080
<-rs.shutdownChan
8181
log.Println("Received interrupt, stopping...")
8282
if err := syscall.Close(rs.fd); err != nil {
83-
log.Printf("Failed to close rad socket with file descriptor %d", rs.fd)
83+
log.Printf("Failed to close raw socket with file descriptor %d", rs.fd)
8484
os.Exit(1)
8585
}
8686
os.Exit(0)

0 commit comments

Comments
 (0)