From 4d5c0d2bf42f9629b9726913c9c893e82fe68cb2 Mon Sep 17 00:00:00 2001 From: adlyq <2833154405@qq.com> Date: Sat, 30 Apr 2022 14:56:40 +0800 Subject: [PATCH] fix: auto-route priority wlan0 in Android --- listener/listener.go | 2 +- .../tun/ipstack/commons/router_android.go | 83 +++++++++++++++++++ listener/tun/ipstack/commons/router_linux.go | 34 ++------ 3 files changed, 89 insertions(+), 30 deletions(-) create mode 100644 listener/tun/ipstack/commons/router_android.go diff --git a/listener/listener.go b/listener/listener.go index 9671bce9..0a2b9ab1 100644 --- a/listener/listener.go +++ b/listener/listener.go @@ -398,7 +398,7 @@ func Cleanup() { if tunStackListener != nil { _ = tunStackListener.Close() if runtime.GOOS == "android" { - prefs := []int{9000, 9001, 9002, 9003} + prefs := []int{9000, 9001, 9002, 9003, 9004} for _, pref := range prefs { _, _ = cmd.ExecCmd(fmt.Sprintf("ip rule del pref %d", pref)) } diff --git a/listener/tun/ipstack/commons/router_android.go b/listener/tun/ipstack/commons/router_android.go new file mode 100644 index 00000000..f906c0c5 --- /dev/null +++ b/listener/tun/ipstack/commons/router_android.go @@ -0,0 +1,83 @@ +package commons + +import ( + "fmt" + "github.com/Dreamacro/clash/common/cmd" + "github.com/Dreamacro/clash/listener/tun/device" + "github.com/Dreamacro/clash/log" + "net/netip" + "strconv" + "strings" +) + +func GetAutoDetectInterface() (string, error) { + res, err := cmd.ExecCmd("sh -c ip route | awk '{print $3}' | xargs echo -n") + if err != nil { + return "", err + } + ifaces := strings.Split(res, " ") + for _, iface := range ifaces { + if iface == "wlan0" { + return "wlan0", nil + } + } + return ifaces[0], nil +} + +func ConfigInterfaceAddress(dev device.Device, addr netip.Prefix, forceMTU int, autoRoute, autoDetectInterface bool) error { + var ( + interfaceName = dev.Name() + ip = addr.Masked().Addr().Next() + ) + + _, err := cmd.ExecCmd(fmt.Sprintf("ip addr add %s dev %s", ip.String(), interfaceName)) + if err != nil { + return err + } + + _, err = cmd.ExecCmd(fmt.Sprintf("ip link set %s up", interfaceName)) + if err != nil { + return err + } + + if autoRoute { + err = configInterfaceRouting(interfaceName, addr, autoDetectInterface) + } + return err +} + +func configInterfaceRouting(interfaceName string, addr netip.Prefix, autoDetectInterface bool) error { + linkIP := addr.Masked().Addr().Next() + const tableId = 1981801 + + for _, route := range defaultRoutes { + if err := execRouterCmd("add", route, interfaceName, linkIP.String(), strconv.Itoa(tableId)); err != nil { + return err + } + } + execAddRuleCmd(fmt.Sprintf("lookup main pref 9000")) + execAddRuleCmd(fmt.Sprintf("from 0.0.0.0 iif lo uidrange 0-4294967294 lookup %d pref 9001", tableId)) + execAddRuleCmd(fmt.Sprintf("from %s iif lo uidrange 0-4294967294 lookup %d pref 9002", linkIP, tableId)) + execAddRuleCmd(fmt.Sprintf("from all iif %s lookup main suppress_prefixlength 0 pref 9003", interfaceName)) + execAddRuleCmd(fmt.Sprintf("not from all iif lo lookup %d pref 9004", tableId)) + + if autoDetectInterface { + go DefaultInterfaceChangeMonitor() + } + + return nil +} + +func execAddRuleCmd(rule string) { + _, err := cmd.ExecCmd("ip rule add " + rule) + if err != nil { + log.Warnln("%s", err) + } +} + +func execRouterCmd(action, route, interfaceName, linkIP, table string) error { + cmdStr := fmt.Sprintf("ip route %s %s dev %s proto kernel scope link src %s table %s", action, route, interfaceName, linkIP, table) + + _, err := cmd.ExecCmd(cmdStr) + return err +} diff --git a/listener/tun/ipstack/commons/router_linux.go b/listener/tun/ipstack/commons/router_linux.go index 60879eac..5fa5d79a 100644 --- a/listener/tun/ipstack/commons/router_linux.go +++ b/listener/tun/ipstack/commons/router_linux.go @@ -1,19 +1,15 @@ +//go:build !android + package commons import ( "fmt" "github.com/Dreamacro/clash/common/cmd" "github.com/Dreamacro/clash/listener/tun/device" - "github.com/Dreamacro/clash/log" "net/netip" - "runtime" - "strconv" ) func GetAutoDetectInterface() (string, error) { - if runtime.GOOS == "android" { - return cmd.ExecCmd("sh -c ip route | awk 'NR==1{print $3}' | xargs echo -n") - } return cmd.ExecCmd("bash -c ip route show | grep 'default via' | awk -F ' ' 'NR==1{print $5}' | xargs echo -n") } @@ -41,23 +37,10 @@ func ConfigInterfaceAddress(dev device.Device, addr netip.Prefix, forceMTU int, func configInterfaceRouting(interfaceName string, addr netip.Prefix, autoDetectInterface bool) error { linkIP := addr.Masked().Addr().Next() - if runtime.GOOS == "android" { - const tableId = 1981801 - for _, route := range defaultRoutes { - if err := execRouterCmd("add", route, interfaceName, linkIP.String(), strconv.Itoa(tableId)); err != nil { - return err - } - } - execAddRuleCmd(fmt.Sprintf("from 0.0.0.0 iif lo uidrange 0-4294967294 lookup %d pref 9000", tableId)) - execAddRuleCmd(fmt.Sprintf("from %s iif lo uidrange 0-4294967294 lookup %d pref 9001", linkIP, tableId)) - execAddRuleCmd(fmt.Sprintf("from all iif %s lookup main suppress_prefixlength 0 pref 9002", interfaceName)) - execAddRuleCmd(fmt.Sprintf("not from all iif lo lookup %d pref 9003", tableId)) - } else { - for _, route := range defaultRoutes { - if err := execRouterCmd("add", route, interfaceName, linkIP.String(), "main"); err != nil { - return err - } + for _, route := range defaultRoutes { + if err := execRouterCmd("add", route, interfaceName, linkIP.String(), "main"); err != nil { + return err } } @@ -68,13 +51,6 @@ func configInterfaceRouting(interfaceName string, addr netip.Prefix, autoDetectI return nil } -func execAddRuleCmd(rule string) { - _, err := cmd.ExecCmd("ip rule add " + rule) - if err != nil { - log.Warnln("%s", err) - } -} - func execRouterCmd(action, route, interfaceName, linkIP, table string) error { cmdStr := fmt.Sprintf("ip route %s %s dev %s proto kernel scope link src %s table %s", action, route, interfaceName, linkIP, table)