2018-06-10 22:50:03 +08:00
package tunnel
import (
2019-02-02 20:47:38 +08:00
"fmt"
2018-12-05 21:13:29 +08:00
"net"
2019-12-28 18:44:01 +08:00
"runtime"
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
2019-12-08 12:17:24 +08:00
"github.com/Dreamacro/clash/adapters/inbound"
"github.com/Dreamacro/clash/adapters/provider"
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"
2018-06-10 22:50:03 +08:00
C "github.com/Dreamacro/clash/constant"
2021-01-23 14:49:46 +08:00
"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-01-23 14:49:46 +08:00
tcpQueue = make ( chan C . ConnContext , 200 )
2020-10-20 17:44:39 +08:00
udpQueue = make ( chan * inbound . PacketAdapter , 200 )
2020-09-17 10:48:42 +08:00
natTable = nat . New ( )
rules [ ] C . Rule
proxies = make ( map [ string ] C . Proxy )
providers map [ string ] provider . ProxyProvider
configMux sync . RWMutex
2019-04-24 12:02:52 +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
udpTimeout = 60 * time . Second
)
func init ( ) {
go process ( )
2018-06-10 22:50:03 +08:00
}
2018-07-26 00:04:59 +08:00
// Add request to queue
2021-01-23 14:49:46 +08:00
func Add ( ctx C . ConnContext ) {
tcpQueue <- ctx
2019-12-28 18:44:01 +08:00
}
// AddPacket add udp Packet to queue
2020-02-15 21:42:46 +08:00
func AddPacket ( packet * inbound . PacketAdapter ) {
2020-10-29 00:32:31 +08:00
select {
case udpQueue <- packet :
default :
}
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
2020-02-15 21:42:46 +08:00
func UpdateRules ( newRules [ ] C . Rule ) {
configMux . Lock ( )
rules = newRules
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
}
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
if runtime . NumCPU ( ) > numUDPWorkers {
numUDPWorkers = runtime . NumCPU ( )
}
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 = ""
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
2020-09-17 10:48:42 +08:00
if resolver . FakeIPEnabled ( ) {
2019-05-09 21:00:29 +08:00
metadata . DstIP = nil
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
}
2020-09-17 10:48:42 +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
}
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-01-23 14:49:46 +08:00
ctx := context . NewPacketConnContext ( metadata )
proxy , rule , err := resolveMetadata ( ctx , 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
}
2020-10-28 21:26:50 +08:00
rawPc , err := proxy . DialUDP ( metadata )
if err != nil {
2020-11-22 23:38:12 +08:00
if rule == nil {
log . Warnln ( "[UDP] dial %s to %s error: %s" , proxy . Name ( ) , metadata . String ( ) , err . Error ( ) )
} else {
log . Warnln ( "[UDP] dial %s (match %s/%s) to %s error: %s" , proxy . Name ( ) , rule . RuleType ( ) . String ( ) , rule . Payload ( ) , metadata . String ( ) , err . Error ( ) )
}
2020-10-28 21:26:50 +08:00
return
}
2021-01-23 14:49:46 +08:00
ctx . InjectPacketConn ( rawPc )
pc := statistic . NewUDPTracker ( rawPc , statistic . DefaultManager , metadata , rule )
2020-10-28 21:26:50 +08:00
switch true {
case rule != nil :
log . Infoln ( "[UDP] %s --> %v match %s(%s) using %s" , metadata . SourceAddress ( ) , metadata . String ( ) , rule . RuleType ( ) . String ( ) , rule . Payload ( ) , rawPc . Chains ( ) . String ( ) )
case mode == Global :
log . Infoln ( "[UDP] %s --> %v using GLOBAL" , metadata . SourceAddress ( ) , metadata . String ( ) )
case mode == Direct :
log . Infoln ( "[UDP] %s --> %v using DIRECT" , metadata . SourceAddress ( ) , metadata . String ( ) )
default :
log . Infoln ( "[UDP] %s --> %v doesn't match any rule using DIRECT" , metadata . SourceAddress ( ) , metadata . String ( ) )
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-01-23 14:49:46 +08:00
func handleTCPConn ( ctx C . ConnContext ) {
defer ctx . Conn ( ) . Close ( )
2019-10-11 20:11:18 +08:00
2021-01-23 14:49:46 +08:00
metadata := ctx . 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-01-23 14:49:46 +08:00
proxy , rule , err := resolveMetadata ( ctx , 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
2019-08-12 14:01:32 +08:00
remoteConn , err := proxy . Dial ( metadata )
2018-06-10 22:50:03 +08:00
if err != nil {
2020-11-22 23:38:12 +08:00
if rule == nil {
log . Warnln ( "[TCP] dial %s to %s error: %s" , proxy . Name ( ) , metadata . String ( ) , err . Error ( ) )
} else {
log . Warnln ( "[TCP] dial %s (match %s/%s) to %s error: %s" , proxy . Name ( ) , rule . RuleType ( ) . String ( ) , rule . Payload ( ) , metadata . String ( ) , err . Error ( ) )
}
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 :
2020-07-18 19:22:09 +08:00
log . Infoln ( "[TCP] %s --> %v match %s(%s) using %s" , metadata . SourceAddress ( ) , metadata . String ( ) , rule . RuleType ( ) . String ( ) , rule . Payload ( ) , remoteConn . Chains ( ) . String ( ) )
2020-02-15 21:42:46 +08:00
case mode == Global :
2020-01-31 14:58:54 +08:00
log . Infoln ( "[TCP] %s --> %v using GLOBAL" , metadata . SourceAddress ( ) , metadata . String ( ) )
2020-02-15 21:42:46 +08:00
case mode == Direct :
2020-01-31 14:58:54 +08:00
log . Infoln ( "[TCP] %s --> %v using DIRECT" , metadata . SourceAddress ( ) , metadata . String ( ) )
default :
log . Infoln ( "[TCP] %s --> %v doesn't match any rule using DIRECT" , metadata . SourceAddress ( ) , metadata . String ( ) )
2019-08-09 01:28:37 +08:00
}
2021-01-23 14:49:46 +08:00
switch c := ctx . ( type ) {
case * context . HTTPContext :
handleHTTP ( c , remoteConn )
default :
handleSocket ( ctx , remoteConn )
2018-07-26 00:04:59 +08:00
}
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 ( ) {
2019-07-25 17:47:39 +08:00
log . Debugln ( "%v UDP is not supported" , adapter . Name ( ) )
2019-04-23 23:29:36 +08:00
continue
}
2019-08-09 01:28:37 +08:00
return adapter , rule , nil
2018-06-10 22:50:03 +08:00
}
}
2020-02-15 21:42:46 +08:00
return proxies [ "DIRECT" ] , nil , nil
2018-06-10 22:50:03 +08:00
}