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"
2018-12-05 21:13:29 +08:00
"net"
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"
2022-03-12 19:07:53 +08:00
P "github.com/Dreamacro/clash/component/process"
2020-02-15 21:42:46 +08:00
"github.com/Dreamacro/clash/component/resolver"
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 (
2021-12-02 22:56:17 +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-03-20 02:39:48 +08:00
configMux sync . RWMutex
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
udpTimeout = 60 * time . Second
)
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
2021-12-02 22:56:17 +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
func RuleProviders ( ) map [ string ] * provider . RuleProvider {
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
}
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
}
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 {
2020-09-17 10:48:42 +08:00
return resolver . MappingEnabled ( ) && metadata . Host == "" && metadata . DstIP != nil
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
2019-10-28 00:02:23 +08:00
if ip := net . ParseIP ( metadata . Host ) ; ip != nil {
metadata . DstIP = ip
2021-03-10 12:11:45 +08:00
metadata . Host = ""
2021-03-12 17:41:37 +08:00
if ip . To4 ( ) != nil {
metadata . AddrType = C . AtypIPv4
} else {
metadata . AddrType = C . AtypIPv6
}
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
metadata . AddrType = C . AtypDomainName
2021-10-18 22:58:16 +08:00
metadata . DNSMode = C . DNSMapping
2020-09-17 10:48:42 +08:00
if resolver . FakeIPEnabled ( ) {
2019-05-09 21:00:29 +08:00
metadata . DstIP = nil
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
metadata . DstIP = node . Data . ( net . IP )
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
}
}
2022-03-05 18:04:04 +08:00
// pre resolve process name
2022-03-13 01:21:23 +08:00
srcPort , err := strconv . Atoi ( metadata . SrcPort )
if err == nil && P . ShouldFindProcess ( metadata ) {
path , err := P . FindProcessName ( metadata . NetWork . String ( ) , metadata . SrcIP , srcPort )
if err != nil {
log . Debugln ( "[Process] find process %s: %v" , metadata . String ( ) , err )
} else {
log . Debugln ( "[Process] %s from process %s" , metadata . String ( ) , path )
metadata . Process = filepath . Base ( path )
metadata . ProcessPath = path
}
}
2022-03-05 18:04:04 +08:00
2020-02-07 20:53:43 +08:00
return nil
}
2021-01-23 14:49:46 +08:00
func resolveMetadata ( ctx 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
2020-03-10 20:36:24 +08:00
var fAddr net . Addr
2020-10-17 12:52:43 +08:00
if resolver . IsExistFakeIP ( metadata . DstIP ) {
2020-03-10 20:36:24 +08:00
fAddr = metadata . UDPAddr ( )
}
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
}
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 {
handleUDPToRemote ( packet , pc , metadata )
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 ( )
2021-10-18 21:08:27 +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 )
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 ( ) )
}
2021-11-17 16:03:47 +08:00
case mode == Script :
2022-01-05 00:33:42 +08:00
log . Infoln ( "[UDP] %s --> %s using SCRIPT %s" , metadata . SourceDetail ( ) , metadata . RemoteAddress ( ) , 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
go handleUDPToLocal ( packet . UDPPacket , pc , key , fAddr )
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 ) {
defer connCtx . Conn ( ) . Close ( )
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
}
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
2021-10-15 21:44:53 +08:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , C . DefaultTCPTimeout )
defer cancel ( )
2021-10-18 21:08:27 +08:00
remoteConn , err := proxy . DialContext ( ctx , metadata . Pure ( ) )
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 {
2021-07-19 15:31:38 +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
}
2021-01-23 14:49:46 +08:00
remoteConn = statistic . NewTCPTracker ( remoteConn , statistic . DefaultManager , metadata , rule )
2019-08-12 14:01:32 +08:00
defer remoteConn . Close ( )
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 ( ) )
}
2021-11-17 16:03:47 +08:00
case mode == Script :
2022-01-05 00:33:42 +08:00
log . Infoln ( "[TCP] %s --> %s using SCRIPT %s" , metadata . SourceDetail ( ) , metadata . RemoteAddress ( ) , 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 {
2020-07-27 13:47:00 +08:00
return rule . ShouldResolveIP ( ) && metadata . Host != "" && metadata . DstIP == nil
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 ( )
2018-06-15 00:49:52 +08:00
2019-04-24 12:02:52 +08:00
var resolved 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 {
2019-09-11 17:00:55 +08:00
ip := node . Data . ( net . IP )
2019-10-27 21:44:07 +08:00
metadata . DstIP = ip
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
}
2019-10-28 00:02:23 +08:00
if rule . Match ( metadata ) {
2020-02-15 21:42:46 +08:00
adapter , ok := proxies [ rule . Adapter ( ) ]
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
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
extra := rule . RuleExtra ( )
if extra != nil {
if extra . NotMatchNetwork ( metadata . NetWork ) {
continue
}
if extra . NotMatchSourceIP ( metadata . SrcIP ) {
continue
}
2022-02-23 14:01:53 +08:00
if extra . NotMatchProcessName ( metadata . Process ) {
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
}
}
2021-11-17 16:03:47 +08:00
return proxies [ "REJECT" ] , nil , nil
}