diff --git a/adapter/outbound.go b/adapter/outbound.go index 91fb9c65..031677e2 100644 --- a/adapter/outbound.go +++ b/adapter/outbound.go @@ -27,6 +27,11 @@ type OutboundWithPreferredRoutes interface { PreferredAddress(address netip.Addr) bool } +type OutboundWithMultiplex interface { + Outbound + MultiplexEnabled() bool +} + type DirectRouteOutbound interface { Outbound NewDirectRouteConnection(metadata InboundContext, routeContext tun.DirectRouteContext, timeout time.Duration) (tun.DirectRouteDestination, error) diff --git a/common/urltest/urltest.go b/common/urltest/urltest.go index 29d790e4..30ead2e2 100644 --- a/common/urltest/urltest.go +++ b/common/urltest/urltest.go @@ -11,6 +11,7 @@ import ( "github.com/sagernet/sing-box/adapter" C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing/common" M "github.com/sagernet/sing/common/metadata" N "github.com/sagernet/sing/common/network" "github.com/sagernet/sing/common/ntp" @@ -72,7 +73,18 @@ func (s *HistoryStorage) Close() error { return nil } -func URLTest(ctx context.Context, link string, detour N.Dialer) (t uint16, err error) { +func URLTest(ctx context.Context, link string, detour N.Dialer) (uint16, error) { + multiplexOutbound, isMultiplexOutbound := common.Cast[adapter.OutboundWithMultiplex](detour) + if isMultiplexOutbound && multiplexOutbound.MultiplexEnabled() { + _, err := urlTest(ctx, link, detour) + if err != nil { + return 0, err + } + } + return urlTest(ctx, link, detour) +} + +func urlTest(ctx context.Context, link string, detour N.Dialer) (t uint16, err error) { if link == "" { link = "https://www.gstatic.com/generate_204" } diff --git a/protocol/shadowsocks/outbound.go b/protocol/shadowsocks/outbound.go index 9b9d9252..ebf21f6a 100644 --- a/protocol/shadowsocks/outbound.go +++ b/protocol/shadowsocks/outbound.go @@ -26,6 +26,8 @@ func RegisterOutbound(registry *outbound.Registry) { outbound.Register[option.ShadowsocksOutboundOptions](registry, C.TypeShadowsocks, NewOutbound) } +var _ adapter.OutboundWithMultiplex = (*Outbound)(nil) + type Outbound struct { outbound.Adapter logger logger.ContextLogger @@ -124,6 +126,10 @@ func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (n } } +func (h *Outbound) MultiplexEnabled() bool { + return h.multiplexDialer != nil +} + func (h *Outbound) InterfaceUpdated() { if h.multiplexDialer != nil { h.multiplexDialer.Reset() diff --git a/protocol/trojan/outbound.go b/protocol/trojan/outbound.go index 26c7c81f..c25af9bb 100644 --- a/protocol/trojan/outbound.go +++ b/protocol/trojan/outbound.go @@ -26,6 +26,8 @@ func RegisterOutbound(registry *outbound.Registry) { outbound.Register[option.TrojanOutboundOptions](registry, C.TypeTrojan, NewOutbound) } +var _ adapter.OutboundWithMultiplex = (*Outbound)(nil) + type Outbound struct { outbound.Adapter logger logger.ContextLogger @@ -107,6 +109,10 @@ func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (n } } +func (h *Outbound) MultiplexEnabled() bool { + return h.multiplexDialer != nil +} + func (h *Outbound) InterfaceUpdated() { if h.transport != nil { h.transport.Close() diff --git a/protocol/vless/outbound.go b/protocol/vless/outbound.go index 36c450a7..007c78f3 100644 --- a/protocol/vless/outbound.go +++ b/protocol/vless/outbound.go @@ -27,6 +27,8 @@ func RegisterOutbound(registry *outbound.Registry) { outbound.Register[option.VLESSOutboundOptions](registry, C.TypeVLESS, NewOutbound) } +var _ adapter.OutboundWithMultiplex = (*Outbound)(nil) + type Outbound struct { outbound.Adapter logger logger.ContextLogger @@ -127,6 +129,10 @@ func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (n } } +func (h *Outbound) MultiplexEnabled() bool { + return h.multiplexDialer != nil +} + func (h *Outbound) InterfaceUpdated() { if h.transport != nil { h.transport.Close() diff --git a/protocol/vmess/outbound.go b/protocol/vmess/outbound.go index 703f06b1..1baf3b35 100644 --- a/protocol/vmess/outbound.go +++ b/protocol/vmess/outbound.go @@ -27,6 +27,8 @@ func RegisterOutbound(registry *outbound.Registry) { outbound.Register[option.VMessOutboundOptions](registry, C.TypeVMess, NewOutbound) } +var _ adapter.OutboundWithMultiplex = (*Outbound)(nil) + type Outbound struct { outbound.Adapter logger logger.ContextLogger @@ -105,6 +107,10 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL return outbound, nil } +func (h *Outbound) MultiplexEnabled() bool { + return h.multiplexDialer != nil +} + func (h *Outbound) InterfaceUpdated() { if h.transport != nil { h.transport.Close()