From 88acf8e098fead3c53e0ae7a060ef71d10dd1a19 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 13 Dec 2022 11:18:32 +0800 Subject: [PATCH] fix: fix bindIfaceToListenConfig() in windows force bind to an ipv4 address --- adapter/outbound/direct.go | 2 +- adapter/outbound/hysteria.go | 4 +--- adapter/outbound/shadowsocks.go | 5 ++--- adapter/outbound/shadowsocksr.go | 5 ++--- adapter/outbound/socks5.go | 26 +++++++++++++------------- adapter/outbound/tuic.go | 6 +----- adapter/outbound/wireguard.go | 2 +- component/dialer/dialer.go | 12 ++++++++++++ dns/util.go | 2 +- 9 files changed, 34 insertions(+), 30 deletions(-) diff --git a/adapter/outbound/direct.go b/adapter/outbound/direct.go index d7ffd478..cf1b2648 100644 --- a/adapter/outbound/direct.go +++ b/adapter/outbound/direct.go @@ -27,7 +27,7 @@ func (d *Direct) DialContext(ctx context.Context, metadata *C.Metadata, opts ... // ListenPacketContext implements C.ProxyAdapter func (d *Direct) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) { opts = append(opts, dialer.WithResolver(resolver.DefaultResolver)) - pc, err := dialer.ListenPacket(ctx, "udp", "", d.Base.DialOptions(opts...)...) + pc, err := dialer.ListenPacket(ctx, dialer.ParseNetwork("udp", metadata.DstIP), "", d.Base.DialOptions(opts...)...) if err != nil { return nil, err } diff --git a/adapter/outbound/hysteria.go b/adapter/outbound/hysteria.go index cd36db5a..e019f7fa 100644 --- a/adapter/outbound/hysteria.go +++ b/adapter/outbound/hysteria.go @@ -334,9 +334,7 @@ type hyDialerWithContext struct { func (h *hyDialerWithContext) ListenPacket(rAddr net.Addr) (net.PacketConn, error) { network := "udp" if addrPort, err := netip.ParseAddrPort(rAddr.String()); err == nil { - if addrPort.Addr().Unmap().Is6() { - network = "udp6" - } + network = dialer.ParseNetwork(network, addrPort.Addr()) } return h.hyDialer(network) } diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go index 39c02b91..74400301 100644 --- a/adapter/outbound/shadowsocks.go +++ b/adapter/outbound/shadowsocks.go @@ -105,14 +105,13 @@ func (ss *ShadowSocks) ListenPacketContext(ctx context.Context, metadata *C.Meta } return newPacketConn(uot.NewClientConn(tcpConn), ss), nil } - pc, err := dialer.ListenPacket(ctx, "udp", "", ss.Base.DialOptions(opts...)...) + addr, err := resolveUDPAddrWithPrefer(ctx, "udp", ss.addr, ss.prefer) if err != nil { return nil, err } - addr, err := resolveUDPAddrWithPrefer(ctx, "udp", ss.addr, ss.prefer) + pc, err := dialer.ListenPacket(ctx, dialer.ParseNetwork("udp", addr.AddrPort().Addr()), "", ss.Base.DialOptions(opts...)...) if err != nil { - pc.Close() return nil, err } pc = ss.method.DialPacketConn(&bufio.BindPacketConn{PacketConn: pc, Addr: addr}) diff --git a/adapter/outbound/shadowsocksr.go b/adapter/outbound/shadowsocksr.go index 8bc9ef65..5d71ed65 100644 --- a/adapter/outbound/shadowsocksr.go +++ b/adapter/outbound/shadowsocksr.go @@ -74,14 +74,13 @@ 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) { - pc, err := dialer.ListenPacket(ctx, "udp", "", ssr.Base.DialOptions(opts...)...) + addr, err := resolveUDPAddrWithPrefer(ctx, "udp", ssr.addr, ssr.prefer) if err != nil { return nil, err } - addr, err := resolveUDPAddrWithPrefer(ctx, "udp", ssr.addr, ssr.prefer) + pc, err := dialer.ListenPacket(ctx, dialer.ParseNetwork("udp", addr.AddrPort().Addr()), "", ssr.Base.DialOptions(opts...)...) if err != nil { - pc.Close() return nil, err } diff --git a/adapter/outbound/socks5.go b/adapter/outbound/socks5.go index 63b76dd3..0da864b6 100644 --- a/adapter/outbound/socks5.go +++ b/adapter/outbound/socks5.go @@ -114,19 +114,6 @@ func (ss *Socks5) ListenPacketContext(ctx context.Context, metadata *C.Metadata, return } - pc, err := dialer.ListenPacket(ctx, "udp", "", ss.Base.DialOptions(opts...)...) - if err != nil { - return - } - - go func() { - io.Copy(io.Discard, c) - c.Close() - // A UDP association terminates when the TCP connection that the UDP - // ASSOCIATE request arrived on terminates. RFC1928 - pc.Close() - }() - // Support unspecified UDP bind address. bindUDPAddr := bindAddr.UDPAddr() if bindUDPAddr == nil { @@ -141,6 +128,19 @@ func (ss *Socks5) ListenPacketContext(ctx context.Context, metadata *C.Metadata, bindUDPAddr.IP = serverAddr.IP } + pc, err := dialer.ListenPacket(ctx, dialer.ParseNetwork("udp", bindUDPAddr.AddrPort().Addr()), "", ss.Base.DialOptions(opts...)...) + if err != nil { + return + } + + go func() { + io.Copy(io.Discard, c) + c.Close() + // A UDP association terminates when the TCP connection that the UDP + // ASSOCIATE request arrived on terminates. RFC1928 + pc.Close() + }() + return newPacketConn(&socksPacketConn{PacketConn: pc, rAddr: bindUDPAddr, tcpConn: c}, ss), nil } diff --git a/adapter/outbound/tuic.go b/adapter/outbound/tuic.go index 5119f8d2..fa171187 100644 --- a/adapter/outbound/tuic.go +++ b/adapter/outbound/tuic.go @@ -79,11 +79,7 @@ func (t *Tuic) dial(ctx context.Context, opts ...dialer.Option) (pc net.PacketCo return nil, nil, err } addr = udpAddr - network := "udp" - if udpAddr.AddrPort().Addr().Unmap().Is6() { - network = "udp6" - } - pc, err = dialer.ListenPacket(ctx, network, "", opts...) + pc, err = dialer.ListenPacket(ctx, dialer.ParseNetwork("udp", udpAddr.AddrPort().Addr()), "", opts...) if err != nil { return nil, nil, err } diff --git a/adapter/outbound/wireguard.go b/adapter/outbound/wireguard.go index 75cb6f9f..ad7a157f 100644 --- a/adapter/outbound/wireguard.go +++ b/adapter/outbound/wireguard.go @@ -65,7 +65,7 @@ func (d *wgDialer) DialContext(ctx context.Context, network string, destination } func (d *wgDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { - return dialer.ListenPacket(ctx, "udp", "", d.options...) + return dialer.ListenPacket(ctx, dialer.ParseNetwork("udp", destination.Addr), "", d.options...) } func NewWireGuard(option WireGuardOption) (*WireGuard, error) { diff --git a/component/dialer/dialer.go b/component/dialer/dialer.go index 44fa2e90..c6b57d6c 100644 --- a/component/dialer/dialer.go +++ b/component/dialer/dialer.go @@ -6,6 +6,7 @@ import ( "fmt" "net" "net/netip" + "runtime" "strings" "sync" @@ -24,6 +25,17 @@ var ( ErrorDisableIPv6 = errors.New("IPv6 is disabled, dialer cancel") ) +func ParseNetwork(network string, addr netip.Addr) string { + if runtime.GOOS == "windows" { // fix bindIfaceToListenConfig() in windows force bind to an ipv4 address + if !strings.HasSuffix(network, "4") && + !strings.HasSuffix(network, "6") && + addr.Unmap().Is6() { + network += "6" + } + } + return network +} + func ApplyOptions(options ...Option) *option { opt := &option{ interfaceName: DefaultInterface.Load(), diff --git a/dns/util.go b/dns/util.go index fb42a9e7..f6b9c090 100644 --- a/dns/util.go +++ b/dns/util.go @@ -207,7 +207,7 @@ func dialContextExtra(ctx context.Context, adapterName string, network string, a DstPort: port, } if !ok { - packetConn, err := dialer.ListenPacket(ctx, network, metadata.RemoteAddress(), opts...) + packetConn, err := dialer.ListenPacket(ctx, dialer.ParseNetwork(network, dstIP), "", opts...) if err != nil { return nil, err }