LjhAUMEM
2026-09-20 18:12:50 +00:00
committed by GitHub
parent 24e6f6d551
commit 8267cf953a
47 changed files with 920 additions and 959 deletions
+5 -16
View File
@@ -14,7 +14,6 @@ import (
googleuuid "github.com/google/uuid" googleuuid "github.com/google/uuid"
"github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/finalmask/fragment" "github.com/xtls/xray-core/transport/internet/finalmask/fragment"
"github.com/xtls/xray-core/transport/internet/finalmask/header/custom" "github.com/xtls/xray-core/transport/internet/finalmask/header/custom"
"github.com/xtls/xray-core/transport/internet/finalmask/mkcp/aes128gcm" "github.com/xtls/xray-core/transport/internet/finalmask/mkcp/aes128gcm"
@@ -909,22 +908,13 @@ func (c *Realm) Build() (proto.Message, error) {
} }
type UDPHop struct { type UDPHop struct {
Sockopt *SocketConfig `json:"sockopt"` Mode string `json:"mode"`
Mode string `json:"mode"` Interval Int32Range `json:"interval"`
Interval Int32Range `json:"interval"` RemoteIPs []string `json:"remoteIPs"`
RemotePorts PortList `json:"remotePorts"` RemotePorts PortList `json:"remotePorts"`
RemoteIPs []string `json:"remoteIPs"`
} }
func (c *UDPHop) Build() (proto.Message, error) { func (c *UDPHop) Build() (proto.Message, error) {
var sockopt *internet.SocketConfig
if c.Sockopt != nil {
var err error
sockopt, err = c.Sockopt.Build()
if err != nil {
return nil, err
}
}
var local, remote, remoteOnce bool var local, remote, remoteOnce bool
for _, mode := range strings.Split(c.Mode, ",") { for _, mode := range strings.Split(c.Mode, ",") {
switch strings.ToLower(mode) { switch strings.ToLower(mode) {
@@ -953,14 +943,13 @@ func (c *UDPHop) Build() (proto.Message, error) {
return nil, errors.New("invalid ip ", ip) return nil, errors.New("invalid ip ", ip)
} }
return &udphop.Config{ return &udphop.Config{
Sockopt: sockopt,
Local: local, Local: local,
Remote: remote, Remote: remote,
RemoteOnce: remoteOnce, RemoteOnce: remoteOnce,
IntervalMin: int64(c.Interval.From), IntervalMin: int64(c.Interval.From),
IntervalMax: int64(c.Interval.To), IntervalMax: int64(c.Interval.To),
RemotePorts: c.RemotePorts.Build().Ports(),
RemoteIPs: remoteIPs, RemoteIPs: remoteIPs,
RemotePorts: c.RemotePorts.Build().Ports(),
}, nil }, nil
} }
+18 -17
View File
@@ -28,6 +28,7 @@ import (
"github.com/xtls/xray-core/features/stats" "github.com/xtls/xray-core/features/stats"
"github.com/xtls/xray-core/transport" "github.com/xtls/xray-core/transport"
"github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/finalmask"
"golang.zx2c4.com/wireguard/device" "golang.zx2c4.com/wireguard/device"
) )
@@ -293,26 +294,26 @@ func (h *Handler) init(ctx context.Context) error {
if err != nil { if err != nil {
return nil, err return nil, err
} }
conn, err := internet.DialSystem(ctx, dest, h.streamSettings.SocketSettings)
if err != nil {
return nil, err
}
var pktConn net.PacketConn var pktConn net.PacketConn
switch c := conn.(type) { if h.streamSettings.FinalMask != nil {
case *internet.PacketConnWrapper: conn, err := h.streamSettings.FinalMask.DialUDP(ctx, dest)
pktConn = c.PacketConn
case *cnc.Connection:
pktConn = &internet.FakePacketConn{Conn: c}
default:
panic(reflect.TypeOf(c))
}
if h.streamSettings.UdpmaskManager != nil {
newConn, err := h.streamSettings.UdpmaskManager.WrapPacketConnClient(pktConn)
if err != nil { if err != nil {
pktConn.Close() return nil, errors.New("failed to dial to dest").Base(err)
return nil, errors.New("mask err").Base(err) }
pktConn = conn.(*finalmask.PacketConnWrapper).PacketConn
} else {
conn, err := internet.DialSystem(ctx, dest, h.streamSettings.SocketSettings)
if err != nil {
return nil, errors.New("failed to dial to dest").Base(err)
}
switch c := conn.(type) {
case *internet.PacketConnWrapper:
pktConn = c.PacketConn
case *cnc.Connection:
pktConn = &internet.FakePacketConn{Conn: c}
default:
panic(reflect.TypeOf(c))
} }
pktConn = newConn
} }
if h.uplinkCounter != nil || h.downlinkCounter != nil { if h.uplinkCounter != nil || h.downlinkCounter != nil {
pktConn = &PacketCounterConnection{ pktConn = &PacketCounterConnection{
+7 -9
View File
@@ -258,18 +258,16 @@ func (s *Server) Start() error {
return errors.New("address is domain") return errors.New("address is domain")
} }
listenFunc := func() (net.PacketConn, error) { listenFunc := func() (net.PacketConn, error) {
pktConn, err := internet.ListenSystemPacket(context.Background(), &net.UDPAddr{IP: s.src.Address.IP(), Port: int(s.src.Port)}, s.streamSettings.SocketSettings) var pktConn net.PacketConn
var err error
if s.streamSettings.FinalMask != nil {
pktConn, err = s.streamSettings.FinalMask.ListenPacket(context.Background(), &net.UDPAddr{IP: s.src.Address.IP(), Port: int(s.src.Port)})
} else {
pktConn, err = internet.ListenSystemPacket(context.Background(), &net.UDPAddr{IP: s.src.Address.IP(), Port: int(s.src.Port)}, s.streamSettings.SocketSettings)
}
if err != nil { if err != nil {
return nil, err return nil, err
} }
if s.streamSettings.UdpmaskManager != nil {
newConn, err := s.streamSettings.UdpmaskManager.WrapPacketConnServer(pktConn)
if err != nil {
pktConn.Close()
return nil, errors.New("mask err").Base(err)
}
pktConn = newConn
}
if s.uplinkCounter != nil || s.downlinkCounter != nil { if s.uplinkCounter != nil || s.downlinkCounter != nil {
pktConn = &PacketCounterConnection{ pktConn = &PacketCounterConnection{
PacketConn: pktConn, PacketConn: pktConn,
+2
View File
@@ -65,6 +65,7 @@ func TestWireguard(t *testing.T) {
ProxySettings: serial.ToTypedMessage(&freedom.Config{ ProxySettings: serial.ToTypedMessage(&freedom.Config{
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}}, FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
}), }),
SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{}),
}, },
}, },
} }
@@ -104,6 +105,7 @@ func TestWireguard(t *testing.T) {
AllowedIps: []string{"0.0.0.0/0", "::0/0"}, AllowedIps: []string{"0.0.0.0/0", "::0/0"},
}}, }},
}), }),
SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{}),
}, },
}, },
} }
+263 -120
View File
@@ -2,103 +2,291 @@ package finalmask
import ( import (
"context" "context"
"net" "fmt"
"slices" "slices"
"github.com/xtls/xray-core/common/buf" "github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/net"
) )
type Udpmask interface { type Dialer struct {
WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) DialTCP func(net.Destination) (net.Conn, error)
WrapPacketConnServer(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) DialUDP func(net.Destination) (net.Conn, error)
} }
type UdpmaskManager struct { type ListenConfig struct {
udpmasks []Udpmask Listen func(net.Addr) (net.Listener, error)
ListenPacket func(net.Addr) (net.PacketConn, error)
} }
func NewUdpmaskManager(udpmasks []Udpmask) *UdpmaskManager { type TCPMask interface {
slices.Reverse(udpmasks) WrapConnClient(net.Conn, *net.Destination, *Dialer) (net.Conn, error)
return &UdpmaskManager{udpmasks: udpmasks} WrapConnServer(net.Conn) (net.Conn, error)
// Listen(net.Listener) (net.Listener, error)
} }
func (m *UdpmaskManager) WrapPacketConnClient(raw net.PacketConn) (net.PacketConn, error) { type UDPMask interface {
var sizes []int WrapPacketConnClient(net.PacketConn, *net.Destination, *Dialer) (net.PacketConn, error)
var conns []net.PacketConn WrapPacketConnServer(net.PacketConn, net.Addr, *ListenConfig) (net.PacketConn, error)
for i, mask := range m.udpmasks { }
if _, ok := mask.(headerConn); ok {
conn, err := mask.WrapPacketConnClient(nil, i, len(m.udpmasks)-1) type FinalMask struct {
if err != nil { tcpMasks []TCPMask
return nil, err udpMasks []UDPMask
} dialTCP func(context.Context, net.Destination) (net.Conn, error)
sizes = append(sizes, conn.(headerSize).Size()) listen func(context.Context, net.Addr) (net.Listener, error)
conns = append(conns, conn) dialUDP func(context.Context, net.Destination) (net.PacketConn, net.Addr, error)
} else { listenPacket func(context.Context, net.Addr) (net.PacketConn, error)
if len(conns) > 0 { }
raw = &headerManagerConn{sizes: sizes, conns: conns, PacketConn: raw}
sizes = nil func NewFinalMask(tcpMasks []TCPMask, udpMasks []UDPMask, dialTCP func(context.Context, net.Destination) (net.Conn, error), listen func(context.Context, net.Addr) (net.Listener, error), dialUDP func(context.Context, net.Destination) (net.PacketConn, net.Addr, error), listenPacket func(context.Context, net.Addr) (net.PacketConn, error)) *FinalMask {
conns = nil slices.Reverse(tcpMasks)
} slices.Reverse(udpMasks)
var err error return &FinalMask{
raw, err = mask.WrapPacketConnClient(raw, i, len(m.udpmasks)-1) tcpMasks: tcpMasks,
if err != nil { udpMasks: udpMasks,
return nil, err dialTCP: dialTCP,
dialUDP: dialUDP,
listen: listen,
listenPacket: listenPacket,
}
}
func (fm *FinalMask) DialTCP(ctx context.Context, dest net.Destination) (net.Conn, error) {
if len(fm.tcpMasks) == 0 {
return fm.dialTCP(ctx, dest)
}
for i := range fm.tcpMasks {
if i > 0 {
if _, ok := fm.tcpMasks[i].(interface{ HandleDial() }); ok {
return nil, fmt.Errorf("incorrect index: %d %T", i, fm.tcpMasks[i])
} }
} }
} }
var conn net.Conn
if len(conns) > 0 { var err error
raw = &headerManagerConn{sizes: sizes, conns: conns, PacketConn: raw} if _, ok := fm.tcpMasks[0].(interface{ HandleDial() }); !ok {
sizes = nil conn, err = fm.dialTCP(ctx, dest)
conns = nil if err != nil {
return nil, err
}
} }
return raw, nil dialer := &Dialer{
DialTCP: func(dest net.Destination) (net.Conn, error) {
return fm.dialTCP(ctx, dest)
},
DialUDP: func(dest net.Destination) (net.Conn, error) {
conn, addr, err := fm.dialUDP(ctx, dest)
if err != nil {
return nil, err
}
return &PacketConnWrapper{PacketConn: conn, udpAddr: addr}, err
},
}
for i := range fm.tcpMasks {
var newConn net.Conn
newConn, err = fm.tcpMasks[i].WrapConnClient(conn, &dest, dialer)
if err != nil {
_ = conn.Close()
return nil, err
}
conn = newConn
}
return conn, nil
} }
func (m *UdpmaskManager) WrapPacketConnServer(raw net.PacketConn) (net.PacketConn, error) { func (fm *FinalMask) Listen(ctx context.Context, addr net.Addr) (net.Listener, error) {
var sizes []int if len(fm.tcpMasks) == 0 {
var conns []net.PacketConn return fm.listen(ctx, addr)
for i, mask := range m.udpmasks { }
if _, ok := mask.(headerConn); ok { off := 0
conn, err := mask.WrapPacketConnServer(nil, i, len(m.udpmasks)-1) listener, err := fm.listen(ctx, addr)
if err != nil { if err != nil {
return nil, err return nil, err
}
for i := range fm.tcpMasks {
if _, ok := fm.tcpMasks[i].(interface {
Listen(net.Listener) (net.Listener, error)
}); ok {
if i-off == 0 {
l, err := fm.tcpMasks[i].(interface {
Listen(net.Listener) (net.Listener, error)
}).Listen(listener)
if err != nil {
listener.Close()
return nil, err
}
listener = l
} else {
l, err := fm.tcpMasks[i].(interface {
Listen(net.Listener) (net.Listener, error)
}).Listen(&TCPListener{Listener: listener, tcpMasks: fm.tcpMasks[off:i]})
if err != nil {
listener.Close()
return nil, err
}
listener = l
} }
sizes = append(sizes, conn.(headerSize).Size()) off = i + 1
conns = append(conns, conn) }
} else { }
if len(conns) > 0 { if off < len(fm.tcpMasks) {
raw = &headerManagerConn{sizes: sizes, conns: conns, PacketConn: raw} return &TCPListener{Listener: listener, tcpMasks: fm.tcpMasks[off:]}, nil
sizes = nil }
conns = nil return listener, nil
} }
var err error
raw, err = mask.WrapPacketConnServer(raw, i, len(m.udpmasks)-1) func (fm *FinalMask) DialUDP(ctx context.Context, dest net.Destination) (net.Conn, error) {
if err != nil { if len(fm.udpMasks) == 0 {
return nil, err conn, addr, err := fm.dialUDP(ctx, dest)
if err != nil {
return nil, err
}
return &PacketConnWrapper{PacketConn: conn, udpAddr: addr}, nil
}
for i := range fm.udpMasks {
if i > 0 {
if _, ok := fm.udpMasks[i].(interface{ HandleDial() }); ok {
return nil, fmt.Errorf("incorrect index: %d %T", i, fm.udpMasks[i])
} }
} }
} }
var conn net.PacketConn
var addr net.Addr
var err error
if _, ok := fm.udpMasks[0].(interface{ HandleDial() }); !ok {
conn, addr, err = fm.dialUDP(ctx, dest)
if err != nil {
return nil, err
}
}
dialer := &Dialer{
DialTCP: func(dest net.Destination) (net.Conn, error) {
return fm.dialTCP(ctx, dest)
},
DialUDP: func(dest net.Destination) (net.Conn, error) {
conn, addr, err := fm.dialUDP(ctx, dest)
if err != nil {
return nil, err
}
return &PacketConnWrapper{PacketConn: conn, udpAddr: addr}, err
},
}
var sizes []int
var conns []net.PacketConn
for i := range fm.udpMasks {
var newConn net.PacketConn
if _, ok := fm.udpMasks[i].(interface{ HeaderConn() }); ok {
newConn, err = fm.udpMasks[i].WrapPacketConnClient(nil, nil, nil)
if err != nil {
_ = conn.Close()
return nil, err
}
sizes = append(sizes, newConn.(interface{ Size() int }).Size())
conns = append(conns, newConn)
} else {
if len(conns) > 0 {
conn = &headerManagerConn{PacketConn: conn, sizes: sizes, conns: conns}
sizes = nil
conns = nil
}
newConn, err = fm.udpMasks[i].WrapPacketConnClient(conn, &dest, dialer)
if err != nil {
_ = conn.Close()
return nil, err
}
conn = newConn
}
}
if len(conns) > 0 { if len(conns) > 0 {
raw = &headerManagerConn{sizes: sizes, conns: conns, PacketConn: raw} conn = &headerManagerConn{PacketConn: conn, sizes: sizes, conns: conns}
sizes = nil sizes = nil
conns = nil conns = nil
} }
return raw, nil if addr == nil {
addr = &net.UDPAddr{IP: []byte{0, 0, 0, 0}}
}
return &PacketConnWrapper{PacketConn: conn, udpAddr: addr}, nil
}
func (fm *FinalMask) ListenPacket(ctx context.Context, addr net.Addr) (net.PacketConn, error) {
if len(fm.udpMasks) == 0 {
return fm.listenPacket(ctx, addr)
}
for i := range fm.udpMasks {
if i > 0 {
if _, ok := fm.udpMasks[i].(interface{ HandleListen() }); ok {
return nil, fmt.Errorf("incorrect index: %d %T", i, fm.udpMasks[i])
}
}
}
var conn net.PacketConn
var err error
if _, ok := fm.udpMasks[0].(interface{ HandleListen() }); !ok {
conn, err = fm.listenPacket(ctx, addr)
if err != nil {
return nil, err
}
}
lc := &ListenConfig{
Listen: func(addr net.Addr) (net.Listener, error) { return fm.listen(ctx, addr) },
ListenPacket: func(addr net.Addr) (net.PacketConn, error) { return fm.listenPacket(ctx, addr) },
}
var sizes []int
var conns []net.PacketConn
for i := range fm.udpMasks {
var newConn net.PacketConn
if _, ok := fm.udpMasks[i].(interface{ HeaderConn() }); ok {
newConn, err = fm.udpMasks[i].WrapPacketConnServer(nil, nil, nil)
if err != nil {
_ = conn.Close()
return nil, err
}
sizes = append(sizes, newConn.(interface{ Size() int }).Size())
conns = append(conns, newConn)
} else {
if len(conns) > 0 {
conn = &headerManagerConn{PacketConn: conn, sizes: sizes, conns: conns}
sizes = nil
conns = nil
}
newConn, err = fm.udpMasks[i].WrapPacketConnServer(conn, addr, lc)
if err != nil {
_ = conn.Close()
return nil, err
}
conn = newConn
}
}
if len(conns) > 0 {
conn = &headerManagerConn{PacketConn: conn, sizes: sizes, conns: conns}
sizes = nil
conns = nil
}
return conn, nil
} }
const ( const (
UDPSize = 4096 UDPSize = 4096
) )
type headerConn interface { type PacketConnWrapper struct {
HeaderConn() net.PacketConn
udpAddr net.Addr
} }
type headerSize interface { func (c *PacketConnWrapper) RemoteAddr() net.Addr {
Size() int return c.udpAddr
}
func (c *PacketConnWrapper) Read(b []byte) (n int, err error) {
n, _, err = c.PacketConn.ReadFrom(b)
return
}
func (c *PacketConnWrapper) Write(b []byte) (n int, err error) {
return c.PacketConn.WriteTo(b, c.udpAddr)
} }
type headerManagerConn struct { type headerManagerConn struct {
@@ -191,72 +379,27 @@ func (c *headerManagerConn) WriteTo(p []byte, addr net.Addr) (n int, err error)
return len(p), nil return len(p), nil
} }
type Tcpmask interface { type TCPListener struct {
WrapConnClient(net.Conn) (net.Conn, error)
WrapConnServer(net.Conn) (net.Conn, error)
}
type TcpmaskManager struct {
tcpmasks []Tcpmask
}
func NewTcpmaskManager(tcpmasks []Tcpmask) *TcpmaskManager {
slices.Reverse(tcpmasks)
return &TcpmaskManager{tcpmasks: tcpmasks}
}
func (m *TcpmaskManager) WrapConnClient(raw net.Conn) (net.Conn, error) {
var err error
for _, mask := range m.tcpmasks {
raw, err = mask.WrapConnClient(raw)
if err != nil {
return nil, err
}
}
return raw, nil
}
func (m *TcpmaskManager) WrapConnServer(raw net.Conn) (net.Conn, error) {
var err error
for _, mask := range m.tcpmasks {
raw, err = mask.WrapConnServer(raw)
if err != nil {
return nil, err
}
}
return raw, nil
}
func (m *TcpmaskManager) WrapListener(l net.Listener) (net.Listener, error) {
return NewTcpListener(m, l)
}
type tcpListener struct {
m *TcpmaskManager
net.Listener net.Listener
tcpMasks []TCPMask
} }
func NewTcpListener(m *TcpmaskManager, l net.Listener) (net.Listener, error) { func (l *TCPListener) Accept() (net.Conn, error) {
return &tcpListener{
m: m,
Listener: l,
}, nil
}
func (l *tcpListener) Accept() (net.Conn, error) {
conn, err := l.Listener.Accept() conn, err := l.Listener.Accept()
if err != nil { if err != nil {
return conn, err return conn, err
} }
newConn, err := l.m.WrapConnServer(conn) for i := range l.tcpMasks {
if err != nil { var newConn net.Conn
errors.LogDebugInner(context.Background(), err, "mask err") newConn, err = l.tcpMasks[i].WrapConnServer(conn)
_ = conn.Close() if err != nil {
return nil, err _ = conn.Close()
return nil, err
}
conn = newConn
} }
return conn, nil
return newConn, nil
} }
type TcpMaskConn interface { type TcpMaskConn interface {
@@ -1,11 +1,14 @@
package fragment package fragment
import "net" import (
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/transport/internet/finalmask"
)
func (c *Config) WrapConnClient(raw net.Conn) (net.Conn, error) { func (c *Config) WrapConnClient(conn net.Conn, dest *net.Destination, dialer *finalmask.Dialer) (net.Conn, error) {
return NewConnClient(c, raw, false) return NewConnClient(c, conn, false)
} }
func (c *Config) WrapConnServer(raw net.Conn) (net.Conn, error) { func (c *Config) WrapConnServer(conn net.Conn) (net.Conn, error) {
return NewConnServer(c, raw, true) return NewConnServer(c, conn, true)
} }
@@ -1,29 +1,30 @@
package custom package custom
import ( import (
"net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/transport/internet/finalmask"
) )
func (c *TCPConfig) WrapConnClient(raw net.Conn) (net.Conn, error) { func (c *TCPConfig) WrapConnClient(conn net.Conn, dest *net.Destination, dialer *finalmask.Dialer) (net.Conn, error) {
return NewConnClientTCP(c, raw) return NewConnClientTCP(c, conn)
} }
func (c *TCPConfig) WrapConnServer(raw net.Conn) (net.Conn, error) { func (c *TCPConfig) WrapConnServer(conn net.Conn) (net.Conn, error) {
return NewConnServerTCP(c, raw) return NewConnServerTCP(c, conn)
} }
func (c *UDPConfig) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) { func (c *UDPConfig) WrapPacketConnClient(conn net.PacketConn, dest *net.Destination, dialer *finalmask.Dialer) (net.PacketConn, error) {
return NewConnClientUDP(c, raw) return NewConnClientUDP(c, conn)
} }
func (c *UDPConfig) WrapPacketConnServer(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) { func (c *UDPConfig) WrapPacketConnServer(conn net.PacketConn, addr net.Addr, lc *finalmask.ListenConfig) (net.PacketConn, error) {
return NewConnServerUDP(c, raw) return NewConnServerUDP(c, conn)
} }
func (c *UDPStandaloneConfig) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) { func (c *UDPStandaloneConfig) WrapPacketConnClient(conn net.PacketConn, dest *net.Destination, dialer *finalmask.Dialer) (net.PacketConn, error) {
return NewConnClientUDPStandalone(c, raw) return NewConnClientUDPStandalone(c, conn)
} }
func (c *UDPStandaloneConfig) WrapPacketConnServer(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) { func (c *UDPStandaloneConfig) WrapPacketConnServer(conn net.PacketConn, addr net.Addr, lc *finalmask.ListenConfig) (net.PacketConn, error) {
return NewConnServerUDPStandalone(c, raw) return NewConnServerUDPStandalone(c, conn)
} }
@@ -9,8 +9,6 @@ import (
"strings" "strings"
"testing" "testing"
"time" "time"
"github.com/xtls/xray-core/transport/internet/finalmask"
) )
func TestMetadataEvaluatorRejectsUnknownName(t *testing.T) { func TestMetadataEvaluatorRejectsUnknownName(t *testing.T) {
@@ -156,7 +154,7 @@ func TestMetadataUDPStandaloneWriteUsesRemotePort(t *testing.T) {
} }
defer serverRaw.Close() defer serverRaw.Close()
client, err := finalmask.NewUdpmaskManager([]finalmask.Udpmask{cfg}).WrapPacketConnClient(clientRaw) client, err := cfg.WrapPacketConnClient(clientRaw, nil, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -301,7 +299,7 @@ func TestMetadataTCPHandshakeUsesEndpointPorts(t *testing.T) {
} }
defer serverRaw.Close() defer serverRaw.Close()
client, err := clientCfg.WrapConnClient(clientRaw) client, err := clientCfg.WrapConnClient(clientRaw, nil, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -5,8 +5,6 @@ import (
"net" "net"
"testing" "testing"
"time" "time"
"github.com/xtls/xray-core/transport/internet/finalmask"
) )
func mustSendRecvUDP(t *testing.T, from net.PacketConn, to net.PacketConn, msg []byte) { func mustSendRecvUDP(t *testing.T, from net.PacketConn, to net.PacketConn, msg []byte) {
@@ -48,7 +46,6 @@ func TestStateUDPResponseReusesPriorCapturedValues(t *testing.T) {
}, },
}, },
} }
maskManager := finalmask.NewUdpmaskManager([]finalmask.Udpmask{cfg})
clientRaw, err := net.ListenPacket("udp", "127.0.0.1:0") clientRaw, err := net.ListenPacket("udp", "127.0.0.1:0")
if err != nil { if err != nil {
@@ -62,11 +59,11 @@ func TestStateUDPResponseReusesPriorCapturedValues(t *testing.T) {
} }
defer serverRaw.Close() defer serverRaw.Close()
client, err := maskManager.WrapPacketConnClient(clientRaw) client, err := cfg.WrapPacketConnClient(clientRaw, nil, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
server, err := maskManager.WrapPacketConnServer(serverRaw) server, err := cfg.WrapPacketConnServer(serverRaw, nil, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -37,7 +37,7 @@ func TestDSLTCPHandshakeReusesCapturedValue(t *testing.T) {
defer clientRaw.Close() defer clientRaw.Close()
defer serverRaw.Close() defer serverRaw.Close()
client, err := cfg.WrapConnClient(clientRaw) client, err := cfg.WrapConnClient(clientRaw, nil, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -117,7 +117,7 @@ func TestDSLTCPClientRejectsMismatchedResponseSequence(t *testing.T) {
defer clientRaw.Close() defer clientRaw.Close()
defer serverRaw.Close() defer serverRaw.Close()
client, err := clientCfg.WrapConnClient(clientRaw) client, err := clientCfg.WrapConnClient(clientRaw, nil, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -1,15 +1,16 @@
package aes128gcm package aes128gcm
import ( import (
"net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/transport/internet/finalmask"
) )
func (c *Config) HeaderConn() {} func (c *Config) HeaderConn() {}
func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) { func (c *Config) WrapPacketConnClient(conn net.PacketConn, dest *net.Destination, dialer *finalmask.Dialer) (net.PacketConn, error) {
return NewConnClient(c, raw) return NewConnClient(c, conn)
} }
func (c *Config) WrapPacketConnServer(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) { func (c *Config) WrapPacketConnServer(conn net.PacketConn, addr net.Addr, lc *finalmask.ListenConfig) (net.PacketConn, error) {
return NewConnServer(c, raw) return NewConnServer(c, conn)
} }
@@ -1,15 +1,16 @@
package header package header
import ( import (
"net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/transport/internet/finalmask"
) )
func (c *Config) HeaderConn() {} func (c *Config) HeaderConn() {}
func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) { func (c *Config) WrapPacketConnClient(conn net.PacketConn, dest *net.Destination, dialer *finalmask.Dialer) (net.PacketConn, error) {
return NewConnClient(c, raw) return NewConnClient(c, conn)
} }
func (c *Config) WrapPacketConnServer(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) { func (c *Config) WrapPacketConnServer(conn net.PacketConn, addr net.Addr, lc *finalmask.ListenConfig) (net.PacketConn, error) {
return NewConnServer(c, raw) return NewConnServer(c, conn)
} }
@@ -1,15 +1,16 @@
package original package original
import ( import (
"net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/transport/internet/finalmask"
) )
func (c *Config) HeaderConn() {} func (c *Config) HeaderConn() {}
func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) { func (c *Config) WrapPacketConnClient(conn net.PacketConn, dest *net.Destination, dialer *finalmask.Dialer) (net.PacketConn, error) {
return NewConnClient(c, raw) return NewConnClient(c, conn)
} }
func (c *Config) WrapPacketConnServer(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) { func (c *Config) WrapPacketConnServer(conn net.PacketConn, addr net.Addr, lc *finalmask.ListenConfig) (net.PacketConn, error) {
return NewConnServer(c, raw) return NewConnServer(c, conn)
} }
+8 -5
View File
@@ -1,11 +1,14 @@
package noise package noise
import "net" import (
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/transport/internet/finalmask"
)
func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) { func (c *Config) WrapPacketConnClient(conn net.PacketConn, dest *net.Destination, dialer *finalmask.Dialer) (net.PacketConn, error) {
return NewConnClient(c, raw) return NewConnClient(c, conn)
} }
func (c *Config) WrapPacketConnServer(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) { func (c *Config) WrapPacketConnServer(conn net.PacketConn, addr net.Addr, lc *finalmask.ListenConfig) (net.PacketConn, error) {
return NewConnServer(c, raw) return NewConnServer(c, conn)
} }
+6 -15
View File
@@ -1,23 +1,14 @@
package realm package realm
import ( import (
"net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/transport/internet/finalmask"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/transport/internet"
) )
func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) { func (c *Config) WrapPacketConnClient(conn net.PacketConn, dest *net.Destination, dialer *finalmask.Dialer) (net.PacketConn, error) {
_, ok1 := raw.(*internet.FakePacketConn) return NewConnClient(c, conn)
if level != 0 || ok1 {
return nil, errors.New("realm requires being at the outermost level")
}
return NewConnClient(c, raw)
} }
func (c *Config) WrapPacketConnServer(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) { func (c *Config) WrapPacketConnServer(conn net.PacketConn, addr net.Addr, lc *finalmask.ListenConfig) (net.PacketConn, error) {
if level != 0 { return NewConnServer(c, conn)
return nil, errors.New("realm requires being at the outermost level")
}
return NewConnServer(c, raw)
} }
@@ -1,23 +1,24 @@
package salamander package salamander
import ( import (
"net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/transport/internet/finalmask"
) )
func (c *Config) HeaderConn() {} func (c *Config) HeaderConn() {}
func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) { func (c *Config) WrapPacketConnClient(conn net.PacketConn, dest *net.Destination, dialer *finalmask.Dialer) (net.PacketConn, error) {
return NewSalamanderConnClient(c, raw) return NewSalamanderConnClient(c, conn)
} }
func (c *Config) WrapPacketConnServer(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) { func (c *Config) WrapPacketConnServer(conn net.PacketConn, addr net.Addr, lc *finalmask.ListenConfig) (net.PacketConn, error) {
return NewSalamanderConnServer(c, raw) return NewSalamanderConnServer(c, conn)
} }
func (c *GeckoConfig) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) { func (c *GeckoConfig) WrapPacketConnClient(conn net.PacketConn, dest *net.Destination, dialer *finalmask.Dialer) (net.PacketConn, error) {
return NewGeckoConnClient(c, raw) return NewGeckoConnClient(c, conn)
} }
func (c *GeckoConfig) WrapPacketConnServer(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) { func (c *GeckoConfig) WrapPacketConnServer(conn net.PacketConn, addr net.Addr, lc *finalmask.ListenConfig) (net.PacketConn, error) {
return NewGeckoConnServer(c, raw) return NewGeckoConnServer(c, conn)
} }
+10 -17
View File
@@ -1,19 +1,18 @@
package sudoku package sudoku
import ( import (
"net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/transport/internet/finalmask"
"github.com/xtls/xray-core/common/errors"
) )
// Sudoku in finalmask mode is a pure appearance transform with no standalone handshake. // Sudoku in finalmask mode is a pure appearance transform with no standalone handshake.
// TCP always keeps classic sudoku on uplink and uses packed downlink optimization on server writes. // TCP always keeps classic sudoku on uplink and uses packed downlink optimization on server writes.
func (c *Config) WrapConnClient(raw net.Conn) (net.Conn, error) { func (c *Config) WrapConnClient(conn net.Conn, dest *net.Destination, dialer *finalmask.Dialer) (net.Conn, error) {
return newPackedDirectionalConn(raw, c, true) return newPackedDirectionalConn(conn, c, true)
} }
func (c *Config) WrapConnServer(raw net.Conn) (net.Conn, error) { func (c *Config) WrapConnServer(conn net.Conn) (net.Conn, error) {
return newPackedDirectionalConn(raw, c, false) return newPackedDirectionalConn(conn, c, false)
} }
func newPackedDirectionalConn(raw net.Conn, config *Config, readPacked bool) (net.Conn, error) { func newPackedDirectionalConn(raw net.Conn, config *Config, readPacked bool) (net.Conn, error) {
@@ -36,16 +35,10 @@ func newPackedDirectionalConn(raw net.Conn, config *Config, readPacked bool) (ne
return newWrappedConn(raw, reader, writer), nil return newWrappedConn(raw, reader, writer), nil
} }
func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) { func (c *Config) WrapPacketConnClient(conn net.PacketConn, dest *net.Destination, dialer *finalmask.Dialer) (net.PacketConn, error) {
if level != levelCount { return NewUDPConn(conn, c)
return nil, errors.New("sudoku udp mask must be the innermost mask in chain")
}
return NewUDPConn(raw, c)
} }
func (c *Config) WrapPacketConnServer(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) { func (c *Config) WrapPacketConnServer(conn net.PacketConn, addr net.Addr, lc *finalmask.ListenConfig) (net.PacketConn, error) {
if level != levelCount { return NewUDPConn(conn, c)
return nil, errors.New("sudoku udp mask must be the innermost mask in chain")
}
return NewUDPConn(raw, c)
} }
+55 -53
View File
@@ -2,12 +2,14 @@ package finalmask_test
import ( import (
"bytes" "bytes"
"context"
"io" "io"
"net" gonet "net"
"strings" "strings"
"testing" "testing"
"time" "time"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/transport/internet/finalmask" "github.com/xtls/xray-core/transport/internet/finalmask"
"github.com/xtls/xray-core/transport/internet/finalmask/header/custom" "github.com/xtls/xray-core/transport/internet/finalmask/header/custom"
) )
@@ -20,11 +22,14 @@ func mustSendRecvTcp(
) { ) {
t.Helper() t.Helper()
waitCh := make(chan error)
go func() { go func() {
_, err := from.Write(msg) _, err := from.Write(msg)
if err != nil { if err != nil {
t.Error(err) t.Fatal(err)
} }
close(waitCh)
}() }()
buf := make([]byte, 1024) buf := make([]byte, 1024)
@@ -40,18 +45,23 @@ func mustSendRecvTcp(
if !bytes.Equal(buf[:n], msg) { if !bytes.Equal(buf[:n], msg) {
t.Fatalf("unexpected data %q", buf[:n]) t.Fatalf("unexpected data %q", buf[:n])
} }
<-waitCh
} }
type layerMaskTcp struct { type layerMaskTcp struct {
name string name string
mask finalmask.Tcpmask mask finalmask.TCPMask
} }
type failingWrapMask struct{} type failingWrapMask struct{}
func (failingWrapMask) TCP() {} func (failingWrapMask) TCP() {}
func (f failingWrapMask) WrapConnClient(raw net.Conn) (net.Conn, error) { return raw, nil } func (f failingWrapMask) WrapConnClient(conn net.Conn, dest *net.Destination, dialer *finalmask.Dialer) (net.Conn, error) {
func (f failingWrapMask) WrapConnServer(raw net.Conn) (net.Conn, error) { return conn, nil
}
func (f failingWrapMask) WrapConnServer(conn net.Conn) (net.Conn, error) {
return nil, io.ErrClosedPipe return nil, io.ErrClosedPipe
} }
@@ -92,32 +102,31 @@ func TestConnReadWrite(t *testing.T) {
t.Run(c.name, func(t *testing.T) { t.Run(c.name, func(t *testing.T) {
mask := c.mask mask := c.mask
maskManager := finalmask.NewTcpmaskManager([]finalmask.Tcpmask{mask}) dialTCP := func(ctx context.Context, dest net.Destination) (net.Conn, error) {
return net.Dial("tcp", dest.NetAddr())
}
listen := func(ctx context.Context, addr net.Addr) (net.Listener, error) {
return net.Listen("tcp", addr.String())
}
finalMask := finalmask.NewFinalMask([]finalmask.TCPMask{mask}, nil, dialTCP, listen, nil, nil)
ln, err := net.Listen("tcp", "127.0.0.1:0") listener, err := finalMask.Listen(context.Background(), &net.TCPAddr{IP: net.LocalHostIP.IP()})
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
t.Cleanup(func() { listener.Close() })
client, err := net.Dial("tcp", ln.Addr().String()) client, err := finalMask.DialTCP(context.Background(), net.TCPDestination(net.IPAddress(listener.Addr().(*net.TCPAddr).IP), net.Port(listener.Addr().(*net.TCPAddr).Port)))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
t.Cleanup(func() { client.Close() })
client, err = maskManager.WrapConnClient(client) server, err := listener.Accept()
if err != nil {
t.Fatal(err)
}
server, err := ln.Accept()
if err != nil {
t.Fatal(err)
}
server, err = maskManager.WrapConnServer(server)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
t.Cleanup(func() { server.Close() })
_ = client.SetDeadline(time.Now().Add(time.Second)) _ = client.SetDeadline(time.Now().Add(time.Second))
_ = server.SetDeadline(time.Now().Add(time.Second)) _ = server.SetDeadline(time.Now().Add(time.Second))
@@ -150,34 +159,32 @@ func TestTCPcustomStaticHandshakeRoundTrip(t *testing.T) {
}, },
}, },
} }
maskManager := finalmask.NewTcpmaskManager([]finalmask.Tcpmask{cfg})
ln, err := net.Listen("tcp", "127.0.0.1:0") dialTCP := func(ctx context.Context, dest net.Destination) (net.Conn, error) {
if err != nil { return net.Dial("tcp", dest.NetAddr())
t.Fatal(err)
} }
defer ln.Close() listen := func(ctx context.Context, addr net.Addr) (net.Listener, error) {
return net.Listen("tcp", addr.String())
}
finalMask := finalmask.NewFinalMask([]finalmask.TCPMask{cfg}, nil, dialTCP, listen, nil, nil)
clientRaw, err := net.Dial("tcp", ln.Addr().String()) listener, err := finalMask.Listen(context.Background(), &net.TCPAddr{IP: net.LocalHostIP.IP()})
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer clientRaw.Close() defer listener.Close()
serverRaw, err := ln.Accept() client, err := finalMask.DialTCP(context.Background(), net.TCPDestination(net.IPAddress(listener.Addr().(*net.TCPAddr).IP), net.Port(listener.Addr().(*net.TCPAddr).Port)))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer serverRaw.Close() defer client.Close()
client, err := maskManager.WrapConnClient(clientRaw) server, err := listener.Accept()
if err != nil {
t.Fatal(err)
}
server, err := maskManager.WrapConnServer(serverRaw)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer server.Close()
_ = client.SetDeadline(time.Now().Add(time.Second)) _ = client.SetDeadline(time.Now().Add(time.Second))
_ = server.SetDeadline(time.Now().Add(time.Second)) _ = server.SetDeadline(time.Now().Add(time.Second))
@@ -220,11 +227,11 @@ func TestTCPcustomClientRejectsMismatchedServerSequence(t *testing.T) {
}, },
} }
clientRaw, serverRaw := net.Pipe() clientRaw, serverRaw := gonet.Pipe()
defer clientRaw.Close() defer clientRaw.Close()
defer serverRaw.Close() defer serverRaw.Close()
client, err := clientCfg.WrapConnClient(clientRaw) client, err := clientCfg.WrapConnClient(clientRaw, nil, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -257,42 +264,37 @@ func TestTCPcustomClientRejectsMismatchedServerSequence(t *testing.T) {
} }
func TestTCPWrapListenerRejectsImmediateWrapErrors(t *testing.T) { func TestTCPWrapListenerRejectsImmediateWrapErrors(t *testing.T) {
clientManager := finalmask.NewTcpmaskManager([]finalmask.Tcpmask{failingWrapMask{}}) dialTCP := func(ctx context.Context, dest net.Destination) (net.Conn, error) {
serverManager := finalmask.NewTcpmaskManager([]finalmask.Tcpmask{failingWrapMask{}}) return net.Dial("tcp", dest.NetAddr())
}
listen := func(ctx context.Context, addr net.Addr) (net.Listener, error) {
return net.Listen("tcp", addr.String())
}
finalMask := finalmask.NewFinalMask([]finalmask.TCPMask{failingWrapMask{}}, nil, dialTCP, listen, nil, nil)
rawLn, err := net.Listen("tcp", "127.0.0.1:0") listener, err := finalMask.Listen(context.Background(), &net.TCPAddr{IP: net.LocalHostIP.IP()})
if err != nil {
t.Fatal(err)
}
defer rawLn.Close()
ln, err := serverManager.WrapListener(rawLn)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer listener.Close()
accepted := make(chan struct { accepted := make(chan struct {
conn net.Conn conn net.Conn
err error err error
}, 1) }, 1)
go func() { go func() {
conn, err := ln.Accept() conn, err := listener.Accept()
accepted <- struct { accepted <- struct {
conn net.Conn conn net.Conn
err error err error
}{conn: conn, err: err} }{conn: conn, err: err}
}() }()
clientRaw, err := net.Dial("tcp", rawLn.Addr().String()) client, err := finalMask.DialTCP(context.Background(), net.TCPDestination(net.IPAddress(listener.Addr().(*net.TCPAddr).IP), net.Port(listener.Addr().(*net.TCPAddr).Port)))
if err != nil {
t.Fatal(err)
}
defer clientRaw.Close()
client, err := clientManager.WrapConnClient(clientRaw)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer client.Close()
_ = client.SetDeadline(time.Now().Add(time.Second)) _ = client.SetDeadline(time.Now().Add(time.Second))
+52 -59
View File
@@ -2,13 +2,15 @@ package finalmask_test
import ( import (
"bytes" "bytes"
"context"
"encoding/binary" "encoding/binary"
"io" "io"
"net" gonet "net"
"sync/atomic" "sync/atomic"
"testing" "testing"
"time" "time"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/proxy" "github.com/xtls/xray-core/proxy"
"github.com/xtls/xray-core/transport/internet/finalmask" "github.com/xtls/xray-core/transport/internet/finalmask"
"github.com/xtls/xray-core/transport/internet/finalmask/header/custom" "github.com/xtls/xray-core/transport/internet/finalmask/header/custom"
@@ -51,7 +53,7 @@ func mustSendRecv(
type layerMask struct { type layerMask struct {
name string name string
mask finalmask.Udpmask mask finalmask.UDPMask
layers int layers int
} }
@@ -213,25 +215,23 @@ func newStandaloneStunLikeUDPServerConfig() *custom.UDPStandaloneConfig {
func newUDPClientServerPair(t *testing.T, cfg *custom.UDPStandaloneConfig) (net.PacketConn, net.PacketConn, net.PacketConn, net.PacketConn) { func newUDPClientServerPair(t *testing.T, cfg *custom.UDPStandaloneConfig) (net.PacketConn, net.PacketConn, net.PacketConn, net.PacketConn) {
t.Helper() t.Helper()
clientRaw, err := net.ListenPacket("udp", "127.0.0.1:0") clientRaw, err := gonet.ListenPacket("udp", "127.0.0.1:0")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
t.Cleanup(func() { _ = clientRaw.Close() }) t.Cleanup(func() { _ = clientRaw.Close() })
serverRaw, err := net.ListenPacket("udp", "127.0.0.1:0") serverRaw, err := gonet.ListenPacket("udp", "127.0.0.1:0")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
t.Cleanup(func() { _ = serverRaw.Close() }) t.Cleanup(func() { _ = serverRaw.Close() })
maskManager := finalmask.NewUdpmaskManager([]finalmask.Udpmask{cfg}) client, err := cfg.WrapPacketConnClient(clientRaw, nil, nil)
client, err := maskManager.WrapPacketConnClient(clientRaw)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
server, err := maskManager.WrapPacketConnServer(serverRaw) server, err := cfg.WrapPacketConnServer(serverRaw, nil, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -348,31 +348,39 @@ func TestPacketConnReadWrite(t *testing.T) {
if layers <= 0 { if layers <= 0 {
layers = 1 layers = 1
} }
masks := make([]finalmask.Udpmask, 0, layers) masks := make([]finalmask.UDPMask, 0, layers)
for i := 0; i < layers; i++ { for i := 0; i < layers; i++ {
masks = append(masks, mask) masks = append(masks, mask)
} }
maskManager := finalmask.NewUdpmaskManager(masks)
client, err := net.ListenPacket("udp", "127.0.0.1:0") dialUDP := func(ctx context.Context, dest net.Destination) (net.PacketConn, net.Addr, error) {
udpAddr, err := net.ResolveUDPAddr("udp", dest.NetAddr())
if err != nil {
return nil, nil, err
}
conn, err := gonet.ListenPacket("udp", "127.0.0.1:0")
if err != nil {
return nil, nil, err
}
return conn, udpAddr, nil
}
listenPacket := func(ctx context.Context, addr net.Addr) (net.PacketConn, error) {
return gonet.ListenPacket(addr.Network(), addr.String())
}
finalMask := finalmask.NewFinalMask(nil, masks, nil, nil, dialUDP, listenPacket)
server, err := finalMask.ListenPacket(context.Background(), &net.UDPAddr{IP: net.LocalHostIP.IP()})
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
t.Cleanup(func() { server.Close() })
client, err = maskManager.WrapPacketConnClient(client) clientConn, err := finalMask.DialUDP(context.Background(), net.UDPDestination(net.IPAddress(server.LocalAddr().(*net.UDPAddr).IP), net.Port(server.LocalAddr().(*net.UDPAddr).Port)))
if err != nil {
t.Fatal(err)
}
server, err := net.ListenPacket("udp", "127.0.0.1:0")
if err != nil {
t.Fatal(err)
}
server, err = maskManager.WrapPacketConnServer(server)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
t.Cleanup(func() { clientConn.Close() })
client := clientConn.(*finalmask.PacketConnWrapper).PacketConn
_ = client.SetDeadline(time.Now().Add(time.Second)) _ = client.SetDeadline(time.Now().Add(time.Second))
_ = server.SetDeadline(time.Now().Add(time.Second)) _ = server.SetDeadline(time.Now().Add(time.Second))
@@ -397,21 +405,20 @@ func TestUDPcustomStaticHeaderWireShape(t *testing.T) {
{Rand: 1, RandMin: 0x30, RandMax: 0x40}, {Rand: 1, RandMin: 0x30, RandMax: 0x40},
}, },
} }
maskManager := finalmask.NewUdpmaskManager([]finalmask.Udpmask{cfg})
clientRaw, err := net.ListenPacket("udp", "127.0.0.1:0") clientRaw, err := gonet.ListenPacket("udp", "127.0.0.1:0")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer clientRaw.Close() defer clientRaw.Close()
serverRaw, err := net.ListenPacket("udp", "127.0.0.1:0") serverRaw, err := gonet.ListenPacket("udp", "127.0.0.1:0")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer serverRaw.Close() defer serverRaw.Close()
client, err := maskManager.WrapPacketConnClient(clientRaw) client, err := cfg.WrapPacketConnClient(clientRaw, nil, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -642,11 +649,11 @@ func TestSudokuBDD(t *testing.T) {
Ascii: "prefer_ascii", Ascii: "prefer_ascii",
} }
clientRaw, serverRaw := net.Pipe() clientRaw, serverRaw := gonet.Pipe()
defer clientRaw.Close() defer clientRaw.Close()
defer serverRaw.Close() defer serverRaw.Close()
clientConn, err := cfg.WrapConnClient(clientRaw) clientConn, err := cfg.WrapConnClient(clientRaw, nil, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -683,11 +690,11 @@ func TestSudokuBDD(t *testing.T) {
PaddingMax: 0, PaddingMax: 0,
} }
clientRaw, serverRaw := net.Pipe() clientRaw, serverRaw := gonet.Pipe()
defer clientRaw.Close() defer clientRaw.Close()
defer serverRaw.Close() defer serverRaw.Close()
clientConn, err := cfg.WrapConnClient(clientRaw) clientConn, err := cfg.WrapConnClient(clientRaw, nil, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -738,10 +745,10 @@ func TestSudokuBDD(t *testing.T) {
countWireBytes := func(wrapServer func(net.Conn, *sudoku.Config) (net.Conn, error), cfg *sudoku.Config) int64 { countWireBytes := func(wrapServer func(net.Conn, *sudoku.Config) (net.Conn, error), cfg *sudoku.Config) int64 {
t.Helper() t.Helper()
clientRaw, serverRaw := net.Pipe() clientRaw, serverRaw := gonet.Pipe()
watchedServerRaw := &countingConn{Conn: serverRaw} watchedServerRaw := &countingConn{Conn: serverRaw}
clientConn, err := cfg.WrapConnClient(clientRaw) clientConn, err := cfg.WrapConnClient(clientRaw, nil, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -793,11 +800,11 @@ func TestSudokuBDD(t *testing.T) {
CustomTables: []string{"xpxvvpvv", "vxpvxvvp"}, CustomTables: []string{"xpxvvpvv", "vxpvxvvp"},
} }
clientRaw, serverRaw := net.Pipe() clientRaw, serverRaw := gonet.Pipe()
defer clientRaw.Close() defer clientRaw.Close()
defer serverRaw.Close() defer serverRaw.Close()
clientConn, err := cfg.WrapConnClient(clientRaw) clientConn, err := cfg.WrapConnClient(clientRaw, nil, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -835,11 +842,11 @@ func TestSudokuBDD(t *testing.T) {
PaddingMax: 0, PaddingMax: 0,
} }
clientRaw, serverRaw := net.Pipe() clientRaw, serverRaw := gonet.Pipe()
defer clientRaw.Close() defer clientRaw.Close()
defer serverRaw.Close() defer serverRaw.Close()
clientConn, err := cfg.WrapConnClient(clientRaw) clientConn, err := cfg.WrapConnClient(clientRaw, nil, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -868,19 +875,6 @@ func TestSudokuBDD(t *testing.T) {
} }
}) })
t.Run("GivenSudokuUDPMask_WhenNotInnermost_ThenWrapFails", func(t *testing.T) {
cfg := &sudoku.Config{Password: "sudoku-udp"}
raw, err := net.ListenPacket("udp", "127.0.0.1:0")
if err != nil {
t.Fatal(err)
}
defer raw.Close()
if _, err := cfg.WrapPacketConnClient(raw, 0, 1); err == nil {
t.Fatal("expected innermost check failure")
}
})
t.Run("GivenSudokuMultiTableUDPMask_WhenClientSendsMultipleDatagrams_ThenPayloadMatches", func(t *testing.T) { t.Run("GivenSudokuMultiTableUDPMask_WhenClientSendsMultipleDatagrams_ThenPayloadMatches", func(t *testing.T) {
cfg := &sudoku.Config{ cfg := &sudoku.Config{
Password: "sudoku-udp-multi", Password: "sudoku-udp-multi",
@@ -889,25 +883,24 @@ func TestSudokuBDD(t *testing.T) {
PaddingMin: 0, PaddingMin: 0,
PaddingMax: 0, PaddingMax: 0,
} }
maskManager := finalmask.NewUdpmaskManager([]finalmask.Udpmask{cfg})
clientRaw, err := net.ListenPacket("udp", "127.0.0.1:0") clientRaw, err := gonet.ListenPacket("udp", "127.0.0.1:0")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer clientRaw.Close() defer clientRaw.Close()
serverRaw, err := net.ListenPacket("udp", "127.0.0.1:0") serverRaw, err := gonet.ListenPacket("udp", "127.0.0.1:0")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer serverRaw.Close() defer serverRaw.Close()
client, err := maskManager.WrapPacketConnClient(clientRaw) client, err := cfg.WrapPacketConnClient(clientRaw, nil, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
server, err := maskManager.WrapPacketConnServer(serverRaw) server, err := cfg.WrapPacketConnServer(serverRaw, nil, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -961,7 +954,7 @@ func TestSudokuBDD(t *testing.T) {
} }
defer serverRaw.Close() defer serverRaw.Close()
clientConn, err := cfg.WrapConnClient(clientRaw) clientConn, err := cfg.WrapConnClient(clientRaw, nil, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -1008,11 +1001,11 @@ func TestSudokuBDD(t *testing.T) {
Ascii: "prefer_entropy", Ascii: "prefer_entropy",
} }
clientRaw, serverRaw := net.Pipe() clientRaw, serverRaw := gonet.Pipe()
defer clientRaw.Close() defer clientRaw.Close()
defer serverRaw.Close() defer serverRaw.Close()
clientConn, err := cfg.WrapConnClient(clientRaw) clientConn, err := cfg.WrapConnClient(clientRaw, nil, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -1032,11 +1025,11 @@ func TestSudokuBDD(t *testing.T) {
Ascii: "prefer_entropy", Ascii: "prefer_entropy",
} }
clientRaw, serverRaw := net.Pipe() clientRaw, serverRaw := gonet.Pipe()
defer clientRaw.Close() defer clientRaw.Close()
defer serverRaw.Close() defer serverRaw.Close()
clientConn, err := cfg.WrapConnClient(clientRaw) clientConn, err := cfg.WrapConnClient(clientRaw, nil, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
+7 -10
View File
@@ -1,20 +1,17 @@
package udphop package udphop
import ( import (
"net"
"github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/transport/internet/finalmask"
) )
func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) { func (c *Config) HandleDial() {}
_, ok1 := raw.(*internet.FakePacketConn)
if level != 0 || ok1 { func (c *Config) WrapPacketConnClient(conn net.PacketConn, dest *net.Destination, dialer *finalmask.Dialer) (net.PacketConn, error) {
return nil, errors.New("udphop requires being at the outermost level") return NewUDPHopConn(c, dest, dialer)
}
return NewUDPHopConn(c, raw)
} }
func (c *Config) WrapPacketConnServer(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) { func (c *Config) WrapPacketConnServer(conn net.PacketConn, addr net.Addr, lc *finalmask.ListenConfig) (net.PacketConn, error) {
return nil, errors.New("udphop: client only") return nil, errors.New("udphop: client only")
} }
@@ -7,7 +7,6 @@
package udphop package udphop
import ( import (
internet "github.com/xtls/xray-core/transport/internet"
protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl" protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect" reflect "reflect"
@@ -24,14 +23,13 @@ const (
type Config struct { type Config struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
Sockopt *internet.SocketConfig `protobuf:"bytes,1,opt,name=sockopt,proto3" json:"sockopt,omitempty"`
Local bool `protobuf:"varint,2,opt,name=local,proto3" json:"local,omitempty"` Local bool `protobuf:"varint,2,opt,name=local,proto3" json:"local,omitempty"`
Remote bool `protobuf:"varint,3,opt,name=remote,proto3" json:"remote,omitempty"` Remote bool `protobuf:"varint,3,opt,name=remote,proto3" json:"remote,omitempty"`
RemoteOnce bool `protobuf:"varint,4,opt,name=remote_once,json=remoteOnce,proto3" json:"remote_once,omitempty"` RemoteOnce bool `protobuf:"varint,4,opt,name=remote_once,json=remoteOnce,proto3" json:"remote_once,omitempty"`
IntervalMin int64 `protobuf:"varint,5,opt,name=interval_min,json=intervalMin,proto3" json:"interval_min,omitempty"` IntervalMin int64 `protobuf:"varint,5,opt,name=interval_min,json=intervalMin,proto3" json:"interval_min,omitempty"`
IntervalMax int64 `protobuf:"varint,6,opt,name=interval_max,json=intervalMax,proto3" json:"interval_max,omitempty"` IntervalMax int64 `protobuf:"varint,6,opt,name=interval_max,json=intervalMax,proto3" json:"interval_max,omitempty"`
RemotePorts []uint32 `protobuf:"varint,7,rep,packed,name=remote_ports,json=remotePorts,proto3" json:"remote_ports,omitempty"` RemoteIPs []string `protobuf:"bytes,7,rep,name=remoteIPs,proto3" json:"remoteIPs,omitempty"`
RemoteIPs []string `protobuf:"bytes,8,rep,name=remoteIPs,proto3" json:"remoteIPs,omitempty"` RemotePorts []uint32 `protobuf:"varint,8,rep,packed,name=remote_ports,json=remotePorts,proto3" json:"remote_ports,omitempty"`
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
} }
@@ -66,13 +64,6 @@ func (*Config) Descriptor() ([]byte, []int) {
return file_transport_internet_finalmask_udphop_config_proto_rawDescGZIP(), []int{0} return file_transport_internet_finalmask_udphop_config_proto_rawDescGZIP(), []int{0}
} }
func (x *Config) GetSockopt() *internet.SocketConfig {
if x != nil {
return x.Sockopt
}
return nil
}
func (x *Config) GetLocal() bool { func (x *Config) GetLocal() bool {
if x != nil { if x != nil {
return x.Local return x.Local
@@ -108,16 +99,16 @@ func (x *Config) GetIntervalMax() int64 {
return 0 return 0
} }
func (x *Config) GetRemotePorts() []uint32 { func (x *Config) GetRemoteIPs() []string {
if x != nil { if x != nil {
return x.RemotePorts return x.RemoteIPs
} }
return nil return nil
} }
func (x *Config) GetRemoteIPs() []string { func (x *Config) GetRemotePorts() []uint32 {
if x != nil { if x != nil {
return x.RemoteIPs return x.RemotePorts
} }
return nil return nil
} }
@@ -126,17 +117,16 @@ var File_transport_internet_finalmask_udphop_config_proto protoreflect.FileDescr
const file_transport_internet_finalmask_udphop_config_proto_rawDesc = "" + const file_transport_internet_finalmask_udphop_config_proto_rawDesc = "" +
"\n" + "\n" +
"0transport/internet/finalmask/udphop/config.proto\x12(xray.transport.internet.finalmask.udphop\x1a\x1ftransport/internet/config.proto\"\x9f\x02\n" + "0transport/internet/finalmask/udphop/config.proto\x12(xray.transport.internet.finalmask.udphop\"\xe4\x01\n" +
"\x06Config\x12?\n" + "\x06Config\x12\x14\n" +
"\asockopt\x18\x01 \x01(\v2%.xray.transport.internet.SocketConfigR\asockopt\x12\x14\n" +
"\x05local\x18\x02 \x01(\bR\x05local\x12\x16\n" + "\x05local\x18\x02 \x01(\bR\x05local\x12\x16\n" +
"\x06remote\x18\x03 \x01(\bR\x06remote\x12\x1f\n" + "\x06remote\x18\x03 \x01(\bR\x06remote\x12\x1f\n" +
"\vremote_once\x18\x04 \x01(\bR\n" + "\vremote_once\x18\x04 \x01(\bR\n" +
"remoteOnce\x12!\n" + "remoteOnce\x12!\n" +
"\finterval_min\x18\x05 \x01(\x03R\vintervalMin\x12!\n" + "\finterval_min\x18\x05 \x01(\x03R\vintervalMin\x12!\n" +
"\finterval_max\x18\x06 \x01(\x03R\vintervalMax\x12!\n" + "\finterval_max\x18\x06 \x01(\x03R\vintervalMax\x12\x1c\n" +
"\fremote_ports\x18\a \x03(\rR\vremotePorts\x12\x1c\n" + "\tremoteIPs\x18\a \x03(\tR\tremoteIPs\x12!\n" +
"\tremoteIPs\x18\b \x03(\tR\tremoteIPsB\x9a\x01\n" + "\fremote_ports\x18\b \x03(\rR\vremotePortsJ\x04\b\x01\x10\x02B\x9a\x01\n" +
",com.xray.transport.internet.finalmask.udphopP\x01Z=github.com/xtls/xray-core/transport/internet/finalmask/udphop\xaa\x02(Xray.Transport.Internet.Finalmask.Udphopb\x06proto3" ",com.xray.transport.internet.finalmask.udphopP\x01Z=github.com/xtls/xray-core/transport/internet/finalmask/udphop\xaa\x02(Xray.Transport.Internet.Finalmask.Udphopb\x06proto3"
var ( var (
@@ -153,16 +143,14 @@ func file_transport_internet_finalmask_udphop_config_proto_rawDescGZIP() []byte
var file_transport_internet_finalmask_udphop_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1) var file_transport_internet_finalmask_udphop_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_transport_internet_finalmask_udphop_config_proto_goTypes = []any{ var file_transport_internet_finalmask_udphop_config_proto_goTypes = []any{
(*Config)(nil), // 0: xray.transport.internet.finalmask.udphop.Config (*Config)(nil), // 0: xray.transport.internet.finalmask.udphop.Config
(*internet.SocketConfig)(nil), // 1: xray.transport.internet.SocketConfig
} }
var file_transport_internet_finalmask_udphop_config_proto_depIdxs = []int32{ var file_transport_internet_finalmask_udphop_config_proto_depIdxs = []int32{
1, // 0: xray.transport.internet.finalmask.udphop.Config.sockopt:type_name -> xray.transport.internet.SocketConfig 0, // [0:0] is the sub-list for method output_type
1, // [1:1] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type
1, // [1:1] is the sub-list for method input_type 0, // [0:0] is the sub-list for extension type_name
1, // [1:1] is the sub-list for extension type_name 0, // [0:0] is the sub-list for extension extendee
1, // [1:1] is the sub-list for extension extendee 0, // [0:0] is the sub-list for field type_name
0, // [0:1] is the sub-list for field type_name
} }
func init() { file_transport_internet_finalmask_udphop_config_proto_init() } func init() { file_transport_internet_finalmask_udphop_config_proto_init() }
@@ -6,16 +6,14 @@ option go_package = "github.com/xtls/xray-core/transport/internet/finalmask/udph
option java_package = "com.xray.transport.internet.finalmask.udphop"; option java_package = "com.xray.transport.internet.finalmask.udphop";
option java_multiple_files = true; option java_multiple_files = true;
import "transport/internet/config.proto";
message Config { message Config {
xray.transport.internet.SocketConfig sockopt = 1; reserved 1;
bool local = 2; bool local = 2;
bool remote = 3; bool remote = 3;
bool remote_once = 4; bool remote_once = 4;
int64 interval_min = 5; int64 interval_min = 5;
int64 interval_max = 6; int64 interval_max = 6;
repeated uint32 remote_ports = 7; repeated string remoteIPs = 7;
repeated string remoteIPs = 8; repeated uint32 remote_ports = 8;
} }
+81 -97
View File
@@ -6,9 +6,7 @@ import (
goerrors "errors" goerrors "errors"
"io" "io"
mrand "math/rand" mrand "math/rand"
gonet "net"
"net/netip" "net/netip"
"reflect"
"sync" "sync"
"time" "time"
@@ -16,8 +14,6 @@ import (
"github.com/xtls/xray-core/common/crypto" "github.com/xtls/xray-core/common/crypto"
"github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/net/cnc"
"github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/finalmask" "github.com/xtls/xray-core/transport/internet/finalmask"
) )
@@ -34,16 +30,14 @@ type packet struct {
} }
type udpHopConn struct { type udpHopConn struct {
conn net.PacketConn dialer *finalmask.Dialer
sockopt *internet.SocketConfig local bool
local bool remote bool
remote bool
remoteOnce bool
intervalMin int64 intervalMin int64
intervalMax int64 intervalMax int64
remotePorts []uint32
remoteIPs []netip.Prefix remoteIPs []netip.Prefix
remotePorts []uint32
deadline time.Time deadline time.Time
readDeadline time.Time readDeadline time.Time
@@ -55,10 +49,10 @@ type udpHopConn struct {
readCh chan packet readCh chan packet
closeCh chan struct{} closeCh chan struct{}
wg sync.WaitGroup wg sync.WaitGroup
mu sync.Mutex mu sync.RWMutex
} }
func NewUDPHopConn(c *Config, raw net.PacketConn) (net.PacketConn, error) { func NewUDPHopConn(c *Config, dest *net.Destination, dialer *finalmask.Dialer) (net.PacketConn, error) {
if c.IntervalMin < 5 || c.IntervalMax < 5 { if c.IntervalMin < 5 || c.IntervalMax < 5 {
return nil, errors.New("invalid interval") return nil, errors.New("invalid interval")
} }
@@ -66,22 +60,40 @@ func NewUDPHopConn(c *Config, raw net.PacketConn) (net.PacketConn, error) {
for _, ip := range c.RemoteIPs { for _, ip := range c.RemoteIPs {
remoteIPs = append(remoteIPs, netip.MustParsePrefix(ip)) remoteIPs = append(remoteIPs, netip.MustParsePrefix(ip))
} }
conn := &udpHopConn{ remotePorts := c.RemotePorts
conn: raw, if c.Remote || c.RemoteOnce {
sockopt: c.Sockopt, if len(remoteIPs) > 0 {
local: c.Local, dest.Address = net.IPAddress(randPrefix(remoteIPs[mrand.Intn(len(remoteIPs))]))
remote: c.Remote, }
remoteOnce: c.RemoteOnce, if len(remotePorts) > 0 {
dest.Port = net.Port(remotePorts[mrand.Intn(len(remotePorts))])
}
}
conn, err := dialer.DialUDP(*dest)
if err != nil {
return nil, err
}
cur := conn.(*finalmask.PacketConnWrapper).PacketConn
addr := conn.RemoteAddr().(*net.UDPAddr)
client := &udpHopConn{
dialer: dialer,
local: c.Local,
remote: c.Remote,
intervalMin: c.IntervalMin, intervalMin: c.IntervalMin,
intervalMax: c.IntervalMax, intervalMax: c.IntervalMax,
remotePorts: c.RemotePorts,
remoteIPs: remoteIPs, remoteIPs: remoteIPs,
remotePorts: remotePorts,
cur: cur,
addr: addr,
readCh: make(chan packet), readCh: make(chan packet),
closeCh: make(chan struct{}), closeCh: make(chan struct{}),
} }
return conn, nil go client.run()
client.wg.Add(1)
go client.recv(client.cur)
return client, nil
} }
func (c *udpHopConn) closed() bool { func (c *udpHopConn) closed() bool {
@@ -93,61 +105,67 @@ func (c *udpHopConn) closed() bool {
} }
} }
func (c *udpHopConn) hop(addr *net.UDPAddr) { func (c *udpHopConn) run() {
ticker := time.NewTicker(time.Second * time.Duration(crypto.RandBetween(c.intervalMin, c.intervalMax+1)))
defer ticker.Stop()
for {
select {
case <-c.closeCh:
return
case <-ticker.C:
ticker.Reset(time.Second * time.Duration(crypto.RandBetween(c.intervalMin, c.intervalMax+1)))
c.hop()
}
}
}
func (c *udpHopConn) hop() {
c.mu.Lock()
defer c.mu.Unlock()
if c.closed() { if c.closed() {
return return
} }
newAddr := &net.UDPAddr{IP: addr.IP, Port: addr.Port} oldIP := c.addr.IP
newConn := c.conn oldPort := c.addr.Port
if c.remote || c.remoteOnce && c.addr == nil { if c.remote {
if len(c.remotePorts) > 0 {
newAddr.Port = int(c.remotePorts[mrand.Intn(len(c.remotePorts))])
}
if len(c.remoteIPs) > 0 { if len(c.remoteIPs) > 0 {
newAddr.IP = randPrefix(c.remoteIPs[mrand.Intn(len(c.remoteIPs))]) c.addr.IP = randPrefix(c.remoteIPs[mrand.Intn(len(c.remoteIPs))])
}
if len(c.remotePorts) > 0 {
c.addr.Port = int(c.remotePorts[mrand.Intn(len(c.remotePorts))])
} }
} }
if c.local { if c.local {
raw, err := internet.DialSystem(context.Background(), net.UDPDestination(net.IPAddress(newAddr.IP), net.Port(newAddr.Port)), c.sockopt) conn, err := c.dialer.DialUDP(net.UDPDestination(net.IPAddress(c.addr.IP), net.Port(c.addr.Port)))
if err != nil { if err != nil {
c.addr.IP = oldIP
c.addr.Port = oldPort
errors.LogErrorInner(context.Background(), err, "hop err") errors.LogErrorInner(context.Background(), err, "hop err")
return return
} }
switch c := raw.(type) { conn.SetDeadline(c.deadline)
case *internet.PacketConnWrapper: conn.SetReadDeadline(c.readDeadline)
newConn = c.PacketConn conn.SetWriteDeadline(c.writeDeadline)
case *cnc.Connection:
newConn = &internet.FakePacketConn{Conn: c}
default:
panic(reflect.TypeOf(c))
}
newConn.SetDeadline(c.deadline)
newConn.SetReadDeadline(c.readDeadline)
newConn.SetWriteDeadline(c.writeDeadline)
if c.pre != nil { if c.pre != nil {
_ = c.pre.Close() _ = c.pre.Close()
} }
c.pre = c.cur c.pre = c.cur
c.cur = conn.(*finalmask.PacketConnWrapper).PacketConn
c.wg.Add(1) c.wg.Add(1)
go c.recv(newConn) go c.recv(c.cur)
} }
c.addr = newAddr
c.cur = newConn
} }
func (c *udpHopConn) recv(conn net.PacketConn) { func (c *udpHopConn) recv(conn net.PacketConn) {
defer c.wg.Done() defer c.wg.Done()
for { for {
if c.closed() {
return
}
p := pool.Get().([]byte) p := pool.Get().([]byte)
n, addr, err := conn.ReadFrom(p) n, addr, err := conn.ReadFrom(p)
if err != nil { if err != nil {
pool.Put(p[:cap(p)]) pool.Put(p[:cap(p)])
if goerrors.Is(err, io.EOF) || goerrors.Is(err, io.ErrClosedPipe) || goerrors.Is(err, gonet.ErrClosed) { if c.closed() {
break return
} }
var netErr net.Error var netErr net.Error
if goerrors.As(err, &netErr) && netErr.Timeout() { if goerrors.As(err, &netErr) && netErr.Timeout() {
@@ -156,9 +174,10 @@ func (c *udpHopConn) recv(conn net.PacketConn) {
case <-c.closeCh: case <-c.closeCh:
return return
} }
continue
} }
errors.LogErrorInner(context.Background(), err, "recv err") errors.LogErrorInner(context.Background(), err, "recv err")
continue return
} }
select { select {
case c.readCh <- packet{p: p[:n], addr: addr}: case c.readCh <- packet{p: p[:n], addr: addr}:
@@ -169,22 +188,6 @@ func (c *udpHopConn) recv(conn net.PacketConn) {
} }
} }
func (c *udpHopConn) hopLoop() {
ticker := time.NewTicker(time.Second * time.Duration(crypto.RandBetween(c.intervalMin, c.intervalMax+1)))
defer ticker.Stop()
for {
select {
case <-ticker.C:
ticker.Reset(time.Second * time.Duration(crypto.RandBetween(c.intervalMin, c.intervalMax+1)))
c.mu.Lock()
c.hop(c.addr)
c.mu.Unlock()
case <-c.closeCh:
return
}
}
}
func (c *udpHopConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) { func (c *udpHopConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
packet, ok := <-c.readCh packet, ok := <-c.readCh
if ok { if ok {
@@ -194,21 +197,12 @@ func (c *udpHopConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
} }
return n, packet.addr, packet.err return n, packet.addr, packet.err
} }
return 0, nil, io.EOF return 0, nil, io.ErrClosedPipe
} }
func (c *udpHopConn) WriteTo(p []byte, addr net.Addr) (n int, err error) { func (c *udpHopConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
c.mu.Lock() c.mu.RLock()
defer c.mu.Unlock() defer c.mu.RUnlock()
if c.cur == nil {
c.hop(addr.(*net.UDPAddr))
if c.cur == nil {
return 0, nil
}
go c.hopLoop()
}
_, err = c.cur.WriteTo(p, c.addr) _, err = c.cur.WriteTo(p, c.addr)
if err != nil { if err != nil {
errors.LogErrorInner(context.Background(), err, "send err") errors.LogErrorInner(context.Background(), err, "send err")
@@ -227,15 +221,12 @@ func (c *udpHopConn) Close() error {
if c.pre != nil { if c.pre != nil {
_ = c.pre.Close() _ = c.pre.Close()
} }
if c.cur != nil { _ = c.cur.Close()
_ = c.cur.Close()
}
_ = c.conn.Close()
c.wg.Wait() c.wg.Wait()
select { select {
case p := <-c.readCh: case packet := <-c.readCh:
if p.p != nil { if packet.p != nil {
pool.Put(p.p[:cap(p.p)]) pool.Put(packet.p[:cap(packet.p)])
} }
default: default:
} }
@@ -244,7 +235,9 @@ func (c *udpHopConn) Close() error {
} }
func (c *udpHopConn) LocalAddr() net.Addr { func (c *udpHopConn) LocalAddr() net.Addr {
return c.conn.LocalAddr() c.mu.RLock()
defer c.mu.RUnlock()
return c.cur.LocalAddr()
} }
func (c *udpHopConn) SetDeadline(t time.Time) error { func (c *udpHopConn) SetDeadline(t time.Time) error {
@@ -254,10 +247,7 @@ func (c *udpHopConn) SetDeadline(t time.Time) error {
if c.pre != nil { if c.pre != nil {
_ = c.pre.SetDeadline(t) _ = c.pre.SetDeadline(t)
} }
if c.cur != nil { return c.cur.SetDeadline(t)
_ = c.cur.SetDeadline(t)
}
return nil
} }
func (c *udpHopConn) SetReadDeadline(t time.Time) error { func (c *udpHopConn) SetReadDeadline(t time.Time) error {
@@ -267,10 +257,7 @@ func (c *udpHopConn) SetReadDeadline(t time.Time) error {
if c.pre != nil { if c.pre != nil {
_ = c.pre.SetReadDeadline(t) _ = c.pre.SetReadDeadline(t)
} }
if c.cur != nil { return c.cur.SetReadDeadline(t)
_ = c.cur.SetReadDeadline(t)
}
return nil
} }
func (c *udpHopConn) SetWriteDeadline(t time.Time) error { func (c *udpHopConn) SetWriteDeadline(t time.Time) error {
@@ -280,10 +267,7 @@ func (c *udpHopConn) SetWriteDeadline(t time.Time) error {
if c.pre != nil { if c.pre != nil {
_ = c.pre.SetWriteDeadline(t) _ = c.pre.SetWriteDeadline(t)
} }
if c.cur != nil { return c.cur.SetWriteDeadline(t)
_ = c.cur.SetWriteDeadline(t)
}
return nil
} }
func randPrefix(p netip.Prefix) []byte { func randPrefix(p netip.Prefix) []byte {
+6 -13
View File
@@ -1,21 +1,14 @@
package xdns package xdns
import ( import (
"net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/transport/internet/finalmask"
) )
func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) { func (c *Config) WrapPacketConnClient(conn net.PacketConn, dest *net.Destination, dialer *finalmask.Dialer) (net.PacketConn, error) {
// _, ok1 := raw.(*internet.FakePacketConn) return NewConnClient(c, conn)
// _, ok2 := raw.(*udphop.UdpHopPacketConn)
// if level != 0 || ok1 || ok2 {
// return nil, errors.New("xdns requires being at the outermost level")
// }
return NewConnClient(c, raw)
} }
func (c *Config) WrapPacketConnServer(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) { func (c *Config) WrapPacketConnServer(conn net.PacketConn, addr net.Addr, lc *finalmask.ListenConfig) (net.PacketConn, error) {
// if level != 0 { return NewConnServer(c, conn)
// return nil, errors.New("xdns requires being at the outermost level")
// }
return NewConnServer(c, raw)
} }
+28 -34
View File
@@ -8,8 +8,7 @@ import (
goerrors "errors" goerrors "errors"
"fmt" "fmt"
"io" "io"
mathrand "math/rand" mrand "math/rand"
"net"
"net/netip" "net/netip"
"sync" "sync"
"time" "time"
@@ -17,6 +16,7 @@ import (
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/transport/internet/finalmask" "github.com/xtls/xray-core/transport/internet/finalmask"
"golang.org/x/net/icmp" "golang.org/x/net/icmp"
"golang.org/x/net/ipv4" "golang.org/x/net/ipv4"
@@ -36,11 +36,11 @@ type packet struct {
} }
type xicmpConnClient struct { type xicmpConnClient struct {
conn net.PacketConn
icmp4 *icmp.PacketConn icmp4 *icmp.PacketConn
icmp6 *icmp.PacketConn icmp6 *icmp.PacketConn
udp bool udp bool
ips []netip.Addr ips []netip.Addr
ip net.IP
clientID [8]byte clientID [8]byte
id int id int
seq int seq int
@@ -50,7 +50,7 @@ type xicmpConnClient struct {
mu sync.Mutex mu sync.Mutex
} }
func NewConnClient(c *Config, raw net.PacketConn) (net.PacketConn, error) { func NewConnClient(c *Config, dest *net.Destination) (net.PacketConn, error) {
var icmp4, icmp6 *icmp.PacketConn var icmp4, icmp6 *icmp.PacketConn
var err4, err6 error var err4, err6 error
if c.DGRAM { if c.DGRAM {
@@ -69,17 +69,24 @@ func NewConnClient(c *Config, raw net.PacketConn) (net.PacketConn, error) {
ips = append(ips, netip.MustParseAddr(ip)) ips = append(ips, netip.MustParseAddr(ip))
} }
var ip net.IP
if len(ips) > 0 {
ip = ips[mrand.Intn(len(ips))].AsSlice()
} else {
ip = dest.Address.IP()
}
var clientID [8]byte var clientID [8]byte
common.Must2(rand.Read(clientID[:])) common.Must2(rand.Read(clientID[:]))
conn := &xicmpConnClient{ conn := &xicmpConnClient{
conn: raw,
icmp4: icmp4, icmp4: icmp4,
icmp6: icmp6, icmp6: icmp6,
udp: c.DGRAM, udp: c.DGRAM,
ips: ips, ips: ips,
ip: ip,
clientID: clientID, clientID: clientID,
id: mathrand.Intn(65536), id: mrand.Intn(65536),
seq: 1, seq: 1,
readCh: make(chan packet), readCh: make(chan packet),
closeCh: make(chan struct{}), closeCh: make(chan struct{}),
@@ -92,10 +99,6 @@ func NewConnClient(c *Config, raw net.PacketConn) (net.PacketConn, error) {
return conn, nil return conn, nil
} }
func (c *xicmpConnClient) ring(a, b uint16) uint16 {
return min(a-b, b-a)
}
func (c *xicmpConnClient) closed() bool { func (c *xicmpConnClient) closed() bool {
select { select {
case <-c.closeCh: case <-c.closeCh:
@@ -110,12 +113,11 @@ func (c *xicmpConnClient) recv4() {
var b [finalmask.UDPSize]byte var b [finalmask.UDPSize]byte
for { for {
if c.closed() {
return
}
n, addr, err := c.icmp4.ReadFrom(b[:]) n, addr, err := c.icmp4.ReadFrom(b[:])
if err != nil { if err != nil {
if c.closed() {
return
}
var netErr net.Error var netErr net.Error
if goerrors.As(err, &netErr) && netErr.Timeout() { if goerrors.As(err, &netErr) && netErr.Timeout() {
select { select {
@@ -125,9 +127,10 @@ func (c *xicmpConnClient) recv4() {
case <-c.closeCh: case <-c.closeCh:
return return
} }
continue
} }
errors.LogErrorInner(context.Background(), err, "recv4 err") errors.LogErrorInner(context.Background(), err, "recv err 4")
continue return
} }
msg, err := icmp.ParseMessage(1, b[:n]) msg, err := icmp.ParseMessage(1, b[:n])
@@ -150,10 +153,6 @@ func (c *xicmpConnClient) recv4() {
continue continue
} }
if c.ring(uint16(echo.Seq), uint16(c.seq)) > 1000 {
continue
}
if len(echo.Data) > 8 && bytes.Equal(echo.Data[:8], c.clientID[:]) { if len(echo.Data) > 8 && bytes.Equal(echo.Data[:8], c.clientID[:]) {
continue continue
} }
@@ -182,12 +181,11 @@ func (c *xicmpConnClient) recv6() {
var b [finalmask.UDPSize]byte var b [finalmask.UDPSize]byte
for { for {
if c.closed() {
return
}
n, addr, err := c.icmp6.ReadFrom(b[:]) n, addr, err := c.icmp6.ReadFrom(b[:])
if err != nil { if err != nil {
if c.closed() {
return
}
var netErr net.Error var netErr net.Error
if goerrors.As(err, &netErr) && netErr.Timeout() { if goerrors.As(err, &netErr) && netErr.Timeout() {
select { select {
@@ -197,9 +195,10 @@ func (c *xicmpConnClient) recv6() {
case <-c.closeCh: case <-c.closeCh:
return return
} }
continue
} }
errors.LogErrorInner(context.Background(), err, "recv6 err") errors.LogErrorInner(context.Background(), err, "recv err 6")
continue return
} }
msg, err := icmp.ParseMessage(58, b[:n]) msg, err := icmp.ParseMessage(58, b[:n])
@@ -222,10 +221,6 @@ func (c *xicmpConnClient) recv6() {
continue continue
} }
if c.ring(uint16(echo.Seq), uint16(c.seq)) > 1000 {
continue
}
if len(echo.Data) > 8 && bytes.Equal(echo.Data[:8], c.clientID[:]) { if len(echo.Data) > 8 && bytes.Equal(echo.Data[:8], c.clientID[:]) {
continue continue
} }
@@ -273,9 +268,9 @@ func (c *xicmpConnClient) WriteTo(p []byte, addr net.Addr) (n int, err error) {
c.seq %= 65536 c.seq %= 65536
c.mu.Unlock() c.mu.Unlock()
ip := addr.(*net.UDPAddr).IP ip := c.ip
if len(c.ips) > 0 { if len(c.ips) > 0 {
ip = c.ips[mathrand.Intn(len(c.ips))].AsSlice() ip = c.ips[mrand.Intn(len(c.ips))].AsSlice()
} }
if c.udp { if c.udp {
@@ -314,7 +309,6 @@ func (c *xicmpConnClient) Close() error {
close(c.closeCh) close(c.closeCh)
_ = c.icmp4.Close() _ = c.icmp4.Close()
_ = c.icmp6.Close() _ = c.icmp6.Close()
_ = c.conn.Close()
c.wg.Wait() c.wg.Wait()
select { select {
case p := <-c.readCh: case p := <-c.readCh:
@@ -328,7 +322,7 @@ func (c *xicmpConnClient) Close() error {
} }
func (c *xicmpConnClient) LocalAddr() net.Addr { func (c *xicmpConnClient) LocalAddr() net.Addr {
return c.conn.LocalAddr() return &net.UDPAddr{IP: []byte{0, 0, 0, 0}}
} }
func (c *xicmpConnClient) SetDeadline(t time.Time) error { func (c *xicmpConnClient) SetDeadline(t time.Time) error {
+13 -13
View File
@@ -1,23 +1,23 @@
package xicmp package xicmp
import ( import (
"net" "errors"
"github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/transport/internet/finalmask"
) )
func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) { func (c *Config) HandleDial() {}
_, ok1 := raw.(*internet.FakePacketConn)
if level != 0 || ok1 { func (c *Config) HandleListen() {}
return nil, errors.New("xicmp requires being at the outermost level")
func (c *Config) WrapPacketConnClient(conn net.PacketConn, dest *net.Destination, dialer *finalmask.Dialer) (net.PacketConn, error) {
if dest.Address.Family().IsDomain() && len(c.IPs) == 0 {
return nil, errors.New("empty ip addresses")
} }
return NewConnClient(c, raw) return NewConnClient(c, dest)
} }
func (c *Config) WrapPacketConnServer(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) { func (c *Config) WrapPacketConnServer(conn net.PacketConn, addr net.Addr, lc *finalmask.ListenConfig) (net.PacketConn, error) {
if level != 0 { return NewConnServer(c)
return nil, errors.New("xicmp requires being at the outermost level")
}
return NewConnServer(c, raw)
} }
+14 -17
View File
@@ -37,7 +37,6 @@ type record struct {
} }
type xicmpConnServer struct { type xicmpConnServer struct {
conn net.PacketConn
icmp4 *icmp.PacketConn icmp4 *icmp.PacketConn
icmp6 *icmp.PacketConn icmp6 *icmp.PacketConn
ips map[netip.Addr]struct{} ips map[netip.Addr]struct{}
@@ -48,7 +47,7 @@ type xicmpConnServer struct {
mu sync.Mutex mu sync.Mutex
} }
func NewConnServer(c *Config, raw net.PacketConn) (net.PacketConn, error) { func NewConnServer(c *Config) (net.PacketConn, error) {
icmp4, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0") icmp4, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0")
if err != nil { if err != nil {
return nil, err return nil, err
@@ -64,7 +63,6 @@ func NewConnServer(c *Config, raw net.PacketConn) (net.PacketConn, error) {
} }
conn := &xicmpConnServer{ conn := &xicmpConnServer{
conn: raw,
icmp4: icmp4, icmp4: icmp4,
icmp6: icmp6, icmp6: icmp6,
ips: ips, ips: ips,
@@ -115,12 +113,11 @@ func (c *xicmpConnServer) recv4() {
var b [finalmask.UDPSize]byte var b [finalmask.UDPSize]byte
for { for {
if c.closed() {
return
}
n, addr, err := c.icmp4.ReadFrom(b[:]) n, addr, err := c.icmp4.ReadFrom(b[:])
if err != nil { if err != nil {
if c.closed() {
return
}
var netErr net.Error var netErr net.Error
if goerrors.As(err, &netErr) && netErr.Timeout() { if goerrors.As(err, &netErr) && netErr.Timeout() {
select { select {
@@ -130,9 +127,10 @@ func (c *xicmpConnServer) recv4() {
case <-c.closeCh: case <-c.closeCh:
return return
} }
continue
} }
errors.LogErrorInner(context.Background(), err, "recv4 err") errors.LogErrorInner(context.Background(), err, "recv err 4")
continue return
} }
msg, err := icmp.ParseMessage(1, b[:n]) msg, err := icmp.ParseMessage(1, b[:n])
@@ -195,12 +193,11 @@ func (c *xicmpConnServer) recv6() {
var b [finalmask.UDPSize]byte var b [finalmask.UDPSize]byte
for { for {
if c.closed() {
return
}
n, addr, err := c.icmp6.ReadFrom(b[:]) n, addr, err := c.icmp6.ReadFrom(b[:])
if err != nil { if err != nil {
if c.closed() {
return
}
var netErr net.Error var netErr net.Error
if goerrors.As(err, &netErr) && netErr.Timeout() { if goerrors.As(err, &netErr) && netErr.Timeout() {
select { select {
@@ -210,9 +207,10 @@ func (c *xicmpConnServer) recv6() {
case <-c.closeCh: case <-c.closeCh:
return return
} }
continue
} }
errors.LogErrorInner(context.Background(), err, "recv6 err") errors.LogErrorInner(context.Background(), err, "recv err 6")
continue return
} }
msg, err := icmp.ParseMessage(58, b[:n]) msg, err := icmp.ParseMessage(58, b[:n])
@@ -330,7 +328,6 @@ func (c *xicmpConnServer) Close() error {
close(c.closeCh) close(c.closeCh)
_ = c.icmp4.Close() _ = c.icmp4.Close()
_ = c.icmp6.Close() _ = c.icmp6.Close()
_ = c.conn.Close()
c.wg.Wait() c.wg.Wait()
select { select {
case p := <-c.readCh: case p := <-c.readCh:
@@ -344,7 +341,7 @@ func (c *xicmpConnServer) Close() error {
} }
func (c *xicmpConnServer) LocalAddr() net.Addr { func (c *xicmpConnServer) LocalAddr() net.Addr {
return c.conn.LocalAddr() return &net.UDPAddr{IP: []byte{0, 0, 0, 0}}
} }
func (c *xicmpConnServer) SetDeadline(t time.Time) error { func (c *xicmpConnServer) SetDeadline(t time.Time) error {
@@ -39,7 +39,6 @@ type record struct {
} }
type xicmpConnServer struct { type xicmpConnServer struct {
conn net.PacketConn
icmp4 *icmp.PacketConn icmp4 *icmp.PacketConn
icmp6 *icmp.PacketConn icmp6 *icmp.PacketConn
ipv4PC *ipv4.PacketConn ipv4PC *ipv4.PacketConn
@@ -52,7 +51,7 @@ type xicmpConnServer struct {
mu sync.Mutex mu sync.Mutex
} }
func NewConnServer(c *Config, raw net.PacketConn) (net.PacketConn, error) { func NewConnServer(c *Config) (net.PacketConn, error) {
icmp4, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0") icmp4, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0")
if err != nil { if err != nil {
return nil, err return nil, err
@@ -68,7 +67,6 @@ func NewConnServer(c *Config, raw net.PacketConn) (net.PacketConn, error) {
} }
conn := &xicmpConnServer{ conn := &xicmpConnServer{
conn: raw,
icmp4: icmp4, icmp4: icmp4,
icmp6: icmp6, icmp6: icmp6,
ipv4PC: icmp4.IPv4PacketConn(), ipv4PC: icmp4.IPv4PacketConn(),
@@ -124,12 +122,11 @@ func (c *xicmpConnServer) recv4() {
var b [finalmask.UDPSize]byte var b [finalmask.UDPSize]byte
for { for {
if c.closed() {
return
}
n, cm, addr, err := c.ipv4PC.ReadFrom(b[:]) n, cm, addr, err := c.ipv4PC.ReadFrom(b[:])
if err != nil { if err != nil {
if c.closed() {
return
}
var netErr net.Error var netErr net.Error
if goerrors.As(err, &netErr) && netErr.Timeout() { if goerrors.As(err, &netErr) && netErr.Timeout() {
select { select {
@@ -139,9 +136,10 @@ func (c *xicmpConnServer) recv4() {
case <-c.closeCh: case <-c.closeCh:
return return
} }
continue
} }
errors.LogErrorInner(context.Background(), err, "recv4 err") errors.LogErrorInner(context.Background(), err, "recv err 4")
continue return
} }
msg, err := icmp.ParseMessage(1, b[:n]) msg, err := icmp.ParseMessage(1, b[:n])
@@ -205,12 +203,11 @@ func (c *xicmpConnServer) recv6() {
var b [finalmask.UDPSize]byte var b [finalmask.UDPSize]byte
for { for {
if c.closed() {
return
}
n, cm, addr, err := c.ipv6PC.ReadFrom(b[:]) n, cm, addr, err := c.ipv6PC.ReadFrom(b[:])
if err != nil { if err != nil {
if c.closed() {
return
}
var netErr net.Error var netErr net.Error
if goerrors.As(err, &netErr) && netErr.Timeout() { if goerrors.As(err, &netErr) && netErr.Timeout() {
select { select {
@@ -220,9 +217,10 @@ func (c *xicmpConnServer) recv6() {
case <-c.closeCh: case <-c.closeCh:
return return
} }
continue
} }
errors.LogErrorInner(context.Background(), err, "recv6 err") errors.LogErrorInner(context.Background(), err, "recv err 6")
continue return
} }
msg, err := icmp.ParseMessage(58, b[:n]) msg, err := icmp.ParseMessage(58, b[:n])
@@ -341,7 +339,6 @@ func (c *xicmpConnServer) Close() error {
close(c.closeCh) close(c.closeCh)
_ = c.icmp4.Close() _ = c.icmp4.Close()
_ = c.icmp6.Close() _ = c.icmp6.Close()
_ = c.conn.Close()
c.wg.Wait() c.wg.Wait()
select { select {
case p := <-c.readCh: case p := <-c.readCh:
@@ -355,7 +352,7 @@ func (c *xicmpConnServer) Close() error {
} }
func (c *xicmpConnServer) LocalAddr() net.Addr { func (c *xicmpConnServer) LocalAddr() net.Addr {
return c.conn.LocalAddr() return &net.UDPAddr{IP: []byte{0, 0, 0, 0}}
} }
func (c *xicmpConnServer) SetDeadline(t time.Time) error { func (c *xicmpConnServer) SetDeadline(t time.Time) error {
+4 -2
View File
@@ -2,10 +2,12 @@ package xmc
import ( import (
"fmt" "fmt"
"net"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/transport/internet/finalmask"
) )
func (c *Config) WrapConnClient(conn net.Conn) (net.Conn, error) { func (c *Config) WrapConnClient(conn net.Conn, dest *net.Destination, dialer *finalmask.Dialer) (net.Conn, error) {
profiles, err := profilesFromConfig(c.Profiles) profiles, err := profilesFromConfig(c.Profiles)
if err != nil { if err != nil {
return nil, fmt.Errorf("minecraft finalmask: %w", err) return nil, fmt.Errorf("minecraft finalmask: %w", err)
+6 -11
View File
@@ -83,7 +83,6 @@ func getGrpcClient(ctx context.Context, dest net.Destination, streamSettings *in
} }
tlsConfig := tls.ConfigFromStreamSettings(streamSettings) tlsConfig := tls.ConfigFromStreamSettings(streamSettings)
realityConfig := reality.ConfigFromStreamSettings(streamSettings) realityConfig := reality.ConfigFromStreamSettings(streamSettings)
sockopt := streamSettings.SocketSettings
grpcSettings := streamSettings.ProtocolSettings.(*Config) grpcSettings := streamSettings.ProtocolSettings.(*Config)
if client, found := globalDialerMap[dialerConf{dest, streamSettings}]; found && client.GetState() != connectivity.Shutdown { if client, found := globalDialerMap[dialerConf{dest, streamSettings}]; found && client.GetState() != connectivity.Shutdown {
@@ -124,17 +123,13 @@ func getGrpcClient(ctx context.Context, dest net.Destination, streamSettings *in
gctx = session.ContextWithOutbounds(gctx, session.OutboundsFromContext(ctx)) gctx = session.ContextWithOutbounds(gctx, session.OutboundsFromContext(ctx))
gctx = session.ContextWithTimeoutOnly(gctx, true) gctx = session.ContextWithTimeoutOnly(gctx, true)
c, err := internet.DialSystem(gctx, net.TCPDestination(address, port), sockopt) var c net.Conn
if streamSettings.FinalMask != nil {
c, err = streamSettings.FinalMask.DialTCP(gctx, net.TCPDestination(address, port))
} else {
c, err = internet.DialSystem(ctx, dest, streamSettings.SocketSettings)
}
if err == nil { if err == nil {
if streamSettings.TcpmaskManager != nil {
newConn, err := streamSettings.TcpmaskManager.WrapConnClient(c)
if err != nil {
c.Close()
return nil, errors.New("mask err").Base(err)
}
c = newConn
}
if tlsConfig != nil { if tlsConfig != nil {
config := tlsConfig.GetTLSConfig(tls.WithDestination(dest)) config := tlsConfig.GetTLSConfig(tls.WithDestination(dest))
if fingerprint := tls.GetFingerprint(tlsConfig.Fingerprint); fingerprint != nil { if fingerprint := tls.GetFingerprint(tlsConfig.Fingerprint); fingerprint != nil {
+11 -19
View File
@@ -104,28 +104,20 @@ func Listen(ctx context.Context, address net.Address, port net.Port, settings *i
go func() { go func() {
var streamListener net.Listener var streamListener net.Listener
var err error var err error
var addr net.Addr
if port == net.Port(0) { // unix if port == net.Port(0) { // unix
streamListener, err = internet.ListenSystem(ctx, &net.UnixAddr{ addr = &net.UnixAddr{Name: address.Domain(), Net: "unix"}
Name: address.Domain(),
Net: "unix",
}, settings.SocketSettings)
if err != nil {
errors.LogErrorInner(ctx, err, "failed to listen on ", address)
return
}
} else { // tcp } else { // tcp
streamListener, err = internet.ListenSystem(ctx, &net.TCPAddr{ addr = &net.TCPAddr{IP: address.IP(), Port: int(port)}
IP: address.IP(),
Port: int(port),
}, settings.SocketSettings)
if err != nil {
errors.LogErrorInner(ctx, err, "failed to listen on ", address, ":", port)
return
}
} }
if settings.FinalMask != nil {
if settings.TcpmaskManager != nil { streamListener, err = settings.FinalMask.Listen(ctx, addr)
streamListener, _ = settings.TcpmaskManager.WrapListener(streamListener) } else {
streamListener, err = internet.ListenSystem(ctx, addr, settings.SocketSettings)
}
if err != nil {
errors.LogErrorInner(ctx, err, "failed to listen on ", address, ":", port)
return
} }
errors.LogDebug(ctx, "gRPC listen for service name `"+grpcSettings.getServiceName()+"` tun `"+grpcSettings.getTunStreamName()+"` multi tun `"+grpcSettings.getTunMultiStreamName()+"`") errors.LogDebug(ctx, "gRPC listen for service name `"+grpcSettings.getServiceName()+"` tun `"+grpcSettings.getTunStreamName()+"` multi tun `"+grpcSettings.getTunMultiStreamName()+"`")
+7 -10
View File
@@ -46,21 +46,18 @@ func (c *ConnRF) Read(b []byte) (int, error) {
func dialhttpUpgrade(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (net.Conn, error) { func dialhttpUpgrade(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (net.Conn, error) {
transportConfiguration := streamSettings.ProtocolSettings.(*Config) transportConfiguration := streamSettings.ProtocolSettings.(*Config)
pconn, err := internet.DialSystem(ctx, dest, streamSettings.SocketSettings) var pconn net.Conn
var err error
if streamSettings.FinalMask != nil {
pconn, err = streamSettings.FinalMask.DialTCP(ctx, dest)
} else {
pconn, err = internet.DialSystem(ctx, dest, streamSettings.SocketSettings)
}
if err != nil { if err != nil {
errors.LogErrorInner(ctx, err, "failed to dial to ", dest) errors.LogErrorInner(ctx, err, "failed to dial to ", dest)
return nil, err return nil, err
} }
if streamSettings.TcpmaskManager != nil {
newConn, err := streamSettings.TcpmaskManager.WrapConnClient(pconn)
if err != nil {
pconn.Close()
return nil, errors.New("mask err").Base(err)
}
pconn = newConn
}
var conn net.Conn var conn net.Conn
var requestURL url.URL var requestURL url.URL
tConfig := tls.ConfigFromStreamSettings(streamSettings) tConfig := tls.ConfigFromStreamSettings(streamSettings)
+11 -19
View File
@@ -124,29 +124,21 @@ func ListenHTTPUpgrade(ctx context.Context, address net.Address, port net.Port,
} }
var listener net.Listener var listener net.Listener
var err error var err error
var addr net.Addr
if port == net.Port(0) { // unix if port == net.Port(0) { // unix
listener, err = internet.ListenSystem(ctx, &net.UnixAddr{ addr = &net.UnixAddr{Name: address.Domain(), Net: "unix"}
Name: address.Domain(),
Net: "unix",
}, streamSettings.SocketSettings)
if err != nil {
return nil, errors.New("failed to listen unix domain socket(for HttpUpgrade) on ", address).Base(err)
}
errors.LogInfo(ctx, "listening unix domain socket(for HttpUpgrade) on ", address)
} else { // tcp } else { // tcp
listener, err = internet.ListenSystem(ctx, &net.TCPAddr{ addr = &net.TCPAddr{IP: address.IP(), Port: int(port)}
IP: address.IP(),
Port: int(port),
}, streamSettings.SocketSettings)
if err != nil {
return nil, errors.New("failed to listen TCP(for HttpUpgrade) on ", address, ":", port).Base(err)
}
errors.LogInfo(ctx, "listening TCP(for HttpUpgrade) on ", address, ":", port)
} }
if streamSettings.FinalMask != nil {
if streamSettings.TcpmaskManager != nil { listener, err = streamSettings.FinalMask.Listen(ctx, addr)
listener, _ = streamSettings.TcpmaskManager.WrapListener(listener) } else {
listener, err = internet.ListenSystem(ctx, addr, streamSettings.SocketSettings)
} }
if err != nil {
return nil, errors.New("failed to listen ", addr.Network(), "(for HttpUpgrade) on ", address, ":", port).Base(err)
}
errors.LogInfo(ctx, "listening ", addr.Network(), "(for HttpUpgrade) on ", address, ":", port)
if streamSettings.SocketSettings != nil && streamSettings.SocketSettings.AcceptProxyProtocol { if streamSettings.SocketSettings != nil && streamSettings.SocketSettings.AcceptProxyProtocol {
errors.LogWarning(ctx, "accepting PROXY protocol") errors.LogWarning(ctx, "accepting PROXY protocol")
+35 -36
View File
@@ -2,7 +2,7 @@ package hysteria
import ( import (
"context" "context"
go_tls "crypto/tls" gotls "crypto/tls"
"net/http" "net/http"
"net/url" "net/url"
"reflect" "reflect"
@@ -28,12 +28,12 @@ import (
type client struct { type client struct {
sync.Mutex sync.Mutex
dest net.Destination dest net.Destination
config *Config config *Config
tlsConfig *go_tls.Config tlsConfig *gotls.Config
socketConfig *internet.SocketConfig socketConfig *internet.SocketConfig
udpmaskManager *finalmask.UdpmaskManager finalMask *finalmask.FinalMask
quicParams *internet.QuicParams quicParams *internet.QuicParams
conn *quic.Conn conn *quic.Conn
tr *quic.Transport tr *quic.Transport
@@ -113,30 +113,29 @@ func (c *client) dial(ctx context.Context) error {
// } // }
var pktConn net.PacketConn var pktConn net.PacketConn
var udpAddr *net.UDPAddr var udpAddr net.Addr
if c.finalMask != nil {
raw, err := internet.DialSystem(ctx, c.dest, c.socketConfig) conn, err := c.finalMask.DialUDP(ctx, c.dest)
if err != nil {
return errors.New("failed to dial to dest").Base(err)
}
switch c := raw.(type) {
case *internet.PacketConnWrapper:
pktConn = c.PacketConn
udpAddr = raw.RemoteAddr().(*net.UDPAddr)
case *cnc.Connection:
pktConn = &internet.FakePacketConn{Conn: c}
udpAddr = &net.UDPAddr{IP: c.RemoteAddr().(*net.TCPAddr).IP, Port: c.RemoteAddr().(*net.TCPAddr).Port}
default:
panic(reflect.TypeOf(c))
}
if c.udpmaskManager != nil {
newConn, err := c.udpmaskManager.WrapPacketConnClient(pktConn)
if err != nil { if err != nil {
pktConn.Close() return errors.New("failed to dial to dest").Base(err)
return errors.New("mask err").Base(err) }
pktConn = conn.(*finalmask.PacketConnWrapper).PacketConn
udpAddr = conn.RemoteAddr()
} else {
conn, err := internet.DialSystem(ctx, c.dest, c.socketConfig)
if err != nil {
return errors.New("failed to dial to dest").Base(err)
}
switch c := conn.(type) {
case *internet.PacketConnWrapper:
pktConn = c.PacketConn
udpAddr = c.RemoteAddr()
case *cnc.Connection:
pktConn = &internet.FakePacketConn{Conn: c}
udpAddr = &net.UDPAddr{IP: []byte{0, 0, 0, 0}}
default:
panic(reflect.TypeOf(c))
} }
pktConn = newConn
} }
tr := &quic.Transport{Conn: pktConn, DisableGSO: quicParams.DisableGSO} tr := &quic.Transport{Conn: pktConn, DisableGSO: quicParams.DisableGSO}
@@ -150,7 +149,7 @@ func (c *client) dial(ctx context.Context) error {
rt := &http3.Transport{ rt := &http3.Transport{
TLSClientConfig: c.tlsConfig, TLSClientConfig: c.tlsConfig,
QUICConfig: quicConfig, QUICConfig: quicConfig,
Dial: func(ctx context.Context, _ string, tlsCfg *go_tls.Config, cfg *quic.Config) (*quic.Conn, error) { Dial: func(ctx context.Context, _ string, tlsCfg *gotls.Config, cfg *quic.Config) (*quic.Conn, error) {
qc, err := tr.DialEarly(ctx, udpAddr, tlsCfg, cfg) qc, err := tr.DialEarly(ctx, udpAddr, tlsCfg, cfg)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -316,12 +315,12 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me
c = manager.m[dialerConf{dest, streamSettings}] c = manager.m[dialerConf{dest, streamSettings}]
if c == nil { if c == nil {
c = &client{ c = &client{
dest: dest, dest: dest,
config: streamSettings.ProtocolSettings.(*Config), config: streamSettings.ProtocolSettings.(*Config),
tlsConfig: tlsConfig.GetTLSConfig(tls.WithDestination(dest)), tlsConfig: tlsConfig.GetTLSConfig(tls.WithDestination(dest)),
socketConfig: streamSettings.SocketSettings, socketConfig: streamSettings.SocketSettings,
udpmaskManager: streamSettings.UdpmaskManager, finalMask: streamSettings.FinalMask,
quicParams: streamSettings.QuicParams, quicParams: streamSettings.QuicParams,
} }
manager.m[dialerConf{dest, streamSettings}] = c manager.m[dialerConf{dest, streamSettings}] = c
} }
+7 -10
View File
@@ -316,20 +316,17 @@ func Listen(ctx context.Context, address net.Address, port net.Port, streamSetti
quicConfig.MaxIncomingStreams = 1024 quicConfig.MaxIncomingStreams = 1024
} }
pktConn, err := internet.ListenSystemPacket(context.Background(), &net.UDPAddr{IP: address.IP(), Port: int(port)}, streamSettings.SocketSettings) var pktConn net.PacketConn
var err error
if streamSettings.FinalMask != nil {
pktConn, err = streamSettings.FinalMask.ListenPacket(context.Background(), &net.UDPAddr{IP: address.IP(), Port: int(port)})
} else {
pktConn, err = internet.ListenSystemPacket(context.Background(), &net.UDPAddr{IP: address.IP(), Port: int(port)}, streamSettings.SocketSettings)
}
if err != nil { if err != nil {
return nil, err return nil, err
} }
if streamSettings.UdpmaskManager != nil {
newConn, err := streamSettings.UdpmaskManager.WrapPacketConnServer(pktConn)
if err != nil {
pktConn.Close()
return nil, errors.New("mask err").Base(err)
}
pktConn = newConn
}
var k *quic.StatelessResetKey var k *quic.StatelessResetKey
if !quicParams.DisableStatelessReset { if !quicParams.DisableStatelessReset {
k = &quic.StatelessResetKey{} k = &quic.StatelessResetKey{}
+7 -28
View File
@@ -3,7 +3,6 @@ package kcp
import ( import (
"context" "context"
"io" "io"
reflect "reflect"
"sync/atomic" "sync/atomic"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
@@ -11,7 +10,6 @@ import (
"github.com/xtls/xray-core/common/dice" "github.com/xtls/xray-core/common/dice"
"github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/net/cnc"
"github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/stat" "github.com/xtls/xray-core/transport/internet/stat"
"github.com/xtls/xray-core/transport/internet/tls" "github.com/xtls/xray-core/transport/internet/tls"
@@ -51,36 +49,17 @@ func DialKCP(ctx context.Context, dest net.Destination, streamSettings *internet
dest.Network = net.Network_UDP dest.Network = net.Network_UDP
errors.LogInfo(ctx, "dialing mKCP to ", dest) errors.LogInfo(ctx, "dialing mKCP to ", dest)
conn, err := internet.DialSystem(ctx, dest, streamSettings.SocketSettings) var conn net.Conn
var err error
if streamSettings.FinalMask != nil {
conn, err = streamSettings.FinalMask.DialUDP(ctx, dest)
} else {
conn, err = internet.DialSystem(ctx, dest, streamSettings.SocketSettings)
}
if err != nil { if err != nil {
return nil, errors.New("failed to dial to dest: ", err).AtWarning().Base(err) return nil, errors.New("failed to dial to dest: ", err).AtWarning().Base(err)
} }
if streamSettings.UdpmaskManager != nil {
var pktConn net.PacketConn
var udpAddr *net.UDPAddr
switch c := conn.(type) {
case *internet.PacketConnWrapper:
pktConn = c.PacketConn
udpAddr = c.RemoteAddr().(*net.UDPAddr)
case *cnc.Connection:
pktConn = &internet.FakePacketConn{Conn: c}
udpAddr = &net.UDPAddr{IP: c.RemoteAddr().(*net.TCPAddr).IP, Port: c.RemoteAddr().(*net.TCPAddr).Port}
default:
panic(reflect.TypeOf(c))
}
newConn, err := streamSettings.UdpmaskManager.WrapPacketConnClient(pktConn)
if err != nil {
pktConn.Close()
return nil, errors.New("mask err").Base(err)
}
pktConn = newConn
conn = &internet.PacketConnWrapper{
PacketConn: pktConn,
Dest: udpAddr,
}
}
kcpSettings := streamSettings.ProtocolSettings.(*Config) kcpSettings := streamSettings.ProtocolSettings.(*Config)
reader := &KCPPacketReader{} reader := &KCPPacketReader{}
+47 -23
View File
@@ -1,7 +1,12 @@
package internet package internet
import ( import (
"context"
"reflect"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/net/cnc"
"github.com/xtls/xray-core/transport/internet/finalmask" "github.com/xtls/xray-core/transport/internet/finalmask"
) )
@@ -12,8 +17,7 @@ type MemoryStreamConfig struct {
ProtocolSettings interface{} ProtocolSettings interface{}
SecurityType string SecurityType string
SecuritySettings interface{} SecuritySettings interface{}
TcpmaskManager *finalmask.TcpmaskManager FinalMask *finalmask.FinalMask
UdpmaskManager *finalmask.UdpmaskManager
QuicParams *QuicParams QuicParams *QuicParams
SocketSettings *SocketConfig SocketSettings *SocketConfig
DownloadSettings *MemoryStreamConfig DownloadSettings *MemoryStreamConfig
@@ -51,33 +55,53 @@ func ToMemoryStreamConfig(s *StreamConfig) (*MemoryStreamConfig, error) {
mss.SecuritySettings = ess mss.SecuritySettings = ess
} }
if s != nil && len(s.Tcpmasks) > 0 { var tcpMasks []finalmask.TCPMask
var masks []finalmask.Tcpmask var udpMasks []finalmask.UDPMask
for _, msg := range s.Tcpmasks {
instance, err := msg.GetInstance() if s != nil {
if err != nil { for i := range s.Tcpmasks {
return nil, err instance := common.Must2(s.Tcpmasks[i].GetInstance())
} tcpMasks = append(tcpMasks, instance.(finalmask.TCPMask))
masks = append(masks, instance.(finalmask.Tcpmask)) }
for i := range s.Udpmasks {
instance := common.Must2(s.Udpmasks[i].GetInstance())
udpMasks = append(udpMasks, instance.(finalmask.UDPMask))
} }
mss.TcpmaskManager = finalmask.NewTcpmaskManager(masks)
} }
dialTCP := func(ctx context.Context, dest net.Destination) (net.Conn, error) {
return DialSystem(ctx, dest, mss.SocketSettings)
}
listen := func(ctx context.Context, addr net.Addr) (net.Listener, error) {
return ListenSystem(ctx, addr, mss.SocketSettings)
}
dialUDP := func(ctx context.Context, dest net.Destination) (net.PacketConn, net.Addr, error) {
conn, err := DialSystem(ctx, dest, mss.SocketSettings)
if err != nil {
return nil, nil, err
}
var newConn net.PacketConn
var udpAddr net.Addr
switch c := conn.(type) {
case *PacketConnWrapper:
newConn = c.PacketConn
udpAddr = conn.RemoteAddr()
case *cnc.Connection:
newConn = &FakePacketConn{Conn: c}
udpAddr = &net.UDPAddr{IP: []byte{0, 0, 0, 0}, Port: 0}
default:
panic(reflect.TypeOf(c))
}
return newConn, udpAddr, nil
}
listenPacket := func(ctx context.Context, addr net.Addr) (net.PacketConn, error) {
return ListenSystemPacket(ctx, addr, mss.SocketSettings)
}
mss.FinalMask = finalmask.NewFinalMask(tcpMasks, udpMasks, dialTCP, listen, dialUDP, listenPacket)
if s != nil && s.QuicParams != nil { if s != nil && s.QuicParams != nil {
mss.QuicParams = s.QuicParams mss.QuicParams = s.QuicParams
} }
if s != nil && len(s.Udpmasks) > 0 {
var masks []finalmask.Udpmask
for _, msg := range s.Udpmasks {
instance, err := msg.GetInstance()
if err != nil {
return nil, err
}
masks = append(masks, instance.(finalmask.Udpmask))
}
mss.UdpmaskManager = finalmask.NewUdpmaskManager(masks)
}
return mss, nil return mss, nil
} }
+30 -33
View File
@@ -8,7 +8,7 @@ import (
"net/http" "net/http"
"net/http/httptrace" "net/http/httptrace"
"net/url" "net/url"
reflect "reflect" "reflect"
"runtime" "runtime"
"strconv" "strconv"
"sync" "sync"
@@ -25,6 +25,7 @@ import (
"github.com/xtls/xray-core/common/signal/done" "github.com/xtls/xray-core/common/signal/done"
"github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/browser_dialer" "github.com/xtls/xray-core/transport/internet/browser_dialer"
"github.com/xtls/xray-core/transport/internet/finalmask"
"github.com/xtls/xray-core/transport/internet/hysteria/congestion" "github.com/xtls/xray-core/transport/internet/hysteria/congestion"
"github.com/xtls/xray-core/transport/internet/hysteria/congestion/bbr" "github.com/xtls/xray-core/transport/internet/hysteria/congestion/bbr"
"github.com/xtls/xray-core/transport/internet/reality" "github.com/xtls/xray-core/transport/internet/reality"
@@ -116,20 +117,17 @@ func createHTTPClient(dest net.Destination, streamSettings *internet.MemoryStrea
transportConfig := streamSettings.ProtocolSettings.(*Config) transportConfig := streamSettings.ProtocolSettings.(*Config)
dialContext := func(ctxInner context.Context) (net.Conn, error) { dialContext := func(ctxInner context.Context) (net.Conn, error) {
conn, err := internet.DialSystem(ctxInner, dest, streamSettings.SocketSettings) var conn net.Conn
var err error
if streamSettings.FinalMask != nil {
conn, err = streamSettings.FinalMask.DialTCP(ctxInner, dest)
} else {
conn, err = internet.DialSystem(ctxInner, dest, streamSettings.SocketSettings)
}
if err != nil { if err != nil {
return nil, err return nil, err
} }
if streamSettings.TcpmaskManager != nil {
newConn, err := streamSettings.TcpmaskManager.WrapConnClient(conn)
if err != nil {
conn.Close()
return nil, errors.New("mask err").Base(err)
}
conn = newConn
}
if realityConfig != nil { if realityConfig != nil {
return reality.UClient(conn, realityConfig, ctxInner, dest) return reality.UClient(conn, realityConfig, ctxInner, dest)
} }
@@ -196,30 +194,29 @@ func createHTTPClient(dest net.Destination, streamSettings *internet.MemoryStrea
TLSClientConfig: gotlsConfig, TLSClientConfig: gotlsConfig,
Dial: func(ctx context.Context, addr string, tlsCfg *gotls.Config, cfg *quic.Config) (*quic.Conn, error) { Dial: func(ctx context.Context, addr string, tlsCfg *gotls.Config, cfg *quic.Config) (*quic.Conn, error) {
var pktConn net.PacketConn var pktConn net.PacketConn
var udpAddr *net.UDPAddr var udpAddr net.Addr
if streamSettings.FinalMask != nil {
raw, err := internet.DialSystem(ctx, dest, streamSettings.SocketSettings) conn, err := streamSettings.FinalMask.DialUDP(ctx, dest)
if err != nil {
return nil, errors.New("failed to dial to dest").Base(err)
}
switch c := raw.(type) {
case *internet.PacketConnWrapper:
pktConn = c.PacketConn
udpAddr = raw.RemoteAddr().(*net.UDPAddr)
case *cnc.Connection:
pktConn = &internet.FakePacketConn{Conn: c}
udpAddr = &net.UDPAddr{IP: c.RemoteAddr().(*net.TCPAddr).IP, Port: c.RemoteAddr().(*net.TCPAddr).Port}
default:
panic(reflect.TypeOf(c))
}
if streamSettings.UdpmaskManager != nil {
newConn, err := streamSettings.UdpmaskManager.WrapPacketConnClient(pktConn)
if err != nil { if err != nil {
pktConn.Close() return nil, errors.New("failed to dial to dest").Base(err)
return nil, errors.New("mask err").Base(err) }
pktConn = conn.(*finalmask.PacketConnWrapper).PacketConn
udpAddr = conn.RemoteAddr()
} else {
conn, err := internet.DialSystem(ctx, dest, streamSettings.SocketSettings)
if err != nil {
return nil, errors.New("failed to dial to dest").Base(err)
}
switch c := conn.(type) {
case *internet.PacketConnWrapper:
pktConn = c.PacketConn
udpAddr = c.RemoteAddr()
case *cnc.Connection:
pktConn = &internet.FakePacketConn{Conn: c}
udpAddr = &net.UDPAddr{IP: []byte{0, 0, 0, 0}}
default:
panic(reflect.TypeOf(c))
} }
pktConn = newConn
} }
tr := &quic.Transport{Conn: pktConn, DisableGSO: quicParams.DisableGSO} tr := &quic.Transport{Conn: pktConn, DisableGSO: quicParams.DisableGSO}
+24 -35
View File
@@ -463,31 +463,17 @@ func ListenXH(ctx context.Context, address net.Address, port net.Port, streamSet
l.isH3 = len(tlsConfig.NextProtos) == 1 && tlsConfig.NextProtos[0] == "h3" l.isH3 = len(tlsConfig.NextProtos) == 1 && tlsConfig.NextProtos[0] == "h3"
var err error var err error
if port == net.Port(0) { // unix if l.isH3 {
l.listener, err = internet.ListenSystem(ctx, &net.UnixAddr{ var pktConn net.PacketConn
Name: address.Domain(), var err error
Net: "unix", if streamSettings.FinalMask != nil {
}, streamSettings.SocketSettings) pktConn, err = streamSettings.FinalMask.ListenPacket(context.Background(), &net.UDPAddr{IP: address.IP(), Port: int(port)})
if err != nil { } else {
return nil, errors.New("failed to listen UNIX domain socket for XHTTP on ", address).Base(err) pktConn, err = internet.ListenSystemPacket(context.Background(), &net.UDPAddr{IP: address.IP(), Port: int(port)}, streamSettings.SocketSettings)
} }
errors.LogInfo(ctx, "listening UNIX domain socket for XHTTP on ", address)
} else if l.isH3 { // quic
Conn, err := internet.ListenSystemPacket(context.Background(), &net.UDPAddr{
IP: address.IP(),
Port: int(port),
}, streamSettings.SocketSettings)
if err != nil { if err != nil {
return nil, errors.New("failed to listen UDP for XHTTP/3 on ", address, ":", port).Base(err) return nil, errors.New("failed to listen UDP for XHTTP/3 on ", address, ":", port).Base(err)
} }
if streamSettings.UdpmaskManager != nil {
newConn, err := streamSettings.UdpmaskManager.WrapPacketConnServer(Conn)
if err != nil {
Conn.Close()
return nil, errors.New("mask err").Base(err)
}
Conn = newConn
}
quicParams := streamSettings.QuicParams quicParams := streamSettings.QuicParams
if quicParams == nil { if quicParams == nil {
@@ -512,7 +498,7 @@ func ListenXH(ctx context.Context, address net.Address, port net.Port, streamSet
common.Must2(rand.Read((*k)[:])) common.Must2(rand.Read((*k)[:]))
} }
tr := &quic.Transport{Conn: Conn, DisableGSO: quicParams.DisableGSO, StatelessResetKey: k} tr := &quic.Transport{Conn: pktConn, DisableGSO: quicParams.DisableGSO, StatelessResetKey: k}
l.h3listener, err = tr.ListenEarly(tlsConfig, quicConfig) l.h3listener, err = tr.ListenEarly(tlsConfig, quicConfig)
if err != nil { if err != nil {
@@ -534,21 +520,24 @@ func ListenXH(ctx context.Context, address net.Address, port net.Port, streamSet
errors.LogErrorInner(ctx, err, "failed to serve HTTP/3 for XHTTP/3") errors.LogErrorInner(ctx, err, "failed to serve HTTP/3 for XHTTP/3")
} }
_ = tr.Close() _ = tr.Close()
_ = Conn.Close() _ = pktConn.Close()
}() }()
} else { // tcp } else {
l.listener, err = internet.ListenSystem(ctx, &net.TCPAddr{ var addr net.Addr
IP: address.IP(), if port == net.Port(0) { // unix
Port: int(port), addr = &net.UnixAddr{Name: address.Domain(), Net: "unix"}
}, streamSettings.SocketSettings) } else { // tcp
if err != nil { addr = &net.TCPAddr{IP: address.IP(), Port: int(port)}
return nil, errors.New("failed to listen TCP for XHTTP on ", address, ":", port).Base(err)
} }
errors.LogInfo(ctx, "listening TCP for XHTTP on ", address, ":", port) if streamSettings.FinalMask != nil {
} l.listener, err = streamSettings.FinalMask.Listen(ctx, addr)
} else {
if !l.isH3 && streamSettings.TcpmaskManager != nil { l.listener, err = internet.ListenSystem(ctx, addr, streamSettings.SocketSettings)
l.listener, _ = streamSettings.TcpmaskManager.WrapListener(l.listener) }
if err != nil {
return nil, errors.New("failed to listen ", addr.Network(), " for XHTTP on ", address, ":", port).Base(err)
}
errors.LogInfo(ctx, "listening ", addr.Network(), " for XHTTP on ", address, ":", port)
} }
// tcp/unix (h1/h2) // tcp/unix (h1/h2)
+1 -1
View File
@@ -235,5 +235,5 @@ func (c *FakePacketConn) WriteTo(p []byte, _ net.Addr) (n int, err error) {
} }
func (c *FakePacketConn) LocalAddr() net.Addr { func (c *FakePacketConn) LocalAddr() net.Addr {
return &net.UDPAddr{IP: c.Conn.LocalAddr().(*net.TCPAddr).IP, Port: c.Conn.LocalAddr().(*net.TCPAddr).Port} return &net.UDPAddr{IP: []byte{0, 0, 0, 0}}
} }
+8 -11
View File
@@ -19,18 +19,15 @@ import (
// Dial dials a new TCP connection to the given destination. // Dial dials a new TCP connection to the given destination.
func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (stat.Connection, error) { func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (stat.Connection, error) {
errors.LogInfo(ctx, "dialing TCP to ", dest) errors.LogInfo(ctx, "dialing TCP to ", dest)
conn, err := internet.DialSystem(ctx, dest, streamSettings.SocketSettings) var conn net.Conn
if err != nil { var err error
return nil, err if streamSettings.FinalMask != nil {
conn, err = streamSettings.FinalMask.DialTCP(ctx, dest)
} else {
conn, err = internet.DialSystem(ctx, dest, streamSettings.SocketSettings)
} }
if err != nil {
if streamSettings.TcpmaskManager != nil { return nil, errors.New("failed to dial to dest").Base(err)
newConn, err := streamSettings.TcpmaskManager.WrapConnClient(conn)
if err != nil {
conn.Close()
return nil, errors.New("mask err").Base(err)
}
conn = newConn
} }
if config := tls.ConfigFromStreamSettings(streamSettings); config != nil { if config := tls.ConfigFromStreamSettings(streamSettings); config != nil {
+11 -19
View File
@@ -41,29 +41,21 @@ func ListenTCP(ctx context.Context, address net.Address, port net.Port, streamSe
} }
var listener net.Listener var listener net.Listener
var err error var err error
var addr net.Addr
if port == net.Port(0) { // unix if port == net.Port(0) { // unix
listener, err = internet.ListenSystem(ctx, &net.UnixAddr{ addr = &net.UnixAddr{Name: address.Domain(), Net: "unix"}
Name: address.Domain(), } else { // tcp
Net: "unix", addr = &net.TCPAddr{IP: address.IP(), Port: int(port)}
}, streamSettings.SocketSettings) }
if err != nil { if streamSettings.FinalMask != nil {
return nil, errors.New("failed to listen Unix Domain Socket on ", address).Base(err) listener, err = streamSettings.FinalMask.Listen(ctx, addr)
}
errors.LogInfo(ctx, "listening Unix Domain Socket on ", address)
} else { } else {
listener, err = internet.ListenSystem(ctx, &net.TCPAddr{ listener, err = internet.ListenSystem(ctx, addr, streamSettings.SocketSettings)
IP: address.IP(),
Port: int(port),
}, streamSettings.SocketSettings)
if err != nil {
return nil, errors.New("failed to listen TCP on ", address, ":", port).Base(err)
}
errors.LogInfo(ctx, "listening TCP on ", address, ":", port)
} }
if err != nil {
if streamSettings.TcpmaskManager != nil { return nil, errors.New("failed to listen ", addr.Network(), " on ", address, ":", port).Base(err)
listener, _ = streamSettings.TcpmaskManager.WrapListener(listener)
} }
errors.LogInfo(ctx, "listening ", addr.Network(), " on ", address, ":", port)
if streamSettings.SocketSettings != nil && streamSettings.SocketSettings.AcceptProxyProtocol { if streamSettings.SocketSettings != nil && streamSettings.SocketSettings.AcceptProxyProtocol {
errors.LogWarning(ctx, "accepting PROXY protocol") errors.LogWarning(ctx, "accepting PROXY protocol")
+7 -36
View File
@@ -2,12 +2,9 @@ package udp
import ( import (
"context" "context"
"reflect"
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/net/cnc"
"github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/stat" "github.com/xtls/xray-core/transport/internet/stat"
) )
@@ -15,40 +12,14 @@ import (
func init() { func init() {
common.Must(internet.RegisterTransportDialer(protocolName, common.Must(internet.RegisterTransportDialer(protocolName,
func(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (stat.Connection, error) { func(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (stat.Connection, error) {
var sockopt *internet.SocketConfig if streamSettings != nil && streamSettings.FinalMask != nil {
if streamSettings != nil { return streamSettings.FinalMask.DialUDP(ctx, dest)
sockopt = streamSettings.SocketSettings } else {
} var sockopt *internet.SocketConfig
conn, err := internet.DialSystem(ctx, dest, sockopt) if streamSettings != nil && streamSettings.SocketSettings != nil {
if err != nil { sockopt = streamSettings.SocketSettings
return nil, err
}
if streamSettings != nil && streamSettings.UdpmaskManager != nil {
var pktConn net.PacketConn
var udpAddr *net.UDPAddr
switch c := conn.(type) {
case *internet.PacketConnWrapper:
pktConn = c.PacketConn
udpAddr = c.RemoteAddr().(*net.UDPAddr)
case *cnc.Connection:
pktConn = &internet.FakePacketConn{Conn: c}
udpAddr = &net.UDPAddr{IP: c.RemoteAddr().(*net.TCPAddr).IP, Port: c.RemoteAddr().(*net.TCPAddr).Port}
default:
panic(reflect.TypeOf(c))
}
newConn, err := streamSettings.UdpmaskManager.WrapPacketConnClient(pktConn)
if err != nil {
pktConn.Close()
return nil, errors.New("mask err").Base(err)
}
pktConn = newConn
conn = &internet.PacketConnWrapper{
PacketConn: pktConn,
Dest: udpAddr,
} }
return internet.DialSystem(ctx, dest, sockopt)
} }
return conn, nil
})) }))
} }
+5 -14
View File
@@ -58,24 +58,15 @@ func ListenUDP(ctx context.Context, address net.Address, port net.Port, streamSe
} }
var err error var err error
hub.conn, err = internet.ListenSystemPacket(ctx, &net.UDPAddr{ if streamSettings.FinalMask != nil {
IP: address.IP(), hub.conn, err = streamSettings.FinalMask.ListenPacket(ctx, &net.UDPAddr{IP: address.IP(), Port: int(port)})
Port: int(port), } else {
}, sockopt) hub.conn, err = internet.ListenSystemPacket(ctx, &net.UDPAddr{IP: address.IP(), Port: int(port)}, streamSettings.SocketSettings)
}
if err != nil { if err != nil {
return nil, err return nil, err
} }
raw := hub.conn
if streamSettings.UdpmaskManager != nil {
hub.conn, err = streamSettings.UdpmaskManager.WrapPacketConnServer(raw)
if err != nil {
raw.Close()
return nil, errors.New("mask err").Base(err)
}
}
errors.LogInfo(ctx, "listening UDP on ", address, ":", port) errors.LogInfo(ctx, "listening UDP on ", address, ":", port)
hub.udpConn, _ = hub.conn.(*net.UDPConn) hub.udpConn, _ = hub.conn.(*net.UDPConn)
hub.cache = make(chan *udp.Packet, hub.capacity) hub.cache = make(chan *udp.Packet, hub.capacity)
+16 -24
View File
@@ -48,20 +48,16 @@ func dialWebSocket(ctx context.Context, dest net.Destination, streamSettings *in
dialer := &websocket.Dialer{ dialer := &websocket.Dialer{
NetDial: func(network, addr string) (net.Conn, error) { NetDial: func(network, addr string) (net.Conn, error) {
conn, err := internet.DialSystem(ctx, dest, streamSettings.SocketSettings) var conn net.Conn
var err error
if streamSettings.FinalMask != nil {
conn, err = streamSettings.FinalMask.DialTCP(ctx, dest)
} else {
conn, err = internet.DialSystem(ctx, dest, streamSettings.SocketSettings)
}
if err != nil { if err != nil {
return nil, err return nil, errors.New("failed to dial to dest").Base(err)
} }
if streamSettings.TcpmaskManager != nil {
newConn, err := streamSettings.TcpmaskManager.WrapConnClient(conn)
if err != nil {
conn.Close()
return nil, errors.New("mask err").Base(err)
}
conn = newConn
}
return conn, err return conn, err
}, },
ReadBufferSize: 4 * 1024, ReadBufferSize: 4 * 1024,
@@ -79,19 +75,15 @@ func dialWebSocket(ctx context.Context, dest net.Destination, streamSettings *in
if fingerprint := tls.GetFingerprint(tConfig.Fingerprint); fingerprint != nil { if fingerprint := tls.GetFingerprint(tConfig.Fingerprint); fingerprint != nil {
dialer.NetDialTLSContext = func(_ context.Context, _, addr string) (net.Conn, error) { dialer.NetDialTLSContext = func(_ context.Context, _, addr string) (net.Conn, error) {
// Like the NetDial in the dialer // Like the NetDial in the dialer
pconn, err := internet.DialSystem(ctx, dest, streamSettings.SocketSettings) var pconn net.Conn
if err != nil { var err error
errors.LogErrorInner(ctx, err, "failed to dial to "+addr) if streamSettings.FinalMask != nil {
return nil, err pconn, err = streamSettings.FinalMask.DialTCP(ctx, dest)
} else {
pconn, err = internet.DialSystem(ctx, dest, streamSettings.SocketSettings)
} }
if err != nil {
if streamSettings.TcpmaskManager != nil { return nil, errors.New("failed to dial to dest").Base(err)
newConn, err := streamSettings.TcpmaskManager.WrapConnClient(pconn)
if err != nil {
pconn.Close()
return nil, errors.New("mask err").Base(err)
}
pconn = newConn
} }
// TLS and apply the handshake // TLS and apply the handshake
+11 -19
View File
@@ -97,29 +97,21 @@ func ListenWS(ctx context.Context, address net.Address, port net.Port, streamSet
} }
var listener net.Listener var listener net.Listener
var err error var err error
var addr net.Addr
if port == net.Port(0) { // unix if port == net.Port(0) { // unix
listener, err = internet.ListenSystem(ctx, &net.UnixAddr{ addr = &net.UnixAddr{Name: address.Domain(), Net: "unix"}
Name: address.Domain(),
Net: "unix",
}, streamSettings.SocketSettings)
if err != nil {
return nil, errors.New("failed to listen unix domain socket(for WS) on ", address).Base(err)
}
errors.LogInfo(ctx, "listening unix domain socket(for WS) on ", address)
} else { // tcp } else { // tcp
listener, err = internet.ListenSystem(ctx, &net.TCPAddr{ addr = &net.TCPAddr{IP: address.IP(), Port: int(port)}
IP: address.IP(),
Port: int(port),
}, streamSettings.SocketSettings)
if err != nil {
return nil, errors.New("failed to listen TCP(for WS) on ", address, ":", port).Base(err)
}
errors.LogInfo(ctx, "listening TCP(for WS) on ", address, ":", port)
} }
if streamSettings.FinalMask != nil {
if streamSettings.TcpmaskManager != nil { listener, err = streamSettings.FinalMask.Listen(ctx, addr)
listener, _ = streamSettings.TcpmaskManager.WrapListener(listener) } else {
listener, err = internet.ListenSystem(ctx, addr, streamSettings.SocketSettings)
} }
if err != nil {
return nil, errors.New("failed to listen ", addr.Network(), "(for WS) on ", address, ":", port).Base(err)
}
errors.LogInfo(ctx, "listening ", addr.Network(), "(for WS) on ", address, ":", port)
if streamSettings.SocketSettings != nil && streamSettings.SocketSettings.AcceptProxyProtocol { if streamSettings.SocketSettings != nil && streamSettings.SocketSettings.AcceptProxyProtocol {
errors.LogWarning(ctx, "accepting PROXY protocol") errors.LogWarning(ctx, "accepting PROXY protocol")
+7 -10
View File
@@ -55,17 +55,14 @@ func newServiceClient(streamSettings *internet.MemoryStreamConfig, timeout time.
} }
} }
conn, err := internet.DialSystem(ctx, target, sockopt) var conn net.Conn
if err != nil { if streamSettings.FinalMask != nil {
return nil, host, err conn, err = streamSettings.FinalMask.DialTCP(ctx, target)
} else {
conn, err = internet.DialSystem(ctx, target, sockopt)
} }
if streamSettings != nil && streamSettings.TcpmaskManager != nil { if err != nil {
masked, err := streamSettings.TcpmaskManager.WrapConnClient(conn) return nil, host, errors.New("failed to dial to dest").Base(err)
if err != nil {
conn.Close()
return nil, host, errors.New("mask err").Base(err)
}
conn = masked
} }
return conn, host, nil return conn, host, nil
} }