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  }