fix: don't ignore bind6 error when udp's target is ipv6 address

This commit is contained in:
wwqgtxx 2024-04-10 15:34:28 +08:00
parent cff7df164f
commit 16fadd2441
7 changed files with 22 additions and 23 deletions

View File

@ -3,6 +3,7 @@ package dhcp
import ( import (
"context" "context"
"net" "net"
"net/netip"
"runtime" "runtime"
"github.com/metacubex/mihomo/component/dialer" "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)) 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...)
} }

View File

@ -75,7 +75,7 @@ func fallbackBindIfaceToDialer(ifaceName string, dialer *net.Dialer, network str
return nil 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) _, port, err := net.SplitHostPort(address)
if err != nil { if err != nil {
port = "0" port = "0"

View File

@ -46,7 +46,7 @@ func bindIfaceToDialer(ifaceName string, dialer *net.Dialer, _ string, _ netip.A
return nil 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) ifaceObj, err := iface.ResolveInterface(ifaceName)
if err != nil { if err != nil {
return "", err return "", err

View File

@ -35,7 +35,7 @@ func bindIfaceToDialer(ifaceName string, dialer *net.Dialer, _ string, _ netip.A
return nil 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)) addControlToListenConfig(lc, bindControl(ifaceName))
return address, nil return address, nil

View File

@ -11,8 +11,8 @@ func bindIfaceToDialer(ifaceName string, dialer *net.Dialer, network string, des
return fallbackBindIfaceToDialer(ifaceName, dialer, network, destination) return fallbackBindIfaceToDialer(ifaceName, dialer, network, destination)
} }
func bindIfaceToListenConfig(ifaceName string, lc *net.ListenConfig, network, address string) (string, error) { func bindIfaceToListenConfig(ifaceName string, lc *net.ListenConfig, network, address string, rAddrPort netip.AddrPort) (string, error) {
return fallbackBindIfaceToListenConfig(ifaceName, lc, network, address) return fallbackBindIfaceToListenConfig(ifaceName, lc, network, address, rAddrPort)
} }
func ParseNetwork(network string, addr netip.Addr) string { func ParseNetwork(network string, addr netip.Addr) string {

View File

@ -36,7 +36,7 @@ func bind6(handle syscall.Handle, ifaceIdx int) error {
return err 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) { return func(ctx context.Context, network, address string, c syscall.RawConn) (err error) {
addrPort, err := netip.ParseAddrPort(address) addrPort, err := netip.ParseAddrPort(address)
if err == nil && !addrPort.Addr().IsGlobalUnicast() { if err == nil && !addrPort.Addr().IsGlobalUnicast() {
@ -55,7 +55,7 @@ func bindControl(ifaceIdx int) controlFn {
innerErr = bind4err innerErr = bind4err
case "udp6": case "udp6":
// golang will set network to udp6 when listenUDP on wildcard ip (eg: ":0", "") // 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 // try bind ipv6, if failed, ignore. it's a workaround for windows disable interface ipv6
if bind4err != nil { if bind4err != nil {
innerErr = fmt.Errorf("%w (%s)", bind6err, bind4err) 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) ifaceObj, err := iface.ResolveInterface(ifaceName)
if err != nil { if err != nil {
return err return err
} }
addControlToDialer(dialer, bindControl(ifaceObj.Index)) addControlToDialer(dialer, bindControl(ifaceObj.Index, netip.AddrPortFrom(destination, 0)))
return nil 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) ifaceObj, err := iface.ResolveInterface(ifaceName)
if err != nil { if err != nil {
return "", err return "", err
} }
addControlToListenConfig(lc, bindControl(ifaceObj.Index)) addControlToListenConfig(lc, bindControl(ifaceObj.Index, rAddrPort))
return address, nil return address, nil
} }

View File

@ -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 { if features.CMFA && DefaultSocketHook != nil {
return listenPacketHooked(ctx, network, address) return listenPacketHooked(ctx, network, address)
} }
@ -91,7 +91,7 @@ func ListenPacket(ctx context.Context, network, address string, options ...Optio
if cfg.fallbackBind { if cfg.fallbackBind {
bind = fallbackBindIfaceToListenConfig bind = fallbackBindIfaceToListenConfig
} }
addr, err := bind(cfg.interfaceName, lc, network, address) addr, err := bind(cfg.interfaceName, lc, network, address, rAddrPort)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -133,11 +133,9 @@ func dialContext(ctx context.Context, network string, destination netip.Addr, po
var address string var address string
if IP4PEnable { if IP4PEnable {
NewDestination, NewPort := lookupIP4P(destination.String(), port) destination, port = lookupIP4P(destination, port)
address = net.JoinHostPort(NewDestination, NewPort)
} else {
address = net.JoinHostPort(destination.String(), port)
} }
address = net.JoinHostPort(destination.String(), port)
netDialer := opt.netDialer netDialer := opt.netDialer
switch netDialer.(type) { 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." // avoid "The requested address is not valid in its context."
opt = WithInterface("") 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 { 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 // kanged from https://github.com/heiher/frp/blob/ip4p/client/ip4p.go
func lookupIP4P(addr string, port string) (string, string) { func lookupIP4P(addr netip.Addr, port string) (netip.Addr, string) {
ip := net.ParseIP(addr) ip := addr.AsSlice()
if ip[0] == 0x20 && ip[1] == 0x01 && if ip[0] == 0x20 && ip[1] == 0x01 &&
ip[2] == 0x00 && ip[3] == 0x00 { 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])) 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
} }
return addr, port return addr, port