128 lines
3.5 KiB
Go
128 lines
3.5 KiB
Go
package engine
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"net"
|
|
"testing"
|
|
|
|
"github.com/google/gopacket/layers"
|
|
)
|
|
|
|
func TestParseL3IPv6UDP(t *testing.T) {
|
|
src := net.ParseIP("2001:db8::10").To16()
|
|
dst := net.ParseIP("2001:db8::20").To16()
|
|
payload := []byte("hello")
|
|
|
|
pkt := buildIPv6UDPPacket(t, src, dst, 12345, 443, payload)
|
|
l3, transport, ok := ParseL3(pkt)
|
|
if !ok {
|
|
t.Fatal("ParseL3 should parse IPv6 packet")
|
|
}
|
|
if l3.Version != 6 {
|
|
t.Fatalf("version=%d want=6", l3.Version)
|
|
}
|
|
if l3.Protocol != 17 {
|
|
t.Fatalf("protocol=%d want=17 (udp)", l3.Protocol)
|
|
}
|
|
if !l3.SrcIPAddr().Equal(src) {
|
|
t.Fatalf("src=%v want=%v", l3.SrcIPAddr(), src)
|
|
}
|
|
if !l3.DstIPAddr().Equal(dst) {
|
|
t.Fatalf("dst=%v want=%v", l3.DstIPAddr(), dst)
|
|
}
|
|
udp, gotPayload, ok := ParseUDP(transport)
|
|
if !ok {
|
|
t.Fatal("ParseUDP should parse transport payload")
|
|
}
|
|
if udp.SrcPort != 12345 || udp.DstPort != 443 {
|
|
t.Fatalf("ports=%d->%d want=12345->443", udp.SrcPort, udp.DstPort)
|
|
}
|
|
if string(gotPayload) != string(payload) {
|
|
t.Fatalf("payload=%q want=%q", string(gotPayload), string(payload))
|
|
}
|
|
}
|
|
|
|
func TestParseL3IPv6HopByHopThenUDP(t *testing.T) {
|
|
src := net.ParseIP("2001:db8::1").To16()
|
|
dst := net.ParseIP("2001:db8::2").To16()
|
|
udpPayload := []byte("abc")
|
|
udpLen := 8 + len(udpPayload)
|
|
totalPayloadLen := 8 + udpLen // 8-byte hop-by-hop extension + udp packet
|
|
|
|
pkt := make([]byte, 40+totalPayloadLen)
|
|
pkt[0] = 0x60
|
|
binary.BigEndian.PutUint16(pkt[4:6], uint16(totalPayloadLen))
|
|
pkt[6] = 0 // Hop-by-hop
|
|
pkt[7] = 64 // Hop limit
|
|
copy(pkt[8:24], src)
|
|
copy(pkt[24:40], dst)
|
|
|
|
off := 40
|
|
pkt[off+0] = 17 // Next header: UDP
|
|
pkt[off+1] = 0 // Hdr Ext Len: (0+1)*8 = 8 bytes
|
|
off += 8
|
|
|
|
binary.BigEndian.PutUint16(pkt[off:off+2], 5353)
|
|
binary.BigEndian.PutUint16(pkt[off+2:off+4], 53)
|
|
binary.BigEndian.PutUint16(pkt[off+4:off+6], uint16(udpLen))
|
|
copy(pkt[off+8:], udpPayload)
|
|
|
|
l3, transport, ok := ParseL3(pkt)
|
|
if !ok {
|
|
t.Fatal("ParseL3 should parse IPv6 packet with extension headers")
|
|
}
|
|
if l3.Version != 6 || l3.Protocol != 17 {
|
|
t.Fatalf("version/protocol=%d/%d want=6/17", l3.Version, l3.Protocol)
|
|
}
|
|
udp, gotPayload, ok := ParseUDP(transport)
|
|
if !ok {
|
|
t.Fatal("ParseUDP should parse UDP after hop-by-hop extension")
|
|
}
|
|
if udp.SrcPort != 5353 || udp.DstPort != 53 {
|
|
t.Fatalf("ports=%d->%d want=5353->53", udp.SrcPort, udp.DstPort)
|
|
}
|
|
if string(gotPayload) != string(udpPayload) {
|
|
t.Fatalf("payload=%q want=%q", string(gotPayload), string(udpPayload))
|
|
}
|
|
}
|
|
|
|
func buildIPv6UDPPacket(t *testing.T, src, dst net.IP, srcPort, dstPort uint16, payload []byte) []byte {
|
|
t.Helper()
|
|
udpLen := 8 + len(payload)
|
|
pkt := make([]byte, 40+udpLen)
|
|
pkt[0] = 0x60
|
|
binary.BigEndian.PutUint16(pkt[4:6], uint16(udpLen))
|
|
pkt[6] = 17
|
|
pkt[7] = 64
|
|
copy(pkt[8:24], src.To16())
|
|
copy(pkt[24:40], dst.To16())
|
|
off := 40
|
|
binary.BigEndian.PutUint16(pkt[off:off+2], srcPort)
|
|
binary.BigEndian.PutUint16(pkt[off+2:off+4], dstPort)
|
|
binary.BigEndian.PutUint16(pkt[off+4:off+6], uint16(udpLen))
|
|
copy(pkt[off+8:], payload)
|
|
return pkt
|
|
}
|
|
|
|
func TestParseL3IPv6FragmentNonFirst(t *testing.T) {
|
|
src := net.ParseIP("2001:db8::a").To16()
|
|
dst := net.ParseIP("2001:db8::b").To16()
|
|
|
|
// IPv6 header + fragment header (offset != 0)
|
|
pkt := make([]byte, 48)
|
|
pkt[0] = 0x60
|
|
binary.BigEndian.PutUint16(pkt[4:6], 8)
|
|
pkt[6] = 44
|
|
pkt[7] = 64
|
|
copy(pkt[8:24], src)
|
|
copy(pkt[24:40], dst)
|
|
pkt[40] = uint8(layers.IPProtocolUDP)
|
|
// fragment offset in 8-byte units: 1 (non-first fragment)
|
|
binary.BigEndian.PutUint16(pkt[42:44], 1<<3)
|
|
|
|
_, _, ok := ParseL3(pkt)
|
|
if ok {
|
|
t.Fatal("ParseL3 should reject non-first IPv6 fragments for L4 parsing")
|
|
}
|
|
}
|