diff --git a/component/dhcp/conn.go b/component/dhcp/conn.go index ff26275b18..61c801bd3e 100644 --- a/component/dhcp/conn.go +++ b/component/dhcp/conn.go @@ -3,6 +3,7 @@ package dhcp import ( "context" "net" + "net/netip" "runtime" "github.com/metacubex/mihomo/component/dialer" @@ -24,5 +25,5 @@ func ListenDHCPClient(ctx context.Context, ifaceName string) (net.PacketConn, er options = append(options, dialer.WithFallbackBind(true)) } - return dialer.ListenPacket(ctx, "udp4", listenAddr, options...) + return dialer.ListenPacket(ctx, "udp4", listenAddr, netip.AddrPortFrom(netip.AddrFrom4([4]byte{255, 255, 255, 255}), 67), options...) } diff --git a/component/dialer/bind.go b/component/dialer/bind.go index 9b6471a323..de6aacd3bd 100644 --- a/component/dialer/bind.go +++ b/component/dialer/bind.go @@ -75,7 +75,7 @@ func fallbackBindIfaceToDialer(ifaceName string, dialer *net.Dialer, network str return nil } -func fallbackBindIfaceToListenConfig(ifaceName string, _ *net.ListenConfig, network, address string) (string, error) { +func fallbackBindIfaceToListenConfig(ifaceName string, _ *net.ListenConfig, network, address string, rAddrPort netip.AddrPort) (string, error) { _, port, err := net.SplitHostPort(address) if err != nil { port = "0" diff --git a/component/dialer/bind_darwin.go b/component/dialer/bind_darwin.go index f83b86f825..fdea24bfdc 100644 --- a/component/dialer/bind_darwin.go +++ b/component/dialer/bind_darwin.go @@ -46,7 +46,7 @@ func bindIfaceToDialer(ifaceName string, dialer *net.Dialer, _ string, _ netip.A return nil } -func bindIfaceToListenConfig(ifaceName string, lc *net.ListenConfig, _, address string) (string, error) { +func bindIfaceToListenConfig(ifaceName string, lc *net.ListenConfig, _, address string, rAddrPort netip.AddrPort) (string, error) { ifaceObj, err := iface.ResolveInterface(ifaceName) if err != nil { return "", err diff --git a/component/dialer/bind_linux.go b/component/dialer/bind_linux.go index 1ec98f3d2b..79cf735b73 100644 --- a/component/dialer/bind_linux.go +++ b/component/dialer/bind_linux.go @@ -35,7 +35,7 @@ func bindIfaceToDialer(ifaceName string, dialer *net.Dialer, _ string, _ netip.A return nil } -func bindIfaceToListenConfig(ifaceName string, lc *net.ListenConfig, _, address string) (string, error) { +func bindIfaceToListenConfig(ifaceName string, lc *net.ListenConfig, _, address string, rAddrPort netip.AddrPort) (string, error) { addControlToListenConfig(lc, bindControl(ifaceName)) return address, nil diff --git a/component/dialer/bind_others.go b/component/dialer/bind_others.go index 44181610f0..b7db962a6c 100644 --- a/component/dialer/bind_others.go +++ b/component/dialer/bind_others.go @@ -11,8 +11,8 @@ func bindIfaceToDialer(ifaceName string, dialer *net.Dialer, network string, des return fallbackBindIfaceToDialer(ifaceName, dialer, network, destination) } -func bindIfaceToListenConfig(ifaceName string, lc *net.ListenConfig, network, address string) (string, error) { - return fallbackBindIfaceToListenConfig(ifaceName, lc, network, address) +func bindIfaceToListenConfig(ifaceName string, lc *net.ListenConfig, network, address string, rAddrPort netip.AddrPort) (string, error) { + return fallbackBindIfaceToListenConfig(ifaceName, lc, network, address, rAddrPort) } func ParseNetwork(network string, addr netip.Addr) string { diff --git a/component/dialer/bind_windows.go b/component/dialer/bind_windows.go index 25a98646bd..9897881890 100644 --- a/component/dialer/bind_windows.go +++ b/component/dialer/bind_windows.go @@ -27,7 +27,7 @@ func bind6(handle syscall.Handle, ifaceIdx int) error { return syscall.SetsockoptInt(handle, syscall.IPPROTO_IPV6, IPV6_UNICAST_IF, ifaceIdx) } -func bindControl(ifaceIdx int) controlFn { +func bindControl(ifaceIdx int, rAddrPort netip.AddrPort) controlFn { return func(ctx context.Context, network, address string, c syscall.RawConn) (err error) { addrPort, err := netip.ParseAddrPort(address) if err == nil && !addrPort.Addr().IsGlobalUnicast() { @@ -46,7 +46,7 @@ func bindControl(ifaceIdx int) controlFn { innerErr = bind4err case "udp6": // golang will set network to udp6 when listenUDP on wildcard ip (eg: ":0", "") - if (!addrPort.Addr().IsValid() || addrPort.Addr().IsUnspecified()) && bind6err != nil { + if (!addrPort.Addr().IsValid() || addrPort.Addr().IsUnspecified()) && bind6err != nil && rAddrPort.Addr().Unmap().Is4() { // try bind ipv6, if failed, ignore. it's a workaround for windows disable interface ipv6 if bind4err != nil { innerErr = bind6err @@ -67,23 +67,23 @@ func bindControl(ifaceIdx int) controlFn { } } -func bindIfaceToDialer(ifaceName string, dialer *net.Dialer, _ string, _ netip.Addr) error { +func bindIfaceToDialer(ifaceName string, dialer *net.Dialer, _ string, destination netip.Addr) error { ifaceObj, err := iface.ResolveInterface(ifaceName) if err != nil { return err } - addControlToDialer(dialer, bindControl(ifaceObj.Index)) + addControlToDialer(dialer, bindControl(ifaceObj.Index, netip.AddrPortFrom(destination, 0))) return nil } -func bindIfaceToListenConfig(ifaceName string, lc *net.ListenConfig, _, address string) (string, error) { +func bindIfaceToListenConfig(ifaceName string, lc *net.ListenConfig, _, address string, rAddrPort netip.AddrPort) (string, error) { ifaceObj, err := iface.ResolveInterface(ifaceName) if err != nil { return "", err } - addControlToListenConfig(lc, bindControl(ifaceObj.Index)) + addControlToListenConfig(lc, bindControl(ifaceObj.Index, rAddrPort)) return address, nil } diff --git a/component/dialer/dialer.go b/component/dialer/dialer.go index 0ed55cee19..55fb7a1d3c 100644 --- a/component/dialer/dialer.go +++ b/component/dialer/dialer.go @@ -37,7 +37,7 @@ func DialContext(ctx context.Context, network, address string, options ...Option } } -func ListenPacket(ctx context.Context, network, address string, options ...Option) (net.PacketConn, error) { +func ListenPacket(ctx context.Context, network, address string, rAddrPort netip.AddrPort, options ...Option) (net.PacketConn, error) { cfg := applyOptions(options...) lc := &net.ListenConfig{} @@ -46,7 +46,7 @@ func ListenPacket(ctx context.Context, network, address string, options ...Optio if cfg.fallbackBind { bind = fallbackBindIfaceToListenConfig } - addr, err := bind(cfg.interfaceName, lc, network, address) + addr, err := bind(cfg.interfaceName, lc, network, address, rAddrPort) if err != nil { return nil, err } @@ -416,7 +416,7 @@ func (d Dialer) ListenPacket(ctx context.Context, network, address string, rAddr // avoid "The requested address is not valid in its context." opt = WithInterface("") } - return ListenPacket(ctx, ParseNetwork(network, rAddrPort.Addr()), address, opt) + return ListenPacket(ctx, ParseNetwork(network, rAddrPort.Addr()), address, rAddrPort, opt) } func NewDialer(options ...Option) Dialer {