mihomo/hub/executor/executor.go
gVisor bot 6c56a3b80e feat: add domain list for sniffer, reverse force logic
when force is false, if domain in the list, will force replace
when force is true, if sniff domain in the list, will skip it
2022-04-16 08:21:31 +08:00

400 lines
9.3 KiB
Go

package executor
import (
"fmt"
"net"
"net/netip"
"os"
"runtime"
"strconv"
"sync"
"github.com/Dreamacro/clash/adapter"
"github.com/Dreamacro/clash/adapter/outboundgroup"
"github.com/Dreamacro/clash/component/auth"
"github.com/Dreamacro/clash/component/dialer"
G "github.com/Dreamacro/clash/component/geodata"
"github.com/Dreamacro/clash/component/iface"
"github.com/Dreamacro/clash/component/profile"
"github.com/Dreamacro/clash/component/profile/cachefile"
"github.com/Dreamacro/clash/component/resolver"
SNI "github.com/Dreamacro/clash/component/sniffer"
"github.com/Dreamacro/clash/component/trie"
"github.com/Dreamacro/clash/config"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/constant/provider"
"github.com/Dreamacro/clash/dns"
P "github.com/Dreamacro/clash/listener"
authStore "github.com/Dreamacro/clash/listener/auth"
"github.com/Dreamacro/clash/listener/tproxy"
"github.com/Dreamacro/clash/log"
"github.com/Dreamacro/clash/tunnel"
)
var mux sync.Mutex
func readConfig(path string) ([]byte, error) {
if _, err := os.Stat(path); os.IsNotExist(err) {
return nil, err
}
data, err := os.ReadFile(path)
if err != nil {
return nil, err
}
if len(data) == 0 {
return nil, fmt.Errorf("configuration file %s is empty", path)
}
return data, err
}
// Parse config with default config path
func Parse() (*config.Config, error) {
return ParseWithPath(C.Path.Config())
}
// ParseWithPath parse config with custom config path
func ParseWithPath(path string) (*config.Config, error) {
buf, err := readConfig(path)
if err != nil {
return nil, err
}
return ParseWithBytes(buf)
}
// ParseWithBytes config with buffer
func ParseWithBytes(buf []byte) (*config.Config, error) {
return config.Parse(buf)
}
// ApplyConfig dispatch configure to all parts
func ApplyConfig(cfg *config.Config, force bool) {
mux.Lock()
defer mux.Unlock()
updateUsers(cfg.Users)
updateProxies(cfg.Proxies, cfg.Providers)
updateRules(cfg.Rules, cfg.RuleProviders)
updateDNS(cfg.DNS, cfg.Tun)
updateGeneral(cfg.General, force)
updateIPTables(cfg)
updateSniffer(cfg.Sniffer)
updateTun(cfg.Tun, cfg.DNS)
updateExperimental(cfg)
updateHosts(cfg.Hosts)
loadProvider(cfg.RuleProviders, cfg.Providers)
updateProfile(cfg)
log.SetLevel(cfg.General.LogLevel)
}
func GetGeneral() *config.General {
ports := P.GetPorts()
var authenticator []string
if auth := authStore.Authenticator(); auth != nil {
authenticator = auth.Users()
}
general := &config.General{
Inbound: config.Inbound{
Port: ports.Port,
SocksPort: ports.SocksPort,
RedirPort: ports.RedirPort,
TProxyPort: ports.TProxyPort,
MixedPort: ports.MixedPort,
Authentication: authenticator,
AllowLan: P.AllowLan(),
BindAddress: P.BindAddress(),
},
Mode: tunnel.Mode(),
LogLevel: log.Level(),
IPv6: !resolver.DisableIPv6,
GeodataLoader: G.LoaderName(),
}
return general
}
func updateExperimental(c *config.Config) {}
func updateDNS(c *config.DNS, t *config.Tun) {
cfg := dns.Config{
Main: c.NameServer,
Fallback: c.Fallback,
IPv6: c.IPv6,
EnhancedMode: c.EnhancedMode,
Pool: c.FakeIPRange,
Hosts: c.Hosts,
FallbackFilter: dns.FallbackFilter{
GeoIP: c.FallbackFilter.GeoIP,
GeoIPCode: c.FallbackFilter.GeoIPCode,
IPCIDR: c.FallbackFilter.IPCIDR,
Domain: c.FallbackFilter.Domain,
GeoSite: c.FallbackFilter.GeoSite,
},
Default: c.DefaultNameserver,
Policy: c.NameServerPolicy,
ProxyServer: c.ProxyServerNameserver,
}
r := dns.NewResolver(cfg)
pr := dns.NewProxyServerHostResolver(r)
m := dns.NewEnhancer(cfg)
// reuse cache of old host mapper
if old := resolver.DefaultHostMapper; old != nil {
m.PatchFrom(old.(*dns.ResolverEnhancer))
}
resolver.DefaultResolver = r
resolver.DefaultHostMapper = m
if pr.HasProxyServer() {
resolver.ProxyServerHostResolver = pr
}
if t.Enable {
resolver.DefaultLocalServer = dns.NewLocalServer(r, m)
}
if c.Enable {
dns.ReCreateServer(c.Listen, r, m)
} else {
if !t.Enable {
resolver.DefaultResolver = nil
resolver.DefaultHostMapper = nil
resolver.DefaultLocalServer = nil
resolver.ProxyServerHostResolver = nil
}
dns.ReCreateServer("", nil, nil)
}
}
func updateHosts(tree *trie.DomainTrie[netip.Addr]) {
resolver.DefaultHosts = tree
}
func updateProxies(proxies map[string]C.Proxy, providers map[string]provider.ProxyProvider) {
tunnel.UpdateProxies(proxies, providers)
}
func updateRules(rules []C.Rule, ruleProviders map[string]*provider.RuleProvider) {
tunnel.UpdateRules(rules, ruleProviders)
}
func loadProvider(ruleProviders map[string]*provider.RuleProvider, proxyProviders map[string]provider.ProxyProvider) {
load := func(pv provider.Provider) {
if pv.VehicleType() == provider.Compatible {
log.Infoln("Start initial compatible provider %s", pv.Name())
} else {
log.Infoln("Start initial provider %s", (pv).Name())
}
if err := (pv).Initial(); err != nil {
switch pv.Type() {
case provider.Proxy:
{
log.Warnln("initial proxy provider %s error: %v", (pv).Name(), err)
}
case provider.Rule:
{
log.Warnln("initial rule provider %s error: %v", (pv).Name(), err)
}
}
}
}
for _, proxyProvider := range proxyProviders {
load(proxyProvider)
}
for _, ruleProvider := range ruleProviders {
load(*ruleProvider)
}
}
func updateTun(tun *config.Tun, dns *config.DNS) {
P.ReCreateTun(tun, dns, tunnel.TCPIn(), tunnel.UDPIn())
}
func updateSniffer(sniffer *config.Sniffer) {
if sniffer.Enable {
dispatcher, err := SNI.NewSnifferDispatcher(sniffer.Sniffers, sniffer.Force, &sniffer.Reverses)
if err != nil {
log.Warnln("initial sniffer failed, err:%v", err)
}
tunnel.UpdateSniffer(dispatcher)
log.Infoln("Sniffer is loaded and working")
} else {
dispatcher, err := SNI.NewCloseSnifferDispatcher()
if err != nil {
log.Warnln("initial sniffer failed, err:%v", err)
}
tunnel.UpdateSniffer(dispatcher)
log.Infoln("Sniffer is closed")
}
}
func updateGeneral(general *config.General, force bool) {
log.SetLevel(general.LogLevel)
tunnel.SetMode(general.Mode)
resolver.DisableIPv6 = !general.IPv6
adapter.UnifiedDelay.Store(general.UnifiedDelay)
dialer.DefaultInterface.Store(general.Interface)
if dialer.DefaultInterface.Load() != "" {
log.Infoln("Use interface name: %s", general.Interface)
}
dialer.DefaultRoutingMark.Store(int32(general.RoutingMark))
if general.RoutingMark > 0 {
log.Infoln("Use routing mark: %#x", general.RoutingMark)
}
iface.FlushCache()
if !force {
return
}
geodataLoader := general.GeodataLoader
G.SetLoader(geodataLoader)
allowLan := general.AllowLan
P.SetAllowLan(allowLan)
bindAddress := general.BindAddress
P.SetBindAddress(bindAddress)
tcpIn := tunnel.TCPIn()
udpIn := tunnel.UDPIn()
P.ReCreateHTTP(general.Port, tcpIn)
P.ReCreateSocks(general.SocksPort, tcpIn, udpIn)
P.ReCreateRedir(general.RedirPort, tcpIn, udpIn)
P.ReCreateTProxy(general.TProxyPort, tcpIn, udpIn)
P.ReCreateMixed(general.MixedPort, tcpIn, udpIn)
}
func updateUsers(users []auth.AuthUser) {
authenticator := auth.NewAuthenticator(users)
authStore.SetAuthenticator(authenticator)
if authenticator != nil {
log.Infoln("Authentication of local server updated")
}
}
func updateProfile(cfg *config.Config) {
profileCfg := cfg.Profile
profile.StoreSelected.Store(profileCfg.StoreSelected)
if profileCfg.StoreSelected {
patchSelectGroup(cfg.Proxies)
}
}
func patchSelectGroup(proxies map[string]C.Proxy) {
mapping := cachefile.Cache().SelectedMap()
if mapping == nil {
return
}
for name, proxy := range proxies {
outbound, ok := proxy.(*adapter.Proxy)
if !ok {
continue
}
selector, ok := outbound.ProxyAdapter.(*outboundgroup.Selector)
if !ok {
continue
}
selected, exist := mapping[name]
if !exist {
continue
}
selector.Set(selected)
}
}
func updateIPTables(cfg *config.Config) {
tproxy.CleanupTProxyIPTables()
iptables := cfg.IPTables
if runtime.GOOS != "linux" || !iptables.Enable {
return
}
var err error
defer func() {
if err != nil {
log.Errorln("[IPTABLES] setting iptables failed: %s", err.Error())
os.Exit(2)
}
}()
if cfg.Tun.Enable {
err = fmt.Errorf("when tun is enabled, iptables cannot be set automatically")
return
}
var (
inboundInterface = "lo"
bypass = iptables.Bypass
tProxyPort = cfg.General.TProxyPort
dnsCfg = cfg.DNS
)
if tProxyPort == 0 {
err = fmt.Errorf("tproxy-port must be greater than zero")
return
}
if !dnsCfg.Enable {
err = fmt.Errorf("DNS server must be enable")
return
}
_, dnsPortStr, err := net.SplitHostPort(dnsCfg.Listen)
if err != nil {
err = fmt.Errorf("DNS server must be correct")
return
}
dnsPort, err := strconv.ParseUint(dnsPortStr, 10, 16)
if err != nil {
err = fmt.Errorf("DNS server must be correct")
return
}
if iptables.InboundInterface != "" {
inboundInterface = iptables.InboundInterface
}
if dialer.DefaultRoutingMark.Load() == 0 {
dialer.DefaultRoutingMark.Store(2158)
}
err = tproxy.SetTProxyIPTables(inboundInterface, bypass, uint16(tProxyPort), uint16(dnsPort))
if err != nil {
return
}
log.Infoln("[IPTABLES] Setting iptables completed")
}
func Shutdown() {
P.Cleanup()
tproxy.CleanupTProxyIPTables()
log.Warnln("Clash shutting down")
}