2018-06-10 22:50:03 +08:00
package tunnel
import (
2021-10-15 21:44:53 +08:00
"context"
2019-02-02 20:47:38 +08:00
"fmt"
2022-04-20 01:31:33 +08:00
P "github.com/Dreamacro/clash/component/process"
2018-12-05 21:13:29 +08:00
"net"
2022-04-20 01:52:51 +08:00
"net/netip"
2022-03-13 01:21:23 +08:00
"path/filepath"
2019-12-28 18:44:01 +08:00
"runtime"
2022-03-12 19:07:53 +08:00
"strconv"
2018-06-10 22:50:03 +08:00
"sync"
2018-06-16 21:34:13 +08:00
"time"
2018-06-10 22:50:03 +08:00
2021-06-10 14:05:56 +08:00
"github.com/Dreamacro/clash/adapter/inbound"
2019-10-11 20:11:18 +08:00
"github.com/Dreamacro/clash/component/nat"
2020-02-15 21:42:46 +08:00
"github.com/Dreamacro/clash/component/resolver"
2022-04-09 22:30:36 +08:00
"github.com/Dreamacro/clash/component/sniffer"
2018-06-10 22:50:03 +08:00
C "github.com/Dreamacro/clash/constant"
2021-07-04 20:32:59 +08:00
"github.com/Dreamacro/clash/constant/provider"
2021-10-15 21:44:53 +08:00
icontext "github.com/Dreamacro/clash/context"
2018-11-21 13:47:46 +08:00
"github.com/Dreamacro/clash/log"
2021-01-23 14:49:46 +08:00
"github.com/Dreamacro/clash/tunnel/statistic"
2018-06-10 22:50:03 +08:00
)
var (
2022-05-24 12:43:26 +08:00
tcpQueue = make ( chan C . ConnContext , 200 )
udpQueue = make ( chan * inbound . PacketAdapter , 200 )
natTable = nat . New ( )
rules [ ] C . Rule
proxies = make ( map [ string ] C . Proxy )
providers map [ string ] provider . ProxyProvider
ruleProviders map [ string ] provider . RuleProvider
2022-11-03 00:31:31 +08:00
sniffingEnable = false
2022-05-24 12:43:26 +08:00
configMux sync . RWMutex
2022-03-20 02:39:48 +08:00
2018-07-26 00:04:59 +08:00
// Outbound Rule
2020-02-15 21:42:46 +08:00
mode = Rule
// default timeout for UDP session
2022-06-14 23:08:07 +08:00
udpTimeout = 60 * time . Second
alwaysFindProcess = false
2022-11-10 21:08:06 +08:00
fakeIPRange netip . Prefix
2020-02-15 21:42:46 +08:00
)
2022-11-10 21:08:06 +08:00
func SetFakeIPRange ( p netip . Prefix ) {
fakeIPRange = p
}
func FakeIPRange ( ) netip . Prefix {
return fakeIPRange
}
2022-05-24 12:43:26 +08:00
func SetSniffing ( b bool ) {
if sniffer . Dispatcher . Enable ( ) {
configMux . Lock ( )
sniffingEnable = b
configMux . Unlock ( )
}
}
func IsSniffing ( ) bool {
return sniffingEnable
}
2020-02-15 21:42:46 +08:00
func init ( ) {
go process ( )
2018-06-10 22:50:03 +08:00
}
2021-06-13 17:23:10 +08:00
// TCPIn return fan-in queue
func TCPIn ( ) chan <- C . ConnContext {
return tcpQueue
2019-12-28 18:44:01 +08:00
}
2021-06-13 17:23:10 +08:00
// UDPIn return fan-in udp queue
func UDPIn ( ) chan <- * inbound . PacketAdapter {
return udpQueue
2018-06-10 22:50:03 +08:00
}
2018-11-21 13:47:46 +08:00
// Rules return all rules
2020-02-15 21:42:46 +08:00
func Rules ( ) [ ] C . Rule {
return rules
2018-06-18 11:31:49 +08:00
}
2018-11-21 13:47:46 +08:00
// UpdateRules handle update rules
2022-04-28 08:55:45 +08:00
func UpdateRules ( newRules [ ] C . Rule , rp map [ string ] provider . RuleProvider ) {
2020-02-15 21:42:46 +08:00
configMux . Lock ( )
rules = newRules
2021-12-02 22:56:17 +08:00
ruleProviders = rp
2020-02-15 21:42:46 +08:00
configMux . Unlock ( )
2018-11-21 13:47:46 +08:00
}
// Proxies return all proxies
2020-02-15 21:42:46 +08:00
func Proxies ( ) map [ string ] C . Proxy {
return proxies
2018-11-21 13:47:46 +08:00
}
2019-12-08 12:17:24 +08:00
// Providers return all compatible providers
2020-02-15 21:42:46 +08:00
func Providers ( ) map [ string ] provider . ProxyProvider {
return providers
2019-12-08 12:17:24 +08:00
}
2021-12-02 22:56:17 +08:00
// RuleProviders return all loaded rule providers
2022-04-28 08:55:45 +08:00
func RuleProviders ( ) map [ string ] provider . RuleProvider {
2021-12-02 22:56:17 +08:00
return ruleProviders
}
2018-11-21 13:47:46 +08:00
// UpdateProxies handle update proxies
2020-02-15 21:42:46 +08:00
func UpdateProxies ( newProxies map [ string ] C . Proxy , newProviders map [ string ] provider . ProxyProvider ) {
configMux . Lock ( )
proxies = newProxies
providers = newProviders
configMux . Unlock ( )
2019-04-24 12:02:52 +08:00
}
2022-04-16 08:21:31 +08:00
func UpdateSniffer ( dispatcher * sniffer . SnifferDispatcher ) {
configMux . Lock ( )
2022-10-14 07:46:33 +08:00
sniffer . Dispatcher = dispatcher
2022-11-03 00:31:31 +08:00
sniffingEnable = dispatcher . Enable ( )
2022-04-16 08:21:31 +08:00
configMux . Unlock ( )
}
2018-11-21 13:47:46 +08:00
// Mode return current mode
2020-02-15 21:42:46 +08:00
func Mode ( ) TunnelMode {
return mode
2018-11-21 13:47:46 +08:00
}
// SetMode change the mode of tunnel
2020-02-15 21:42:46 +08:00
func SetMode ( m TunnelMode ) {
mode = m
}
2022-06-14 23:08:07 +08:00
// SetAlwaysFindProcess set always find process info, may be increase many memory
func SetAlwaysFindProcess ( findProcess bool ) {
alwaysFindProcess = findProcess
}
2019-12-28 18:44:01 +08:00
// processUDP starts a loop to handle udp packet
2020-02-15 21:42:46 +08:00
func processUDP ( ) {
2020-10-20 17:44:39 +08:00
queue := udpQueue
for conn := range queue {
2020-02-15 21:42:46 +08:00
handleUDPConn ( conn )
2019-12-28 18:44:01 +08:00
}
}
2020-02-15 21:42:46 +08:00
func process ( ) {
2019-12-28 18:44:01 +08:00
numUDPWorkers := 4
2021-10-27 21:27:19 +08:00
if num := runtime . GOMAXPROCS ( 0 ) ; num > numUDPWorkers {
numUDPWorkers = num
2019-12-28 18:44:01 +08:00
}
for i := 0 ; i < numUDPWorkers ; i ++ {
2020-02-15 21:42:46 +08:00
go processUDP ( )
2019-12-28 18:44:01 +08:00
}
2019-10-11 20:11:18 +08:00
2020-10-20 17:44:39 +08:00
queue := tcpQueue
for conn := range queue {
2020-02-15 21:42:46 +08:00
go handleTCPConn ( conn )
2018-06-10 22:50:03 +08:00
}
}
2020-02-15 21:42:46 +08:00
func needLookupIP ( metadata * C . Metadata ) bool {
2022-04-20 01:52:51 +08:00
return resolver . MappingEnabled ( ) && metadata . Host == "" && metadata . DstIP . IsValid ( )
2019-02-11 15:44:42 +08:00
}
2020-02-15 21:42:46 +08:00
func preHandleMetadata ( metadata * C . Metadata ) error {
2020-02-07 20:53:43 +08:00
// handle IP string on host
2022-04-20 01:52:51 +08:00
if ip , err := netip . ParseAddr ( metadata . Host ) ; err == nil {
2019-10-28 00:02:23 +08:00
metadata . DstIP = ip
2021-03-10 12:11:45 +08:00
metadata . Host = ""
2019-10-28 00:02:23 +08:00
}
2019-05-03 00:05:14 +08:00
// preprocess enhanced-mode metadata
2020-02-15 21:42:46 +08:00
if needLookupIP ( metadata ) {
2020-09-17 10:48:42 +08:00
host , exist := resolver . FindHostByIP ( metadata . DstIP )
2018-12-05 21:13:29 +08:00
if exist {
metadata . Host = host
2021-10-18 22:58:16 +08:00
metadata . DNSMode = C . DNSMapping
2020-09-17 10:48:42 +08:00
if resolver . FakeIPEnabled ( ) {
2022-04-20 01:52:51 +08:00
metadata . DstIP = netip . Addr { }
2021-10-18 21:08:27 +08:00
metadata . DNSMode = C . DNSFakeIP
2020-04-27 21:28:24 +08:00
} else if node := resolver . DefaultHosts . Search ( host ) ; node != nil {
// redir-host should lookup the hosts
2022-11-02 22:28:18 +08:00
metadata . DstIP = node . Data ( )
2019-05-03 00:05:14 +08:00
}
2022-03-15 02:55:06 +08:00
} else if resolver . IsFakeIP ( metadata . DstIP ) {
2020-02-07 20:53:43 +08:00
return fmt . Errorf ( "fake DNS record %s missing" , metadata . DstIP )
2018-12-05 21:13:29 +08:00
}
}
2020-02-07 20:53:43 +08:00
return nil
}
2022-04-11 06:28:42 +08:00
func resolveMetadata ( _ C . PlainContext , metadata * C . Metadata ) ( proxy C . Proxy , rule C . Rule , err error ) {
2020-02-15 21:42:46 +08:00
switch mode {
2018-11-21 13:47:46 +08:00
case Direct :
2020-02-15 21:42:46 +08:00
proxy = proxies [ "DIRECT" ]
2018-11-21 13:47:46 +08:00
case Global :
2020-02-15 21:42:46 +08:00
proxy = proxies [ "GLOBAL" ]
2018-07-12 23:28:38 +08:00
// Rule
default :
2020-02-15 21:42:46 +08:00
proxy , rule , err = match ( metadata )
2018-07-12 23:28:38 +08:00
}
2021-01-23 14:49:46 +08:00
return
2019-10-11 20:11:18 +08:00
}
2019-02-02 20:47:38 +08:00
2020-02-15 21:42:46 +08:00
func handleUDPConn ( packet * inbound . PacketAdapter ) {
2019-12-28 18:44:01 +08:00
metadata := packet . Metadata ( )
2019-10-11 20:11:18 +08:00
if ! metadata . Valid ( ) {
log . Warnln ( "[Metadata] not valid: %#v" , metadata )
return
2019-07-25 17:47:39 +08:00
}
2020-10-28 21:26:50 +08:00
// make a fAddr if request ip is fakeip
2022-07-05 21:09:29 +08:00
var fAddr netip . Addr
2020-10-17 12:52:43 +08:00
if resolver . IsExistFakeIP ( metadata . DstIP ) {
2022-07-05 21:09:29 +08:00
fAddr = metadata . DstIP
2020-03-10 20:36:24 +08:00
}
2020-02-15 21:42:46 +08:00
if err := preHandleMetadata ( metadata ) ; err != nil {
2020-02-07 20:53:43 +08:00
log . Debugln ( "[Metadata PreHandle] error: %s" , err )
return
2020-01-31 19:26:33 +08:00
}
2022-07-05 21:09:29 +08:00
// local resolve UDP dns
if ! metadata . Resolved ( ) {
ip , err := resolver . ResolveIP ( metadata . Host )
if err != nil {
return
}
metadata . DstIP = ip
}
2020-01-31 14:43:54 +08:00
key := packet . LocalAddr ( ) . String ( )
2020-10-28 21:26:50 +08:00
handle := func ( ) bool {
pc := natTable . Get ( key )
if pc != nil {
2022-04-11 06:28:42 +08:00
_ = handleUDPToRemote ( packet , pc , metadata )
2020-10-28 21:26:50 +08:00
return true
}
return false
}
if handle ( ) {
2019-10-11 20:11:18 +08:00
return
}
lockKey := key + "-lock"
2020-10-28 21:26:50 +08:00
cond , loaded := natTable . GetOrCreateLock ( lockKey )
2019-12-28 18:44:01 +08:00
2019-10-11 20:11:18 +08:00
go func ( ) {
2020-10-28 21:26:50 +08:00
if loaded {
cond . L . Lock ( )
cond . Wait ( )
handle ( )
cond . L . Unlock ( )
return
}
2019-10-11 20:11:18 +08:00
2020-10-28 21:26:50 +08:00
defer func ( ) {
2020-02-15 21:42:46 +08:00
natTable . Delete ( lockKey )
2020-10-28 21:26:50 +08:00
cond . Broadcast ( )
} ( )
2021-10-15 21:44:53 +08:00
pCtx := icontext . NewPacketConnContext ( metadata )
proxy , rule , err := resolveMetadata ( pCtx , metadata )
2020-10-28 21:26:50 +08:00
if err != nil {
log . Warnln ( "[UDP] Parse metadata failed: %s" , err . Error ( ) )
return
2019-04-24 10:29:29 +08:00
}
2021-10-15 21:44:53 +08:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , C . DefaultUDPTimeout )
defer cancel ( )
2022-10-02 20:08:41 +08:00
rawPc , err := proxy . ListenPacketContext ( ctx , metadata . Pure ( ) )
2020-10-28 21:26:50 +08:00
if err != nil {
2020-11-22 23:38:12 +08:00
if rule == nil {
2021-07-19 15:31:38 +08:00
log . Warnln ( "[UDP] dial %s to %s error: %s" , proxy . Name ( ) , metadata . RemoteAddress ( ) , err . Error ( ) )
2020-11-22 23:38:12 +08:00
} else {
2021-07-19 15:31:38 +08:00
log . Warnln ( "[UDP] dial %s (match %s/%s) to %s error: %s" , proxy . Name ( ) , rule . RuleType ( ) . String ( ) , rule . Payload ( ) , metadata . RemoteAddress ( ) , err . Error ( ) )
2020-11-22 23:38:12 +08:00
}
2020-10-28 21:26:50 +08:00
return
}
2021-10-15 21:44:53 +08:00
pCtx . InjectPacketConn ( rawPc )
2022-05-04 16:57:08 +08:00
2021-01-23 14:49:46 +08:00
pc := statistic . NewUDPTracker ( rawPc , statistic . DefaultManager , metadata , rule )
2020-10-28 21:26:50 +08:00
switch true {
case rule != nil :
2022-01-05 11:24:00 +08:00
if rule . Payload ( ) != "" {
log . Infoln ( "[UDP] %s --> %s match %s using %s" , metadata . SourceDetail ( ) , metadata . RemoteAddress ( ) , fmt . Sprintf ( "%s(%s)" , rule . RuleType ( ) . String ( ) , rule . Payload ( ) ) , rawPc . Chains ( ) . String ( ) )
} else {
log . Infoln ( "[UDP] %s --> %s match %s using %s" , metadata . SourceDetail ( ) , metadata . RemoteAddress ( ) , rule . Payload ( ) , rawPc . Chains ( ) . String ( ) )
}
2020-10-28 21:26:50 +08:00
case mode == Global :
2022-01-05 00:33:42 +08:00
log . Infoln ( "[UDP] %s --> %s using GLOBAL" , metadata . SourceDetail ( ) , metadata . RemoteAddress ( ) )
2020-10-28 21:26:50 +08:00
case mode == Direct :
2022-01-05 00:33:42 +08:00
log . Infoln ( "[UDP] %s --> %s using DIRECT" , metadata . SourceDetail ( ) , metadata . RemoteAddress ( ) )
2020-10-28 21:26:50 +08:00
default :
2022-01-05 00:33:42 +08:00
log . Infoln ( "[UDP] %s --> %s doesn't match any rule using DIRECT" , metadata . SourceDetail ( ) , metadata . RemoteAddress ( ) )
2019-08-09 01:28:37 +08:00
}
2020-10-28 21:26:50 +08:00
2022-07-05 21:09:29 +08:00
oAddr := metadata . DstIP
go handleUDPToLocal ( packet . UDPPacket , pc , key , oAddr , fAddr )
2020-10-28 21:26:50 +08:00
natTable . Set ( key , pc )
handle ( )
2019-10-11 20:11:18 +08:00
} ( )
}
2019-08-09 01:28:37 +08:00
2021-10-15 21:44:53 +08:00
func handleTCPConn ( connCtx C . ConnContext ) {
2022-04-11 06:28:42 +08:00
defer func ( conn net . Conn ) {
_ = conn . Close ( )
} ( connCtx . Conn ( ) )
2019-10-11 20:11:18 +08:00
2021-10-15 21:44:53 +08:00
metadata := connCtx . Metadata ( )
2019-10-11 20:11:18 +08:00
if ! metadata . Valid ( ) {
log . Warnln ( "[Metadata] not valid: %#v" , metadata )
return
2019-04-23 23:29:36 +08:00
}
2020-02-15 21:42:46 +08:00
if err := preHandleMetadata ( metadata ) ; err != nil {
2020-02-07 20:53:43 +08:00
log . Debugln ( "[Metadata PreHandle] error: %s" , err )
return
}
2022-05-24 12:43:26 +08:00
if sniffer . Dispatcher . Enable ( ) && sniffingEnable {
2022-04-16 08:21:31 +08:00
sniffer . Dispatcher . TCPSniff ( connCtx . Conn ( ) , metadata )
2022-04-09 22:30:36 +08:00
}
2021-10-15 21:44:53 +08:00
proxy , rule , err := resolveMetadata ( connCtx , metadata )
2019-10-11 20:11:18 +08:00
if err != nil {
2020-11-20 00:27:37 +08:00
log . Warnln ( "[Metadata] parse failed: %s" , err . Error ( ) )
2019-10-11 20:11:18 +08:00
return
}
2019-07-25 17:47:39 +08:00
2022-10-29 09:02:38 +08:00
dialMetadata := metadata
if len ( metadata . Host ) > 0 {
if node := resolver . DefaultHosts . Search ( metadata . Host ) ; node != nil {
2022-11-10 21:08:06 +08:00
if dstIp := node . Data ( ) ; ! FakeIPRange ( ) . Contains ( dstIp ) {
dialMetadata . DstIP = dstIp
dialMetadata . DNSMode = C . DNSHosts
dialMetadata = dialMetadata . Pure ( )
}
2022-10-29 09:02:38 +08:00
}
}
2022-04-12 20:20:04 +08:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , C . DefaultTCPTimeout )
defer cancel ( )
2022-10-29 09:02:38 +08:00
remoteConn , err := proxy . DialContext ( ctx , dialMetadata )
2018-06-10 22:50:03 +08:00
if err != nil {
2020-11-22 23:38:12 +08:00
if rule == nil {
2021-07-19 15:31:38 +08:00
log . Warnln ( "[TCP] dial %s to %s error: %s" , proxy . Name ( ) , metadata . RemoteAddress ( ) , err . Error ( ) )
2020-11-22 23:38:12 +08:00
} else {
2022-04-22 16:27:51 +08:00
log . Warnln ( "[TCP] dial %s (match %s(%s)) to %s error: %s" , proxy . Name ( ) , rule . RuleType ( ) . String ( ) , rule . Payload ( ) , metadata . RemoteAddress ( ) , err . Error ( ) )
2020-11-22 23:38:12 +08:00
}
2018-06-10 22:50:03 +08:00
return
}
2022-05-04 16:57:08 +08:00
2021-01-23 14:49:46 +08:00
remoteConn = statistic . NewTCPTracker ( remoteConn , statistic . DefaultManager , metadata , rule )
2022-04-11 06:28:42 +08:00
defer func ( remoteConn C . Conn ) {
_ = remoteConn . Close ( )
} ( remoteConn )
2018-06-10 22:50:03 +08:00
2020-01-31 14:58:54 +08:00
switch true {
case rule != nil :
2022-01-05 11:24:00 +08:00
if rule . Payload ( ) != "" {
log . Infoln ( "[TCP] %s --> %s match %s using %s" , metadata . SourceDetail ( ) , metadata . RemoteAddress ( ) , fmt . Sprintf ( "%s(%s)" , rule . RuleType ( ) . String ( ) , rule . Payload ( ) ) , remoteConn . Chains ( ) . String ( ) )
} else {
log . Infoln ( "[TCP] %s --> %s match %s using %s" , metadata . SourceDetail ( ) , metadata . RemoteAddress ( ) , rule . RuleType ( ) . String ( ) , remoteConn . Chains ( ) . String ( ) )
}
2020-02-15 21:42:46 +08:00
case mode == Global :
2022-01-05 00:33:42 +08:00
log . Infoln ( "[TCP] %s --> %s using GLOBAL" , metadata . SourceDetail ( ) , metadata . RemoteAddress ( ) )
2020-02-15 21:42:46 +08:00
case mode == Direct :
2022-01-05 00:33:42 +08:00
log . Infoln ( "[TCP] %s --> %s using DIRECT" , metadata . SourceDetail ( ) , metadata . RemoteAddress ( ) )
2020-01-31 14:58:54 +08:00
default :
2022-01-05 00:33:42 +08:00
log . Infoln ( "[TCP] %s --> %s doesn't match any rule using DIRECT" , metadata . SourceAddress ( ) , metadata . RemoteAddress ( ) )
2019-08-09 01:28:37 +08:00
}
2021-10-15 21:44:53 +08:00
handleSocket ( connCtx , remoteConn )
2018-06-10 22:50:03 +08:00
}
2020-02-15 21:42:46 +08:00
func shouldResolveIP ( rule C . Rule , metadata * C . Metadata ) bool {
2022-04-20 01:52:51 +08:00
return rule . ShouldResolveIP ( ) && metadata . Host != "" && ! metadata . DstIP . IsValid ( )
2019-02-02 20:47:38 +08:00
}
2020-02-15 21:42:46 +08:00
func match ( metadata * C . Metadata ) ( C . Proxy , C . Rule , error ) {
configMux . RLock ( )
defer configMux . RUnlock ( )
2022-08-12 03:04:58 +08:00
var (
resolved bool
processFound bool
)
2019-09-11 17:00:55 +08:00
2020-02-15 21:42:46 +08:00
if node := resolver . DefaultHosts . Search ( metadata . Host ) ; node != nil {
2022-11-02 22:28:18 +08:00
metadata . DstIP = node . Data ( )
2019-09-11 17:00:55 +08:00
resolved = true
}
2020-02-15 21:42:46 +08:00
for _ , rule := range rules {
if ! resolved && shouldResolveIP ( rule , metadata ) {
ip , err := resolver . ResolveIP ( metadata . Host )
2019-02-02 20:47:38 +08:00
if err != nil {
2019-04-24 12:02:52 +08:00
log . Debugln ( "[DNS] resolve %s error: %s" , metadata . Host , err . Error ( ) )
} else {
log . Debugln ( "[DNS] %s --> %s" , metadata . Host , ip . String ( ) )
2019-10-27 21:44:07 +08:00
metadata . DstIP = ip
2019-02-02 20:47:38 +08:00
}
2019-04-24 12:02:52 +08:00
resolved = true
2019-02-02 20:47:38 +08:00
}
2022-08-12 03:04:58 +08:00
if ! processFound && ( alwaysFindProcess || rule . ShouldFindProcess ( ) ) {
2022-06-14 22:50:57 +08:00
srcPort , err := strconv . ParseUint ( metadata . SrcPort , 10 , 16 )
2022-06-14 23:14:43 +08:00
uid , path , err := P . FindProcessName ( metadata . NetWork . String ( ) , metadata . SrcIP , int ( srcPort ) )
if err != nil {
log . Debugln ( "[Process] find process %s: %v" , metadata . String ( ) , err )
} else {
2022-07-13 22:27:49 +08:00
metadata . Process = filepath . Base ( path )
metadata . ProcessPath = path
2022-08-12 12:49:35 +08:00
if uid != - 1 {
metadata . Uid = & uid
}
2022-08-12 03:04:58 +08:00
processFound = true
2022-06-14 22:50:57 +08:00
}
}
feat: support sub-rule, eg.
rules:
- SUB-RULE,(AND,((NETWORK,TCP),(DOMAIN-KEYWORD,google))),TEST2
- SUB-RULE,(GEOIP,!CN),TEST1
- MATCH,DIRECT
sub-rules:
TEST2:
- MATCH,Proxy
TEST1:
- RULE-SET,Local,DIRECT,no-resolve
- GEOSITE,CN,Domestic
- GEOIP,CN,Domestic
- MATCH,Proxy
2022-09-06 17:30:35 +08:00
if matched , ada := rule . Match ( metadata ) ; matched {
adapter , ok := proxies [ ada ]
2019-04-23 23:29:36 +08:00
if ! ok {
continue
2018-06-10 22:50:03 +08:00
}
2019-04-23 23:29:36 +08:00
2022-10-30 23:08:18 +08:00
// parse multi-layer nesting
passed := false
for adapter := adapter ; adapter != nil ; adapter = adapter . Unwrap ( metadata , false ) {
if adapter . Type ( ) == C . Pass {
passed = true
break
}
}
if passed {
2022-03-28 16:36:34 +08:00
log . Debugln ( "%s match Pass rule" , adapter . Name ( ) )
2022-03-27 23:44:51 +08:00
continue
}
2019-04-23 23:29:36 +08:00
if metadata . NetWork == C . UDP && ! adapter . SupportUDP ( ) {
2021-04-05 13:31:10 +08:00
log . Debugln ( "%s UDP is not supported" , adapter . Name ( ) )
2019-04-23 23:29:36 +08:00
continue
}
2021-11-17 16:03:47 +08:00
2019-08-09 01:28:37 +08:00
return adapter , rule , nil
2018-06-10 22:50:03 +08:00
}
}
2022-06-09 13:52:02 +08:00
return proxies [ "DIRECT" ] , nil , nil
2021-11-17 16:03:47 +08:00
}