github.com/yaling888/clash@v1.53.0/hub/executor/executor.go (about) 1 package executor 2 3 import ( 4 "fmt" 5 "net/netip" 6 "os" 7 "strings" 8 "sync" 9 10 "github.com/phuslu/log" 11 "github.com/samber/lo" 12 13 "github.com/yaling888/clash/adapter" 14 "github.com/yaling888/clash/adapter/outboundgroup" 15 "github.com/yaling888/clash/component/auth" 16 "github.com/yaling888/clash/component/dialer" 17 "github.com/yaling888/clash/component/iface" 18 "github.com/yaling888/clash/component/profile" 19 "github.com/yaling888/clash/component/profile/cachefile" 20 "github.com/yaling888/clash/component/resolver" 21 "github.com/yaling888/clash/component/trie" 22 "github.com/yaling888/clash/config" 23 C "github.com/yaling888/clash/constant" 24 "github.com/yaling888/clash/constant/provider" 25 "github.com/yaling888/clash/dns" 26 "github.com/yaling888/clash/listener" 27 authStore "github.com/yaling888/clash/listener/auth" 28 L "github.com/yaling888/clash/log" 29 "github.com/yaling888/clash/tunnel" 30 ) 31 32 var mux sync.Mutex 33 34 func readConfig(path string) ([]byte, error) { 35 if _, err := os.Stat(path); os.IsNotExist(err) { 36 return nil, err 37 } 38 data, err := os.ReadFile(path) 39 if err != nil { 40 return nil, err 41 } 42 43 if len(data) == 0 { 44 return nil, fmt.Errorf("configuration file %s is empty", path) 45 } 46 47 return data, err 48 } 49 50 // Parse config with default config path 51 func Parse() (*config.Config, error) { 52 return ParseWithPath(C.Path.Config()) 53 } 54 55 // ParseWithPath parse config with custom config path 56 func ParseWithPath(path string) (*config.Config, error) { 57 buf, err := readConfig(path) 58 if err != nil { 59 return nil, err 60 } 61 62 return ParseWithBytes(buf) 63 } 64 65 // ParseWithBytes config with buffer 66 func ParseWithBytes(buf []byte) (*config.Config, error) { 67 return config.Parse(buf) 68 } 69 70 // ApplyConfig dispatch configure to all parts 71 func ApplyConfig(cfg *config.Config, force bool) { 72 mux.Lock() 73 defer mux.Unlock() 74 75 updateUsers(cfg.Users) 76 updateProxies(cfg.Proxies, cfg.Providers) 77 updateRules(cfg.Rules) 78 updateScript(cfg.RuleProviders, cfg.MainMatcher) 79 updateHosts(cfg.Hosts) 80 updateMitm(cfg.Mitm) 81 updateProfile(cfg) 82 updateDNS(cfg.DNS, &cfg.General.Tun) 83 updateGeneral(cfg.General, force) 84 updateInbounds(cfg.Inbounds, force) 85 updateExperimental(cfg) 86 updateTunnels(cfg.Tunnels) 87 88 L.SetLevel(cfg.General.LogLevel) 89 } 90 91 func GetGeneral() *config.General { 92 ports := listener.GetPorts() 93 auths := make([]string, 0) 94 if authM := authStore.Authenticator(); authM != nil { 95 auths = lo.Map(authM.Users(), func(s string, _ int) string { 96 l := len(s) 97 if l == 0 { 98 return "" 99 } 100 return fmt.Sprintf("%s****%s", s[0:1], s[l-1:l]) 101 }) 102 } 103 104 general := &config.General{ 105 LegacyInbound: config.LegacyInbound{ 106 Port: ports.Port, 107 SocksPort: ports.SocksPort, 108 RedirPort: ports.RedirPort, 109 TProxyPort: ports.TProxyPort, 110 MixedPort: ports.MixedPort, 111 MitmPort: ports.MitmPort, 112 AllowLan: listener.AllowLan(), 113 BindAddress: listener.BindAddress(), 114 }, 115 Authentication: auths, 116 Mode: tunnel.Mode(), 117 LogLevel: L.Level(), 118 IPv6: !resolver.DisableIPv6, 119 Sniffing: tunnel.Sniffing(), 120 Tun: C.GetTunConf(), 121 } 122 123 return general 124 } 125 126 func updateExperimental(c *config.Config) { 127 tunnel.UDPFallbackMatch.Store(c.Experimental.UDPFallbackMatch) 128 129 udpPolicy := c.Experimental.UDPFallbackPolicy 130 if strings.EqualFold(udpPolicy, "direct") || strings.EqualFold(udpPolicy, "reject") { 131 udpPolicy = strings.ToUpper(udpPolicy) 132 } 133 tunnel.UDPFallbackPolicy.Store(udpPolicy) 134 } 135 136 func updateDNS(c *config.DNS, t *C.Tun) { 137 cfg := dns.Config{ 138 Main: c.NameServer, 139 Fallback: c.Fallback, 140 IPv6: c.IPv6, 141 EnhancedMode: c.EnhancedMode, 142 Pool: c.FakeIPRange, 143 Hosts: c.Hosts, 144 FallbackFilter: dns.FallbackFilter{ 145 GeoIP: c.FallbackFilter.GeoIP, 146 GeoIPCode: c.FallbackFilter.GeoIPCode, 147 IPCIDR: c.FallbackFilter.IPCIDR, 148 Domain: c.FallbackFilter.Domain, 149 GeoSite: c.FallbackFilter.GeoSite, 150 }, 151 Default: c.DefaultNameserver, 152 Policy: c.NameServerPolicy, 153 ProxyServer: c.ProxyServerNameserver, 154 Remote: c.RemoteNameserver, 155 SearchDomains: c.SearchDomains, 156 } 157 158 r := dns.NewResolver(cfg) 159 m := dns.NewEnhancer(cfg) 160 161 // reuse cache of old host mapper 162 if old := resolver.DefaultHostMapper; old != nil { 163 m.PatchFrom(old.(*dns.ResolverEnhancer)) 164 } 165 166 resolver.DefaultResolver = r 167 resolver.DefaultHostMapper = m 168 resolver.DefaultLocalServer = dns.NewLocalServer(r, m) 169 170 resolver.RemoteDnsResolve = c.RemoteDnsResolve 171 172 if c.Enable { 173 dns.ReCreateServer(c.Listen, r, m) 174 } else { 175 if !t.Enable { 176 resolver.DefaultResolver = nil 177 resolver.DefaultHostMapper = nil 178 resolver.DefaultLocalServer = nil 179 } 180 dns.ReCreateServer("", nil, nil) 181 } 182 183 if cfg.Pool != nil { 184 t.TunAddressPrefix = cfg.Pool.IPNet() 185 } 186 } 187 188 func updateHosts(tree *trie.DomainTrie[netip.Addr]) { 189 resolver.DefaultHosts = tree 190 } 191 192 func updateProxies(proxies map[string]C.Proxy, providers map[string]provider.ProxyProvider) { 193 tunnel.UpdateProxies(proxies, providers) 194 } 195 196 func updateRules(rules []C.Rule) { 197 tunnel.UpdateRules(rules) 198 } 199 200 func updateScript(providers map[string]C.Rule, matcher C.Matcher) { 201 tunnel.UpdateScript(providers, matcher) 202 } 203 204 func updateMitm(mitm *config.Mitm) { 205 tunnel.UpdateRewrites(mitm.Hosts, mitm.Rules) 206 } 207 208 func updateTunnels(tunnels []config.Tunnel) { 209 listener.PatchTunnel(tunnels, tunnel.TCPIn(), tunnel.UDPIn()) 210 } 211 212 func updateInbounds(inbounds []C.Inbound, force bool) { 213 if !force { 214 return 215 } 216 tcpIn := tunnel.TCPIn() 217 udpIn := tunnel.UDPIn() 218 219 listener.ReCreateListeners(inbounds, tcpIn, udpIn) 220 } 221 222 func updateGeneral(general *config.General, force bool) { 223 tunnel.SetMode(general.Mode) 224 resolver.SetDisableIPv6(!general.IPv6) 225 226 defaultInterface := general.Interface 227 if defaultInterface != "" || (defaultInterface == "" && !general.Tun.Enable) { 228 dialer.DefaultInterface.Store(defaultInterface) 229 if defaultInterface != "" { 230 log.Info().Str("name", defaultInterface).Msg("[Config] default interface") 231 } 232 } 233 234 if general.RoutingMark > 0 || (general.RoutingMark == 0 && general.TProxyPort == 0) { 235 dialer.DefaultRoutingMark.Store(int32(general.RoutingMark)) 236 if general.RoutingMark > 0 { 237 log.Info().Int("mark", general.RoutingMark).Msg("[Config] routing") 238 } 239 } 240 241 iface.FlushCache() 242 243 if !force { 244 return 245 } 246 247 allowLan := general.AllowLan 248 listener.SetAllowLan(allowLan) 249 250 bindAddress := general.BindAddress 251 listener.SetBindAddress(bindAddress) 252 253 sniffing := general.Sniffing 254 tunnel.SetSniffing(sniffing) 255 256 log.Info().Bool("sniffing", sniffing).Msg("[Config] tls") 257 258 general.Tun.StopRouteListener = true 259 260 tcpIn := tunnel.TCPIn() 261 udpIn := tunnel.UDPIn() 262 ports := listener.Ports{ 263 Port: general.Port, 264 SocksPort: general.SocksPort, 265 RedirPort: general.RedirPort, 266 TProxyPort: general.TProxyPort, 267 MixedPort: general.MixedPort, 268 MitmPort: general.MitmPort, 269 } 270 271 listener.ReCreatePortsListeners(ports, tcpIn, udpIn) 272 listener.ReCreateAutoRedir(general.EBpf.AutoRedir, defaultInterface, tcpIn, udpIn) 273 listener.ReCreateTun(&general.Tun, tcpIn, udpIn) 274 listener.ReCreateRedirToTun(general.EBpf.RedirectToTun) 275 } 276 277 func updateUsers(users []auth.AuthUser) { 278 authenticator := auth.NewAuthenticator(users) 279 authStore.SetAuthenticator(authenticator) 280 if authenticator != nil { 281 log.Info().Msg("[Inbound] authentication of local server updated") 282 } 283 } 284 285 func updateProfile(cfg *config.Config) { 286 profileCfg := cfg.Profile 287 288 profile.StoreSelected.Store(profileCfg.StoreSelected) 289 if profileCfg.StoreSelected { 290 patchSelectGroup(cfg.Proxies) 291 } 292 293 L.SetTracing(profileCfg.Tracing) 294 } 295 296 func patchSelectGroup(proxies map[string]C.Proxy) { 297 mapping := cachefile.Cache().SelectedMap() 298 if mapping == nil { 299 return 300 } 301 302 for name, proxy := range proxies { 303 outbound, ok := proxy.(*adapter.Proxy) 304 if !ok { 305 continue 306 } 307 308 selector, ok := outbound.ProxyAdapter.(*outboundgroup.Selector) 309 if !ok { 310 continue 311 } 312 313 selected, exist := mapping[name] 314 if !exist { 315 continue 316 } 317 318 _ = selector.Set(selected) 319 } 320 } 321 322 func Shutdown() { 323 listener.Cleanup() 324 resolver.StoreFakePoolState() 325 326 L.SetLevel(L.INFO) 327 log.Info().Msg("[Main] Clash shutting down") 328 }