diff --git a/adapter/outbound/base.go b/adapter/outbound/base.go index 76f9bd39..5b6ef705 100644 --- a/adapter/outbound/base.go +++ b/adapter/outbound/base.go @@ -3,7 +3,6 @@ package outbound import ( "context" "encoding/json" - "errors" "net" "strings" @@ -47,31 +46,31 @@ func (b *Base) Type() C.AdapterType { // StreamConn implements C.ProxyAdapter func (b *Base) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { - return c, errors.New("no support") + return c, C.ErrNotSupport } func (b *Base) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) { - return nil, errors.New("no support") + return nil, C.ErrNotSupport } // DialContextWithDialer implements C.ProxyAdapter func (b *Base) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.Conn, err error) { - return nil, errors.New("no support") + return nil, C.ErrNotSupport } // ListenPacketContext implements C.ProxyAdapter func (b *Base) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) { - return nil, errors.New("no support") + return nil, C.ErrNotSupport } // ListenPacketWithDialer implements C.ProxyAdapter func (b *Base) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.PacketConn, err error) { - return nil, errors.New("no support") + return nil, C.ErrNotSupport } // SupportWithDialer implements C.ProxyAdapter -func (b *Base) SupportWithDialer() bool { - return false +func (b *Base) SupportWithDialer() C.NetWork { + return C.InvalidNet } // SupportUOT implements C.ProxyAdapter diff --git a/adapter/outbound/http.go b/adapter/outbound/http.go index 645177a4..2d5fd899 100644 --- a/adapter/outbound/http.go +++ b/adapter/outbound/http.go @@ -92,8 +92,8 @@ func (h *Http) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metad } // SupportWithDialer implements C.ProxyAdapter -func (h *Http) SupportWithDialer() bool { - return true +func (h *Http) SupportWithDialer() C.NetWork { + return C.TCP } func (h *Http) shakeHand(metadata *C.Metadata, rw io.ReadWriter) error { diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go index ac4cc31e..14bd96b0 100644 --- a/adapter/outbound/shadowsocks.go +++ b/adapter/outbound/shadowsocks.go @@ -205,8 +205,8 @@ func (ss *ShadowSocks) ListenPacketWithDialer(ctx context.Context, dialer C.Dial } // SupportWithDialer implements C.ProxyAdapter -func (ss *ShadowSocks) SupportWithDialer() bool { - return true +func (ss *ShadowSocks) SupportWithDialer() C.NetWork { + return C.ALLNet } // ListenPacketOnStreamConn implements C.ProxyAdapter @@ -219,7 +219,7 @@ func (ss *ShadowSocks) ListenPacketOnStreamConn(c net.Conn, metadata *C.Metadata return newPacketConn(uot.NewLazyConn(c, uot.Request{Destination: destination}), ss), nil } } - return nil, errors.New("no support") + return nil, C.ErrNotSupport } // SupportUOT implements C.ProxyAdapter diff --git a/adapter/outbound/shadowsocksr.go b/adapter/outbound/shadowsocksr.go index e96116d4..2b94ab0c 100644 --- a/adapter/outbound/shadowsocksr.go +++ b/adapter/outbound/shadowsocksr.go @@ -116,8 +116,8 @@ func (ssr *ShadowSocksR) ListenPacketWithDialer(ctx context.Context, dialer C.Di } // SupportWithDialer implements C.ProxyAdapter -func (ssr *ShadowSocksR) SupportWithDialer() bool { - return true +func (ssr *ShadowSocksR) SupportWithDialer() C.NetWork { + return C.ALLNet } func NewShadowSocksR(option ShadowSocksROption) (*ShadowSocksR, error) { diff --git a/adapter/outbound/snell.go b/adapter/outbound/snell.go index d6d0436d..1ec0a430 100644 --- a/adapter/outbound/snell.go +++ b/adapter/outbound/snell.go @@ -136,8 +136,8 @@ func (s *Snell) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, met } // SupportWithDialer implements C.ProxyAdapter -func (s *Snell) SupportWithDialer() bool { - return true +func (s *Snell) SupportWithDialer() C.NetWork { + return C.ALLNet } // SupportUOT implements C.ProxyAdapter diff --git a/adapter/outbound/socks5.go b/adapter/outbound/socks5.go index b328b634..26f5733b 100644 --- a/adapter/outbound/socks5.go +++ b/adapter/outbound/socks5.go @@ -97,8 +97,8 @@ func (ss *Socks5) DialContextWithDialer(ctx context.Context, dialer C.Dialer, me } // SupportWithDialer implements C.ProxyAdapter -func (ss *Socks5) SupportWithDialer() bool { - return true +func (ss *Socks5) SupportWithDialer() C.NetWork { + return C.TCP } // ListenPacketContext implements C.ProxyAdapter diff --git a/adapter/outbound/trojan.go b/adapter/outbound/trojan.go index 013164c4..b9bbc33f 100644 --- a/adapter/outbound/trojan.go +++ b/adapter/outbound/trojan.go @@ -214,8 +214,8 @@ func (t *Trojan) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, me } // SupportWithDialer implements C.ProxyAdapter -func (t *Trojan) SupportWithDialer() bool { - return true +func (t *Trojan) SupportWithDialer() C.NetWork { + return C.ALLNet } // ListenPacketOnStreamConn implements C.ProxyAdapter diff --git a/adapter/outbound/tuic.go b/adapter/outbound/tuic.go index 6640c46a..f2452ae2 100644 --- a/adapter/outbound/tuic.go +++ b/adapter/outbound/tuic.go @@ -86,8 +86,8 @@ func (t *Tuic) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, meta } // SupportWithDialer implements C.ProxyAdapter -func (t *Tuic) SupportWithDialer() bool { - return true +func (t *Tuic) SupportWithDialer() C.NetWork { + return C.ALLNet } func (t *Tuic) dial(ctx context.Context, opts ...dialer.Option) (pc net.PacketConn, addr net.Addr, err error) { diff --git a/adapter/outbound/vless.go b/adapter/outbound/vless.go index b5ae66e1..b7a22245 100644 --- a/adapter/outbound/vless.go +++ b/adapter/outbound/vless.go @@ -345,8 +345,8 @@ func (v *Vless) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, met } // SupportWithDialer implements C.ProxyAdapter -func (v *Vless) SupportWithDialer() bool { - return true +func (v *Vless) SupportWithDialer() C.NetWork { + return C.ALLNet } // ListenPacketOnStreamConn implements C.ProxyAdapter diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go index 048b381c..c5212eef 100644 --- a/adapter/outbound/vmess.go +++ b/adapter/outbound/vmess.go @@ -368,8 +368,8 @@ func (v *Vmess) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, met } // SupportWithDialer implements C.ProxyAdapter -func (v *Vmess) SupportWithDialer() bool { - return true +func (v *Vmess) SupportWithDialer() C.NetWork { + return C.ALLNet } // ListenPacketOnStreamConn implements C.ProxyAdapter diff --git a/adapter/outboundgroup/relay.go b/adapter/outboundgroup/relay.go index 74c2f73b..c3fe8bd6 100644 --- a/adapter/outboundgroup/relay.go +++ b/adapter/outboundgroup/relay.go @@ -89,7 +89,10 @@ func (r *Relay) SupportUDP() bool { if proxy.SupportUOT() { return true } - if !proxy.SupportWithDialer() { + switch proxy.SupportWithDialer() { + case C.ALLNet: + case C.UDP: + default: // C.TCP and C.NONet return false } } diff --git a/component/dialer/dialer.go b/component/dialer/dialer.go index d70e9173..f6dfaf86 100644 --- a/component/dialer/dialer.go +++ b/component/dialer/dialer.go @@ -321,15 +321,15 @@ func sortationAddr(ips []netip.Addr) (ipv4s, ipv6s []netip.Addr) { } type Dialer struct { - opt option + Opt option } func (d Dialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) { - return DialContext(ctx, network, address, WithOption(d.opt)) + return DialContext(ctx, network, address, WithOption(d.Opt)) } func (d Dialer) ListenPacket(ctx context.Context, network, address string, rAddrPort netip.AddrPort) (net.PacketConn, error) { - opt := WithOption(d.opt) + opt := WithOption(d.Opt) if rAddrPort.Addr().Unmap().IsLoopback() { // avoid "The requested address is not valid in its context." opt = WithInterface("") @@ -339,5 +339,5 @@ func (d Dialer) ListenPacket(ctx context.Context, network, address string, rAddr func NewDialer(options ...Option) Dialer { opt := applyOptions(options...) - return Dialer{opt: *opt} + return Dialer{Opt: *opt} } diff --git a/component/proxydialer/proxydialer.go b/component/proxydialer/proxydialer.go index 83428d59..fad3835d 100644 --- a/component/proxydialer/proxydialer.go +++ b/component/proxydialer/proxydialer.go @@ -8,16 +8,17 @@ import ( "strings" N "github.com/Dreamacro/clash/common/net" + "github.com/Dreamacro/clash/component/dialer" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/tunnel" ) type proxyDialer struct { - proxy C.Proxy + proxy C.ProxyAdapter dialer C.Dialer } -func New(proxy C.Proxy, dialer C.Dialer) C.Dialer { +func New(proxy C.ProxyAdapter, dialer C.Dialer) C.Dialer { return proxyDialer{proxy: proxy, dialer: dialer} } @@ -35,14 +36,23 @@ func (p proxyDialer) DialContext(ctx context.Context, network, address string) ( return nil, err } if strings.Contains(network, "udp") { // using in wireguard outbound - currentMeta.NetWork = C.UDP - pc, err := p.proxy.ListenPacketWithDialer(ctx, p.dialer, currentMeta) + pc, err := p.listenPacket(ctx, currentMeta) if err != nil { return nil, err } return N.NewBindPacketConn(pc, currentMeta.UDPAddr()), nil } - return p.proxy.DialContextWithDialer(ctx, p.dialer, currentMeta) + switch p.proxy.SupportWithDialer() { + case C.ALLNet: + fallthrough + case C.TCP: + return p.proxy.DialContextWithDialer(ctx, p.dialer, currentMeta) + default: // fallback to old function + if d, ok := p.dialer.(dialer.Dialer); ok { // fallback to old function + return p.proxy.DialContext(ctx, currentMeta, dialer.WithOption(d.Opt)) + } + return nil, C.ErrNotSupport + } } func (p proxyDialer) ListenPacket(ctx context.Context, network, address string, rAddrPort netip.AddrPort) (net.PacketConn, error) { @@ -50,8 +60,22 @@ func (p proxyDialer) ListenPacket(ctx context.Context, network, address string, if err != nil { return nil, err } + return p.listenPacket(ctx, currentMeta) +} + +func (p proxyDialer) listenPacket(ctx context.Context, currentMeta *C.Metadata) (net.PacketConn, error) { currentMeta.NetWork = C.UDP - return p.proxy.ListenPacketWithDialer(ctx, p.dialer, currentMeta) + switch p.proxy.SupportWithDialer() { + case C.ALLNet: + fallthrough + case C.UDP: + return p.proxy.ListenPacketWithDialer(ctx, p.dialer, currentMeta) + default: // fallback to old function + if d, ok := p.dialer.(dialer.Dialer); ok { // fallback to old function + return p.proxy.ListenPacketContext(ctx, currentMeta, dialer.WithOption(d.Opt)) + } + return nil, C.ErrNotSupport + } } func addrToMetadata(rawAddress string) (addr *C.Metadata, err error) { diff --git a/constant/adapters.go b/constant/adapters.go index ce9f9911..3b401734 100644 --- a/constant/adapters.go +++ b/constant/adapters.go @@ -2,6 +2,7 @@ package constant import ( "context" + "errors" "fmt" "net" "net/netip" @@ -44,6 +45,8 @@ const ( DefaultTLSTimeout = DefaultTCPTimeout ) +var ErrNotSupport = errors.New("no support") + type Connection interface { Chains() Chain AppendToChains(adapter ProxyAdapter) @@ -117,7 +120,7 @@ type ProxyAdapter interface { // SupportUOT return UDP over TCP support SupportUOT() bool - SupportWithDialer() bool + SupportWithDialer() NetWork DialContextWithDialer(ctx context.Context, dialer Dialer, metadata *Metadata) (Conn, error) ListenPacketWithDialer(ctx context.Context, dialer Dialer, metadata *Metadata) (PacketConn, error) diff --git a/constant/metadata.go b/constant/metadata.go index 599a6055..4ff20305 100644 --- a/constant/metadata.go +++ b/constant/metadata.go @@ -15,7 +15,10 @@ const ( TCP NetWork = iota UDP ALLNet + InvalidNet = 0xff +) +const ( HTTP Type = iota HTTPS SOCKS4 @@ -33,12 +36,16 @@ const ( type NetWork int func (n NetWork) String() string { - if n == TCP { + switch n { + case TCP: return "tcp" - } else if n == UDP { + case UDP: return "udp" + case ALLNet: + return "all" + default: + return "invalid" } - return "all" } func (n NetWork) MarshalJSON() ([]byte, error) {