LjhAUMEM
2026-05-29 19:48:22 +08:00
committed by RPRX
parent 569459c54c
commit aba22722a6
38 changed files with 499 additions and 1484 deletions
@@ -16,8 +16,6 @@ func (c *TCPConfig) WrapConnServer(raw net.Conn) (net.Conn, error) {
func (c *UDPConfig) UDP() {}
func (c *UDPConfig) HeaderConn() {}
func (c *UDPConfig) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
return NewConnClientUDP(c, raw)
}
@@ -2,11 +2,14 @@ package custom
import (
"bytes"
"context"
"net"
"sync"
"time"
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/transport/internet/finalmask"
)
const udpStandaloneBufferSize = 4096
@@ -29,16 +32,16 @@ func (h *udpCustomClient) Serialize(b []byte) {
copy(b, evaluated)
}
func (h *udpCustomClient) Match(b []byte) bool {
func (h *udpCustomClient) Match(b []byte, addr net.Addr) bool {
var initial map[string][]byte
if h.state != nil {
initial, _ = h.state.get(udpStateKey(nil))
initial, _ = h.state.get(udpStateKey(addr))
}
vars, ok := matchUDPItems(h.server, b, h.read, initial)
if ok {
h.vars = vars
if h.state != nil {
h.state.set(udpStateKey(nil), vars)
h.state.set(udpStateKey(addr), vars)
}
}
return ok
@@ -73,24 +76,38 @@ func NewConnClientUDP(c *UDPConfig, raw net.PacketConn) (net.PacketConn, error)
return conn, nil
}
func (c *udpCustomClientConn) Size() int {
return len(c.header.merged)
}
func (c *udpCustomClientConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
if !c.header.Match(p) {
return 0, addr, errors.New("header mismatch")
b := p
if len(b) < finalmask.UDPSize {
buf := buf.New()
buf.Resize(0, finalmask.UDPSize)
b = buf.Bytes()
defer buf.Release()
}
return len(p) - c.header.read, addr, nil
for {
n, addr, err := c.PacketConn.ReadFrom(b)
if err != nil {
return n, addr, err
}
if !c.header.Match(b[:n], addr) {
errors.LogError(context.Background(), "[mask] drop packet from ", addr, " with size ", n, " > header mismatch")
continue
}
copy(p, b[c.header.read:n])
return n - c.header.read, addr, nil
}
}
func (c *udpCustomClientConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
var localAddr net.Addr
if c.PacketConn != nil {
localAddr = c.PacketConn.LocalAddr()
}
ctx := newEvalContextWithAddrs(localAddr, addr)
buf := buf.New()
buf.Resize(0, finalmask.UDPSize)
b := buf.Bytes()
defer buf.Release()
ctx := newEvalContextWithAddrs(c.PacketConn.LocalAddr(), addr)
if vars, ok := c.header.state.get(udpStateKey(addr)); ok {
ctx.vars = cloneVars(vars)
} else if len(c.header.vars) > 0 {
@@ -98,13 +115,21 @@ func (c *udpCustomClientConn) WriteTo(p []byte, addr net.Addr) (n int, err error
}
evaluated, err := evaluateUDPItemsWithContext(c.header.client, ctx)
if err != nil {
return 0, err
errors.LogErrorInner(context.Background(), err, "[mask] drop packet to ", addr, " with size ", len(p))
return 0, nil
}
if len(evaluated) != len(c.header.merged) {
return 0, errors.New("header size mismatch")
errors.LogError(context.Background(), "[mask] drop packet to ", addr, " with size ", len(p), " > header size mismatch")
return 0, nil
}
c.header.state.set(udpStateKey(addr), ctx.vars)
copy(p, evaluated)
copy(b, evaluated)
copy(b[len(evaluated):], p)
_, err = c.PacketConn.WriteTo(b[:len(evaluated)+len(p)], addr)
if err != nil {
errors.LogErrorInner(context.Background(), err, "[mask] drop packet to ", addr, " with size ", len(p))
return 0, err
}
return len(p), nil
}
@@ -127,16 +152,16 @@ func (h *udpCustomServer) Serialize(b []byte) {
copy(b, evaluated)
}
func (h *udpCustomServer) Match(b []byte) bool {
func (h *udpCustomServer) Match(b []byte, addr net.Addr) bool {
var initial map[string][]byte
if h.state != nil {
initial, _ = h.state.get(udpStateKey(nil))
initial, _ = h.state.get(udpStateKey(addr))
}
vars, ok := matchUDPItems(h.client, b, h.read, initial)
if ok {
h.vars = vars
if h.state != nil {
h.state.set(udpStateKey(nil), vars)
h.state.set(udpStateKey(addr), vars)
}
}
return ok
@@ -171,24 +196,38 @@ func NewConnServerUDP(c *UDPConfig, raw net.PacketConn) (net.PacketConn, error)
return conn, nil
}
func (c *udpCustomServerConn) Size() int {
return len(c.header.merged)
}
func (c *udpCustomServerConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
if !c.header.Match(p) {
return 0, addr, errors.New("header mismatch")
b := p
if len(b) < finalmask.UDPSize {
buf := buf.New()
buf.Resize(0, finalmask.UDPSize)
b = buf.Bytes()
defer buf.Release()
}
return len(p) - c.header.read, addr, nil
for {
n, addr, err := c.PacketConn.ReadFrom(b)
if err != nil {
return n, addr, err
}
if !c.header.Match(b[:n], addr) {
errors.LogError(context.Background(), "[mask] drop packet from ", addr, " with size ", n, " > header mismatch")
continue
}
copy(p, b[c.header.read:n])
return n - c.header.read, addr, nil
}
}
func (c *udpCustomServerConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
var localAddr net.Addr
if c.PacketConn != nil {
localAddr = c.PacketConn.LocalAddr()
}
ctx := newEvalContextWithAddrs(localAddr, addr)
buf := buf.New()
buf.Resize(0, finalmask.UDPSize)
b := buf.Bytes()
defer buf.Release()
ctx := newEvalContextWithAddrs(c.PacketConn.LocalAddr(), addr)
if vars, ok := c.header.state.get(udpStateKey(addr)); ok {
ctx.vars = cloneVars(vars)
} else if len(c.header.vars) > 0 {
@@ -196,13 +235,21 @@ func (c *udpCustomServerConn) WriteTo(p []byte, addr net.Addr) (n int, err error
}
evaluated, err := evaluateUDPItemsWithContext(c.header.server, ctx)
if err != nil {
return 0, err
errors.LogErrorInner(context.Background(), err, "[mask] drop packet to ", addr, " with size ", len(p))
return 0, nil
}
if len(evaluated) != len(c.header.merged) {
return 0, errors.New("header size mismatch")
errors.LogError(context.Background(), "[mask] drop packet to ", addr, " with size ", len(p), " > header size mismatch")
return 0, nil
}
c.header.state.set(udpStateKey(addr), ctx.vars)
copy(p, evaluated)
copy(b, evaluated)
copy(b[len(evaluated):], p)
_, err = c.PacketConn.WriteTo(b[:len(evaluated)+len(p)], addr)
if err != nil {
errors.LogErrorInner(context.Background(), err, "[mask] drop packet to ", addr, " with size ", len(p))
return 0, err
}
return len(p), nil
}
@@ -1,43 +1,9 @@
package custom
import (
"bytes"
"net"
"testing"
)
func TestDSLUDPClientSizeTracksEvaluatedItems(t *testing.T) {
conn, err := NewConnClientUDP(&UDPConfig{
Client: []*UDPItem{
{
Rand: 2,
RandMin: 0x2A,
RandMax: 0x2A,
Save: "txid",
},
{
Var: "txid",
},
{
Expr: &Expr{
Op: "concat",
Args: []*ExprArg{
{Value: &ExprArg_Bytes{Bytes: []byte{0xAB}}},
{Value: &ExprArg_Bytes{Bytes: []byte{0xCD}}},
},
},
},
},
}, nil)
if err != nil {
t.Fatal(err)
}
if got := conn.(*udpCustomClientConn).Size(); got != 6 {
t.Fatalf("unexpected header size: got=%d want=6", got)
}
}
func TestDSLUDPServerMatchCapturesSavedValues(t *testing.T) {
conn, err := NewConnServerUDP(&UDPConfig{
Client: []*UDPItem{
@@ -55,7 +21,7 @@ func TestDSLUDPServerMatchCapturesSavedValues(t *testing.T) {
}
server := conn.(*udpCustomServerConn)
if !server.header.Match([]byte{0x01, 0x02, 0x01, 0x02}) {
if !server.header.Match([]byte{0x01, 0x02, 0x01, 0x02}, nil) {
t.Fatal("expected packet to match")
}
@@ -81,108 +47,7 @@ func TestDSLUDPServerRejectsMalformedVarReference(t *testing.T) {
}
server := conn.(*udpCustomServerConn)
if server.header.Match([]byte{0x01, 0x02, 0x03, 0x04}) {
if server.header.Match([]byte{0x01, 0x02, 0x03, 0x04}, nil) {
t.Fatal("expected packet mismatch")
}
}
func TestDSLUDPClientWriteSupportsExtendedExprOps(t *testing.T) {
conn, err := NewConnClientUDP(&UDPConfig{
Client: []*UDPItem{
{
Expr: &Expr{
Op: "le16",
Args: []*ExprArg{
{
Value: &ExprArg_Expr{
Expr: &Expr{
Op: "add",
Args: []*ExprArg{
{Value: &ExprArg_U64{U64: 1}},
{Value: &ExprArg_U64{U64: 2}},
},
},
},
},
},
},
},
{
Expr: &Expr{
Op: "pad",
Args: []*ExprArg{
{Value: &ExprArg_Bytes{Bytes: []byte{0xAA}}},
{Value: &ExprArg_U64{U64: 3}},
{Value: &ExprArg_Bytes{Bytes: []byte{0xBB}}},
},
},
},
{
Expr: &Expr{
Op: "truncate",
Args: []*ExprArg{
{Value: &ExprArg_Bytes{Bytes: []byte{1, 2, 3, 4}}},
{Value: &ExprArg_U64{U64: 2}},
},
},
},
{
Expr: &Expr{
Op: "be16",
Args: []*ExprArg{
{
Value: &ExprArg_Expr{
Expr: &Expr{
Op: "or",
Args: []*ExprArg{
{
Value: &ExprArg_Expr{
Expr: &Expr{
Op: "shl",
Args: []*ExprArg{
{Value: &ExprArg_U64{U64: 1}},
{Value: &ExprArg_U64{U64: 8}},
},
},
},
},
{
Value: &ExprArg_Expr{
Expr: &Expr{
Op: "shr",
Args: []*ExprArg{
{Value: &ExprArg_U64{U64: 0x80}},
{Value: &ExprArg_U64{U64: 7}},
},
},
},
},
},
},
},
},
},
},
},
},
}, nil)
if err != nil {
t.Fatal(err)
}
client := conn.(*udpCustomClientConn)
buf := make([]byte, client.Size())
if _, err := client.WriteTo(buf, &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 53}); err != nil {
t.Fatal(err)
}
want := []byte{
0x03, 0x00,
0xAA, 0xBB, 0xBB,
0x01, 0x02,
0x01, 0x01,
}
if !bytes.Equal(buf, want) {
t.Fatalf("unexpected encoded header: %x", buf)
}
}