github.com/yaling888/clash@v1.53.0/tunnel/tunnel.go (about)

     1  package tunnel
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"math/rand/v2"
     7  	"net"
     8  	"net/netip"
     9  	"path/filepath"
    10  	"runtime"
    11  	"sync"
    12  	"time"
    13  
    14  	"github.com/phuslu/log"
    15  	"github.com/samber/lo"
    16  	"go.uber.org/atomic"
    17  
    18  	A "github.com/yaling888/clash/adapter"
    19  	"github.com/yaling888/clash/adapter/inbound"
    20  	"github.com/yaling888/clash/component/nat"
    21  	P "github.com/yaling888/clash/component/process"
    22  	"github.com/yaling888/clash/component/resolver"
    23  	"github.com/yaling888/clash/component/trie"
    24  	C "github.com/yaling888/clash/constant"
    25  	"github.com/yaling888/clash/constant/provider"
    26  	icontext "github.com/yaling888/clash/context"
    27  	"github.com/yaling888/clash/tunnel/statistic"
    28  )
    29  
    30  var (
    31  	tcpQueue     = make(chan C.ConnContext, 512)
    32  	udpQueue     = make(chan *inbound.PacketAdapter, 1024)
    33  	natTable     = nat.New[string, C.PacketConn]()
    34  	addrTable    = nat.New[string, netip.Addr]()
    35  	rules        []C.Rule
    36  	proxies      = make(map[string]C.Proxy)
    37  	providers    map[string]provider.ProxyProvider
    38  	rewrites     C.RewriteRule
    39  	rewriteHosts *trie.DomainTrie[bool]
    40  	configMux    sync.RWMutex
    41  
    42  	// Outbound Rule
    43  	mode = Rule
    44  
    45  	// sniffing switch
    46  	sniffing = false
    47  
    48  	// default timeout for UDP session
    49  	udpTimeout = 60 * time.Second
    50  
    51  	// mitmProxy mitm proxy
    52  	mitmProxy C.Proxy
    53  
    54  	// scriptMainMatcher script main function eval
    55  	scriptMainMatcher C.Matcher
    56  
    57  	scriptProxyProvidersGetter = func() map[string][]C.Proxy {
    58  		providersMap := make(map[string][]C.Proxy)
    59  		for k, v := range providers {
    60  			providersMap[k] = v.Proxies()
    61  		}
    62  		return providersMap
    63  	}
    64  
    65  	UDPFallbackMatch  = atomic.NewBool(false)
    66  	UDPFallbackPolicy = atomic.NewString("")
    67  )
    68  
    69  func init() {
    70  	go process()
    71  }
    72  
    73  // TCPIn return fan-in queue
    74  func TCPIn() chan<- C.ConnContext {
    75  	return tcpQueue
    76  }
    77  
    78  // UDPIn return fan-in udp queue
    79  func UDPIn() chan<- *inbound.PacketAdapter {
    80  	return udpQueue
    81  }
    82  
    83  // Rules return all rules
    84  func Rules() []C.Rule {
    85  	return rules
    86  }
    87  
    88  // UpdateRules handle update rules
    89  func UpdateRules(newRules []C.Rule) {
    90  	configMux.Lock()
    91  	rules = newRules
    92  	configMux.Unlock()
    93  }
    94  
    95  // Proxies return all proxies
    96  func Proxies() map[string]C.Proxy {
    97  	return proxies
    98  }
    99  
   100  // Providers return all compatible providers
   101  func Providers() map[string]provider.ProxyProvider {
   102  	return providers
   103  }
   104  
   105  func FindProxyByName(name string) (proxy C.Proxy, found bool) {
   106  	proxy, found = proxies[name]
   107  	if found {
   108  		return
   109  	}
   110  	pds := providers
   111  	for _, pd := range pds {
   112  		if pd.VehicleType() == provider.Compatible {
   113  			continue
   114  		}
   115  		ps := pd.Proxies()
   116  		for _, p := range ps {
   117  			if found = p.Name() == name; found {
   118  				proxy = p
   119  				return
   120  			}
   121  		}
   122  	}
   123  	return
   124  }
   125  
   126  func FetchRawProxyAdapter(proxy C.Proxy, metadata *C.Metadata) (C.Proxy, []string) {
   127  	var (
   128  		chains   = []string{proxy.Name()}
   129  		rawProxy = proxy
   130  		subProxy = proxy.Unwrap(metadata)
   131  	)
   132  	for subProxy != nil {
   133  		chains = append(chains, subProxy.Name())
   134  		rawProxy = subProxy
   135  		subProxy = subProxy.Unwrap(metadata)
   136  	}
   137  	return rawProxy, chains
   138  }
   139  
   140  // UpdateProxies handle update proxies
   141  func UpdateProxies(newProxies map[string]C.Proxy, newProviders map[string]provider.ProxyProvider) {
   142  	configMux.Lock()
   143  	old := proxies
   144  	oldPDs := providers
   145  	proxies = newProxies
   146  	providers = newProviders
   147  	C.GetScriptProxyProviders = scriptProxyProvidersGetter
   148  	statistic.DefaultManager.Cleanup()
   149  	provider.Cleanup(old, oldPDs)
   150  	configMux.Unlock()
   151  }
   152  
   153  // Mode return current mode
   154  func Mode() TunnelMode {
   155  	return mode
   156  }
   157  
   158  // SetMode change the mode of tunnel
   159  func SetMode(m TunnelMode) {
   160  	mode = m
   161  }
   162  
   163  func Sniffing() bool {
   164  	return sniffing
   165  }
   166  
   167  func SetSniffing(s bool) {
   168  	sniffing = s
   169  }
   170  
   171  // SetMitmOutbound set the MITM outbound
   172  func SetMitmOutbound(outbound C.ProxyAdapter) {
   173  	if outbound != nil {
   174  		mitmProxy = A.NewProxy(outbound)
   175  	} else {
   176  		mitmProxy = nil
   177  	}
   178  }
   179  
   180  // Rewrites return all rewrites
   181  func Rewrites() C.RewriteRule {
   182  	return rewrites
   183  }
   184  
   185  // UpdateRewrites handle update rewrites
   186  func UpdateRewrites(hosts *trie.DomainTrie[bool], rules C.RewriteRule) {
   187  	configMux.Lock()
   188  	rewriteHosts = hosts
   189  	rewrites = rules
   190  	configMux.Unlock()
   191  }
   192  
   193  // UpdateScript update script config
   194  func UpdateScript(providers map[string]C.Rule, matcher C.Matcher) {
   195  	configMux.Lock()
   196  	C.SetScriptRuleProviders(providers)
   197  	scriptMainMatcher = matcher
   198  	configMux.Unlock()
   199  }
   200  
   201  // processUDP starts a loop to handle udp packet
   202  func processUDP() {
   203  	queue := udpQueue
   204  	for conn := range queue {
   205  		handleUDPConn(conn)
   206  	}
   207  }
   208  
   209  func process() {
   210  	numUDPWorkers := 4
   211  	if num := runtime.GOMAXPROCS(0); num > numUDPWorkers {
   212  		numUDPWorkers = num
   213  	}
   214  	for i := 0; i < numUDPWorkers; i++ {
   215  		go processUDP()
   216  	}
   217  
   218  	queue := tcpQueue
   219  	for conn := range queue {
   220  		go handleTCPConn(conn)
   221  	}
   222  }
   223  
   224  func needLookupIP(metadata *C.Metadata) bool {
   225  	return resolver.MappingEnabled() && metadata.Host == "" && metadata.DstIP.IsValid()
   226  }
   227  
   228  func preHandleMetadata(metadata *C.Metadata) error {
   229  	// handle IP string on host
   230  	if ip, err := netip.ParseAddr(metadata.Host); err == nil {
   231  		metadata.DstIP = ip
   232  		metadata.Host = ""
   233  	}
   234  
   235  	// preprocess enhanced-mode metadata
   236  	if needLookupIP(metadata) {
   237  		host, exist := resolver.FindHostByIP(metadata.DstIP)
   238  		if exist {
   239  			metadata.Host = host
   240  			metadata.DNSMode = C.DNSMapping
   241  			if resolver.FakeIPEnabled() && (metadata.NetWork != C.UDP || resolver.IsFakeIP(metadata.DstIP)) {
   242  				metadata.DstIP = netip.Addr{}
   243  				metadata.DNSMode = C.DNSFakeIP
   244  			} else if node := resolver.DefaultHosts.Search(host); node != nil {
   245  				// redir-host should look up the hosts
   246  				metadata.DstIP = node.Data
   247  			}
   248  		} else if resolver.IsFakeIP(metadata.DstIP) {
   249  			return fmt.Errorf("fake DNS record %s missing", metadata.DstIP)
   250  		}
   251  	}
   252  
   253  	return nil
   254  }
   255  
   256  func resolveMetadata(_ C.PlainContext, metadata *C.Metadata) (proxy C.Proxy, rule C.Rule, err error) {
   257  	if metadata.NetWork == C.TCP && mitmProxy != nil && metadata.Type != C.MITM &&
   258  		((rewriteHosts != nil && rewriteHosts.Search(metadata.String()) != nil) || metadata.DstPort == 80) {
   259  		proxy = mitmProxy
   260  		return
   261  	}
   262  
   263  	if metadata.SpecialProxy != "" {
   264  		var exist bool
   265  		proxy, exist = FindProxyByName(metadata.SpecialProxy)
   266  		if !exist {
   267  			err = fmt.Errorf("proxy %s not found", metadata.SpecialProxy)
   268  		}
   269  		return
   270  	}
   271  
   272  	switch mode {
   273  	case Rule:
   274  		proxy, rule, err = match(metadata)
   275  	case Script:
   276  		proxy, err = matchScript(metadata)
   277  		if err != nil {
   278  			err = fmt.Errorf("execute script failed: %w", err)
   279  		}
   280  	case Direct:
   281  		proxy = proxies["DIRECT"]
   282  	case Global:
   283  		proxy = proxies["GLOBAL"]
   284  	default:
   285  		panic(fmt.Sprintf("unknown mode: %s", mode))
   286  	}
   287  	return
   288  }
   289  
   290  func resolveDNS(metadata *C.Metadata, proxy, rawProxy C.Proxy) (isRemote bool, err error) {
   291  	if metadata.Host == "" || metadata.DNSMode == C.DNSMapping {
   292  		return
   293  	}
   294  
   295  	if proxy.DisableDnsResolve() || rawProxy.DisableDnsResolve() {
   296  		isRemote = false
   297  	} else {
   298  		isRemote = resolver.RemoteDnsResolve
   299  	}
   300  
   301  	isUDP := metadata.NetWork == C.UDP
   302  
   303  	if isRemote {
   304  		var (
   305  			hasV6  = rawProxy.HasV6() && !(isUDP && metadata.Type == C.TUN)
   306  			rAddrs []netip.Addr
   307  		)
   308  		if hasV6 {
   309  			rAddrs, err = resolver.LookupIPByProxy(context.Background(), metadata.Host, rawProxy.Name())
   310  		} else {
   311  			rAddrs, err = resolver.LookupIPv4ByProxy(context.Background(), metadata.Host, rawProxy.Name())
   312  		}
   313  		if err != nil {
   314  			return
   315  		}
   316  		if isUDP {
   317  			metadata.DstIP = rAddrs[0]
   318  		} else {
   319  			if hasV6 {
   320  				v6 := lo.Filter(rAddrs, func(addr netip.Addr, _ int) bool {
   321  					return addr.Is6()
   322  				})
   323  				if len(v6) > 0 {
   324  					rAddrs = v6 // priority use ipv6
   325  				}
   326  			}
   327  			metadata.DstIP = rAddrs[rand.IntN(len(rAddrs))]
   328  		}
   329  	} else if isUDP {
   330  		err = localResolveDNS(metadata, true)
   331  	} else { // tcp
   332  		metadata.DstIP = netip.Addr{}
   333  	}
   334  	return
   335  }
   336  
   337  func localResolveDNS(metadata *C.Metadata, udp bool) (err error) {
   338  	if metadata.Resolved() {
   339  		return nil
   340  	}
   341  	var rAddrs []netip.Addr
   342  	if udp && metadata.Type == C.TUN {
   343  		rAddrs, err = resolver.LookupIPv4(context.Background(), metadata.Host)
   344  	} else {
   345  		rAddrs, err = resolver.LookupIP(context.Background(), metadata.Host)
   346  	}
   347  	if err != nil {
   348  		return err
   349  	}
   350  	if udp {
   351  		metadata.DstIP = rAddrs[0]
   352  	} else {
   353  		metadata.DstIP = rAddrs[rand.IntN(len(rAddrs))]
   354  	}
   355  	return nil
   356  }
   357  
   358  func handleUDPConn(packet *inbound.PacketAdapter) {
   359  	metadata := packet.Metadata()
   360  	if !metadata.Valid() {
   361  		log.Warn().Msgf("[Metadata] not valid: %#v", metadata)
   362  		packet.Drop()
   363  		return
   364  	}
   365  
   366  	var (
   367  		fAddr netip.Addr // make a fAddr if request ip is fakeip
   368  		rKey  string     // localAddrPort + remoteFakeIP + remotePort
   369  		key   = packet.LocalAddr().String()
   370  	)
   371  
   372  	if resolver.IsExistFakeIP(metadata.DstIP) {
   373  		fAddr = metadata.DstIP
   374  		rKey = key + fAddr.String() + metadata.DstPort.String()
   375  	}
   376  
   377  	if err := preHandleMetadata(metadata); err != nil {
   378  		log.Debug().Err(err).Msg("[Metadata] prehandle failed")
   379  		packet.Drop()
   380  		return
   381  	}
   382  
   383  	log.Debug().EmbedObject(metadata).Any("inbound", metadata.Type).Msg("[UDP] accept session")
   384  
   385  	handle := func() bool {
   386  		pc := natTable.Get(key)
   387  		if pc != nil {
   388  			if !metadata.Resolved() {
   389  				if rAddr := addrTable.Get(rKey); rAddr.IsValid() {
   390  					metadata.DstIP = rAddr
   391  				} else {
   392  					return false
   393  				}
   394  			}
   395  			_ = handleUDPToRemote(packet, pc, metadata)
   396  			return true
   397  		}
   398  		return false
   399  	}
   400  
   401  	if handle() {
   402  		packet.Drop()
   403  		return
   404  	}
   405  
   406  	lockKey := key + "-lock"
   407  	cond, loaded := natTable.GetOrCreateLock(lockKey)
   408  
   409  	go func() {
   410  		defer packet.Drop()
   411  
   412  		if loaded {
   413  			cond.L.Lock()
   414  			cond.Wait()
   415  			handle()
   416  			cond.L.Unlock()
   417  			return
   418  		}
   419  
   420  		defer func() {
   421  			natTable.Delete(lockKey)
   422  			cond.Broadcast()
   423  		}()
   424  
   425  		pCtx := icontext.NewPacketConnContext(metadata)
   426  		proxy, rule, err := resolveMetadata(pCtx, metadata)
   427  		if err != nil {
   428  			log.Warn().Err(err).Msg("[Metadata] parse failed")
   429  			return
   430  		}
   431  
   432  		rawProxy, chains := FetchRawProxyAdapter(proxy, metadata)
   433  
   434  		isRemote, err := resolveDNS(metadata, proxy, rawProxy)
   435  		if err != nil {
   436  			if isRemote {
   437  				log.Warn().Err(err).
   438  					Str("proxy", rawProxy.Name()).
   439  					Str("host", metadata.Host).
   440  					Msg("[UDP] remote resolve DNS failed")
   441  			} else {
   442  				log.Warn().Err(err).
   443  					Str("host", metadata.Host).
   444  					Msg("[UDP] resolve DNS failed")
   445  			}
   446  			return
   447  		}
   448  
   449  		ctx, cancel := context.WithTimeout(context.Background(), C.DefaultUDPTimeout)
   450  		defer cancel()
   451  
   452  		rawPc, err := rawProxy.ListenPacketContext(ctx, metadata)
   453  		if err != nil {
   454  			if rule == nil {
   455  				log.Warn().
   456  					Err(err).
   457  					Str("proxy", rawProxy.Name()).
   458  					Any("rAddr", C.LogAddr{M: *metadata}).
   459  					Msg("[UDP] dial failed")
   460  			} else {
   461  				log.Warn().
   462  					Err(err).
   463  					Str("proxy", rawProxy.Name()).
   464  					Any("rAddr", C.LogAddr{M: *metadata}).
   465  					Any("rule", rule.RuleType()).
   466  					Str("rulePayload", rule.Payload()).
   467  					Any("ruleGroup", rule.RuleGroups()).
   468  					Msg("[UDP] dial failed")
   469  			}
   470  			return
   471  		}
   472  
   473  		if len(chains) > 1 {
   474  			rawPc.SetChains(lo.Reverse(chains))
   475  		}
   476  
   477  		pCtx.InjectPacketConn(rawPc)
   478  		pc := statistic.NewUDPTracker(rawPc, statistic.DefaultManager, metadata, rule)
   479  
   480  		switch true {
   481  		case metadata.SpecialProxy != "":
   482  			log.Info().
   483  				EmbedObject(metadata).
   484  				Any("proxy", rawPc).
   485  				Msg("[UDP] tunnel connected")
   486  		case rule != nil:
   487  			log.Info().
   488  				EmbedObject(metadata).
   489  				Any("mode", mode).
   490  				Any("rule", C.LogRule{R: rule}).
   491  				Any("proxy", rawPc).
   492  				Any("ruleGroup", rule.RuleGroups()).
   493  				Msg("[UDP] connected")
   494  		default:
   495  			log.Info().EmbedObject(metadata).Any("mode", mode).Any("proxy", rawPc).Msg("[UDP] connected")
   496  		}
   497  
   498  		oAddr := metadata.DstIP
   499  		go handleUDPToLocal(packet.UDPPacket, pc, key, rKey, oAddr, fAddr)
   500  
   501  		if rKey != "" {
   502  			addrTable.Set(rKey, oAddr)
   503  		}
   504  
   505  		natTable.Set(key, pc)
   506  		handle()
   507  	}()
   508  }
   509  
   510  func handleTCPConn(connCtx C.ConnContext) {
   511  	defer func(conn net.Conn) {
   512  		_ = conn.Close()
   513  	}(connCtx.Conn())
   514  
   515  	metadata := connCtx.Metadata()
   516  	if !metadata.Valid() {
   517  		log.Warn().Msgf("[Metadata] not valid: %#v", metadata)
   518  		return
   519  	}
   520  
   521  	if err := preHandleMetadata(metadata); err != nil {
   522  		log.Debug().Err(err).Msg("[Metadata] prehandle failed")
   523  		return
   524  	}
   525  
   526  	log.Debug().EmbedObject(metadata).Any("inbound", metadata.Type).Msg("[TCP] accept connection")
   527  
   528  	proxy, rule, err := resolveMetadata(connCtx, metadata)
   529  	if err != nil {
   530  		log.Warn().Err(err).Msg("[Metadata] parse failed")
   531  		return
   532  	}
   533  
   534  	var (
   535  		rawProxy C.Proxy
   536  		chains   []string
   537  
   538  		isMitmOutbound = proxy == mitmProxy
   539  	)
   540  
   541  	if !isMitmOutbound {
   542  		rawProxy, chains = FetchRawProxyAdapter(proxy, metadata)
   543  		isRemote, err2 := resolveDNS(metadata, proxy, rawProxy)
   544  		if err2 != nil {
   545  			if isRemote {
   546  				log.Warn().Err(err2).
   547  					Str("proxy", rawProxy.Name()).
   548  					Str("host", metadata.Host).
   549  					Msg("[TCP] remote resolve DNS failed")
   550  			} else {
   551  				log.Warn().Err(err2).
   552  					Str("host", metadata.Host).
   553  					Msg("[TCP] resolve DNS failed")
   554  			}
   555  			return
   556  		}
   557  	} else {
   558  		rawProxy = proxy
   559  	}
   560  
   561  	ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTCPTimeout)
   562  	defer cancel()
   563  	remoteConn, err := rawProxy.DialContext(ctx, metadata)
   564  	if err != nil {
   565  		if rule == nil {
   566  			log.Warn().
   567  				Err(err).
   568  				Str("proxy", rawProxy.Name()).
   569  				Any("rAddr", C.LogAddr{M: *metadata}).
   570  				Msg("[TCP] dial failed")
   571  		} else {
   572  			log.Warn().
   573  				Err(err).
   574  				Str("proxy", rawProxy.Name()).
   575  				Any("rAddr", C.LogAddr{M: *metadata}).
   576  				Any("rule", rule.RuleType()).
   577  				Str("rulePayload", rule.Payload()).
   578  				Any("ruleGroup", rule.RuleGroups()).
   579  				Msg("[TCP] dial failed")
   580  		}
   581  		return
   582  	}
   583  
   584  	if len(chains) > 1 {
   585  		remoteConn.SetChains(lo.Reverse(chains))
   586  	}
   587  
   588  	if rawProxy.Name() != "REJECT" && !isMitmOutbound {
   589  		remoteConn = statistic.NewTCPTracker(remoteConn, statistic.DefaultManager, metadata, rule)
   590  		if sniffing {
   591  			remoteConn = statistic.NewSniffing(remoteConn, metadata, rule)
   592  		}
   593  	}
   594  
   595  	defer func(remoteConn C.Conn) {
   596  		_ = remoteConn.Close()
   597  	}(remoteConn)
   598  
   599  	switch {
   600  	case isMitmOutbound:
   601  	case metadata.SpecialProxy != "":
   602  		log.Info().
   603  			EmbedObject(metadata).
   604  			Any("proxy", remoteConn).
   605  			Msg("[TCP] tunnel connected")
   606  	case rule != nil:
   607  		log.Info().
   608  			EmbedObject(metadata).
   609  			Any("mode", mode).
   610  			Any("rule", C.LogRule{R: rule}).
   611  			Any("proxy", remoteConn).
   612  			Any("ruleGroup", rule.RuleGroups()).
   613  			Msg("[TCP] connected")
   614  	default:
   615  		log.Info().
   616  			EmbedObject(metadata).
   617  			Any("mode", mode).
   618  			Any("proxy", remoteConn).
   619  			Msg("[TCP] connected")
   620  	}
   621  
   622  	handleSocket(connCtx, remoteConn)
   623  }
   624  
   625  func shouldResolveIP(rule C.Rule, metadata *C.Metadata) bool {
   626  	return rule.ShouldResolveIP() && metadata.Host != "" && !metadata.DstIP.IsValid()
   627  }
   628  
   629  func match(metadata *C.Metadata) (C.Proxy, C.Rule, error) {
   630  	configMux.RLock()
   631  	defer configMux.RUnlock()
   632  
   633  	var (
   634  		resolved     bool
   635  		processFound bool
   636  	)
   637  
   638  	if node := resolver.DefaultHosts.Search(metadata.Host); node != nil {
   639  		metadata.DstIP = node.Data
   640  		resolved = true
   641  	}
   642  
   643  	adapter, rule := matchRule(rules, metadata, &resolved, &processFound)
   644  
   645  	if adapter != nil {
   646  		return adapter, rule, nil
   647  	}
   648  
   649  	if len(rules) == 0 {
   650  		return proxies["DIRECT"], nil, nil
   651  	}
   652  
   653  	return proxies["REJECT"], nil, nil
   654  }
   655  
   656  func matchRule(subRules []C.Rule, metadata *C.Metadata, resolved, processFound *bool) (C.Proxy, C.Rule) {
   657  	for _, rule := range subRules {
   658  		if !*resolved && shouldResolveIP(rule, metadata) {
   659  			rAddrs, err := resolver.LookupIP(context.Background(), metadata.Host)
   660  			if err != nil {
   661  				log.Debug().
   662  					Err(err).
   663  					Str("host", metadata.Host).
   664  					Msg("[Matcher] resolve failed")
   665  			} else {
   666  				ip := rAddrs[0]
   667  				if l := len(rAddrs); l > 1 && metadata.NetWork != C.UDP {
   668  					ip = rAddrs[rand.IntN(l)]
   669  				}
   670  				log.Debug().
   671  					Str("host", metadata.Host).
   672  					NetIPAddr("ip", ip).
   673  					Msg("[Matcher] resolve success")
   674  
   675  				metadata.DstIP = ip
   676  			}
   677  			*resolved = true
   678  		}
   679  
   680  		if !*processFound && rule.ShouldFindProcess() {
   681  			*processFound = true
   682  
   683  			if metadata.OriginDst.IsValid() {
   684  				path, err2 := P.FindProcessPath(
   685  					metadata.NetWork.String(),
   686  					netip.AddrPortFrom(metadata.SrcIP, uint16(metadata.SrcPort)),
   687  					metadata.OriginDst,
   688  				)
   689  
   690  				if err2 != nil {
   691  					log.Debug().
   692  						Err(err2).
   693  						Any("addr", C.LogAddr{M: *metadata, HostOnly: true}).
   694  						Msg("[Matcher] find process failed")
   695  				} else {
   696  					log.Debug().
   697  						Any("addr", C.LogAddr{M: *metadata, HostOnly: true}).
   698  						Str("path", path).
   699  						Msg("[Matcher] find process success")
   700  
   701  					metadata.Process = filepath.Base(path)
   702  					metadata.ProcessPath = path
   703  				}
   704  			}
   705  		}
   706  
   707  		if rule.Match(metadata) {
   708  			if rule.RuleType() == C.Group {
   709  				adapter, subRule := matchRule(rule.SubRules(), metadata, resolved, processFound)
   710  				if adapter != nil {
   711  					return adapter, subRule
   712  				}
   713  				continue
   714  			}
   715  
   716  			adapter, ok := FindProxyByName(rule.Adapter())
   717  			if !ok {
   718  				continue
   719  			}
   720  
   721  			extra := rule.RuleExtra()
   722  			if extra != nil {
   723  				if extra.NotMatchNetwork(metadata.NetWork) {
   724  					continue
   725  				}
   726  
   727  				if extra.NotMatchSourceIP(metadata.SrcIP) {
   728  					continue
   729  				}
   730  
   731  				if extra.NotMatchProcessName(metadata.Process) {
   732  					continue
   733  				}
   734  			}
   735  
   736  			if metadata.NetWork == C.UDP && !adapter.SupportUDP() {
   737  				if !UDPFallbackMatch.Load() {
   738  					policy := UDPFallbackPolicy.Load()
   739  					if policy != "" {
   740  						if adapter2, ok2 := FindProxyByName(policy); ok2 {
   741  							return adapter2, rule
   742  						}
   743  						log.Warn().
   744  							Str("policy", policy).
   745  							Msg("[Matcher] UDP fallback policy not found, skip use policy")
   746  					}
   747  				} else {
   748  					log.Debug().
   749  						Str("proxy", adapter.Name()).
   750  						Msg("[Matcher] UDP is not supported, skip match")
   751  					continue
   752  				}
   753  			}
   754  
   755  			return adapter, rule
   756  		}
   757  	}
   758  
   759  	return nil, nil
   760  }
   761  
   762  func matchScript(metadata *C.Metadata) (C.Proxy, error) {
   763  	configMux.RLock()
   764  	defer configMux.RUnlock()
   765  
   766  	if node := resolver.DefaultHosts.Search(metadata.Host); node != nil {
   767  		metadata.DstIP = node.Data
   768  	}
   769  
   770  	adapterName, err := scriptMainMatcher.Eval(metadata)
   771  	if err != nil {
   772  		return nil, err
   773  	}
   774  
   775  	adapter, ok := FindProxyByName(adapterName)
   776  	if !ok {
   777  		return nil, fmt.Errorf("proxy %s not found", adapterName)
   778  	}
   779  
   780  	if metadata.NetWork == C.UDP && !adapter.SupportUDP() {
   781  		if !UDPFallbackMatch.Load() {
   782  			policy := UDPFallbackPolicy.Load()
   783  			if policy != "" {
   784  				if adapter2, ok2 := FindProxyByName(policy); ok2 {
   785  					return adapter2, nil
   786  				}
   787  				log.Warn().
   788  					Str("policy", policy).
   789  					Msg("[Matcher] UDP fallback policy not found, skip use policy")
   790  			}
   791  		} else {
   792  			log.Debug().
   793  				Str("proxy", adapterName).
   794  				Msg("[Matcher] UDP is not supported, use `REJECT` policy")
   795  			return proxies["REJECT"], nil
   796  		}
   797  	}
   798  
   799  	return adapter, nil
   800  }