Files
Mellaris/engine/packet_ipv6_test.go
T
2026-05-14 09:41:07 +05:30

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")
}
}