github.com/kelleygo/clashcore@v1.0.2/tunnel/tunnel.go (about) 1 package tunnel 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "net" 8 "net/netip" 9 "path/filepath" 10 "runtime" 11 "sync" 12 "time" 13 14 N "github.com/kelleygo/clashcore/common/net" 15 "github.com/kelleygo/clashcore/component/loopback" 16 "github.com/kelleygo/clashcore/component/nat" 17 P "github.com/kelleygo/clashcore/component/process" 18 "github.com/kelleygo/clashcore/component/resolver" 19 "github.com/kelleygo/clashcore/component/slowdown" 20 "github.com/kelleygo/clashcore/component/sniffer" 21 C "github.com/kelleygo/clashcore/constant" 22 "github.com/kelleygo/clashcore/constant/features" 23 "github.com/kelleygo/clashcore/constant/provider" 24 icontext "github.com/kelleygo/clashcore/context" 25 "github.com/kelleygo/clashcore/log" 26 "github.com/kelleygo/clashcore/tunnel/statistic" 27 ) 28 29 var ( 30 status = newAtomicStatus(Suspend) 31 tcpQueue = make(chan C.ConnContext, 200) 32 udpQueue = make(chan C.PacketAdapter, 200) 33 natTable = nat.New() 34 rules []C.Rule 35 listeners = make(map[string]C.InboundListener) 36 subRules map[string][]C.Rule 37 proxies = make(map[string]C.Proxy) 38 providers map[string]provider.ProxyProvider 39 ruleProviders map[string]provider.RuleProvider 40 sniffingEnable = false 41 configMux sync.RWMutex 42 43 // Outbound Rule 44 mode = Rule 45 46 // default timeout for UDP session 47 udpTimeout = 60 * time.Second 48 49 findProcessMode P.FindProcessMode 50 51 fakeIPRange netip.Prefix 52 ) 53 54 type tunnel struct{} 55 56 var Tunnel C.Tunnel = tunnel{} 57 58 func (t tunnel) HandleTCPConn(conn net.Conn, metadata *C.Metadata) { 59 connCtx := icontext.NewConnContext(conn, metadata) 60 handleTCPConn(connCtx) 61 } 62 63 func (t tunnel) HandleUDPPacket(packet C.UDPPacket, metadata *C.Metadata) { 64 packetAdapter := C.NewPacketAdapter(packet, metadata) 65 select { 66 case udpQueue <- packetAdapter: 67 default: 68 } 69 } 70 71 func (t tunnel) NatTable() C.NatTable { 72 return natTable 73 } 74 75 func OnSuspend() { 76 status.Store(Suspend) 77 } 78 79 func OnInnerLoading() { 80 status.Store(Inner) 81 } 82 83 func OnRunning() { 84 status.Store(Running) 85 } 86 87 func Status() TunnelStatus { 88 return status.Load() 89 } 90 91 func SetFakeIPRange(p netip.Prefix) { 92 fakeIPRange = p 93 } 94 95 func FakeIPRange() netip.Prefix { 96 return fakeIPRange 97 } 98 99 func SetSniffing(b bool) { 100 if sniffer.Dispatcher.Enable() { 101 configMux.Lock() 102 sniffingEnable = b 103 configMux.Unlock() 104 } 105 } 106 107 func IsSniffing() bool { 108 return sniffingEnable 109 } 110 111 func init() { 112 go process() 113 } 114 115 // TCPIn return fan-in queue 116 // Deprecated: using Tunnel instead 117 func TCPIn() chan<- C.ConnContext { 118 return tcpQueue 119 } 120 121 // UDPIn return fan-in udp queue 122 // Deprecated: using Tunnel instead 123 func UDPIn() chan<- C.PacketAdapter { 124 return udpQueue 125 } 126 127 // NatTable return nat table 128 func NatTable() C.NatTable { 129 return natTable 130 } 131 132 // Rules return all rules 133 func Rules() []C.Rule { 134 return rules 135 } 136 137 func Listeners() map[string]C.InboundListener { 138 return listeners 139 } 140 141 // UpdateRules handle update rules 142 func UpdateRules(newRules []C.Rule, newSubRule map[string][]C.Rule, rp map[string]provider.RuleProvider) { 143 configMux.Lock() 144 rules = newRules 145 ruleProviders = rp 146 subRules = newSubRule 147 configMux.Unlock() 148 } 149 150 // Proxies return all proxies 151 func Proxies() map[string]C.Proxy { 152 return proxies 153 } 154 155 func ProxiesWithProviders() map[string]C.Proxy { 156 allProxies := make(map[string]C.Proxy) 157 for name, proxy := range proxies { 158 allProxies[name] = proxy 159 } 160 for _, p := range providers { 161 for _, proxy := range p.Proxies() { 162 name := proxy.Name() 163 allProxies[name] = proxy 164 } 165 } 166 return allProxies 167 } 168 169 // Providers return all compatible providers 170 func Providers() map[string]provider.ProxyProvider { 171 return providers 172 } 173 174 // RuleProviders return all loaded rule providers 175 func RuleProviders() map[string]provider.RuleProvider { 176 return ruleProviders 177 } 178 179 // UpdateProxies handle update proxies 180 func UpdateProxies(newProxies map[string]C.Proxy, newProviders map[string]provider.ProxyProvider) { 181 configMux.Lock() 182 proxies = newProxies 183 providers = newProviders 184 configMux.Unlock() 185 } 186 187 func UpdateListeners(newListeners map[string]C.InboundListener) { 188 configMux.Lock() 189 defer configMux.Unlock() 190 listeners = newListeners 191 } 192 193 func UpdateSniffer(dispatcher *sniffer.SnifferDispatcher) { 194 configMux.Lock() 195 sniffer.Dispatcher = dispatcher 196 sniffingEnable = dispatcher.Enable() 197 configMux.Unlock() 198 } 199 200 // Mode return current mode 201 func Mode() TunnelMode { 202 return mode 203 } 204 205 // SetMode change the mode of tunnel 206 func SetMode(m TunnelMode) { 207 mode = m 208 } 209 210 // SetFindProcessMode replace SetAlwaysFindProcess 211 // always find process info if legacyAlways = true or mode.Always() = true, may be increase many memory 212 func SetFindProcessMode(mode P.FindProcessMode) { 213 findProcessMode = mode 214 } 215 216 func isHandle(t C.Type) bool { 217 status := status.Load() 218 return status == Running || (status == Inner && t == C.INNER) 219 } 220 221 // processUDP starts a loop to handle udp packet 222 func processUDP() { 223 queue := udpQueue 224 for conn := range queue { 225 handleUDPConn(conn) 226 } 227 } 228 229 func process() { 230 numUDPWorkers := 4 231 if num := runtime.GOMAXPROCS(0); num > numUDPWorkers { 232 numUDPWorkers = num 233 } 234 for i := 0; i < numUDPWorkers; i++ { 235 go processUDP() 236 } 237 238 queue := tcpQueue 239 for conn := range queue { 240 go handleTCPConn(conn) 241 } 242 } 243 244 func needLookupIP(metadata *C.Metadata) bool { 245 return resolver.MappingEnabled() && metadata.Host == "" && metadata.DstIP.IsValid() 246 } 247 248 func preHandleMetadata(metadata *C.Metadata) error { 249 // handle IP string on host 250 if ip, err := netip.ParseAddr(metadata.Host); err == nil { 251 metadata.DstIP = ip 252 metadata.Host = "" 253 } 254 255 // preprocess enhanced-mode metadata 256 if needLookupIP(metadata) { 257 host, exist := resolver.FindHostByIP(metadata.DstIP) 258 if exist { 259 metadata.Host = host 260 metadata.DNSMode = C.DNSMapping 261 if resolver.FakeIPEnabled() { 262 metadata.DstIP = netip.Addr{} 263 metadata.DNSMode = C.DNSFakeIP 264 } else if node, ok := resolver.DefaultHosts.Search(host, false); ok { 265 // redir-host should lookup the hosts 266 metadata.DstIP, _ = node.RandIP() 267 } else if node != nil && node.IsDomain { 268 metadata.Host = node.Domain 269 } 270 } else if resolver.IsFakeIP(metadata.DstIP) { 271 return fmt.Errorf("fake DNS record %s missing", metadata.DstIP) 272 } 273 } else if node, ok := resolver.DefaultHosts.Search(metadata.Host, true); ok { 274 // try use domain mapping 275 metadata.Host = node.Domain 276 } 277 278 return nil 279 } 280 281 func resolveMetadata(metadata *C.Metadata) (proxy C.Proxy, rule C.Rule, err error) { 282 if metadata.SpecialProxy != "" { 283 var exist bool 284 proxy, exist = proxies[metadata.SpecialProxy] 285 if !exist { 286 err = fmt.Errorf("proxy %s not found", metadata.SpecialProxy) 287 } 288 return 289 } 290 291 switch mode { 292 case Direct: 293 proxy = proxies["DIRECT"] 294 case Global: 295 proxy = proxies["GLOBAL"] 296 // Rule 297 default: 298 proxy, rule, err = match(metadata) 299 } 300 return 301 } 302 303 func handleUDPConn(packet C.PacketAdapter) { 304 if !isHandle(packet.Metadata().Type) { 305 packet.Drop() 306 return 307 } 308 309 metadata := packet.Metadata() 310 if !metadata.Valid() { 311 packet.Drop() 312 log.Warnln("[Metadata] not valid: %#v", metadata) 313 return 314 } 315 316 // make a fAddr if request ip is fakeip 317 var fAddr netip.Addr 318 if resolver.IsExistFakeIP(metadata.DstIP) { 319 fAddr = metadata.DstIP 320 } 321 322 if err := preHandleMetadata(metadata); err != nil { 323 packet.Drop() 324 log.Debugln("[Metadata PreHandle] error: %s", err) 325 return 326 } 327 328 if sniffer.Dispatcher.Enable() && sniffingEnable { 329 sniffer.Dispatcher.UDPSniff(packet) 330 } 331 332 // local resolve UDP dns 333 if !metadata.Resolved() { 334 ip, err := resolver.ResolveIP(context.Background(), metadata.Host) 335 if err != nil { 336 return 337 } 338 metadata.DstIP = ip 339 } 340 341 key := packet.LocalAddr().String() 342 343 handle := func() bool { 344 pc, proxy := natTable.Get(key) 345 if pc != nil { 346 if proxy != nil { 347 proxy.UpdateWriteBack(packet) 348 } 349 _ = handleUDPToRemote(packet, pc, metadata) 350 return true 351 } 352 return false 353 } 354 355 if handle() { 356 packet.Drop() 357 return 358 } 359 360 cond, loaded := natTable.GetOrCreateLock(key) 361 362 go func() { 363 defer packet.Drop() 364 365 if loaded { 366 cond.L.Lock() 367 cond.Wait() 368 handle() 369 cond.L.Unlock() 370 return 371 } 372 373 defer func() { 374 natTable.DeleteLock(key) 375 cond.Broadcast() 376 }() 377 378 proxy, rule, err := resolveMetadata(metadata) 379 if err != nil { 380 log.Warnln("[UDP] Parse metadata failed: %s", err.Error()) 381 return 382 } 383 384 ctx, cancel := context.WithTimeout(context.Background(), C.DefaultUDPTimeout) 385 defer cancel() 386 rawPc, err := retry(ctx, func(ctx context.Context) (C.PacketConn, error) { 387 return proxy.ListenPacketContext(ctx, metadata.Pure()) 388 }, func(err error) { 389 if rule == nil { 390 log.Warnln( 391 "[UDP] dial %s %s --> %s error: %s", 392 proxy.Name(), 393 metadata.SourceDetail(), 394 metadata.RemoteAddress(), 395 err.Error(), 396 ) 397 } else { 398 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()) 399 } 400 }) 401 if err != nil { 402 return 403 } 404 405 pc := statistic.NewUDPTracker(rawPc, statistic.DefaultManager, metadata, rule, 0, 0, true) 406 407 switch true { 408 case metadata.SpecialProxy != "": 409 log.Infoln("[UDP] %s --> %s using %s", metadata.SourceDetail(), metadata.RemoteAddress(), metadata.SpecialProxy) 410 case rule != nil: 411 if rule.Payload() != "" { 412 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()) 413 if rawPc.Chains().Last() == "REJECT-DROP" { 414 pc.Close() 415 return 416 } 417 } else { 418 log.Infoln("[UDP] %s --> %s match %s using %s", metadata.SourceDetail(), metadata.RemoteAddress(), rule.Payload(), rawPc.Chains().String()) 419 } 420 case mode == Global: 421 log.Infoln("[UDP] %s --> %s using GLOBAL", metadata.SourceDetail(), metadata.RemoteAddress()) 422 case mode == Direct: 423 log.Infoln("[UDP] %s --> %s using DIRECT", metadata.SourceDetail(), metadata.RemoteAddress()) 424 default: 425 log.Infoln("[UDP] %s --> %s doesn't match any rule using DIRECT", metadata.SourceDetail(), metadata.RemoteAddress()) 426 } 427 428 oAddrPort := metadata.AddrPort() 429 writeBackProxy := nat.NewWriteBackProxy(packet) 430 natTable.Set(key, pc, writeBackProxy) 431 432 go handleUDPToLocal(writeBackProxy, pc, key, oAddrPort, fAddr) 433 434 handle() 435 }() 436 } 437 438 func handleTCPConn(connCtx C.ConnContext) { 439 if !isHandle(connCtx.Metadata().Type) { 440 _ = connCtx.Conn().Close() 441 return 442 } 443 444 defer func(conn net.Conn) { 445 _ = conn.Close() 446 }(connCtx.Conn()) 447 448 metadata := connCtx.Metadata() 449 if !metadata.Valid() { 450 log.Warnln("[Metadata] not valid: %#v", metadata) 451 return 452 } 453 454 preHandleFailed := false 455 if err := preHandleMetadata(metadata); err != nil { 456 log.Debugln("[Metadata PreHandle] error: %s", err) 457 preHandleFailed = true 458 } 459 460 conn := connCtx.Conn() 461 conn.ResetPeeked() // reset before sniffer 462 if sniffer.Dispatcher.Enable() && sniffingEnable { 463 // Try to sniff a domain when `preHandleMetadata` failed, this is usually 464 // caused by a "Fake DNS record missing" error when enhanced-mode is fake-ip. 465 if sniffer.Dispatcher.TCPSniff(conn, metadata) { 466 // we now have a domain name 467 preHandleFailed = false 468 } 469 } 470 471 // If both trials have failed, we can do nothing but give up 472 if preHandleFailed { 473 log.Debugln("[Metadata PreHandle] failed to sniff a domain for connection %s --> %s, give up", 474 metadata.SourceDetail(), metadata.RemoteAddress()) 475 return 476 } 477 478 peekMutex := sync.Mutex{} 479 if !conn.Peeked() { 480 peekMutex.Lock() 481 go func() { 482 defer peekMutex.Unlock() 483 _ = conn.SetReadDeadline(time.Now().Add(200 * time.Millisecond)) 484 _, _ = conn.Peek(1) 485 _ = conn.SetReadDeadline(time.Time{}) 486 }() 487 } 488 489 proxy, rule, err := resolveMetadata(metadata) 490 if err != nil { 491 log.Warnln("[Metadata] parse failed: %s", err.Error()) 492 return 493 } 494 495 dialMetadata := metadata 496 if len(metadata.Host) > 0 { 497 if node, ok := resolver.DefaultHosts.Search(metadata.Host, false); ok { 498 if dstIp, _ := node.RandIP(); !FakeIPRange().Contains(dstIp) { 499 dialMetadata.DstIP = dstIp 500 dialMetadata.DNSMode = C.DNSHosts 501 dialMetadata = dialMetadata.Pure() 502 } 503 } 504 } 505 506 var peekBytes []byte 507 var peekLen int 508 509 ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTCPTimeout) 510 defer cancel() 511 remoteConn, err := retry(ctx, func(ctx context.Context) (remoteConn C.Conn, err error) { 512 remoteConn, err = proxy.DialContext(ctx, dialMetadata) 513 if err != nil { 514 return 515 } 516 517 if N.NeedHandshake(remoteConn) { 518 defer func() { 519 for _, chain := range remoteConn.Chains() { 520 if chain == "REJECT" { 521 err = nil 522 return 523 } 524 } 525 if err != nil { 526 remoteConn = nil 527 } 528 }() 529 peekMutex.Lock() 530 defer peekMutex.Unlock() 531 peekBytes, _ = conn.Peek(conn.Buffered()) 532 _, err = remoteConn.Write(peekBytes) 533 if err != nil { 534 return 535 } 536 if peekLen = len(peekBytes); peekLen > 0 { 537 _, _ = conn.Discard(peekLen) 538 } 539 } 540 return 541 }, func(err error) { 542 if rule == nil { 543 log.Warnln( 544 "[TCP] dial %s %s --> %s error: %s", 545 proxy.Name(), 546 metadata.SourceDetail(), 547 metadata.RemoteAddress(), 548 err.Error(), 549 ) 550 } else { 551 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()) 552 } 553 }) 554 if err != nil { 555 return 556 } 557 558 remoteConn = statistic.NewTCPTracker(remoteConn, statistic.DefaultManager, metadata, rule, 0, int64(peekLen), true) 559 defer func(remoteConn C.Conn) { 560 _ = remoteConn.Close() 561 }(remoteConn) 562 563 switch true { 564 case metadata.SpecialProxy != "": 565 log.Infoln("[TCP] %s --> %s using %s", metadata.SourceDetail(), metadata.RemoteAddress(), metadata.SpecialProxy) 566 case rule != nil: 567 if rule.Payload() != "" { 568 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()) 569 } else { 570 log.Infoln("[TCP] %s --> %s match %s using %s", metadata.SourceDetail(), metadata.RemoteAddress(), rule.RuleType().String(), remoteConn.Chains().String()) 571 } 572 case mode == Global: 573 log.Infoln("[TCP] %s --> %s using GLOBAL", metadata.SourceDetail(), metadata.RemoteAddress()) 574 case mode == Direct: 575 log.Infoln("[TCP] %s --> %s using DIRECT", metadata.SourceDetail(), metadata.RemoteAddress()) 576 default: 577 log.Infoln( 578 "[TCP] %s --> %s doesn't match any rule using DIRECT", 579 metadata.SourceDetail(), 580 metadata.RemoteAddress(), 581 ) 582 } 583 584 _ = conn.SetReadDeadline(time.Now()) // stop unfinished peek 585 peekMutex.Lock() 586 defer peekMutex.Unlock() 587 _ = conn.SetReadDeadline(time.Time{}) // reset 588 handleSocket(conn, remoteConn) 589 } 590 591 func shouldResolveIP(rule C.Rule, metadata *C.Metadata) bool { 592 return rule.ShouldResolveIP() && metadata.Host != "" && !metadata.DstIP.IsValid() 593 } 594 595 func match(metadata *C.Metadata) (C.Proxy, C.Rule, error) { 596 configMux.RLock() 597 defer configMux.RUnlock() 598 var ( 599 resolved bool 600 attemptProcessLookup = metadata.Type != C.INNER 601 ) 602 603 if node, ok := resolver.DefaultHosts.Search(metadata.Host, false); ok { 604 metadata.DstIP, _ = node.RandIP() 605 resolved = true 606 } 607 608 for _, rule := range getRules(metadata) { 609 if !resolved && shouldResolveIP(rule, metadata) { 610 func() { 611 ctx, cancel := context.WithTimeout(context.Background(), resolver.DefaultDNSTimeout) 612 defer cancel() 613 ip, err := resolver.ResolveIP(ctx, metadata.Host) 614 if err != nil { 615 log.Debugln("[DNS] resolve %s error: %s", metadata.Host, err.Error()) 616 } else { 617 log.Debugln("[DNS] %s --> %s", metadata.Host, ip.String()) 618 metadata.DstIP = ip 619 } 620 resolved = true 621 }() 622 } 623 624 if attemptProcessLookup && !findProcessMode.Off() && (findProcessMode.Always() || rule.ShouldFindProcess()) { 625 attemptProcessLookup = false 626 if !features.CMFA { 627 // normal check for process 628 uid, path, err := P.FindProcessName(metadata.NetWork.String(), metadata.SrcIP, int(metadata.SrcPort)) 629 if err != nil { 630 log.Debugln("[Process] find process %s error: %v", metadata.String(), err) 631 } else { 632 metadata.Process = filepath.Base(path) 633 metadata.ProcessPath = path 634 metadata.Uid = uid 635 } 636 } else { 637 // check package names 638 pkg, err := P.FindPackageName(metadata) 639 if err != nil { 640 log.Debugln("[Process] find process %s error: %v", metadata.String(), err) 641 } else { 642 metadata.Process = pkg 643 } 644 } 645 } 646 647 if matched, ada := rule.Match(metadata); matched { 648 adapter, ok := proxies[ada] 649 if !ok { 650 continue 651 } 652 653 // parse multi-layer nesting 654 passed := false 655 for adapter := adapter; adapter != nil; adapter = adapter.Unwrap(metadata, false) { 656 if adapter.Type() == C.Pass { 657 passed = true 658 break 659 } 660 } 661 if passed { 662 log.Debugln("%s match Pass rule", adapter.Name()) 663 continue 664 } 665 666 if metadata.NetWork == C.UDP && !adapter.SupportUDP() { 667 log.Debugln("%s UDP is not supported", adapter.Name()) 668 continue 669 } 670 671 return adapter, rule, nil 672 } 673 } 674 675 return proxies["DIRECT"], nil, nil 676 } 677 678 func getRules(metadata *C.Metadata) []C.Rule { 679 if sr, ok := subRules[metadata.SpecialRules]; ok { 680 log.Debugln("[Rule] use %s rules", metadata.SpecialRules) 681 return sr 682 } else { 683 log.Debugln("[Rule] use default rules") 684 return rules 685 } 686 } 687 688 func shouldStopRetry(err error) bool { 689 if errors.Is(err, resolver.ErrIPNotFound) { 690 return true 691 } 692 if errors.Is(err, resolver.ErrIPVersion) { 693 return true 694 } 695 if errors.Is(err, resolver.ErrIPv6Disabled) { 696 return true 697 } 698 if errors.Is(err, loopback.ErrReject) { 699 return true 700 } 701 return false 702 } 703 704 func retry[T any](ctx context.Context, ft func(context.Context) (T, error), fe func(err error)) (t T, err error) { 705 s := slowdown.New() 706 for i := 0; i < 10; i++ { 707 t, err = ft(ctx) 708 if err != nil { 709 if fe != nil { 710 fe(err) 711 } 712 if shouldStopRetry(err) { 713 return 714 } 715 if s.Wait(ctx) == nil { 716 continue 717 } else { 718 return 719 } 720 } else { 721 break 722 } 723 } 724 return 725 }