diff --git a/component/dhcp/conn.go b/component/dhcp/conn.go index ff26275b..61c801bd 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 9b6471a3..de6aacd3 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 f83b86f8..fdea24bf 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 1ec98f3d..79cf735b 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 44181610..b7db962a 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 120f1657..98a076d0 100644 --- a/component/dialer/bind_windows.go +++ b/component/dialer/bind_windows.go @@ -36,7 +36,7 @@ func bind6(handle syscall.Handle, ifaceIdx int) error { return err } -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() { @@ -55,7 +55,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 = fmt.Errorf("%w (%s)", bind6err, bind4err) @@ -76,23 +76,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 12e7c960..8fb5a0a6 100644 --- a/component/dialer/dialer.go +++ b/component/dialer/dialer.go @@ -78,7 +78,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) { if features.CMFA && DefaultSocketHook != nil { return listenPacketHooked(ctx, network, address) } @@ -91,7 +91,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 } @@ -133,11 +133,9 @@ func dialContext(ctx context.Context, network string, destination netip.Addr, po var address string if IP4PEnable { - NewDestination, NewPort := lookupIP4P(destination.String(), port) - address = net.JoinHostPort(NewDestination, NewPort) - } else { - address = net.JoinHostPort(destination.String(), port) + destination, port = lookupIP4P(destination, port) } + address = net.JoinHostPort(destination.String(), port) netDialer := opt.netDialer switch netDialer.(type) { @@ -385,7 +383,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 { @@ -399,13 +397,13 @@ func GetIP4PEnable(enableIP4PConvert bool) { // kanged from https://github.com/heiher/frp/blob/ip4p/client/ip4p.go -func lookupIP4P(addr string, port string) (string, string) { - ip := net.ParseIP(addr) +func lookupIP4P(addr netip.Addr, port string) (netip.Addr, string) { + ip := addr.AsSlice() if ip[0] == 0x20 && ip[1] == 0x01 && ip[2] == 0x00 && ip[3] == 0x00 { - addr = net.IPv4(ip[12], ip[13], ip[14], ip[15]).String() + addr = netip.AddrFrom4([4]byte{ip[12], ip[13], ip[14], ip[15]}) port = strconv.Itoa(int(ip[10])<<8 + int(ip[11])) - log.Debugln("Convert IP4P address %s to %s", ip, net.JoinHostPort(addr, port)) + log.Debugln("Convert IP4P address %s to %s", ip, net.JoinHostPort(addr.String(), port)) return addr, port } return addr, port