github.com/kelleygo/clashcore@v1.0.2/hub/executor/executor.go (about) 1 package executor 2 3 import ( 4 "fmt" 5 "net" 6 "net/netip" 7 "os" 8 "runtime" 9 "strconv" 10 "sync" 11 "time" 12 13 "github.com/kelleygo/clashcore/adapter" 14 "github.com/kelleygo/clashcore/adapter/inbound" 15 "github.com/kelleygo/clashcore/adapter/outboundgroup" 16 "github.com/kelleygo/clashcore/component/auth" 17 "github.com/kelleygo/clashcore/component/ca" 18 "github.com/kelleygo/clashcore/component/dialer" 19 G "github.com/kelleygo/clashcore/component/geodata" 20 "github.com/kelleygo/clashcore/component/iface" 21 "github.com/kelleygo/clashcore/component/profile" 22 "github.com/kelleygo/clashcore/component/profile/cachefile" 23 "github.com/kelleygo/clashcore/component/resolver" 24 SNI "github.com/kelleygo/clashcore/component/sniffer" 25 "github.com/kelleygo/clashcore/component/trie" 26 "github.com/kelleygo/clashcore/config" 27 C "github.com/kelleygo/clashcore/constant" 28 "github.com/kelleygo/clashcore/constant/features" 29 "github.com/kelleygo/clashcore/constant/provider" 30 "github.com/kelleygo/clashcore/dns" 31 "github.com/kelleygo/clashcore/listener" 32 authStore "github.com/kelleygo/clashcore/listener/auth" 33 LC "github.com/kelleygo/clashcore/listener/config" 34 "github.com/kelleygo/clashcore/listener/inner" 35 "github.com/kelleygo/clashcore/listener/tproxy" 36 "github.com/kelleygo/clashcore/log" 37 "github.com/kelleygo/clashcore/ntp" 38 "github.com/kelleygo/clashcore/tunnel" 39 ) 40 41 var mux sync.Mutex 42 43 func readConfig(path string) ([]byte, error) { 44 if _, err := os.Stat(path); os.IsNotExist(err) { 45 return nil, err 46 } 47 data, err := os.ReadFile(path) 48 if err != nil { 49 return nil, err 50 } 51 52 if len(data) == 0 { 53 return nil, fmt.Errorf("configuration file %s is empty", path) 54 } 55 56 return data, err 57 } 58 59 // Parse config with default config path 60 func Parse() (*config.Config, error) { 61 return ParseWithPath(C.Path.Config()) 62 } 63 64 // ParseWithPath parse config with custom config path 65 func ParseWithPath(path string) (*config.Config, error) { 66 buf, err := readConfig(path) 67 if err != nil { 68 return nil, err 69 } 70 71 return ParseWithBytes(buf) 72 } 73 74 // ParseWithBytes config with buffer 75 func ParseWithBytes(buf []byte) (*config.Config, error) { 76 return config.Parse(buf) 77 } 78 79 // ApplyConfig dispatch configure to all parts 80 func ApplyConfig(cfg *config.Config, force bool) { 81 mux.Lock() 82 defer mux.Unlock() 83 84 tunnel.OnSuspend() 85 86 ca.ResetCertificate() 87 for _, c := range cfg.TLS.CustomTrustCert { 88 if err := ca.AddCertificate(c); err != nil { 89 log.Warnln("%s\nadd error: %s", c, err.Error()) 90 } 91 } 92 93 updateUsers(cfg.Users) 94 updateProxies(cfg.Proxies, cfg.Providers) 95 updateRules(cfg.Rules, cfg.SubRules, cfg.RuleProviders) 96 updateSniffer(cfg.Sniffer) 97 updateHosts(cfg.Hosts) 98 updateGeneral(cfg.General) 99 updateNTP(cfg.NTP) 100 updateDNS(cfg.DNS, cfg.RuleProviders, cfg.General.IPv6) 101 updateListeners(cfg.General, cfg.Listeners, force) 102 updateIPTables(cfg) 103 updateTun(cfg.General) 104 updateExperimental(cfg) 105 updateTunnels(cfg.Tunnels) 106 107 tunnel.OnInnerLoading() 108 109 initInnerTcp() 110 loadProxyProvider(cfg.Providers) 111 updateProfile(cfg) 112 loadRuleProvider(cfg.RuleProviders) 113 runtime.GC() 114 tunnel.OnRunning() 115 hcCompatibleProvider(cfg.Providers) 116 117 log.SetLevel(cfg.General.LogLevel) 118 } 119 120 func initInnerTcp() { 121 inner.New(tunnel.Tunnel) 122 } 123 124 func GetGeneral() *config.General { 125 ports := listener.GetPorts() 126 var authenticator []string 127 if auth := authStore.Authenticator(); auth != nil { 128 authenticator = auth.Users() 129 } 130 131 general := &config.General{ 132 Inbound: config.Inbound{ 133 Port: ports.Port, 134 SocksPort: ports.SocksPort, 135 RedirPort: ports.RedirPort, 136 TProxyPort: ports.TProxyPort, 137 MixedPort: ports.MixedPort, 138 Tun: listener.GetTunConf(), 139 TuicServer: listener.GetTuicConf(), 140 ShadowSocksConfig: ports.ShadowSocksConfig, 141 VmessConfig: ports.VmessConfig, 142 Authentication: authenticator, 143 SkipAuthPrefixes: inbound.SkipAuthPrefixes(), 144 LanAllowedIPs: inbound.AllowedIPs(), 145 LanDisAllowedIPs: inbound.DisAllowedIPs(), 146 AllowLan: listener.AllowLan(), 147 BindAddress: listener.BindAddress(), 148 }, 149 Controller: config.Controller{}, 150 Mode: tunnel.Mode(), 151 LogLevel: log.Level(), 152 IPv6: !resolver.DisableIPv6, 153 GeodataMode: G.GeodataMode(), 154 GeoAutoUpdate: G.GeoAutoUpdate(), 155 GeoUpdateInterval: G.GeoUpdateInterval(), 156 GeodataLoader: G.LoaderName(), 157 GeositeMatcher: G.SiteMatcherName(), 158 Interface: dialer.DefaultInterface.Load(), 159 Sniffing: tunnel.IsSniffing(), 160 TCPConcurrent: dialer.GetTcpConcurrent(), 161 } 162 163 return general 164 } 165 166 func updateListeners(general *config.General, listeners map[string]C.InboundListener, force bool) { 167 listener.PatchInboundListeners(listeners, tunnel.Tunnel, true) 168 if !force { 169 return 170 } 171 172 allowLan := general.AllowLan 173 listener.SetAllowLan(allowLan) 174 inbound.SetSkipAuthPrefixes(general.SkipAuthPrefixes) 175 inbound.SetAllowedIPs(general.LanAllowedIPs) 176 inbound.SetDisAllowedIPs(general.LanDisAllowedIPs) 177 178 bindAddress := general.BindAddress 179 listener.SetBindAddress(bindAddress) 180 listener.ReCreateHTTP(general.Port, tunnel.Tunnel) 181 listener.ReCreateSocks(general.SocksPort, tunnel.Tunnel) 182 listener.ReCreateRedir(general.RedirPort, tunnel.Tunnel) 183 if !features.CMFA { 184 listener.ReCreateAutoRedir(general.EBpf.AutoRedir, tunnel.Tunnel) 185 } 186 listener.ReCreateTProxy(general.TProxyPort, tunnel.Tunnel) 187 listener.ReCreateMixed(general.MixedPort, tunnel.Tunnel) 188 listener.ReCreateShadowSocks(general.ShadowSocksConfig, tunnel.Tunnel) 189 listener.ReCreateVmess(general.VmessConfig, tunnel.Tunnel) 190 listener.ReCreateTuic(general.TuicServer, tunnel.Tunnel) 191 } 192 193 func updateExperimental(c *config.Config) { 194 if c.Experimental.QUICGoDisableGSO { 195 _ = os.Setenv("QUIC_GO_DISABLE_GSO", strconv.FormatBool(true)) 196 } 197 if c.Experimental.QUICGoDisableECN { 198 _ = os.Setenv("QUIC_GO_DISABLE_ECN", strconv.FormatBool(true)) 199 } 200 dialer.GetIP4PEnable(c.Experimental.IP4PEnable) 201 } 202 203 func updateNTP(c *config.NTP) { 204 if c.Enable { 205 ntp.ReCreateNTPService( 206 net.JoinHostPort(c.Server, strconv.Itoa(c.Port)), 207 time.Duration(c.Interval), 208 c.DialerProxy, 209 c.WriteToSystem, 210 ) 211 } 212 } 213 214 func updateDNS(c *config.DNS, ruleProvider map[string]provider.RuleProvider, generalIPv6 bool) { 215 if !c.Enable { 216 resolver.DefaultResolver = nil 217 resolver.DefaultHostMapper = nil 218 resolver.DefaultLocalServer = nil 219 dns.ReCreateServer("", nil, nil) 220 return 221 } 222 cfg := dns.Config{ 223 Main: c.NameServer, 224 Fallback: c.Fallback, 225 IPv6: c.IPv6 && generalIPv6, 226 IPv6Timeout: c.IPv6Timeout, 227 EnhancedMode: c.EnhancedMode, 228 Pool: c.FakeIPRange, 229 Hosts: c.Hosts, 230 FallbackFilter: dns.FallbackFilter{ 231 GeoIP: c.FallbackFilter.GeoIP, 232 GeoIPCode: c.FallbackFilter.GeoIPCode, 233 IPCIDR: c.FallbackFilter.IPCIDR, 234 Domain: c.FallbackFilter.Domain, 235 GeoSite: c.FallbackFilter.GeoSite, 236 }, 237 Default: c.DefaultNameserver, 238 Policy: c.NameServerPolicy, 239 ProxyServer: c.ProxyServerNameserver, 240 RuleProviders: ruleProvider, 241 CacheAlgorithm: c.CacheAlgorithm, 242 } 243 244 r := dns.NewResolver(cfg) 245 pr := dns.NewProxyServerHostResolver(r) 246 m := dns.NewEnhancer(cfg) 247 248 // reuse cache of old host mapper 249 if old := resolver.DefaultHostMapper; old != nil { 250 m.PatchFrom(old.(*dns.ResolverEnhancer)) 251 } 252 253 resolver.DefaultResolver = r 254 resolver.DefaultHostMapper = m 255 resolver.DefaultLocalServer = dns.NewLocalServer(r, m) 256 257 if pr.Invalid() { 258 resolver.ProxyServerHostResolver = pr 259 } 260 261 dns.ReCreateServer(c.Listen, r, m) 262 } 263 264 func updateHosts(tree *trie.DomainTrie[resolver.HostValue]) { 265 resolver.DefaultHosts = resolver.NewHosts(tree) 266 } 267 268 func updateProxies(proxies map[string]C.Proxy, providers map[string]provider.ProxyProvider) { 269 tunnel.UpdateProxies(proxies, providers) 270 } 271 272 func updateRules(rules []C.Rule, subRules map[string][]C.Rule, ruleProviders map[string]provider.RuleProvider) { 273 tunnel.UpdateRules(rules, subRules, ruleProviders) 274 } 275 276 func loadProvider(pv provider.Provider) { 277 if pv.VehicleType() == provider.Compatible { 278 return 279 } else { 280 log.Infoln("Start initial provider %s", (pv).Name()) 281 } 282 283 if err := pv.Initial(); err != nil { 284 switch pv.Type() { 285 case provider.Proxy: 286 { 287 log.Errorln("initial proxy provider %s error: %v", (pv).Name(), err) 288 } 289 case provider.Rule: 290 { 291 log.Errorln("initial rule provider %s error: %v", (pv).Name(), err) 292 } 293 294 } 295 } 296 } 297 298 func loadRuleProvider(ruleProviders map[string]provider.RuleProvider) { 299 wg := sync.WaitGroup{} 300 ch := make(chan struct{}, concurrentCount) 301 for _, ruleProvider := range ruleProviders { 302 ruleProvider := ruleProvider 303 wg.Add(1) 304 ch <- struct{}{} 305 go func() { 306 defer func() { <-ch; wg.Done() }() 307 loadProvider(ruleProvider) 308 309 }() 310 } 311 312 wg.Wait() 313 } 314 315 func loadProxyProvider(proxyProviders map[string]provider.ProxyProvider) { 316 // limit concurrent size 317 wg := sync.WaitGroup{} 318 ch := make(chan struct{}, concurrentCount) 319 for _, proxyProvider := range proxyProviders { 320 proxyProvider := proxyProvider 321 wg.Add(1) 322 ch <- struct{}{} 323 go func() { 324 defer func() { <-ch; wg.Done() }() 325 loadProvider(proxyProvider) 326 }() 327 } 328 329 wg.Wait() 330 } 331 func hcCompatibleProvider(proxyProviders map[string]provider.ProxyProvider) { 332 // limit concurrent size 333 wg := sync.WaitGroup{} 334 ch := make(chan struct{}, concurrentCount) 335 for _, proxyProvider := range proxyProviders { 336 proxyProvider := proxyProvider 337 if proxyProvider.VehicleType() == provider.Compatible { 338 log.Infoln("Start initial Compatible provider %s", proxyProvider.Name()) 339 wg.Add(1) 340 ch <- struct{}{} 341 go func() { 342 defer func() { <-ch; wg.Done() }() 343 if err := proxyProvider.Initial(); err != nil { 344 log.Errorln("initial Compatible provider %s error: %v", proxyProvider.Name(), err) 345 } 346 }() 347 } 348 349 } 350 351 } 352 func updateTun(general *config.General) { 353 if general == nil { 354 return 355 } 356 listener.ReCreateTun(general.Tun, tunnel.Tunnel) 357 listener.ReCreateRedirToTun(general.Tun.RedirectToTun) 358 } 359 360 func updateSniffer(sniffer *config.Sniffer) { 361 if sniffer.Enable { 362 dispatcher, err := SNI.NewSnifferDispatcher( 363 sniffer.Sniffers, sniffer.ForceDomain, sniffer.SkipDomain, 364 sniffer.ForceDnsMapping, sniffer.ParsePureIp, 365 ) 366 if err != nil { 367 log.Warnln("initial sniffer failed, err:%v", err) 368 } 369 370 tunnel.UpdateSniffer(dispatcher) 371 log.Infoln("Sniffer is loaded and working") 372 } else { 373 dispatcher, err := SNI.NewCloseSnifferDispatcher() 374 if err != nil { 375 log.Warnln("initial sniffer failed, err:%v", err) 376 } 377 378 tunnel.UpdateSniffer(dispatcher) 379 log.Infoln("Sniffer is closed") 380 } 381 } 382 383 func updateTunnels(tunnels []LC.Tunnel) { 384 listener.PatchTunnel(tunnels, tunnel.Tunnel) 385 } 386 387 func updateGeneral(general *config.General) { 388 tunnel.SetMode(general.Mode) 389 tunnel.SetFindProcessMode(general.FindProcessMode) 390 resolver.DisableIPv6 = !general.IPv6 391 392 if general.TCPConcurrent { 393 dialer.SetTcpConcurrent(general.TCPConcurrent) 394 log.Infoln("Use tcp concurrent") 395 } 396 397 inbound.SetTfo(general.InboundTfo) 398 inbound.SetMPTCP(general.InboundMPTCP) 399 400 adapter.UnifiedDelay.Store(general.UnifiedDelay) 401 402 dialer.DefaultInterface.Store(general.Interface) 403 dialer.DefaultRoutingMark.Store(int32(general.RoutingMark)) 404 if general.RoutingMark > 0 { 405 log.Infoln("Use routing mark: %#x", general.RoutingMark) 406 } 407 408 iface.FlushCache() 409 G.SetLoader(general.GeodataLoader) 410 G.SetSiteMatcher(general.GeositeMatcher) 411 } 412 413 func updateUsers(users []auth.AuthUser) { 414 authenticator := auth.NewAuthenticator(users) 415 authStore.SetAuthenticator(authenticator) 416 if authenticator != nil { 417 log.Infoln("Authentication of local server updated") 418 } 419 } 420 421 func updateProfile(cfg *config.Config) { 422 profileCfg := cfg.Profile 423 424 profile.StoreSelected.Store(profileCfg.StoreSelected) 425 if profileCfg.StoreSelected { 426 patchSelectGroup(cfg.Proxies) 427 } 428 } 429 430 func patchSelectGroup(proxies map[string]C.Proxy) { 431 mapping := cachefile.Cache().SelectedMap() 432 if mapping == nil { 433 return 434 } 435 436 for name, proxy := range proxies { 437 outbound, ok := proxy.(*adapter.Proxy) 438 if !ok { 439 continue 440 } 441 442 selector, ok := outbound.ProxyAdapter.(outboundgroup.SelectAble) 443 if !ok { 444 continue 445 } 446 447 selected, exist := mapping[name] 448 if !exist { 449 continue 450 } 451 452 selector.ForceSet(selected) 453 } 454 } 455 456 func updateIPTables(cfg *config.Config) { 457 tproxy.CleanupTProxyIPTables() 458 459 iptables := cfg.IPTables 460 if runtime.GOOS != "linux" || !iptables.Enable { 461 return 462 } 463 464 var err error 465 defer func() { 466 if err != nil { 467 log.Errorln("[IPTABLES] setting iptables failed: %s", err.Error()) 468 os.Exit(2) 469 } 470 }() 471 472 if cfg.General.Tun.Enable { 473 err = fmt.Errorf("when tun is enabled, iptables cannot be set automatically") 474 return 475 } 476 477 var ( 478 inboundInterface = "lo" 479 bypass = iptables.Bypass 480 tProxyPort = cfg.General.TProxyPort 481 dnsCfg = cfg.DNS 482 DnsRedirect = iptables.DnsRedirect 483 484 dnsPort netip.AddrPort 485 ) 486 487 if tProxyPort == 0 { 488 err = fmt.Errorf("tproxy-port must be greater than zero") 489 return 490 } 491 492 if DnsRedirect { 493 if !dnsCfg.Enable { 494 err = fmt.Errorf("DNS server must be enable") 495 return 496 } 497 498 dnsPort, err = netip.ParseAddrPort(dnsCfg.Listen) 499 if err != nil { 500 err = fmt.Errorf("DNS server must be correct") 501 return 502 } 503 } 504 505 if iptables.InboundInterface != "" { 506 inboundInterface = iptables.InboundInterface 507 } 508 509 if dialer.DefaultRoutingMark.Load() == 0 { 510 dialer.DefaultRoutingMark.Store(2158) 511 } 512 513 err = tproxy.SetTProxyIPTables(inboundInterface, bypass, uint16(tProxyPort), DnsRedirect, dnsPort.Port()) 514 if err != nil { 515 return 516 } 517 518 log.Infoln("[IPTABLES] Setting iptables completed") 519 } 520 521 func Shutdown() { 522 listener.Cleanup() 523 tproxy.CleanupTProxyIPTables() 524 resolver.StoreFakePoolState() 525 526 log.Warnln("YiClashCore shutting down") 527 }