diff --git a/config/config.go b/config/config.go index cca2bfb2..9e047729 100644 --- a/config/config.go +++ b/config/config.go @@ -52,6 +52,7 @@ type General struct { GeodataMode bool `json:"geodata-mode"` GeodataLoader string `json:"geodata-loader"` TCPConcurrent bool `json:"tcp-concurrent"` + Tun Tun `json:"tun"` } // Inbound config diff --git a/hub/executor/executor.go b/hub/executor/executor.go index 2fe8d09d..960c83a5 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -111,6 +111,7 @@ func GetGeneral() *config.General { LogLevel: log.Level(), IPv6: !resolver.DisableIPv6, GeodataLoader: G.LoaderName(), + Tun: P.GetTunConf(), } return general @@ -231,7 +232,11 @@ func loadProxyProvider(proxyProviders map[string]provider.ProxyProvider) { } func updateTun(tun *config.Tun, dns *config.DNS) { - P.ReCreateTun(tun, dns, tunnel.TCPIn(), tunnel.UDPIn()) + var tunAddressPrefix *netip.Prefix + if dns.FakeIPRange != nil { + tunAddressPrefix = dns.FakeIPRange.IPNet() + } + P.ReCreateTun(tun, tunAddressPrefix, tunnel.TCPIn(), tunnel.UDPIn()) } func updateSniffer(sniffer *config.Sniffer) { diff --git a/listener/listener.go b/listener/listener.go index 0a2b9ab1..62019f68 100644 --- a/listener/listener.go +++ b/listener/listener.go @@ -5,8 +5,9 @@ import ( "github.com/Dreamacro/clash/common/cmd" "github.com/Dreamacro/clash/listener/inner" "net" - "os" + "net/netip" "runtime" + "sort" "strconv" "sync" @@ -24,8 +25,10 @@ import ( ) var ( - allowLan = false - bindAddress = "*" + allowLan = false + bindAddress = "*" + lastTunConf *config.Tun + lastTunAddressPrefix *netip.Prefix socksListener *socks.Listener socksUDPListener *socks.UDPListener @@ -55,6 +58,15 @@ type Ports struct { MixedPort int `json:"mixed-port"` } +func GetTunConf() config.Tun { + if lastTunConf == nil { + return config.Tun{ + Enable: false, + } + } + return *lastTunConf +} + func AllowLan() bool { return allowLan } @@ -312,7 +324,7 @@ func ReCreateMixed(port int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.P log.Infoln("Mixed(http+socks) proxy listening at: %s", mixedListener.Address()) } -func ReCreateTun(tunConf *config.Tun, dnsCfg *config.DNS, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) { +func ReCreateTun(tunConf *config.Tun, tunAddressPrefix *netip.Prefix, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) { tunMux.Lock() defer tunMux.Unlock() @@ -320,22 +332,35 @@ func ReCreateTun(tunConf *config.Tun, dnsCfg *config.DNS, tcpIn chan<- C.ConnCon defer func() { if err != nil { log.Errorln("Start TUN listening error: %s", err.Error()) - os.Exit(2) } }() + if tunAddressPrefix == nil { + tunAddressPrefix = lastTunAddressPrefix + } + + if !hasTunConfigChange(tunConf, tunAddressPrefix) { + return + } + if tunStackListener != nil { - tunStackListener.Close() + _ = tunStackListener.Close() tunStackListener = nil + lastTunConf = nil + lastTunAddressPrefix = nil } if !tunConf.Enable { return } - tunStackListener, err = tun.New(tunConf, dnsCfg, tcpIn, udpIn) + + tunStackListener, err = tun.New(tunConf, tunAddressPrefix, tcpIn, udpIn) if err != nil { - log.Warnln("Failed to start TUN interface: %s", err.Error()) + log.Warnln("Failed to start TUN interface: %s", err) } + + lastTunConf = tunConf + lastTunAddressPrefix = tunAddressPrefix } // GetPorts return the ports of proxy servers @@ -394,6 +419,47 @@ func genAddr(host string, port int, allowLan bool) string { return fmt.Sprintf("127.0.0.1:%d", port) } +func hasTunConfigChange(tunConf *config.Tun, tunAddressPrefix *netip.Prefix) bool { + if lastTunConf == nil { + return true + } + + if len(lastTunConf.DNSHijack) != len(tunConf.DNSHijack) { + return true + } + + sort.Slice(lastTunConf.DNSHijack, func(i, j int) bool { + return lastTunConf.DNSHijack[i].Addr().Less(lastTunConf.DNSHijack[j].Addr()) + }) + + sort.Slice(tunConf.DNSHijack, func(i, j int) bool { + return tunConf.DNSHijack[i].Addr().Less(tunConf.DNSHijack[j].Addr()) + }) + + for i, dns := range tunConf.DNSHijack { + if dns != lastTunConf.DNSHijack[i] { + return true + } + } + + if lastTunConf.Enable != tunConf.Enable || + lastTunConf.Device != tunConf.Device || + lastTunConf.Stack != tunConf.Stack || + lastTunConf.AutoRoute != tunConf.AutoRoute { + return true + } + + if (tunAddressPrefix != nil && lastTunAddressPrefix == nil) || (tunAddressPrefix == nil && lastTunAddressPrefix != nil) { + return true + } + + if tunAddressPrefix != nil && lastTunAddressPrefix != nil && *tunAddressPrefix != *lastTunAddressPrefix { + return true + } + + return false +} + func Cleanup() { if tunStackListener != nil { _ = tunStackListener.Close() diff --git a/listener/tun/tun_adapter.go b/listener/tun/tun_adapter.go index 39a8f245..96b2ca52 100644 --- a/listener/tun/tun_adapter.go +++ b/listener/tun/tun_adapter.go @@ -23,18 +23,14 @@ import ( ) // New TunAdapter -func New(tunConf *config.Tun, dnsConf *config.DNS, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) (ipstack.Stack, error) { - var tunAddressPrefix string - if dnsConf.FakeIPRange != nil { - tunAddressPrefix = dnsConf.FakeIPRange.IPNet().String() - } +func New(tunConf *config.Tun, tunAddressPrefix *netip.Prefix, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) (ipstack.Stack, error) { var ( - tunAddress, _ = netip.ParsePrefix(tunAddressPrefix) - devName = tunConf.Device - stackType = tunConf.Stack - autoRoute = tunConf.AutoRoute - mtu = 9000 + tunAddress = netip.Prefix{} + devName = tunConf.Device + stackType = tunConf.Stack + autoRoute = tunConf.AutoRoute + mtu = 9000 tunDevice device.Device tunStack ipstack.Stack @@ -42,6 +38,10 @@ func New(tunConf *config.Tun, dnsConf *config.DNS, tcpIn chan<- C.ConnContext, u err error ) + if tunAddressPrefix != nil { + tunAddress = *tunAddressPrefix + } + if devName == "" { devName = generateDeviceName() }