mirror of
https://github.com/XTLS/Xray-core.git
synced 2026-07-06 11:48:47 +00:00
Finalmask: Add mkcp-legacy (UDP) to replace mkcp-* and legacy header-* (#6201)
https://github.com/XTLS/Xray-core/pull/6193#issuecomment-4543737699 https://github.com/XTLS/Xray-core/pull/6201#issuecomment-4574213827 Example: https://github.com/XTLS/Xray-core/pull/6201#issue-4525483699
This commit is contained in:
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user