From 3d2b4b1f3aa4c8ecba6d9f0e61b67fb64ff7e8be Mon Sep 17 00:00:00 2001 From: yaling888 <73897884+yaling888@users.noreply.github.com> Date: Wed, 18 May 2022 05:58:58 +0800 Subject: [PATCH] Refactor: get default route interface by syscall on darwin --- listener/tun/ipstack/commons/router_darwin.go | 53 ++++++++++++++++--- 1 file changed, 46 insertions(+), 7 deletions(-) diff --git a/listener/tun/ipstack/commons/router_darwin.go b/listener/tun/ipstack/commons/router_darwin.go index 5cbab1fa..a889aaf5 100644 --- a/listener/tun/ipstack/commons/router_darwin.go +++ b/listener/tun/ipstack/commons/router_darwin.go @@ -2,24 +2,23 @@ package commons import ( "fmt" + "net" "net/netip" "strings" + "syscall" "github.com/Dreamacro/clash/common/cmd" "github.com/Dreamacro/clash/listener/tun/device" + + "golang.org/x/net/route" ) func GetAutoDetectInterface() (string, error) { - rs, err := cmd.ExecCmd("/bin/bash -c /sbin/route -n get default | grep 'interface:' | awk -F ' ' 'NR==1{print $2}' | xargs echo -n") + iface, err := defaultRouteInterface() if err != nil { return "", err } - - if rs == "" || strings.HasSuffix(rs, "\n") { - return "", fmt.Errorf("invalid interface name: %s", rs) - } - - return rs, nil + return iface.Name, nil } func ConfigInterfaceAddress(dev device.Device, addr netip.Prefix, forceMTU int, autoRoute bool) error { @@ -71,3 +70,43 @@ func execRouterCmd(action, inet, route string, interfaceName string) error { _, err := cmd.ExecCmd(fmt.Sprintf("/sbin/route %s %s %s -interface %s", action, inet, route, interfaceName)) return err } + +func defaultRouteInterface() (*net.Interface, error) { + rib, err := route.FetchRIB(syscall.AF_UNSPEC, syscall.NET_RT_DUMP2, 0) + if err != nil { + return nil, fmt.Errorf("route.FetchRIB: %w", err) + } + + msgs, err := route.ParseRIB(syscall.NET_RT_IFLIST2, rib) + if err != nil { + return nil, fmt.Errorf("route.ParseRIB: %w", err) + } + + for _, message := range msgs { + routeMessage := message.(*route.RouteMessage) + if routeMessage.Flags&(syscall.RTF_UP|syscall.RTF_GATEWAY|syscall.RTF_STATIC) == 0 { + continue + } + + addresses := routeMessage.Addrs + + if (addresses[0].Family() == syscall.AF_INET && addresses[0].(*route.Inet4Addr).IP != *(*[4]byte)(net.IPv4zero)) || + (addresses[0].Family() == syscall.AF_INET6 && addresses[0].(*route.Inet6Addr).IP != *(*[16]byte)(net.IPv6zero)) { + + continue + } + + iface, err1 := net.InterfaceByIndex(routeMessage.Index) + if err1 != nil { + continue + } + + if strings.HasPrefix(iface.Name, "utun") { + continue + } + + return iface, nil + } + + return nil, fmt.Errorf("ambiguous gateway interfaces found") +}