package vless import ( "bytes" "encoding/binary" "net" "testing" ) func buildRequest(t *testing.T, uuid [16]byte, addons []byte, cmd byte, port uint16, addrType byte, addr []byte) []byte { t.Helper() var buf bytes.Buffer buf.WriteByte(Version) // version buf.Write(uuid[:]) // UUID if addons == nil { buf.WriteByte(0) // addons length } else { buf.WriteByte(byte(len(addons))) buf.Write(addons) } buf.WriteByte(cmd) // command var portBuf [2]byte binary.BigEndian.PutUint16(portBuf[:], port) buf.Write(portBuf[:]) // port buf.WriteByte(addrType) // address type buf.Write(addr) // address return buf.Bytes() } func TestParseRequest_TCPIPv4(t *testing.T) { uuid := [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16} ip := net.ParseIP("192.168.1.1").To4() data := buildRequest(t, uuid, nil, CmdTCP, 8080, AddrIPv4, ip) req, err := ParseRequest(bytes.NewReader(data)) if err != nil { t.Fatalf("unexpected error: %v", err) } if req.UUID != uuid { t.Errorf("UUID mismatch: got %v, want %v", req.UUID, uuid) } if req.Command != CmdTCP { t.Errorf("Command mismatch: got %d, want %d", req.Command, CmdTCP) } if req.Port != 8080 { t.Errorf("Port mismatch: got %d, want 8080", req.Port) } if req.Address != "192.168.1.1" { t.Errorf("Address mismatch: got %q, want %q", req.Address, "192.168.1.1") } if req.Target() != "192.168.1.1:8080" { t.Errorf("Target mismatch: got %q", req.Target()) } } func TestParseRequest_UDPDomain(t *testing.T) { uuid := [16]byte{0xaa, 0xbb, 0xcc, 0xdd} domain := "example.com" addrBuf := append([]byte{byte(len(domain))}, []byte(domain)...) data := buildRequest(t, uuid, nil, CmdUDP, 53, AddrDomain, addrBuf) req, err := ParseRequest(bytes.NewReader(data)) if err != nil { t.Fatalf("unexpected error: %v", err) } if req.Command != CmdUDP { t.Errorf("Command mismatch: got %d, want %d", req.Command, CmdUDP) } if req.Port != 53 { t.Errorf("Port mismatch: got %d, want 53", req.Port) } if req.Address != "example.com" { t.Errorf("Address mismatch: got %q, want %q", req.Address, "example.com") } } func TestParseRequest_TCPIPv6(t *testing.T) { uuid := [16]byte{0xff} ip := net.ParseIP("2001:db8::1").To16() data := buildRequest(t, uuid, nil, CmdTCP, 443, AddrIPv6, ip) req, err := ParseRequest(bytes.NewReader(data)) if err != nil { t.Fatalf("unexpected error: %v", err) } if req.Address != "2001:db8::1" { t.Errorf("Address mismatch: got %q, want %q", req.Address, "2001:db8::1") } } func TestParseRequest_WithAddons(t *testing.T) { uuid := [16]byte{0x01} addons := []byte{0x0a, 0x0b, 0x0c} ip := net.ParseIP("10.0.0.1").To4() data := buildRequest(t, uuid, addons, CmdTCP, 80, AddrIPv4, ip) req, err := ParseRequest(bytes.NewReader(data)) if err != nil { t.Fatalf("unexpected error: %v", err) } if len(req.Addons) != 3 { t.Errorf("Addons length mismatch: got %d, want 3", len(req.Addons)) } if req.Address != "10.0.0.1" { t.Errorf("Address mismatch: got %q", req.Address) } } func TestParseRequest_BadVersion(t *testing.T) { data := []byte{0x01} // version 1, invalid _, err := ParseRequest(bytes.NewReader(data)) if err == nil { t.Fatal("expected error for bad version") } } func TestParseRequest_Truncated(t *testing.T) { // Only version + partial UUID. data := []byte{0x00, 0x01, 0x02} _, err := ParseRequest(bytes.NewReader(data)) if err == nil { t.Fatal("expected error for truncated input") } } func TestParseRequest_BadCommand(t *testing.T) { uuid := [16]byte{} ip := net.ParseIP("1.2.3.4").To4() data := buildRequest(t, uuid, nil, 0x03, 80, AddrIPv4, ip) // cmd=Mux, unsupported _, err := ParseRequest(bytes.NewReader(data)) if err == nil { t.Fatal("expected error for unsupported command") } } func TestParseRequest_BadAddrType(t *testing.T) { uuid := [16]byte{} // Build manually with bad address type. var buf bytes.Buffer buf.WriteByte(Version) buf.Write(uuid[:]) buf.WriteByte(0) // no addons buf.WriteByte(0x01) // TCP var portBuf [2]byte binary.BigEndian.PutUint16(portBuf[:], 80) buf.Write(portBuf[:]) buf.WriteByte(0xFF) // bad address type _, err := ParseRequest(bytes.NewReader(buf.Bytes())) if err == nil { t.Fatal("expected error for bad address type") } } func TestWriteResponse(t *testing.T) { var buf bytes.Buffer if err := WriteResponse(&buf); err != nil { t.Fatalf("unexpected error: %v", err) } if buf.Len() != 2 { t.Fatalf("response length mismatch: got %d, want 2", buf.Len()) } if buf.Bytes()[0] != 0x00 || buf.Bytes()[1] != 0x00 { t.Errorf("response bytes mismatch: got %v, want [0x00, 0x00]", buf.Bytes()) } }