From 407509c98565d6f653439221143eaf05f4d40a60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Fri, 23 Sep 2022 13:14:31 +0800 Subject: [PATCH] Fix leaks and add test --- common/mux/service.go | 22 ++++++---- go.mod | 2 +- go.sum | 4 +- outbound/hysteria.go | 5 ++- outbound/trojan.go | 4 ++ outbound/vless.go | 8 ++-- outbound/vmess.go | 2 +- outbound/wireguard.go | 9 ++-- test/box_test.go | 13 +++++- test/clash_test.go | 7 ---- test/go.mod | 9 ++-- test/go.sum | 20 +++++---- test/mux_cool_test.go | 61 ++++++++++++++++++++++++++++ test/mux_test.go | 12 ++---- test/vmess_test.go | 2 +- transport/v2rayquic/client.go | 10 ++++- transport/wireguard/client_bind.go | 24 ++++++++++- transport/wireguard/device_stack.go | 6 +-- transport/wireguard/device_system.go | 6 +++ 19 files changed, 167 insertions(+), 59 deletions(-) diff --git a/common/mux/service.go b/common/mux/service.go index de9a498a..3dfae46c 100644 --- a/common/mux/service.go +++ b/common/mux/service.go @@ -14,6 +14,7 @@ import ( M "github.com/sagernet/sing/common/metadata" N "github.com/sagernet/sing/common/network" "github.com/sagernet/sing/common/rw" + "github.com/sagernet/sing/common/task" ) func NewConnection(ctx context.Context, router adapter.Router, errorHandler E.Handler, logger log.ContextLogger, conn net.Conn, metadata adapter.InboundContext) error { @@ -25,14 +26,21 @@ func NewConnection(ctx context.Context, router adapter.Router, errorHandler E.Ha if err != nil { return err } - var stream net.Conn - for { - stream, err = session.Accept() - if err != nil { - return err + var group task.Group + group.Append0(func(ctx context.Context) error { + var stream net.Conn + for { + stream, err = session.Accept() + if err != nil { + return err + } + go newConnection(ctx, router, errorHandler, logger, stream, metadata) } - go newConnection(ctx, router, errorHandler, logger, stream, metadata) - } + }) + group.Cleanup(func() { + session.Close() + }) + return group.Run(ctx) } func newConnection(ctx context.Context, router adapter.Router, errorHandler E.Handler, logger log.ContextLogger, stream net.Conn, metadata adapter.InboundContext) { diff --git a/go.mod b/go.mod index 6d46500c..adddd701 100644 --- a/go.mod +++ b/go.mod @@ -27,7 +27,7 @@ require ( github.com/sagernet/sing-dns v0.0.0-20220915084601-812e0864b45b github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6 github.com/sagernet/sing-tun v0.0.0-20220922083325-80ee99472704 - github.com/sagernet/sing-vmess v0.0.0-20220921140858-b6a1bdee672f + github.com/sagernet/sing-vmess v0.0.0-20220923035311-d70afe4ab2c9 github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195 github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e github.com/spf13/cobra v1.5.0 diff --git a/go.sum b/go.sum index df0edca7..dec353a2 100644 --- a/go.sum +++ b/go.sum @@ -153,8 +153,8 @@ github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6 h1:JJfDe github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6/go.mod h1:EX3RbZvrwAkPI2nuGa78T2iQXmrkT+/VQtskjou42xM= github.com/sagernet/sing-tun v0.0.0-20220922083325-80ee99472704 h1:DOQQXQbB2gq4n2FuMHrL07HRs2naCCsuiu/9l1JFb9A= github.com/sagernet/sing-tun v0.0.0-20220922083325-80ee99472704/go.mod h1:5AhPUv9jWDQ3pv3Mj78SL/1TSjhoaj6WNASxRKLqXqM= -github.com/sagernet/sing-vmess v0.0.0-20220921140858-b6a1bdee672f h1:xyJ3Wbibcug4DxLi/FCHX2Td667SfieyZv645b8+eEE= -github.com/sagernet/sing-vmess v0.0.0-20220921140858-b6a1bdee672f/go.mod h1:bwhAdSNET1X+j9DOXGj9NIQR39xgcWIk1rOQ9lLD+gM= +github.com/sagernet/sing-vmess v0.0.0-20220923035311-d70afe4ab2c9 h1:w7JlEa4xHXuuPTL3Opb+Z5f/l66SYi54rSfobzuxSF8= +github.com/sagernet/sing-vmess v0.0.0-20220923035311-d70afe4ab2c9/go.mod h1:bwhAdSNET1X+j9DOXGj9NIQR39xgcWIk1rOQ9lLD+gM= github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195 h1:5VBIbVw9q7aKbrFdT83mjkyvQ+VaRsQ6yflTepfln38= github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195/go.mod h1:yedWtra8nyGJ+SyI+ziwuaGMzBatbB10P1IOOZbbSK8= github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e h1:7uw2njHFGE+VpWamge6o56j2RWk4omF6uLKKxMmcWvs= diff --git a/outbound/hysteria.go b/outbound/hysteria.go index 529083b2..200820b9 100644 --- a/outbound/hysteria.go +++ b/outbound/hysteria.go @@ -38,6 +38,7 @@ type Hysteria struct { recvBPS uint64 connAccess sync.Mutex conn quic.Connection + rawConn net.Conn udpAccess sync.RWMutex udpSessions map[uint32]chan *hysteria.UDPMessage udpDefragger hysteria.Defragger @@ -149,7 +150,6 @@ func (h *Hysteria) offer(ctx context.Context) (quic.Connection, error) { if err != nil { return nil, err } - h.conn = conn if common.Contains(h.network, N.NetworkUDP) { for _, session := range h.udpSessions { close(session) @@ -201,6 +201,8 @@ func (h *Hysteria) offerNew(ctx context.Context) (quic.Connection, error) { return nil, E.New("remote error: ", serverHello.Message) } quicConn.SetCongestionControl(hysteria.NewBrutalSender(congestion.ByteCount(serverHello.RecvBPS))) + h.conn = quicConn + h.rawConn = udpConn return quicConn, nil } @@ -240,6 +242,7 @@ func (h *Hysteria) Close() error { defer h.udpAccess.Unlock() if h.conn != nil { h.conn.CloseWithError(0, "") + h.rawConn.Close() } for _, session := range h.udpSessions { close(session) diff --git a/outbound/trojan.go b/outbound/trojan.go index 20e64802..4db92f41 100644 --- a/outbound/trojan.go +++ b/outbound/trojan.go @@ -103,6 +103,10 @@ func (h *Trojan) NewPacketConnection(ctx context.Context, conn N.PacketConn, met return NewPacketConnection(ctx, h, conn, metadata) } +func (h *Trojan) Close() error { + return common.Close(h.multiplexDialer, h.transport) +} + type trojanDialer Trojan func (h *trojanDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { diff --git a/outbound/vless.go b/outbound/vless.go index 45df44d0..4805608a 100644 --- a/outbound/vless.go +++ b/outbound/vless.go @@ -74,10 +74,6 @@ func NewVLESS(ctx context.Context, router adapter.Router, logger log.ContextLogg return outbound, nil } -func (h *VLESS) Close() error { - return common.Close(h.transport) -} - func (h *VLESS) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { ctx, metadata := adapter.AppendContext(ctx) metadata.Outbound = h.tag @@ -145,3 +141,7 @@ func (h *VLESS) NewConnection(ctx context.Context, conn net.Conn, metadata adapt func (h *VLESS) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error { return NewPacketConnection(ctx, h, conn, metadata) } + +func (h *VLESS) Close() error { + return common.Close(h.transport) +} diff --git a/outbound/vmess.go b/outbound/vmess.go index 6efa4529..428f9b77 100644 --- a/outbound/vmess.go +++ b/outbound/vmess.go @@ -96,7 +96,7 @@ func NewVMess(ctx context.Context, router adapter.Router, logger log.ContextLogg } func (h *VMess) Close() error { - return common.Close(h.transport) + return common.Close(h.multiplexDialer, h.transport) } func (h *VMess) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { diff --git a/outbound/wireguard.go b/outbound/wireguard.go index ef74f535..0a8d245d 100644 --- a/outbound/wireguard.go +++ b/outbound/wireguard.go @@ -162,9 +162,8 @@ func (w *WireGuard) Start() error { } func (w *WireGuard) Close() error { - return common.Close( - w.tunDevice, - common.PtrOrNil(w.device), - common.PtrOrNil(w.bind), - ) + if w.device != nil { + w.device.Close() + } + return common.Close(w.tunDevice) } diff --git a/test/box_test.go b/test/box_test.go index ca9572cb..d2f20c9a 100644 --- a/test/box_test.go +++ b/test/box_test.go @@ -15,9 +15,14 @@ import ( "github.com/sagernet/sing/protocol/socks" "github.com/stretchr/testify/require" + "go.uber.org/goleak" ) -func startInstance(t *testing.T, options option.Options) { +func TestMain(m *testing.M) { + goleak.VerifyTestMain(m) +} + +func startInstance(t *testing.T, options option.Options) *box.Box { if debug.Enabled { options.Log = &option.LogOptions{ Level: "trace", @@ -27,10 +32,12 @@ func startInstance(t *testing.T, options option.Options) { Level: "warning", } } + // ctx := context.Background() + ctx, cancel := context.WithCancel(context.Background()) var instance *box.Box var err error for retry := 0; retry < 3; retry++ { - instance, err = box.New(context.Background(), options) + instance, err = box.New(ctx, options) require.NoError(t, err) err = instance.Start() if err != nil { @@ -42,7 +49,9 @@ func startInstance(t *testing.T, options option.Options) { require.NoError(t, err) t.Cleanup(func() { instance.Close() + cancel() }) + return instance } func testSuit(t *testing.T, clientPort uint16, testPort uint16) { diff --git a/test/clash_test.go b/test/clash_test.go index e6d50c6c..0c40d1be 100644 --- a/test/clash_test.go +++ b/test/clash_test.go @@ -7,7 +7,6 @@ import ( "errors" "io" "net" - "net/http" _ "net/http/pprof" "net/netip" "sync" @@ -101,12 +100,6 @@ func init() { io.Copy(io.Discard, imageStream) } - go func() { - err = http.ListenAndServe("0.0.0.0:8965", nil) - if err != nil { - log.Debug(err) - } - }() } func newPingPongPair() (chan []byte, chan []byte, func(t *testing.T) error) { diff --git a/test/go.mod b/test/go.mod index a80b9c69..8dacd8f9 100644 --- a/test/go.mod +++ b/test/go.mod @@ -10,10 +10,11 @@ require ( github.com/docker/docker v20.10.18+incompatible github.com/docker/go-connections v0.4.0 github.com/gofrs/uuid v4.3.0+incompatible - github.com/sagernet/sing v0.0.0-20220916071326-834794b006ea + github.com/sagernet/sing v0.0.0-20220921101604-86d7d510231f github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6 github.com/spyzhov/ajson v0.7.1 github.com/stretchr/testify v1.8.0 + go.uber.org/goleak v1.2.0 golang.org/x/net v0.0.0-20220909164309-bea034e7d591 ) @@ -67,8 +68,8 @@ require ( github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 // indirect github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb // indirect github.com/sagernet/sing-dns v0.0.0-20220915084601-812e0864b45b // indirect - github.com/sagernet/sing-tun v0.0.0-20220916073459-0032242c9617 // indirect - github.com/sagernet/sing-vmess v0.0.0-20220917033734-9b634758039d // indirect + github.com/sagernet/sing-tun v0.0.0-20220922083325-80ee99472704 // indirect + github.com/sagernet/sing-vmess v0.0.0-20220923035311-d70afe4ab2c9 // indirect github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195 // indirect github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e // indirect github.com/sirupsen/logrus v1.9.0 // indirect @@ -78,7 +79,7 @@ require ( go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.22.0 // indirect go4.org/netipx v0.0.0-20220812043211-3cc044ffd68d // indirect - golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 // indirect + golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0 // indirect golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect golang.org/x/sys v0.0.0-20220913120320-3275c407cedc // indirect diff --git a/test/go.sum b/test/go.sum index 81d234b3..9dc261b7 100644 --- a/test/go.sum +++ b/test/go.sum @@ -165,16 +165,16 @@ github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb h1:wc0yQ+SBn4TaTY github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb/go.mod h1:MIccjRKnPTjWwAOpl+AUGWOkzyTd9tERytudxu+1ra4= github.com/sagernet/sing v0.0.0-20220812082120-05f9836bff8f/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= -github.com/sagernet/sing v0.0.0-20220916071326-834794b006ea h1:ZAWvZdeByPBBz3Vs+w3Erbh+DDo7D4biokoPhXl0nNU= -github.com/sagernet/sing v0.0.0-20220916071326-834794b006ea/go.mod h1:x3NHUeJBQwV75L51zwmLKQdLtRvR+M4PmXkfQtU1vIY= +github.com/sagernet/sing v0.0.0-20220921101604-86d7d510231f h1:GX416thAwyc0vHBOal/qplvdhFgYO2dHD5GqADCJ0Ig= +github.com/sagernet/sing v0.0.0-20220921101604-86d7d510231f/go.mod h1:x3NHUeJBQwV75L51zwmLKQdLtRvR+M4PmXkfQtU1vIY= github.com/sagernet/sing-dns v0.0.0-20220915084601-812e0864b45b h1:cXCMNJ9heZ+c6l+qUcku60x9KyXo4SOAaJfg/6spOmU= github.com/sagernet/sing-dns v0.0.0-20220915084601-812e0864b45b/go.mod h1:SrvWLfOSlnFmH32CWXicfilAGgIXR0VjrH6yRbuXYww= github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6 h1:JJfDeYYhWunvtxsU/mOVNTmFQmnzGx9dY034qG6G3g4= github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6/go.mod h1:EX3RbZvrwAkPI2nuGa78T2iQXmrkT+/VQtskjou42xM= -github.com/sagernet/sing-tun v0.0.0-20220916073459-0032242c9617 h1:fNTNmylhB/UjoBLusmrFu2B1fat4OCkDkQXTgrE7ZsE= -github.com/sagernet/sing-tun v0.0.0-20220916073459-0032242c9617/go.mod h1:5AhPUv9jWDQ3pv3Mj78SL/1TSjhoaj6WNASxRKLqXqM= -github.com/sagernet/sing-vmess v0.0.0-20220917033734-9b634758039d h1:/GNWxSrQj4chFYk2jahIXNPdvUa9DW8IdgyqYFbq9oQ= -github.com/sagernet/sing-vmess v0.0.0-20220917033734-9b634758039d/go.mod h1:u66Vv7NHXJWfeAmhh7JuJp/cwxmuQlM56QoZ7B7Mmd0= +github.com/sagernet/sing-tun v0.0.0-20220922083325-80ee99472704 h1:DOQQXQbB2gq4n2FuMHrL07HRs2naCCsuiu/9l1JFb9A= +github.com/sagernet/sing-tun v0.0.0-20220922083325-80ee99472704/go.mod h1:5AhPUv9jWDQ3pv3Mj78SL/1TSjhoaj6WNASxRKLqXqM= +github.com/sagernet/sing-vmess v0.0.0-20220923035311-d70afe4ab2c9 h1:w7JlEa4xHXuuPTL3Opb+Z5f/l66SYi54rSfobzuxSF8= +github.com/sagernet/sing-vmess v0.0.0-20220923035311-d70afe4ab2c9/go.mod h1:bwhAdSNET1X+j9DOXGj9NIQR39xgcWIk1rOQ9lLD+gM= github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195 h1:5VBIbVw9q7aKbrFdT83mjkyvQ+VaRsQ6yflTepfln38= github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195/go.mod h1:yedWtra8nyGJ+SyI+ziwuaGMzBatbB10P1IOOZbbSK8= github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e h1:7uw2njHFGE+VpWamge6o56j2RWk4omF6uLKKxMmcWvs= @@ -205,8 +205,9 @@ go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqe go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= +go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo= go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= @@ -220,8 +221,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM= -golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0 h1:a5Yg6ylndHHYJqIPrdq0AhvR6KTvDTAvgBtaidhEevY= +golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA= golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA= @@ -229,6 +230,7 @@ golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTk golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= diff --git a/test/mux_cool_test.go b/test/mux_cool_test.go index 2c20a105..edf74832 100644 --- a/test/mux_cool_test.go +++ b/test/mux_cool_test.go @@ -107,3 +107,64 @@ func TestMuxCoolClient(t *testing.T) { }) testSuit(t, clientPort, testPort) } + +func TestMuxCoolSelf(t *testing.T) { + user := newUUID() + startInstance(t, option.Options{ + Inbounds: []option.Inbound{ + { + Type: C.TypeMixed, + Tag: "mixed-in", + MixedOptions: option.HTTPMixedInboundOptions{ + ListenOptions: option.ListenOptions{ + Listen: option.ListenAddress(netip.IPv4Unspecified()), + ListenPort: clientPort, + }, + }, + }, + { + Type: C.TypeVMess, + VMessOptions: option.VMessInboundOptions{ + ListenOptions: option.ListenOptions{ + Listen: option.ListenAddress(netip.IPv4Unspecified()), + ListenPort: serverPort, + }, + Users: []option.VMessUser{ + { + Name: "sekai", + UUID: user.String(), + }, + }, + }, + }, + }, + Outbounds: []option.Outbound{ + { + Type: C.TypeDirect, + }, + { + Type: C.TypeVMess, + Tag: "vmess-out", + VMessOptions: option.VMessOutboundOptions{ + ServerOptions: option.ServerOptions{ + Server: "127.0.0.1", + ServerPort: serverPort, + }, + UUID: user.String(), + PacketEncoding: "xudp", + }, + }, + }, + Route: &option.RouteOptions{ + Rules: []option.Rule{ + { + DefaultOptions: option.DefaultRule{ + Inbound: []string{"mixed-in"}, + Outbound: "vmess-out", + }, + }, + }, + }, + }) + testSuit(t, clientPort, testPort) +} diff --git a/test/mux_test.go b/test/mux_test.go index 36caace1..95d01ecc 100644 --- a/test/mux_test.go +++ b/test/mux_test.go @@ -17,6 +17,10 @@ var muxProtocols = []mux.Protocol{ mux.ProtocolSMux, } +func TestVMessSMux(t *testing.T) { + testVMessMux(t, mux.ProtocolSMux.String()) +} + func TestShadowsocksMux(t *testing.T) { for _, protocol := range muxProtocols { t.Run(protocol.String(), func(t *testing.T) { @@ -25,14 +29,6 @@ func TestShadowsocksMux(t *testing.T) { } } -func TestVMessMux(t *testing.T) { - for _, protocol := range muxProtocols { - t.Run(protocol.String(), func(t *testing.T) { - testVMessMux(t, protocol.String()) - }) - } -} - func testShadowsocksMux(t *testing.T, protocol string) { method := shadowaead_2022.List[0] password := mkBase64(t, 16) diff --git a/test/vmess_test.go b/test/vmess_test.go index e4cc2097..dd783f84 100644 --- a/test/vmess_test.go +++ b/test/vmess_test.go @@ -18,7 +18,7 @@ func newUUID() uuid.UUID { return user } -func _TestVMessAuto(t *testing.T) { +func TestVMessAuto(t *testing.T) { security := "auto" t.Run("self", func(t *testing.T) { testVMessSelf(t, security, 0, false, false, false) diff --git a/transport/v2rayquic/client.go b/transport/v2rayquic/client.go index 7dfb6ee0..8809ce72 100644 --- a/transport/v2rayquic/client.go +++ b/transport/v2rayquic/client.go @@ -25,8 +25,9 @@ type Client struct { serverAddr M.Socksaddr tlsConfig *tls.STDConfig quicConfig *quic.Config - conn quic.Connection connAccess sync.Mutex + conn quic.Connection + rawConn net.Conn } func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, options option.V2RayQUICOptions, tlsConfig tls.Config) (adapter.V2RayClientTransport, error) { @@ -64,7 +65,6 @@ func (c *Client) offer() (quic.Connection, error) { if err != nil { return nil, err } - c.conn = conn return conn, nil } @@ -80,6 +80,8 @@ func (c *Client) offerNew() (quic.Connection, error) { packetConn.Close() return nil, err } + c.conn = quicConn + c.rawConn = udpConn return quicConn, nil } @@ -94,3 +96,7 @@ func (c *Client) DialContext(ctx context.Context) (net.Conn, error) { } return &hysteria.StreamWrapper{Conn: conn, Stream: stream}, nil } + +func (c *Client) Close() error { + return common.Close(c.conn, c.rawConn) +} diff --git a/transport/wireguard/client_bind.go b/transport/wireguard/client_bind.go index 1c806385..270e09fd 100644 --- a/transport/wireguard/client_bind.go +++ b/transport/wireguard/client_bind.go @@ -20,6 +20,7 @@ type ClientBind struct { peerAddr M.Socksaddr connAccess sync.Mutex conn *wireConn + done chan struct{} } func NewClientBind(ctx context.Context, dialer N.Dialer, peerAddr M.Socksaddr) *ClientBind { @@ -63,6 +64,12 @@ func (c *ClientBind) connect() (*wireConn, error) { } func (c *ClientBind) Open(port uint16) (fns []conn.ReceiveFunc, actualPort uint16, err error) { + select { + case <-c.done: + err = net.ErrClosed + return + default: + } return []conn.ReceiveFunc{c.receive}, 0, nil } @@ -75,7 +82,12 @@ func (c *ClientBind) receive(b []byte) (n int, ep conn.Endpoint, err error) { n, err = udpConn.Read(b) if err != nil { udpConn.Close() - err = &wireError{err} + select { + case <-c.done: + default: + err = &wireError{err} + } + return } ep = Endpoint(c.peerAddr) return @@ -85,6 +97,16 @@ func (c *ClientBind) Close() error { c.connAccess.Lock() defer c.connAccess.Unlock() common.Close(common.PtrOrNil(c.conn)) + if c.done == nil { + c.done = make(chan struct{}) + return nil + } + select { + case <-c.done: + return net.ErrClosed + default: + close(c.done) + } return nil } diff --git a/transport/wireguard/device_stack.go b/transport/wireguard/device_stack.go index e7b54e6a..117ed4c2 100644 --- a/transport/wireguard/device_stack.go +++ b/transport/wireguard/device_stack.go @@ -35,7 +35,6 @@ type StackDevice struct { events chan tun.Event outbound chan *stack.PacketBuffer dispatcher stack.NetworkDispatcher - done chan struct{} addr4 tcpip.Address addr6 tcpip.Address } @@ -51,7 +50,6 @@ func NewStackDevice(localAddresses []netip.Prefix, mtu uint32) (*StackDevice, er mtu: mtu, events: make(chan tun.Event, 1), outbound: make(chan *stack.PacketBuffer, 256), - done: make(chan struct{}), } err := ipStack.CreateNIC(defaultNIC, (*wireEndpoint)(tunDevice)) if err != nil { @@ -193,11 +191,11 @@ func (w *StackDevice) Events() chan tun.Event { func (w *StackDevice) Close() error { select { - case <-w.done: + case <-w.events: return os.ErrClosed default: + close(w.events) } - close(w.done) w.stack.Close() for _, endpoint := range w.stack.CleanupEndpoints() { endpoint.Abort() diff --git a/transport/wireguard/device_system.go b/transport/wireguard/device_system.go index 9cd26eac..1159f568 100644 --- a/transport/wireguard/device_system.go +++ b/transport/wireguard/device_system.go @@ -106,5 +106,11 @@ func (w *SystemDevice) Events() chan wgTun.Event { } func (w *SystemDevice) Close() error { + select { + case <-w.events: + return os.ErrClosed + default: + close(w.events) + } return w.device.Close() }