refactor: new way to get interface change even for linux
This commit is contained in:
90
listener/tun/ipstack/commons/auto_linux.go
Normal file
90
listener/tun/ipstack/commons/auto_linux.go
Normal file
@ -0,0 +1,90 @@
|
||||
package commons
|
||||
|
||||
import (
|
||||
"github.com/Dreamacro/clash/component/dialer"
|
||||
"github.com/Dreamacro/clash/component/iface"
|
||||
"github.com/Dreamacro/clash/log"
|
||||
"github.com/vishvananda/netlink"
|
||||
"go.uber.org/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
monitorStarted = atomic.NewBool(false)
|
||||
monitorStop = make(chan struct{}, 2)
|
||||
)
|
||||
|
||||
func StartDefaultInterfaceChangeMonitor() {
|
||||
go func() {
|
||||
if monitorStarted.Load() {
|
||||
return
|
||||
}
|
||||
monitorStarted.Store(true)
|
||||
|
||||
done := make(chan struct{})
|
||||
ch := make(chan netlink.RouteUpdate, 2)
|
||||
err := netlink.RouteSubscribe(ch, done)
|
||||
if err != nil {
|
||||
log.Warnln("[TUN] auto detect interface fail: %s", err)
|
||||
return
|
||||
}
|
||||
log.Debugln("[TUN] start auto detect interface monitor")
|
||||
defer func() {
|
||||
close(done)
|
||||
monitorStarted.Store(false)
|
||||
log.Debugln("[TUN] stop auto detect interface monitor")
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-monitorStop:
|
||||
default:
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-monitorStop:
|
||||
return
|
||||
case <-ch:
|
||||
}
|
||||
|
||||
interfaceName, err := GetAutoDetectInterface()
|
||||
if err != nil {
|
||||
t := time.NewTicker(2 * time.Second)
|
||||
for {
|
||||
select {
|
||||
case ch <- <-ch:
|
||||
break
|
||||
case <-t.C:
|
||||
interfaceName, err = GetAutoDetectInterface()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
t.Stop()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Debugln("[TUN] detect interface: %s", err)
|
||||
continue
|
||||
}
|
||||
|
||||
old := dialer.DefaultInterface.Load()
|
||||
if interfaceName == old {
|
||||
continue
|
||||
}
|
||||
|
||||
dialer.DefaultInterface.Store(interfaceName)
|
||||
iface.FlushCache()
|
||||
|
||||
log.Warnln("[TUN] default interface changed by monitor, %s => %s", old, interfaceName)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func StopDefaultInterfaceChangeMonitor() {
|
||||
if monitorStarted.Load() {
|
||||
monitorStop <- struct{}{}
|
||||
}
|
||||
}
|
67
listener/tun/ipstack/commons/auto_others.go
Normal file
67
listener/tun/ipstack/commons/auto_others.go
Normal file
@ -0,0 +1,67 @@
|
||||
//go:build !linux
|
||||
|
||||
package commons
|
||||
|
||||
import (
|
||||
"github.com/Dreamacro/clash/component/dialer"
|
||||
"github.com/Dreamacro/clash/component/iface"
|
||||
"github.com/Dreamacro/clash/log"
|
||||
"go.uber.org/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
monitorDuration = 3 * time.Second
|
||||
monitorStarted = atomic.NewBool(false)
|
||||
monitorStop = make(chan struct{}, 2)
|
||||
)
|
||||
|
||||
func StartDefaultInterfaceChangeMonitor() {
|
||||
go func() {
|
||||
if monitorStarted.Load() {
|
||||
return
|
||||
}
|
||||
monitorStarted.Store(true)
|
||||
t := time.NewTicker(monitorDuration)
|
||||
log.Debugln("[TUN] start auto detect interface monitor")
|
||||
defer func() {
|
||||
monitorStarted.Store(false)
|
||||
t.Stop()
|
||||
log.Debugln("[TUN] stop auto detect interface monitor")
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-monitorStop:
|
||||
default:
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-t.C:
|
||||
interfaceName, err := GetAutoDetectInterface()
|
||||
if err != nil {
|
||||
log.Warnln("[TUN] default interface monitor err: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
old := dialer.DefaultInterface.Load()
|
||||
if interfaceName == old {
|
||||
continue
|
||||
}
|
||||
|
||||
dialer.DefaultInterface.Store(interfaceName)
|
||||
iface.FlushCache()
|
||||
|
||||
log.Warnln("[TUN] default interface changed by monitor, %s => %s", old, interfaceName)
|
||||
case <-monitorStop:
|
||||
break
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func StopDefaultInterfaceChangeMonitor() {
|
||||
if monitorStarted.Load() {
|
||||
monitorStop <- struct{}{}
|
||||
}
|
||||
}
|
@ -2,21 +2,13 @@ package commons
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/Dreamacro/clash/component/dialer"
|
||||
"github.com/Dreamacro/clash/component/iface"
|
||||
"github.com/Dreamacro/clash/log"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
defaultRoutes = []string{"1.0.0.0/8", "2.0.0.0/7", "4.0.0.0/6", "8.0.0.0/5", "16.0.0.0/4", "32.0.0.0/3", "64.0.0.0/2", "128.0.0.0/1"}
|
||||
|
||||
monitorDuration = 3 * time.Second
|
||||
monitorStarted = false
|
||||
monitorStop = make(chan struct{}, 2)
|
||||
monitorMux sync.Mutex
|
||||
)
|
||||
|
||||
func ipv4MaskString(bits int) string {
|
||||
@ -28,59 +20,6 @@ func ipv4MaskString(bits int) string {
|
||||
return fmt.Sprintf("%d.%d.%d.%d", m[0], m[1], m[2], m[3])
|
||||
}
|
||||
|
||||
func StartDefaultInterfaceChangeMonitor() {
|
||||
go func() {
|
||||
monitorMux.Lock()
|
||||
if monitorStarted {
|
||||
monitorMux.Unlock()
|
||||
return
|
||||
}
|
||||
monitorStarted = true
|
||||
monitorMux.Unlock()
|
||||
|
||||
select {
|
||||
case <-monitorStop:
|
||||
default:
|
||||
}
|
||||
|
||||
t := time.NewTicker(monitorDuration)
|
||||
defer t.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-t.C:
|
||||
interfaceName, err := GetAutoDetectInterface()
|
||||
if err != nil {
|
||||
log.Warnln("[TUN] default interface monitor err: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
old := dialer.DefaultInterface.Load()
|
||||
if interfaceName == old {
|
||||
continue
|
||||
}
|
||||
|
||||
dialer.DefaultInterface.Store(interfaceName)
|
||||
iface.FlushCache()
|
||||
|
||||
log.Warnln("[TUN] default interface changed by monitor, %s => %s", old, interfaceName)
|
||||
case <-monitorStop:
|
||||
break
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func StopDefaultInterfaceChangeMonitor() {
|
||||
monitorMux.Lock()
|
||||
defer monitorMux.Unlock()
|
||||
|
||||
if monitorStarted {
|
||||
monitorStop <- struct{}{}
|
||||
monitorStarted = false
|
||||
}
|
||||
}
|
||||
|
||||
func WaitForTunClose(deviceName string) {
|
||||
t := time.NewTicker(600 * time.Millisecond)
|
||||
defer t.Stop()
|
||||
|
@ -10,7 +10,11 @@ import (
|
||||
)
|
||||
|
||||
func GetAutoDetectInterface() (string, error) {
|
||||
return cmd.ExecCmd("bash -c ip route show | grep 'default via' | awk -F ' ' 'NR==1{print $5}' | xargs echo -n")
|
||||
execCmd, err := cmd.ExecCmd("bash -c ip route show | grep 'default via' | awk -F ' ' 'NR==1{print $5}' | xargs echo -n")
|
||||
if execCmd == "" {
|
||||
return "", fmt.Errorf("interface not found")
|
||||
}
|
||||
return execCmd, err
|
||||
}
|
||||
|
||||
func ConfigInterfaceAddress(dev device.Device, addr netip.Prefix, forceMTU int, autoRoute bool) error {
|
||||
|
Reference in New Issue
Block a user