From ec0136af1b5b9a925b6d6c328af55601698ef1fc Mon Sep 17 00:00:00 2001 From: gVisor bot Date: Mon, 19 Dec 2022 21:34:07 +0800 Subject: [PATCH] chore: rebuild relay --- adapter/outbound/base.go | 18 ++-- adapter/outbound/http.go | 12 ++- adapter/outbound/shadowsocks.go | 31 +++--- adapter/outbound/shadowsocksr.go | 30 +++--- adapter/outbound/snell.go | 21 ++-- adapter/outbound/socks5.go | 12 ++- adapter/outbound/trojan.go | 44 +++++--- adapter/outbound/vless.go | 49 +++++++-- adapter/outbound/vmess.go | 56 +++++++--- adapter/outboundgroup/relay.go | 174 +++++++++---------------------- adapter/outboundgroup/util.go | 2 +- common/net/bind.go | 36 +++++++ component/dialer/dialer.go | 12 +++ constant/adapters.go | 13 ++- dns/util.go | 32 +----- 15 files changed, 296 insertions(+), 246 deletions(-) create mode 100644 common/net/bind.go diff --git a/adapter/outbound/base.go b/adapter/outbound/base.go index d328d5c6..d7ffec5a 100644 --- a/adapter/outbound/base.go +++ b/adapter/outbound/base.go @@ -57,26 +57,26 @@ func (b *Base) DialContext(ctx context.Context, metadata *C.Metadata, opts ...di return nil, errors.New("no support") } +// 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") +} + // 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") } -// ListenPacketOnPacketConn implements C.ProxyAdapter -func (b *Base) ListenPacketOnPacketConn(ctx context.Context, c C.PacketConn, metadata *C.Metadata) (C.PacketConn, error) { +// 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") } -// SupportLPPC implements C.ProxyAdapter -func (b *Base) SupportLPPC() bool { +// SupportWithDialer implements C.ProxyAdapter +func (b *Base) SupportWithDialer() bool { return false } -// ListenPacketOnStreamConn implements C.ProxyAdapter -func (b *Base) ListenPacketOnStreamConn(c net.Conn, metadata *C.Metadata) (_ C.PacketConn, err error) { - return nil, errors.New("no support") -} - // SupportUOT implements C.ProxyAdapter func (b *Base) SupportUOT() bool { return false diff --git a/adapter/outbound/http.go b/adapter/outbound/http.go index c5c06208..3e7060e6 100644 --- a/adapter/outbound/http.go +++ b/adapter/outbound/http.go @@ -61,7 +61,12 @@ func (h *Http) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { // DialContext implements C.ProxyAdapter func (h *Http) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.Conn, err error) { - c, err := dialer.DialContext(ctx, "tcp", h.addr, h.Base.DialOptions(opts...)...) + return h.DialContextWithDialer(ctx, dialer.Dialer{Options: h.Base.DialOptions(opts...)}, metadata) +} + +// DialContextWithDialer implements C.ProxyAdapter +func (h *Http) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.Conn, err error) { + c, err := dialer.DialContext(ctx, "tcp", h.addr) if err != nil { return nil, fmt.Errorf("%s connect error: %w", h.addr, err) } @@ -79,6 +84,11 @@ func (h *Http) DialContext(ctx context.Context, metadata *C.Metadata, opts ...di return NewConn(c, h), nil } +// SupportWithDialer implements C.ProxyAdapter +func (h *Http) SupportWithDialer() bool { + return true +} + func (h *Http) shakeHand(metadata *C.Metadata, rw io.ReadWriter) error { addr := metadata.RemoteAddress() req := &http.Request{ diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go index 4760e806..46a8b9bf 100644 --- a/adapter/outbound/shadowsocks.go +++ b/adapter/outbound/shadowsocks.go @@ -84,7 +84,12 @@ func (ss *ShadowSocks) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, e // DialContext implements C.ProxyAdapter func (ss *ShadowSocks) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.Conn, err error) { - c, err := dialer.DialContext(ctx, "tcp", ss.addr, ss.Base.DialOptions(opts...)...) + return ss.DialContextWithDialer(ctx, dialer.Dialer{Options: ss.Base.DialOptions(opts...)}, metadata) +} + +// DialContextWithDialer implements C.ProxyAdapter +func (ss *ShadowSocks) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.Conn, err error) { + c, err := dialer.DialContext(ctx, "tcp", ss.addr) if err != nil { return nil, fmt.Errorf("%s connect error: %w", ss.addr, err) } @@ -100,8 +105,13 @@ func (ss *ShadowSocks) DialContext(ctx context.Context, metadata *C.Metadata, op // ListenPacketContext implements C.ProxyAdapter func (ss *ShadowSocks) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) { + return ss.ListenPacketWithDialer(ctx, dialer.Dialer{Options: ss.Base.DialOptions(opts...)}, metadata) +} + +// ListenPacketWithDialer implements C.ProxyAdapter +func (ss *ShadowSocks) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.PacketConn, err error) { if ss.option.UDPOverTCP { - tcpConn, err := ss.DialContext(ctx, metadata, opts...) + tcpConn, err := ss.DialContextWithDialer(ctx, dialer, metadata) if err != nil { return nil, err } @@ -112,7 +122,7 @@ func (ss *ShadowSocks) ListenPacketContext(ctx context.Context, metadata *C.Meta return nil, err } - pc, err := dialer.ListenPacket(ctx, dialer.ParseNetwork("udp", addr.AddrPort().Addr()), "", ss.Base.DialOptions(opts...)...) + pc, err := dialer.ListenPacket(ctx, "udp", "", addr.AddrPort()) if err != nil { return nil, err } @@ -120,19 +130,8 @@ func (ss *ShadowSocks) ListenPacketContext(ctx context.Context, metadata *C.Meta return newPacketConn(pc, ss), nil } -// ListenPacketOnPacketConn implements C.ProxyAdapter -func (ss *ShadowSocks) ListenPacketOnPacketConn(ctx context.Context, c C.PacketConn, metadata *C.Metadata) (_ C.PacketConn, err error) { - addr, err := resolveUDPAddrWithPrefer(ctx, "udp", ss.addr, ss.prefer) - if err != nil { - return nil, err - } - - pc := ss.method.DialPacketConn(&bufio.BindPacketConn{PacketConn: c, Addr: addr}) - return newPacketConn(pc, ss), nil -} - -// SupportLPPC implements C.ProxyAdapter -func (ss *ShadowSocks) SupportLPPC() bool { +// SupportWithDialer implements C.ProxyAdapter +func (ss *ShadowSocks) SupportWithDialer() bool { return true } diff --git a/adapter/outbound/shadowsocksr.go b/adapter/outbound/shadowsocksr.go index 237b9c03..99b8edc3 100644 --- a/adapter/outbound/shadowsocksr.go +++ b/adapter/outbound/shadowsocksr.go @@ -60,7 +60,12 @@ func (ssr *ShadowSocksR) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, // DialContext implements C.ProxyAdapter func (ssr *ShadowSocksR) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.Conn, err error) { - c, err := dialer.DialContext(ctx, "tcp", ssr.addr, ssr.Base.DialOptions(opts...)...) + return ssr.DialContextWithDialer(ctx, dialer.Dialer{Options: ssr.Base.DialOptions(opts...)}, metadata) +} + +// DialContextWithDialer implements C.ProxyAdapter +func (ssr *ShadowSocksR) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.Conn, err error) { + c, err := dialer.DialContext(ctx, "tcp", ssr.addr) if err != nil { return nil, fmt.Errorf("%s connect error: %w", ssr.addr, err) } @@ -76,12 +81,17 @@ func (ssr *ShadowSocksR) DialContext(ctx context.Context, metadata *C.Metadata, // ListenPacketContext implements C.ProxyAdapter func (ssr *ShadowSocksR) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) { + return ssr.ListenPacketWithDialer(ctx, dialer.Dialer{Options: ssr.Base.DialOptions(opts...)}, metadata) +} + +// ListenPacketWithDialer implements C.ProxyAdapter +func (ssr *ShadowSocksR) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.PacketConn, err error) { addr, err := resolveUDPAddrWithPrefer(ctx, "udp", ssr.addr, ssr.prefer) if err != nil { return nil, err } - pc, err := dialer.ListenPacket(ctx, dialer.ParseNetwork("udp", addr.AddrPort().Addr()), "", ssr.Base.DialOptions(opts...)...) + pc, err := dialer.ListenPacket(ctx, "udp", "", addr.AddrPort()) if err != nil { return nil, err } @@ -91,20 +101,8 @@ func (ssr *ShadowSocksR) ListenPacketContext(ctx context.Context, metadata *C.Me return newPacketConn(&ssPacketConn{PacketConn: pc, rAddr: addr}, ssr), nil } -// ListenPacketOnPacketConn implements C.ProxyAdapter -func (ssr *ShadowSocksR) ListenPacketOnPacketConn(ctx context.Context, c C.PacketConn, metadata *C.Metadata) (_ C.PacketConn, err error) { - addr, err := resolveUDPAddrWithPrefer(ctx, "udp", ssr.addr, ssr.prefer) - if err != nil { - return nil, err - } - - pc := ssr.cipher.PacketConn(c) - pc = ssr.protocol.PacketConn(pc) - return newPacketConn(&ssPacketConn{PacketConn: pc, rAddr: addr}, ssr), nil -} - -// SupportLPPC implements C.ProxyAdapter -func (ssr *ShadowSocksR) SupportLPPC() bool { +// SupportWithDialer implements C.ProxyAdapter +func (ssr *ShadowSocksR) SupportWithDialer() bool { return true } diff --git a/adapter/outbound/snell.go b/adapter/outbound/snell.go index c4fe77ff..bc1fa0c1 100644 --- a/adapter/outbound/snell.go +++ b/adapter/outbound/snell.go @@ -78,7 +78,12 @@ func (s *Snell) DialContext(ctx context.Context, metadata *C.Metadata, opts ...d return NewConn(c, s), err } - c, err := dialer.DialContext(ctx, "tcp", s.addr, s.Base.DialOptions(opts...)...) + return s.DialContextWithDialer(ctx, dialer.Dialer{Options: s.Base.DialOptions(opts...)}, metadata) +} + +// DialContextWithDialer implements C.ProxyAdapter +func (s *Snell) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.Conn, err error) { + c, err := dialer.DialContext(ctx, "tcp", s.addr) if err != nil { return nil, fmt.Errorf("%s connect error: %w", s.addr, err) } @@ -94,7 +99,12 @@ func (s *Snell) DialContext(ctx context.Context, metadata *C.Metadata, opts ...d // ListenPacketContext implements C.ProxyAdapter func (s *Snell) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) { - c, err := dialer.DialContext(ctx, "tcp", s.addr, s.Base.DialOptions(opts...)...) + return s.ListenPacketWithDialer(ctx, dialer.Dialer{Options: s.Base.DialOptions(opts...)}, metadata) +} + +// ListenPacketWithDialer implements C.ProxyAdapter +func (s *Snell) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (C.PacketConn, error) { + c, err := dialer.DialContext(ctx, "tcp", s.addr) if err != nil { return nil, err } @@ -110,10 +120,9 @@ func (s *Snell) ListenPacketContext(ctx context.Context, metadata *C.Metadata, o return newPacketConn(pc, s), nil } -// ListenPacketOnStreamConn implements C.ProxyAdapter -func (s *Snell) ListenPacketOnStreamConn(c net.Conn, metadata *C.Metadata) (_ C.PacketConn, err error) { - pc := snell.PacketConn(c) - return newPacketConn(pc, s), nil +// SupportWithDialer implements C.ProxyAdapter +func (s *Snell) SupportWithDialer() bool { + return true } // SupportUOT implements C.ProxyAdapter diff --git a/adapter/outbound/socks5.go b/adapter/outbound/socks5.go index 62de1621..ccd13da7 100644 --- a/adapter/outbound/socks5.go +++ b/adapter/outbound/socks5.go @@ -65,7 +65,12 @@ func (ss *Socks5) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) // DialContext implements C.ProxyAdapter func (ss *Socks5) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.Conn, err error) { - c, err := dialer.DialContext(ctx, "tcp", ss.addr, ss.Base.DialOptions(opts...)...) + return ss.DialContextWithDialer(ctx, dialer.Dialer{Options: ss.Base.DialOptions(opts...)}, metadata) +} + +// DialContextWithDialer implements C.ProxyAdapter +func (ss *Socks5) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.Conn, err error) { + c, err := dialer.DialContext(ctx, "tcp", ss.addr) if err != nil { return nil, fmt.Errorf("%s connect error: %w", ss.addr, err) } @@ -83,6 +88,11 @@ func (ss *Socks5) DialContext(ctx context.Context, metadata *C.Metadata, opts .. return NewConn(c, ss), nil } +// SupportWithDialer implements C.ProxyAdapter +func (ss *Socks5) SupportWithDialer() bool { + return true +} + // ListenPacketContext implements C.ProxyAdapter func (ss *Socks5) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.PacketConn, err error) { c, err := dialer.DialContext(ctx, "tcp", ss.addr, ss.Base.DialOptions(opts...)...) diff --git a/adapter/outbound/trojan.go b/adapter/outbound/trojan.go index 18d61c4a..9bfb0126 100644 --- a/adapter/outbound/trojan.go +++ b/adapter/outbound/trojan.go @@ -120,8 +120,12 @@ func (t *Trojan) DialContext(ctx context.Context, metadata *C.Metadata, opts ... return NewConn(c, t), nil } + return t.DialContextWithDialer(ctx, dialer.Dialer{Options: t.Base.DialOptions(opts...)}, metadata) +} - c, err := dialer.DialContext(ctx, "tcp", t.addr, t.Base.DialOptions(opts...)...) +// DialContextWithDialer implements C.ProxyAdapter +func (t *Trojan) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.Conn, err error) { + c, err := dialer.DialContext(ctx, "tcp", t.addr) if err != nil { return nil, fmt.Errorf("%s connect error: %w", t.addr, err) } @@ -152,19 +156,30 @@ func (t *Trojan) ListenPacketContext(ctx context.Context, metadata *C.Metadata, defer func() { safeConnClose(c, err) }() - } else { - c, err = dialer.DialContext(ctx, "tcp", t.addr, t.Base.DialOptions(opts...)...) + err = t.instance.WriteHeader(c, trojan.CommandUDP, serializesSocksAddr(metadata)) if err != nil { - return nil, fmt.Errorf("%s connect error: %w", t.addr, err) - } - defer func() { - safeConnClose(c, err) - }() - tcpKeepAlive(c) - c, err = t.plainStream(c) - if err != nil { - return nil, fmt.Errorf("%s connect error: %w", t.addr, err) + return nil, err } + + pc := t.instance.PacketConn(c) + return newPacketConn(pc, t), err + } + return t.ListenPacketWithDialer(ctx, dialer.Dialer{Options: t.Base.DialOptions(opts...)}, metadata) +} + +// ListenPacketWithDialer implements C.ProxyAdapter +func (t *Trojan) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.PacketConn, err error) { + c, err := dialer.DialContext(ctx, "tcp", t.addr) + if err != nil { + return nil, fmt.Errorf("%s connect error: %w", t.addr, err) + } + defer func() { + safeConnClose(c, err) + }() + tcpKeepAlive(c) + c, err = t.plainStream(c) + if err != nil { + return nil, fmt.Errorf("%s connect error: %w", t.addr, err) } err = t.instance.WriteHeader(c, trojan.CommandUDP, serializesSocksAddr(metadata)) @@ -176,6 +191,11 @@ func (t *Trojan) ListenPacketContext(ctx context.Context, metadata *C.Metadata, return newPacketConn(pc, t), err } +// SupportWithDialer implements C.ProxyAdapter +func (t *Trojan) SupportWithDialer() bool { + return true +} + // ListenPacketOnStreamConn implements C.ProxyAdapter func (t *Trojan) ListenPacketOnStreamConn(c net.Conn, metadata *C.Metadata) (_ C.PacketConn, err error) { pc := t.instance.PacketConn(c) diff --git a/adapter/outbound/vless.go b/adapter/outbound/vless.go index aaf60cb9..28ebfb05 100644 --- a/adapter/outbound/vless.go +++ b/adapter/outbound/vless.go @@ -219,8 +219,12 @@ func (v *Vless) DialContext(ctx context.Context, metadata *C.Metadata, opts ...d return NewConn(c, v), nil } + return v.DialContextWithDialer(ctx, dialer.Dialer{Options: v.Base.DialOptions(opts...)}, metadata) +} - c, err := dialer.DialContext(ctx, "tcp", v.addr, v.Base.DialOptions(opts...)...) +// DialContextWithDialer implements C.ProxyAdapter +func (v *Vless) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.Conn, err error) { + c, err := dialer.DialContext(ctx, "tcp", v.addr) if err != nil { return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error()) } @@ -256,18 +260,36 @@ func (v *Vless) ListenPacketContext(ctx context.Context, metadata *C.Metadata, o }() c, err = v.client.StreamConn(c, parseVlessAddr(metadata)) - } else { - c, err = dialer.DialContext(ctx, "tcp", v.addr, v.Base.DialOptions(opts...)...) - if err != nil { - return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error()) - } - tcpKeepAlive(c) - defer func() { - safeConnClose(c, err) - }() - c, err = v.StreamConn(c, metadata) + if err != nil { + return nil, fmt.Errorf("new vless client error: %v", err) + } + + return v.ListenPacketOnStreamConn(c, metadata) } + return v.ListenPacketWithDialer(ctx, dialer.Dialer{Options: v.Base.DialOptions(opts...)}, metadata) +} + +// ListenPacketWithDialer implements C.ProxyAdapter +func (v *Vless) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.PacketConn, err error) { + // vless use stream-oriented udp with a special address, so we needs a net.UDPAddr + if !metadata.Resolved() { + ip, err := resolver.ResolveIP(ctx, metadata.Host) + if err != nil { + return nil, errors.New("can't resolve ip") + } + metadata.DstIP = ip + } + c, err := dialer.DialContext(ctx, "tcp", v.addr) + if err != nil { + return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error()) + } + tcpKeepAlive(c) + defer func() { + safeConnClose(c, err) + }() + + c, err = v.StreamConn(c, metadata) if err != nil { return nil, fmt.Errorf("new vless client error: %v", err) @@ -276,6 +298,11 @@ func (v *Vless) ListenPacketContext(ctx context.Context, metadata *C.Metadata, o return v.ListenPacketOnStreamConn(c, metadata) } +// SupportWithDialer implements C.ProxyAdapter +func (v *Vless) SupportWithDialer() bool { + return true +} + // ListenPacketOnStreamConn implements C.ProxyAdapter func (v *Vless) ListenPacketOnStreamConn(c net.Conn, metadata *C.Metadata) (_ C.PacketConn, err error) { return newPacketConn(&vlessPacketConn{Conn: c, rAddr: metadata.UDPAddr()}, v), nil diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go index 9573cd08..5697e056 100644 --- a/adapter/outbound/vmess.go +++ b/adapter/outbound/vmess.go @@ -232,8 +232,12 @@ func (v *Vmess) DialContext(ctx context.Context, metadata *C.Metadata, opts ...d return NewConn(c, v), nil } + return v.DialContextWithDialer(ctx, dialer.Dialer{Options: v.Base.DialOptions(opts...)}, metadata) +} - c, err := dialer.DialContext(ctx, "tcp", v.addr, v.Base.DialOptions(opts...)...) +// DialContextWithDialer implements C.ProxyAdapter +func (v *Vmess) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.Conn, err error) { + c, err := dialer.DialContext(ctx, "tcp", v.addr) if err != nil { return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error()) } @@ -280,29 +284,47 @@ func (v *Vmess) ListenPacketContext(ctx context.Context, metadata *C.Metadata, o } else { c, err = v.client.DialPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) } - } else { - c, err = dialer.DialContext(ctx, "tcp", v.addr, v.Base.DialOptions(opts...)...) - if err != nil { - return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error()) - } - tcpKeepAlive(c) - defer func() { - safeConnClose(c, err) - }() - c, err = v.StreamConn(c, metadata) + if err != nil { + return nil, fmt.Errorf("new vmess client error: %v", err) + } + return v.ListenPacketOnStreamConn(c, metadata) + } + c, err = dialer.DialContext(ctx, "tcp", v.addr, v.Base.DialOptions(opts...)...) + if err != nil { + return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error()) + } + tcpKeepAlive(c) + defer func() { + safeConnClose(c, err) + }() + + c, err = v.StreamConn(c, metadata) + return v.ListenPacketWithDialer(ctx, dialer.Dialer{Options: v.Base.DialOptions(opts...)}, metadata) +} + +// ListenPacketWithDialer implements C.ProxyAdapter +func (v *Vmess) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.PacketConn, err error) { + // vmess use stream-oriented udp with a special address, so we needs a net.UDPAddr + if !metadata.Resolved() { + ip, err := resolver.ResolveIP(ctx, metadata.Host) + if err != nil { + return nil, errors.New("can't resolve ip") + } + metadata.DstIP = ip } + c, err := dialer.DialContext(ctx, "tcp", v.addr) if err != nil { return nil, fmt.Errorf("new vmess client error: %v", err) } - if v.option.PacketAddr { - return newPacketConn(&threadSafePacketConn{PacketConn: packetaddr.NewBindConn(c)}, v), nil - } else if pc, ok := c.(net.PacketConn); ok { - return newPacketConn(&threadSafePacketConn{PacketConn: pc}, v), nil - } - return newPacketConn(&vmessPacketConn{Conn: c, rAddr: metadata.UDPAddr()}, v), nil + return v.ListenPacketOnStreamConn(c, metadata) +} + +// SupportWithDialer implements C.ProxyAdapter +func (v *Vmess) SupportWithDialer() bool { + return true } // ListenPacketOnStreamConn implements C.ProxyAdapter diff --git a/adapter/outboundgroup/relay.go b/adapter/outboundgroup/relay.go index ee302097..8205ee52 100644 --- a/adapter/outboundgroup/relay.go +++ b/adapter/outboundgroup/relay.go @@ -3,10 +3,12 @@ package outboundgroup import ( "context" "encoding/json" - "fmt" "net" + "net/netip" + "strings" "github.com/Dreamacro/clash/adapter/outbound" + N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/component/dialer" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/constant/provider" @@ -16,6 +18,36 @@ type Relay struct { *GroupBase } +type proxyDialer struct { + proxy C.Proxy + dialer C.Dialer +} + +func (p proxyDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) { + currentMeta, err := addrToMetadata(address) + if err != nil { + return nil, err + } + if strings.Contains(network, "udp") { // should not support this operation + currentMeta.NetWork = C.UDP + pc, err := p.proxy.ListenPacketWithDialer(ctx, p.dialer, currentMeta) + if err != nil { + return nil, err + } + return N.NewBindPacketConn(pc, currentMeta.UDPAddr()), nil + } + return p.proxy.DialContextWithDialer(ctx, p.dialer, currentMeta) +} + +func (p proxyDialer) ListenPacket(ctx context.Context, network, address string, rAddrPort netip.AddrPort) (net.PacketConn, error) { + currentMeta, err := addrToMetadata(rAddrPort.String()) + if err != nil { + return nil, err + } + currentMeta.NetWork = C.UDP + return p.proxy.ListenPacketWithDialer(ctx, p.dialer, currentMeta) +} + // DialContext implements C.ProxyAdapter func (r *Relay) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) { proxies, chainProxies := r.proxies(metadata, true) @@ -26,47 +58,20 @@ func (r *Relay) DialContext(ctx context.Context, metadata *C.Metadata, opts ...d case 1: return proxies[0].DialContext(ctx, metadata, r.Base.DialOptions(opts...)...) } - - first := proxies[0] + var d C.Dialer + d = dialer.Dialer{Options: r.Base.DialOptions(opts...)} + for _, proxy := range proxies[:len(proxies)-1] { + d = proxyDialer{ + proxy: proxy, + dialer: d, + } + } last := proxies[len(proxies)-1] - - var c net.Conn - var currentMeta *C.Metadata - var err error - - currentMeta, err = addrToMetadata(proxies[1].Addr()) + conn, err := last.DialContextWithDialer(ctx, d, metadata) if err != nil { return nil, err } - c, err = first.DialContext(ctx, currentMeta, r.Base.DialOptions(opts...)...) - if err != nil { - return nil, fmt.Errorf("%s connect error: %w", first.Addr(), err) - } - - first = proxies[1] - - for _, proxy := range proxies[2:] { - currentMeta, err = addrToMetadata(proxy.Addr()) - if err != nil { - return nil, err - } - - c, err = first.StreamConn(c, currentMeta) - if err != nil { - return nil, fmt.Errorf("%s connect error: %w", first.Addr(), err) - } - - first = proxy - } - - c, err = last.StreamConn(c, metadata) - if err != nil { - return nil, fmt.Errorf("%s connect error: %w", last.Addr(), err) - } - - conn := outbound.NewConn(c, last) - for i := len(chainProxies) - 2; i >= 0; i-- { conn.AppendToChains(chainProxies[i]) } @@ -87,95 +92,18 @@ func (r *Relay) ListenPacketContext(ctx context.Context, metadata *C.Metadata, o return proxies[0].ListenPacketContext(ctx, metadata, r.Base.DialOptions(opts...)...) } - udtId := -1 - for i, proxy := range proxies { - if !proxy.SupportUDP() { - return nil, fmt.Errorf("%s don't support udp", proxy.Name()) - } - if proxy.SupportUOT() { - udtId = i // we need the latest id, so don't break + var d C.Dialer + d = dialer.Dialer{Options: r.Base.DialOptions(opts...)} + for _, proxy := range proxies[:len(proxies)-1] { + d = proxyDialer{ + proxy: proxy, + dialer: d, } } - - first := proxies[0] last := proxies[len(proxies)-1] - - var pc C.PacketConn - var currentMeta *C.Metadata - if udtId != -1 { - c, err := dialer.DialContext(ctx, "tcp", first.Addr(), r.Base.DialOptions(opts...)...) - if err != nil { - return nil, fmt.Errorf("%s connect error: %w", first.Addr(), err) - } - tcpKeepAlive(c) - - for _, proxy := range proxies[1 : udtId+1] { - currentMeta, err = addrToMetadata(proxy.Addr()) - if err != nil { - return nil, err - } - - c, err = first.StreamConn(c, currentMeta) - if err != nil { - return nil, fmt.Errorf("%s connect error: %w", first.Addr(), err) - } - - first = proxy - } - - if first == last { - currentMeta = metadata - } else { - currentMeta, err = addrToMetadata(proxies[udtId+1].Addr()) - if err != nil { - return nil, err - } - currentMeta.NetWork = C.UDP - } - c, err = first.StreamConn(c, currentMeta) - if err != nil { - return nil, fmt.Errorf("%s connect error: %w", first.Addr(), err) - } - - pc, err = first.ListenPacketOnStreamConn(c, currentMeta) - if err != nil { - return nil, fmt.Errorf("%s connect error: %w", first.Addr(), err) - } - if first == last { - return pc, nil - } - } else { - currentMeta, err = addrToMetadata(proxies[1].Addr()) - if err != nil { - return nil, err - } - currentMeta.NetWork = C.UDP - pc, err = first.ListenPacketContext(ctx, currentMeta, r.Base.DialOptions(opts...)...) - if err != nil { - return nil, fmt.Errorf("%s connect error: %w", first.Addr(), err) - } - udtId = 0 - } - - first = proxies[udtId+1] - for _, proxy := range proxies[udtId+2:] { - currentMeta, err = addrToMetadata(proxy.Addr()) - if err != nil { - return nil, err - } - currentMeta.NetWork = C.UDP - - pc, err = first.ListenPacketOnPacketConn(ctx, pc, currentMeta) - if err != nil { - return nil, fmt.Errorf("%s connect error: %w", first.Addr(), err) - } - - first = proxy - } - - pc, err = last.ListenPacketOnPacketConn(ctx, pc, metadata) + pc, err := last.ListenPacketWithDialer(ctx, d, metadata) if err != nil { - return nil, fmt.Errorf("%s connect error: %w", last.Addr(), err) + return nil, err } for i := len(chainProxies) - 2; i >= 0; i-- { @@ -201,7 +129,7 @@ func (r *Relay) SupportUDP() bool { if proxy.SupportUOT() { return true } - if !proxy.SupportLPPC() { + if !proxy.SupportWithDialer() { return false } } diff --git a/adapter/outboundgroup/util.go b/adapter/outboundgroup/util.go index 3c769b2f..578011f8 100644 --- a/adapter/outboundgroup/util.go +++ b/adapter/outboundgroup/util.go @@ -24,7 +24,7 @@ func addrToMetadata(rawAddress string) (addr *C.Metadata, err error) { } else { addr = &C.Metadata{ Host: "", - DstIP: ip, + DstIP: ip.Unmap(), DstPort: port, } } diff --git a/common/net/bind.go b/common/net/bind.go new file mode 100644 index 00000000..1e20a8c0 --- /dev/null +++ b/common/net/bind.go @@ -0,0 +1,36 @@ +package net + +import "net" + +type bindPacketConn struct { + net.PacketConn + rAddr net.Addr +} + +func (wpc *bindPacketConn) Read(b []byte) (n int, err error) { + n, _, err = wpc.PacketConn.ReadFrom(b) + return n, err +} + +func (wpc *bindPacketConn) Write(b []byte) (n int, err error) { + return wpc.PacketConn.WriteTo(b, wpc.rAddr) +} + +func (wpc *bindPacketConn) RemoteAddr() net.Addr { + return wpc.rAddr +} + +func (wpc *bindPacketConn) LocalAddr() net.Addr { + if wpc.PacketConn.LocalAddr() == nil { + return &net.UDPAddr{IP: net.IPv4zero, Port: 0} + } else { + return wpc.PacketConn.LocalAddr() + } +} + +func NewBindPacketConn(pc net.PacketConn, rAddr net.Addr) net.Conn { + return &bindPacketConn{ + PacketConn: pc, + rAddr: rAddr, + } +} diff --git a/component/dialer/dialer.go b/component/dialer/dialer.go index c6b57d6c..256ff495 100644 --- a/component/dialer/dialer.go +++ b/component/dialer/dialer.go @@ -444,3 +444,15 @@ func concurrentIPv6DialContext(ctx context.Context, network, address string, opt return concurrentDialContext(ctx, network, ips, port, opt) } + +type Dialer struct { + Options []Option +} + +func (d Dialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) { + return DialContext(ctx, network, address, d.Options...) +} + +func (d Dialer) ListenPacket(ctx context.Context, network, address string, rAddrPort netip.AddrPort) (net.PacketConn, error) { + return ListenPacket(ctx, ParseNetwork(network, rAddrPort.Addr()), address, d.Options...) +} diff --git a/constant/adapters.go b/constant/adapters.go index 419708cf..c13a85c4 100644 --- a/constant/adapters.go +++ b/constant/adapters.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "net" + "net/netip" "time" "github.com/Dreamacro/clash/component/dialer" @@ -81,6 +82,11 @@ type PacketConn interface { // WriteWithMetadata(p []byte, metadata *Metadata) (n int, err error) } +type Dialer interface { + DialContext(ctx context.Context, network, address string) (net.Conn, error) + ListenPacket(ctx context.Context, network, address string, rAddrPort netip.AddrPort) (net.PacketConn, error) +} + type ProxyAdapter interface { Name() string Type() AdapterType @@ -89,6 +95,7 @@ type ProxyAdapter interface { SupportTFO() bool MarshalJSON() ([]byte, error) + // Deprecated: use DialContextWithDialer and ListenPacketWithDialer instead. // StreamConn wraps a protocol around net.Conn with Metadata. // // Examples: @@ -106,10 +113,10 @@ type ProxyAdapter interface { // SupportUOT return UDP over TCP support SupportUOT() bool - ListenPacketOnStreamConn(c net.Conn, metadata *Metadata) (PacketConn, error) - SupportLPPC() bool - ListenPacketOnPacketConn(ctx context.Context, c PacketConn, metadata *Metadata) (PacketConn, error) + SupportWithDialer() bool + DialContextWithDialer(ctx context.Context, dialer Dialer, metadata *Metadata) (Conn, error) + ListenPacketWithDialer(ctx context.Context, dialer Dialer, metadata *Metadata) (PacketConn, error) // Unwrap extracts the proxy from a proxy-group. It returns nil when nothing to extract. Unwrap(metadata *Metadata, touch bool) Proxy diff --git a/dns/util.go b/dns/util.go index dfd2bafd..3f7700ea 100644 --- a/dns/util.go +++ b/dns/util.go @@ -11,6 +11,7 @@ import ( "time" "github.com/Dreamacro/clash/common/cache" + N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/common/nnip" "github.com/Dreamacro/clash/common/picker" "github.com/Dreamacro/clash/component/dialer" @@ -134,32 +135,6 @@ func msgToDomain(msg *D.Msg) string { return "" } -type wrapPacketConn struct { - net.PacketConn - rAddr net.Addr -} - -func (wpc *wrapPacketConn) Read(b []byte) (n int, err error) { - n, _, err = wpc.PacketConn.ReadFrom(b) - return n, err -} - -func (wpc *wrapPacketConn) Write(b []byte) (n int, err error) { - return wpc.PacketConn.WriteTo(b, wpc.rAddr) -} - -func (wpc *wrapPacketConn) RemoteAddr() net.Addr { - return wpc.rAddr -} - -func (wpc *wrapPacketConn) LocalAddr() net.Addr { - if wpc.PacketConn.LocalAddr() == nil { - return &net.UDPAddr{IP: net.IPv4zero, Port: 0} - } else { - return wpc.PacketConn.LocalAddr() - } -} - type dialHandler func(ctx context.Context, network, addr string) (net.Conn, error) func getDialHandler(r *Resolver, proxyAdapter string, opts ...dialer.Option) dialHandler { @@ -213,10 +188,7 @@ func getDialHandler(r *Resolver, proxyAdapter string, opts ...dialer.Option) dia return nil, err } - return &wrapPacketConn{ - PacketConn: packetConn, - rAddr: metadata.UDPAddr(), - }, nil + return N.NewBindPacketConn(packetConn, metadata.UDPAddr()), nil } } }