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-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"
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
2022-11-24 12:32:35 +08:00
"github.com/jpillora/backoff"
2023-11-03 21:01:45 +08:00
N "github.com/metacubex/mihomo/common/net"
"github.com/metacubex/mihomo/component/nat"
P "github.com/metacubex/mihomo/component/process"
"github.com/metacubex/mihomo/component/resolver"
"github.com/metacubex/mihomo/component/sniffer"
C "github.com/metacubex/mihomo/constant"
2023-11-17 19:39:57 +08:00
"github.com/metacubex/mihomo/constant/features"
2023-11-03 21:01:45 +08:00
"github.com/metacubex/mihomo/constant/provider"
icontext "github.com/metacubex/mihomo/context"
"github.com/metacubex/mihomo/log"
"github.com/metacubex/mihomo/tunnel/statistic"
2018-06-10 22:50:03 +08:00
)
var (
2023-03-15 00:10:54 +08:00
status = newAtomicStatus ( Suspend )
2022-05-24 12:43:26 +08:00
tcpQueue = make ( chan C . ConnContext , 200 )
2022-12-04 14:37:52 +08:00
udpQueue = make ( chan C . PacketAdapter , 200 )
2022-05-24 12:43:26 +08:00
natTable = nat . New ( )
rules [ ] C . Rule
2022-12-04 21:53:13 +08:00
listeners = make ( map [ string ] C . InboundListener )
2022-12-04 13:37:14 +08:00
subRules map [ string ] [ ] C . Rule
2022-05-24 12:43:26 +08:00
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
2023-01-05 16:58:36 +08:00
findProcessMode P . FindProcessMode
2022-11-10 21:08:06 +08:00
fakeIPRange netip . Prefix
2020-02-15 21:42:46 +08:00
)
2023-09-28 18:59:31 +08:00
type tunnel struct { }
var Tunnel C . Tunnel = tunnel { }
2023-10-11 10:55:12 +08:00
func ( t tunnel ) HandleTCPConn ( conn net . Conn , metadata * C . Metadata ) {
connCtx := icontext . NewConnContext ( conn , metadata )
2023-09-28 18:59:31 +08:00
handleTCPConn ( connCtx )
}
2023-10-11 10:55:12 +08:00
func ( t tunnel ) HandleUDPPacket ( packet C . UDPPacket , metadata * C . Metadata ) {
packetAdapter := C . NewPacketAdapter ( packet , metadata )
2023-09-28 18:59:31 +08:00
select {
2023-10-11 10:55:12 +08:00
case udpQueue <- packetAdapter :
2023-09-28 18:59:31 +08:00
default :
}
}
func ( t tunnel ) NatTable ( ) C . NatTable {
return natTable
}
2023-03-14 22:37:07 +08:00
func OnSuspend ( ) {
2023-03-15 00:10:54 +08:00
status . Store ( Suspend )
2023-03-14 22:37:07 +08:00
}
func OnInnerLoading ( ) {
2023-03-15 00:10:54 +08:00
status . Store ( Inner )
2023-03-14 22:37:07 +08:00
}
func OnRunning ( ) {
2023-03-15 00:10:54 +08:00
status . Store ( Running )
}
func Status ( ) TunnelStatus {
return status . Load ( )
2023-03-14 22:37:07 +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
2023-09-28 18:59:31 +08:00
// Deprecated: using Tunnel instead
2021-06-13 17:23:10 +08:00
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
2023-09-28 18:59:31 +08:00
// Deprecated: using Tunnel instead
2022-12-04 14:37:52 +08:00
func UDPIn ( ) chan <- C . PacketAdapter {
2021-06-13 17:23:10 +08:00
return udpQueue
2018-06-10 22:50:03 +08:00
}
2023-02-18 13:16:07 +08:00
// NatTable return nat table
func NatTable ( ) C . NatTable {
return natTable
}
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
}
2022-12-04 21:53:13 +08:00
func Listeners ( ) map [ string ] C . InboundListener {
2022-12-04 15:15:23 +08:00
return listeners
}
2022-12-04 17:20:24 +08:00
2018-11-21 13:47:46 +08:00
// UpdateRules handle update rules
2022-12-04 13:37:14 +08:00
func UpdateRules ( newRules [ ] C . Rule , newSubRule map [ string ] [ ] 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
2022-12-04 13:37:14 +08:00
subRules = newSubRule
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
}
2023-09-24 15:39:14 +08:00
func ProxiesWithProviders ( ) map [ string ] C . Proxy {
allProxies := make ( map [ string ] C . Proxy )
for name , proxy := range proxies {
allProxies [ name ] = proxy
}
for _ , p := range providers {
for _ , proxy := range p . Proxies ( ) {
name := proxy . Name ( )
allProxies [ name ] = proxy
}
}
return allProxies
}
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-12-04 21:53:13 +08:00
func UpdateListeners ( newListeners map [ string ] C . InboundListener ) {
2022-12-04 15:15:23 +08:00
configMux . Lock ( )
defer configMux . Unlock ( )
2022-12-04 17:20:24 +08:00
listeners = newListeners
2022-12-04 15:15:23 +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
}
2023-01-05 16:58:36 +08:00
// SetFindProcessMode replace SetAlwaysFindProcess
// always find process info if legacyAlways = true or mode.Always() = true, may be increase many memory
2023-01-20 16:29:08 +08:00
func SetFindProcessMode ( mode P . FindProcessMode ) {
findProcessMode = mode
2022-06-14 23:08:07 +08:00
}
2023-03-14 22:37:07 +08:00
func isHandle ( t C . Type ) bool {
2023-03-15 00:10:54 +08:00
status := status . Load ( )
return status == Running || ( status == Inner && t == C . INNER )
2023-03-14 22:37:07 +08:00
}
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
2023-03-12 15:00:59 +08:00
} else if node , ok := resolver . DefaultHosts . Search ( host , false ) ; ok {
2020-04-27 21:28:24 +08:00
// redir-host should lookup the hosts
2023-03-12 15:00:59 +08:00
metadata . DstIP , _ = node . RandIP ( )
} else if node != nil && node . IsDomain {
metadata . Host = node . Domain
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
}
2023-03-12 15:00:59 +08:00
} else if node , ok := resolver . DefaultHosts . Search ( metadata . Host , true ) ; ok {
// try use domain mapping
metadata . Host = node . Domain
2018-12-05 21:13:29 +08:00
}
2020-02-07 20:53:43 +08:00
return nil
}
2023-10-11 10:55:12 +08:00
func resolveMetadata ( metadata * C . Metadata ) ( proxy C . Proxy , rule C . Rule , err error ) {
2022-11-18 22:57:33 +08:00
if metadata . SpecialProxy != "" {
var exist bool
proxy , exist = proxies [ metadata . SpecialProxy ]
if ! exist {
err = fmt . Errorf ( "proxy %s not found" , metadata . SpecialProxy )
}
2022-11-22 19:16:08 +08:00
return
2022-11-18 22:57:33 +08:00
}
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
2022-12-04 14:37:52 +08:00
func handleUDPConn ( packet C . PacketAdapter ) {
2023-09-28 18:59:31 +08:00
if ! isHandle ( packet . Metadata ( ) . Type ) {
packet . Drop ( )
return
}
2019-12-28 18:44:01 +08:00
metadata := packet . Metadata ( )
2019-10-11 20:11:18 +08:00
if ! metadata . Valid ( ) {
2023-04-05 14:05:23 +08:00
packet . Drop ( )
2019-10-11 20:11:18 +08:00
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 {
2023-04-05 14:05:23 +08:00
packet . Drop ( )
2020-02-07 20:53:43 +08:00
log . Debugln ( "[Metadata PreHandle] error: %s" , err )
return
2020-01-31 19:26:33 +08:00
}
2023-10-19 18:30:20 +08:00
if sniffer . Dispatcher . Enable ( ) && sniffingEnable {
sniffer . Dispatcher . UDPSniff ( packet )
}
2020-01-31 14:43:54 +08:00
key := packet . LocalAddr ( ) . String ( )
2020-10-28 21:26:50 +08:00
handle := func ( ) bool {
2023-06-03 21:40:09 +08:00
pc , proxy := natTable . Get ( key )
2020-10-28 21:26:50 +08:00
if pc != nil {
2023-06-03 21:40:09 +08:00
if proxy != nil {
proxy . UpdateWriteBack ( packet )
}
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 ( ) {
2023-04-05 14:05:23 +08:00
packet . Drop ( )
2019-10-11 20:11:18 +08:00
return
}
2023-09-02 16:54:35 +08:00
cond , loaded := natTable . GetOrCreateLock ( key )
2019-12-28 18:44:01 +08:00
2019-10-11 20:11:18 +08:00
go func ( ) {
2023-04-05 14:05:23 +08:00
defer packet . Drop ( )
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 ( ) {
2023-09-02 16:54:35 +08:00
natTable . DeleteLock ( key )
2020-10-28 21:26:50 +08:00
cond . Broadcast ( )
} ( )
2023-10-11 10:55:12 +08:00
proxy , rule , err := resolveMetadata ( 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
}
2023-12-18 14:51:36 +08:00
// local resolve UDP dns
if ! metadata . Resolved ( ) && proxy . Type ( ) != C . Reject && proxy . Type ( ) != C . RejectDrop {
ip , err := resolver . ResolveIP ( context . Background ( ) , metadata . Host )
if err != nil {
packet . Drop ( )
return
}
metadata . DstIP = ip
}
2021-10-15 21:44:53 +08:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , C . DefaultUDPTimeout )
defer cancel ( )
2022-11-24 12:32:35 +08:00
rawPc , err := retry ( ctx , func ( ctx context . Context ) ( C . PacketConn , error ) {
return proxy . ListenPacketContext ( ctx , metadata . Pure ( ) )
} , func ( err error ) {
2020-11-22 23:38:12 +08:00
if rule == nil {
2022-09-02 16:59:00 +08:00
log . Warnln (
"[UDP] dial %s %s --> %s error: %s" ,
proxy . Name ( ) ,
2023-01-25 13:00:18 +08:00
metadata . SourceDetail ( ) ,
2022-09-02 16:59:00 +08:00
metadata . RemoteAddress ( ) ,
err . Error ( ) ,
)
2020-11-22 23:38:12 +08:00
} else {
2023-01-25 13:00:18 +08:00
log . Warnln ( "[UDP] dial %s (match %s/%s) %s --> %s error: %s" , proxy . Name ( ) , rule . RuleType ( ) . String ( ) , rule . Payload ( ) , metadata . SourceDetail ( ) , metadata . RemoteAddress ( ) , err . Error ( ) )
2020-11-22 23:38:12 +08:00
}
2022-11-24 12:32:35 +08:00
} )
if err != nil {
2020-10-28 21:26:50 +08:00
return
}
2022-05-04 16:57:08 +08:00
2023-04-11 23:58:56 +08:00
pc := statistic . NewUDPTracker ( rawPc , statistic . DefaultManager , metadata , rule , 0 , 0 , true )
2020-10-28 21:26:50 +08:00
switch true {
2022-11-18 22:57:33 +08:00
case metadata . SpecialProxy != "" :
2023-01-25 13:00:18 +08:00
log . Infoln ( "[UDP] %s --> %s using %s" , metadata . SourceDetail ( ) , metadata . RemoteAddress ( ) , metadata . SpecialProxy )
2020-10-28 21:26:50 +08:00
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
2023-05-27 13:43:41 +08:00
oAddrPort := metadata . AddrPort ( )
2023-06-03 21:40:09 +08:00
writeBackProxy := nat . NewWriteBackProxy ( packet )
natTable . Set ( key , pc , writeBackProxy )
2023-02-17 16:31:15 +08:00
2023-06-03 21:40:09 +08:00
go handleUDPToLocal ( writeBackProxy , pc , key , oAddrPort , fAddr )
2020-10-28 21:26:50 +08:00
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 ) {
2023-09-28 18:59:31 +08:00
if ! isHandle ( connCtx . Metadata ( ) . Type ) {
_ = connCtx . Conn ( ) . Close ( )
return
}
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
}
2023-09-24 19:27:55 +08:00
preHandleFailed := false
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 )
2023-09-24 19:27:55 +08:00
preHandleFailed = true
2020-02-07 20:53:43 +08:00
}
2023-02-24 09:54:54 +08:00
conn := connCtx . Conn ( )
2023-02-27 00:26:49 +08:00
conn . ResetPeeked ( ) // reset before sniffer
2022-05-24 12:43:26 +08:00
if sniffer . Dispatcher . Enable ( ) && sniffingEnable {
2023-09-24 19:27:55 +08:00
// Try to sniff a domain when `preHandleMetadata` failed, this is usually
// caused by a "Fake DNS record missing" error when enhanced-mode is fake-ip.
if sniffer . Dispatcher . TCPSniff ( conn , metadata ) {
// we now have a domain name
preHandleFailed = false
}
}
// If both trials have failed, we can do nothing but give up
if preHandleFailed {
log . Debugln ( "[Metadata PreHandle] failed to sniff a domain for connection %s --> %s, give up" ,
metadata . SourceDetail ( ) , metadata . RemoteAddress ( ) )
return
2023-02-24 09:54:54 +08:00
}
peekMutex := sync . Mutex { }
if ! conn . Peeked ( ) {
peekMutex . Lock ( )
go func ( ) {
defer peekMutex . Unlock ( )
_ = conn . SetReadDeadline ( time . Now ( ) . Add ( 200 * time . Millisecond ) )
_ , _ = conn . Peek ( 1 )
_ = conn . SetReadDeadline ( time . Time { } )
} ( )
2022-04-09 22:30:36 +08:00
}
2023-10-11 10:55:12 +08:00
proxy , rule , err := resolveMetadata ( 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 {
2023-03-12 15:00:59 +08:00
if node , ok := resolver . DefaultHosts . Search ( metadata . Host , false ) ; ok {
if dstIp , _ := node . RandIP ( ) ; ! FakeIPRange ( ) . Contains ( dstIp ) {
2022-11-10 21:08:06 +08:00
dialMetadata . DstIP = dstIp
dialMetadata . DNSMode = C . DNSHosts
dialMetadata = dialMetadata . Pure ( )
}
2022-10-29 09:02:38 +08:00
}
}
2023-02-24 09:54:54 +08:00
var peekBytes [ ] byte
2023-02-25 19:41:01 +08:00
var peekLen int
2023-02-24 09:54:54 +08:00
2022-04-12 20:20:04 +08:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , C . DefaultTCPTimeout )
defer cancel ( )
2023-02-27 09:46:16 +08:00
remoteConn , err := retry ( ctx , func ( ctx context . Context ) ( remoteConn C . Conn , err error ) {
remoteConn , err = proxy . DialContext ( ctx , dialMetadata )
2023-02-24 09:54:54 +08:00
if err != nil {
2023-02-27 09:46:16 +08:00
return
2023-02-26 11:11:54 +08:00
}
2023-02-27 09:46:16 +08:00
2023-02-27 00:26:49 +08:00
if N . NeedHandshake ( remoteConn ) {
2023-02-27 09:46:16 +08:00
defer func ( ) {
for _ , chain := range remoteConn . Chains ( ) {
if chain == "REJECT" {
err = nil
return
}
}
if err != nil {
remoteConn = nil
}
} ( )
2023-02-27 00:26:49 +08:00
peekMutex . Lock ( )
defer peekMutex . Unlock ( )
peekBytes , _ = conn . Peek ( conn . Buffered ( ) )
_ , err = remoteConn . Write ( peekBytes )
if err != nil {
2023-02-27 09:46:16 +08:00
return
2023-02-27 00:26:49 +08:00
}
if peekLen = len ( peekBytes ) ; peekLen > 0 {
_ , _ = conn . Discard ( peekLen )
}
2023-02-24 09:54:54 +08:00
}
2023-02-27 09:46:16 +08:00
return
2022-11-24 12:32:35 +08:00
} , func ( err error ) {
2020-11-22 23:38:12 +08:00
if rule == nil {
2022-09-02 16:59:00 +08:00
log . Warnln (
"[TCP] dial %s %s --> %s error: %s" ,
proxy . Name ( ) ,
2023-01-25 13:00:18 +08:00
metadata . SourceDetail ( ) ,
2022-09-02 16:59:00 +08:00
metadata . RemoteAddress ( ) ,
err . Error ( ) ,
)
2020-11-22 23:38:12 +08:00
} else {
2023-01-25 13:00:18 +08:00
log . Warnln ( "[TCP] dial %s (match %s/%s) %s --> %s error: %s" , proxy . Name ( ) , rule . RuleType ( ) . String ( ) , rule . Payload ( ) , metadata . SourceDetail ( ) , metadata . RemoteAddress ( ) , err . Error ( ) )
2020-11-22 23:38:12 +08:00
}
2022-11-24 12:32:35 +08:00
} )
if err != nil {
2018-06-10 22:50:03 +08:00
return
}
2022-05-04 16:57:08 +08:00
2023-04-11 23:58:56 +08:00
remoteConn = statistic . NewTCPTracker ( remoteConn , statistic . DefaultManager , metadata , rule , 0 , int64 ( peekLen ) , true )
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 {
2022-11-18 22:57:33 +08:00
case metadata . SpecialProxy != "" :
2023-01-25 13:00:18 +08:00
log . Infoln ( "[TCP] %s --> %s using %s" , metadata . SourceDetail ( ) , metadata . RemoteAddress ( ) , metadata . SpecialProxy )
2020-01-31 14:58:54 +08:00
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-09-02 16:59:00 +08:00
log . Infoln (
"[TCP] %s --> %s doesn't match any rule using DIRECT" ,
2023-01-25 13:00:18 +08:00
metadata . SourceDetail ( ) ,
2022-09-02 16:59:00 +08:00
metadata . RemoteAddress ( ) ,
)
2019-08-09 01:28:37 +08:00
}
2023-02-27 00:26:49 +08:00
_ = conn . SetReadDeadline ( time . Now ( ) ) // stop unfinished peek
2023-02-26 11:18:01 +08:00
peekMutex . Lock ( )
defer peekMutex . Unlock ( )
2023-02-27 00:26:49 +08:00
_ = conn . SetReadDeadline ( time . Time { } ) // reset
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 (
2023-06-08 18:07:56 +08:00
resolved bool
attemptProcessLookup = true
2022-08-12 03:04:58 +08:00
)
2019-09-11 17:00:55 +08:00
2023-03-12 15:00:59 +08:00
if node , ok := resolver . DefaultHosts . Search ( metadata . Host , false ) ; ok {
metadata . DstIP , _ = node . RandIP ( )
2019-09-11 17:00:55 +08:00
resolved = true
}
2022-12-04 13:37:14 +08:00
for _ , rule := range getRules ( metadata ) {
2020-02-15 21:42:46 +08:00
if ! resolved && shouldResolveIP ( rule , metadata ) {
2022-11-12 13:18:36 +08:00
func ( ) {
ctx , cancel := context . WithTimeout ( context . Background ( ) , resolver . DefaultDNSTimeout )
defer cancel ( )
ip , err := resolver . ResolveIP ( ctx , metadata . Host )
if err != nil {
log . Debugln ( "[DNS] resolve %s error: %s" , metadata . Host , err . Error ( ) )
} else {
log . Debugln ( "[DNS] %s --> %s" , metadata . Host , ip . String ( ) )
metadata . DstIP = ip
}
resolved = true
} ( )
2019-02-02 20:47:38 +08:00
}
2023-06-08 18:07:56 +08:00
if attemptProcessLookup && ! findProcessMode . Off ( ) && ( findProcessMode . Always ( ) || rule . ShouldFindProcess ( ) ) {
attemptProcessLookup = false
2023-11-17 23:12:10 +08:00
if ! features . CMFA {
2023-11-17 19:39:57 +08:00
// normal check for process
uid , path , err := P . FindProcessName ( metadata . NetWork . String ( ) , metadata . SrcIP , int ( metadata . SrcPort ) )
if err != nil {
log . Debugln ( "[Process] find process %s error: %v" , metadata . String ( ) , err )
} else {
metadata . Process = filepath . Base ( path )
metadata . ProcessPath = path
metadata . Uid = uid
}
2022-06-14 23:14:43 +08:00
} else {
2023-11-17 19:39:57 +08:00
// check package names
pkg , err := P . FindPackageName ( metadata )
if err != nil {
log . Debugln ( "[Process] find process %s error: %v" , metadata . String ( ) , err )
} else {
metadata . Process = pkg
}
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
}
2022-11-24 12:32:35 +08:00
2022-12-04 13:37:14 +08:00
func getRules ( metadata * C . Metadata ) [ ] C . Rule {
2022-12-04 22:08:20 +08:00
if sr , ok := subRules [ metadata . SpecialRules ] ; ok {
2022-12-05 19:48:54 +08:00
log . Debugln ( "[Rule] use %s rules" , metadata . SpecialRules )
2022-12-04 13:37:14 +08:00
return sr
} else {
2022-12-05 19:48:54 +08:00
log . Debugln ( "[Rule] use default rules" )
2022-12-04 13:37:14 +08:00
return rules
}
}
2022-11-24 12:32:35 +08:00
func retry [ T any ] ( ctx context . Context , ft func ( context . Context ) ( T , error ) , fe func ( err error ) ) ( t T , err error ) {
b := & backoff . Backoff {
Min : 10 * time . Millisecond ,
Max : 1 * time . Second ,
Factor : 2 ,
Jitter : true ,
}
for i := 0 ; i < 10 ; i ++ {
t , err = ft ( ctx )
if err != nil {
if fe != nil {
fe ( err )
}
select {
case <- time . After ( b . Duration ( ) ) :
continue
case <- ctx . Done ( ) :
return
}
} else {
break
}
}
return
}