diff --git a/config/config.go b/config/config.go index 655ac832..beed864f 100644 --- a/config/config.go +++ b/config/config.go @@ -884,7 +884,7 @@ func parseAuthentication(rawRecords []string) []auth.AuthUser { func parseTun(rawTun RawTun, general *General) (*Tun, error) { if rawTun.Enable && rawTun.AutoDetectInterface { - autoDetectInterfaceName, err := commons.GetAutoDetectInterface() + autoDetectInterfaceName, err := commons.GetAutoDetectInterface(rawTun.Device) if err != nil { log.Warnln("Can not find auto detect interface.[%s]", err) } else { diff --git a/listener/tun/ipstack/commons/router.go b/listener/tun/ipstack/commons/router.go index c6c697e5..83a8a794 100644 --- a/listener/tun/ipstack/commons/router.go +++ b/listener/tun/ipstack/commons/router.go @@ -23,17 +23,17 @@ func ipv4MaskString(bits int) string { return fmt.Sprintf("%d.%d.%d.%d", m[0], m[1], m[2], m[3]) } -func DefaultInterfaceChangeMonitor() { +func DefaultInterfaceChangeMonitor(tunName string) { t := time.NewTicker(defaultInterfaceMonitorDuration) defer t.Stop() for { <-t.C - interfaceName, err := GetAutoDetectInterface() + interfaceName, err := GetAutoDetectInterface(tunName) if err != nil { log.Warnln("[TUN] default interface monitor exited, cause: %v", err) - break + continue } old := dialer.DefaultInterface.Load() diff --git a/listener/tun/ipstack/commons/router_android.go b/listener/tun/ipstack/commons/router_android.go index f906c0c5..8982224d 100644 --- a/listener/tun/ipstack/commons/router_android.go +++ b/listener/tun/ipstack/commons/router_android.go @@ -10,18 +10,30 @@ import ( "strings" ) -func GetAutoDetectInterface() (string, error) { - res, err := cmd.ExecCmd("sh -c ip route | awk '{print $3}' | xargs echo -n") +func GetAutoDetectInterface(tunName string) (ifn string, err error) { + cmdRes, err := cmd.ExecCmd("ip route show") if err != nil { - return "", err + return } - ifaces := strings.Split(res, " ") - for _, iface := range ifaces { - if iface == "wlan0" { - return "wlan0", nil + + for _, route := range strings.Split(cmdRes, "\n") { + rs := strings.Split(route, " ") + if len(rs) > 2 { + if rs[2] == tunName { + continue + } + ifn = rs[2] + if ifn == "wlan0" { + return + } } } - return ifaces[0], nil + + if ifn == "" { + return "", fmt.Errorf("interface not found") + } + return + //err = fmt.Errorf("interface not found") } func ConfigInterfaceAddress(dev device.Device, addr netip.Prefix, forceMTU int, autoRoute, autoDetectInterface bool) error { @@ -40,6 +52,10 @@ func ConfigInterfaceAddress(dev device.Device, addr netip.Prefix, forceMTU int, return err } + if err = execRouterCmd("add", addr.Masked().String(), interfaceName, ip.String(), "main"); err != nil { + return err + } + if autoRoute { err = configInterfaceRouting(interfaceName, addr, autoDetectInterface) } @@ -62,7 +78,7 @@ func configInterfaceRouting(interfaceName string, addr netip.Prefix, autoDetectI execAddRuleCmd(fmt.Sprintf("not from all iif lo lookup %d pref 9004", tableId)) if autoDetectInterface { - go DefaultInterfaceChangeMonitor() + go DefaultInterfaceChangeMonitor(interfaceName) } return nil diff --git a/listener/tun/ipstack/commons/router_darwin.go b/listener/tun/ipstack/commons/router_darwin.go index abead15a..da81526c 100644 --- a/listener/tun/ipstack/commons/router_darwin.go +++ b/listener/tun/ipstack/commons/router_darwin.go @@ -8,7 +8,7 @@ import ( "github.com/Dreamacro/clash/listener/tun/device" ) -func GetAutoDetectInterface() (string, error) { +func GetAutoDetectInterface(string) (string, error) { return cmd.ExecCmd("bash -c route -n get default | grep 'interface:' | awk -F ' ' 'NR==1{print $2}' | xargs echo -n") } @@ -55,7 +55,7 @@ func configInterfaceRouting(interfaceName string, addr netip.Prefix, autoDetectI } if autoDetectInterface { - go DefaultInterfaceChangeMonitor() + go DefaultInterfaceChangeMonitor(interfaceName) } return execRouterCmd("add", "-inet6", "2000::/3", interfaceName) diff --git a/listener/tun/ipstack/commons/router_linux.go b/listener/tun/ipstack/commons/router_linux.go index 4a11f99f..99787704 100644 --- a/listener/tun/ipstack/commons/router_linux.go +++ b/listener/tun/ipstack/commons/router_linux.go @@ -9,7 +9,7 @@ import ( "net/netip" ) -func GetAutoDetectInterface() (string, error) { +func GetAutoDetectInterface(string) (string, error) { return cmd.ExecCmd("bash -c ip route show | grep 'default via' | awk -F ' ' 'NR==1{print $5}' | xargs echo -n") } @@ -47,7 +47,7 @@ func configInterfaceRouting(interfaceName string, addr netip.Prefix, autoDetectI } if autoDetectInterface { - go DefaultInterfaceChangeMonitor() + go DefaultInterfaceChangeMonitor(interfaceName) } return nil diff --git a/listener/tun/ipstack/commons/router_others.go b/listener/tun/ipstack/commons/router_others.go index cec981cc..a26952e6 100644 --- a/listener/tun/ipstack/commons/router_others.go +++ b/listener/tun/ipstack/commons/router_others.go @@ -10,7 +10,7 @@ import ( "github.com/Dreamacro/clash/listener/tun/device" ) -func GetAutoDetectInterface() (string, error) { +func GetAutoDetectInterface(string) (string, error) { return "", fmt.Errorf("can not auto detect interface-name on this OS: %s, you must be detecting interface-name by manual", runtime.GOOS) } diff --git a/listener/tun/ipstack/commons/router_windows.go b/listener/tun/ipstack/commons/router_windows.go index b9d1a68c..4feb9db6 100644 --- a/listener/tun/ipstack/commons/router_windows.go +++ b/listener/tun/ipstack/commons/router_windows.go @@ -18,7 +18,7 @@ import ( var wintunInterfaceName string -func GetAutoDetectInterface() (string, error) { +func GetAutoDetectInterface(string) (string, error) { ifname, err := getAutoDetectInterfaceByFamily(winipcfg.AddressFamily(windows.AF_INET)) if err == nil { return ifname, err @@ -206,7 +206,7 @@ startOver: wintunInterfaceName = dev.Name() if autoDetectInterface { - go DefaultInterfaceChangeMonitor() + go DefaultInterfaceChangeMonitor(dev.Name()) } return nil