github.com/yaling888/clash@v1.53.0/tunnel/tunnel.go (about) 1 package tunnel 2 3 import ( 4 "context" 5 "fmt" 6 "math/rand/v2" 7 "net" 8 "net/netip" 9 "path/filepath" 10 "runtime" 11 "sync" 12 "time" 13 14 "github.com/phuslu/log" 15 "github.com/samber/lo" 16 "go.uber.org/atomic" 17 18 A "github.com/yaling888/clash/adapter" 19 "github.com/yaling888/clash/adapter/inbound" 20 "github.com/yaling888/clash/component/nat" 21 P "github.com/yaling888/clash/component/process" 22 "github.com/yaling888/clash/component/resolver" 23 "github.com/yaling888/clash/component/trie" 24 C "github.com/yaling888/clash/constant" 25 "github.com/yaling888/clash/constant/provider" 26 icontext "github.com/yaling888/clash/context" 27 "github.com/yaling888/clash/tunnel/statistic" 28 ) 29 30 var ( 31 tcpQueue = make(chan C.ConnContext, 512) 32 udpQueue = make(chan *inbound.PacketAdapter, 1024) 33 natTable = nat.New[string, C.PacketConn]() 34 addrTable = nat.New[string, netip.Addr]() 35 rules []C.Rule 36 proxies = make(map[string]C.Proxy) 37 providers map[string]provider.ProxyProvider 38 rewrites C.RewriteRule 39 rewriteHosts *trie.DomainTrie[bool] 40 configMux sync.RWMutex 41 42 // Outbound Rule 43 mode = Rule 44 45 // sniffing switch 46 sniffing = false 47 48 // default timeout for UDP session 49 udpTimeout = 60 * time.Second 50 51 // mitmProxy mitm proxy 52 mitmProxy C.Proxy 53 54 // scriptMainMatcher script main function eval 55 scriptMainMatcher C.Matcher 56 57 scriptProxyProvidersGetter = func() map[string][]C.Proxy { 58 providersMap := make(map[string][]C.Proxy) 59 for k, v := range providers { 60 providersMap[k] = v.Proxies() 61 } 62 return providersMap 63 } 64 65 UDPFallbackMatch = atomic.NewBool(false) 66 UDPFallbackPolicy = atomic.NewString("") 67 ) 68 69 func init() { 70 go process() 71 } 72 73 // TCPIn return fan-in queue 74 func TCPIn() chan<- C.ConnContext { 75 return tcpQueue 76 } 77 78 // UDPIn return fan-in udp queue 79 func UDPIn() chan<- *inbound.PacketAdapter { 80 return udpQueue 81 } 82 83 // Rules return all rules 84 func Rules() []C.Rule { 85 return rules 86 } 87 88 // UpdateRules handle update rules 89 func UpdateRules(newRules []C.Rule) { 90 configMux.Lock() 91 rules = newRules 92 configMux.Unlock() 93 } 94 95 // Proxies return all proxies 96 func Proxies() map[string]C.Proxy { 97 return proxies 98 } 99 100 // Providers return all compatible providers 101 func Providers() map[string]provider.ProxyProvider { 102 return providers 103 } 104 105 func FindProxyByName(name string) (proxy C.Proxy, found bool) { 106 proxy, found = proxies[name] 107 if found { 108 return 109 } 110 pds := providers 111 for _, pd := range pds { 112 if pd.VehicleType() == provider.Compatible { 113 continue 114 } 115 ps := pd.Proxies() 116 for _, p := range ps { 117 if found = p.Name() == name; found { 118 proxy = p 119 return 120 } 121 } 122 } 123 return 124 } 125 126 func FetchRawProxyAdapter(proxy C.Proxy, metadata *C.Metadata) (C.Proxy, []string) { 127 var ( 128 chains = []string{proxy.Name()} 129 rawProxy = proxy 130 subProxy = proxy.Unwrap(metadata) 131 ) 132 for subProxy != nil { 133 chains = append(chains, subProxy.Name()) 134 rawProxy = subProxy 135 subProxy = subProxy.Unwrap(metadata) 136 } 137 return rawProxy, chains 138 } 139 140 // UpdateProxies handle update proxies 141 func UpdateProxies(newProxies map[string]C.Proxy, newProviders map[string]provider.ProxyProvider) { 142 configMux.Lock() 143 old := proxies 144 oldPDs := providers 145 proxies = newProxies 146 providers = newProviders 147 C.GetScriptProxyProviders = scriptProxyProvidersGetter 148 statistic.DefaultManager.Cleanup() 149 provider.Cleanup(old, oldPDs) 150 configMux.Unlock() 151 } 152 153 // Mode return current mode 154 func Mode() TunnelMode { 155 return mode 156 } 157 158 // SetMode change the mode of tunnel 159 func SetMode(m TunnelMode) { 160 mode = m 161 } 162 163 func Sniffing() bool { 164 return sniffing 165 } 166 167 func SetSniffing(s bool) { 168 sniffing = s 169 } 170 171 // SetMitmOutbound set the MITM outbound 172 func SetMitmOutbound(outbound C.ProxyAdapter) { 173 if outbound != nil { 174 mitmProxy = A.NewProxy(outbound) 175 } else { 176 mitmProxy = nil 177 } 178 } 179 180 // Rewrites return all rewrites 181 func Rewrites() C.RewriteRule { 182 return rewrites 183 } 184 185 // UpdateRewrites handle update rewrites 186 func UpdateRewrites(hosts *trie.DomainTrie[bool], rules C.RewriteRule) { 187 configMux.Lock() 188 rewriteHosts = hosts 189 rewrites = rules 190 configMux.Unlock() 191 } 192 193 // UpdateScript update script config 194 func UpdateScript(providers map[string]C.Rule, matcher C.Matcher) { 195 configMux.Lock() 196 C.SetScriptRuleProviders(providers) 197 scriptMainMatcher = matcher 198 configMux.Unlock() 199 } 200 201 // processUDP starts a loop to handle udp packet 202 func processUDP() { 203 queue := udpQueue 204 for conn := range queue { 205 handleUDPConn(conn) 206 } 207 } 208 209 func process() { 210 numUDPWorkers := 4 211 if num := runtime.GOMAXPROCS(0); num > numUDPWorkers { 212 numUDPWorkers = num 213 } 214 for i := 0; i < numUDPWorkers; i++ { 215 go processUDP() 216 } 217 218 queue := tcpQueue 219 for conn := range queue { 220 go handleTCPConn(conn) 221 } 222 } 223 224 func needLookupIP(metadata *C.Metadata) bool { 225 return resolver.MappingEnabled() && metadata.Host == "" && metadata.DstIP.IsValid() 226 } 227 228 func preHandleMetadata(metadata *C.Metadata) error { 229 // handle IP string on host 230 if ip, err := netip.ParseAddr(metadata.Host); err == nil { 231 metadata.DstIP = ip 232 metadata.Host = "" 233 } 234 235 // preprocess enhanced-mode metadata 236 if needLookupIP(metadata) { 237 host, exist := resolver.FindHostByIP(metadata.DstIP) 238 if exist { 239 metadata.Host = host 240 metadata.DNSMode = C.DNSMapping 241 if resolver.FakeIPEnabled() && (metadata.NetWork != C.UDP || resolver.IsFakeIP(metadata.DstIP)) { 242 metadata.DstIP = netip.Addr{} 243 metadata.DNSMode = C.DNSFakeIP 244 } else if node := resolver.DefaultHosts.Search(host); node != nil { 245 // redir-host should look up the hosts 246 metadata.DstIP = node.Data 247 } 248 } else if resolver.IsFakeIP(metadata.DstIP) { 249 return fmt.Errorf("fake DNS record %s missing", metadata.DstIP) 250 } 251 } 252 253 return nil 254 } 255 256 func resolveMetadata(_ C.PlainContext, metadata *C.Metadata) (proxy C.Proxy, rule C.Rule, err error) { 257 if metadata.NetWork == C.TCP && mitmProxy != nil && metadata.Type != C.MITM && 258 ((rewriteHosts != nil && rewriteHosts.Search(metadata.String()) != nil) || metadata.DstPort == 80) { 259 proxy = mitmProxy 260 return 261 } 262 263 if metadata.SpecialProxy != "" { 264 var exist bool 265 proxy, exist = FindProxyByName(metadata.SpecialProxy) 266 if !exist { 267 err = fmt.Errorf("proxy %s not found", metadata.SpecialProxy) 268 } 269 return 270 } 271 272 switch mode { 273 case Rule: 274 proxy, rule, err = match(metadata) 275 case Script: 276 proxy, err = matchScript(metadata) 277 if err != nil { 278 err = fmt.Errorf("execute script failed: %w", err) 279 } 280 case Direct: 281 proxy = proxies["DIRECT"] 282 case Global: 283 proxy = proxies["GLOBAL"] 284 default: 285 panic(fmt.Sprintf("unknown mode: %s", mode)) 286 } 287 return 288 } 289 290 func resolveDNS(metadata *C.Metadata, proxy, rawProxy C.Proxy) (isRemote bool, err error) { 291 if metadata.Host == "" || metadata.DNSMode == C.DNSMapping { 292 return 293 } 294 295 if proxy.DisableDnsResolve() || rawProxy.DisableDnsResolve() { 296 isRemote = false 297 } else { 298 isRemote = resolver.RemoteDnsResolve 299 } 300 301 isUDP := metadata.NetWork == C.UDP 302 303 if isRemote { 304 var ( 305 hasV6 = rawProxy.HasV6() && !(isUDP && metadata.Type == C.TUN) 306 rAddrs []netip.Addr 307 ) 308 if hasV6 { 309 rAddrs, err = resolver.LookupIPByProxy(context.Background(), metadata.Host, rawProxy.Name()) 310 } else { 311 rAddrs, err = resolver.LookupIPv4ByProxy(context.Background(), metadata.Host, rawProxy.Name()) 312 } 313 if err != nil { 314 return 315 } 316 if isUDP { 317 metadata.DstIP = rAddrs[0] 318 } else { 319 if hasV6 { 320 v6 := lo.Filter(rAddrs, func(addr netip.Addr, _ int) bool { 321 return addr.Is6() 322 }) 323 if len(v6) > 0 { 324 rAddrs = v6 // priority use ipv6 325 } 326 } 327 metadata.DstIP = rAddrs[rand.IntN(len(rAddrs))] 328 } 329 } else if isUDP { 330 err = localResolveDNS(metadata, true) 331 } else { // tcp 332 metadata.DstIP = netip.Addr{} 333 } 334 return 335 } 336 337 func localResolveDNS(metadata *C.Metadata, udp bool) (err error) { 338 if metadata.Resolved() { 339 return nil 340 } 341 var rAddrs []netip.Addr 342 if udp && metadata.Type == C.TUN { 343 rAddrs, err = resolver.LookupIPv4(context.Background(), metadata.Host) 344 } else { 345 rAddrs, err = resolver.LookupIP(context.Background(), metadata.Host) 346 } 347 if err != nil { 348 return err 349 } 350 if udp { 351 metadata.DstIP = rAddrs[0] 352 } else { 353 metadata.DstIP = rAddrs[rand.IntN(len(rAddrs))] 354 } 355 return nil 356 } 357 358 func handleUDPConn(packet *inbound.PacketAdapter) { 359 metadata := packet.Metadata() 360 if !metadata.Valid() { 361 log.Warn().Msgf("[Metadata] not valid: %#v", metadata) 362 packet.Drop() 363 return 364 } 365 366 var ( 367 fAddr netip.Addr // make a fAddr if request ip is fakeip 368 rKey string // localAddrPort + remoteFakeIP + remotePort 369 key = packet.LocalAddr().String() 370 ) 371 372 if resolver.IsExistFakeIP(metadata.DstIP) { 373 fAddr = metadata.DstIP 374 rKey = key + fAddr.String() + metadata.DstPort.String() 375 } 376 377 if err := preHandleMetadata(metadata); err != nil { 378 log.Debug().Err(err).Msg("[Metadata] prehandle failed") 379 packet.Drop() 380 return 381 } 382 383 log.Debug().EmbedObject(metadata).Any("inbound", metadata.Type).Msg("[UDP] accept session") 384 385 handle := func() bool { 386 pc := natTable.Get(key) 387 if pc != nil { 388 if !metadata.Resolved() { 389 if rAddr := addrTable.Get(rKey); rAddr.IsValid() { 390 metadata.DstIP = rAddr 391 } else { 392 return false 393 } 394 } 395 _ = handleUDPToRemote(packet, pc, metadata) 396 return true 397 } 398 return false 399 } 400 401 if handle() { 402 packet.Drop() 403 return 404 } 405 406 lockKey := key + "-lock" 407 cond, loaded := natTable.GetOrCreateLock(lockKey) 408 409 go func() { 410 defer packet.Drop() 411 412 if loaded { 413 cond.L.Lock() 414 cond.Wait() 415 handle() 416 cond.L.Unlock() 417 return 418 } 419 420 defer func() { 421 natTable.Delete(lockKey) 422 cond.Broadcast() 423 }() 424 425 pCtx := icontext.NewPacketConnContext(metadata) 426 proxy, rule, err := resolveMetadata(pCtx, metadata) 427 if err != nil { 428 log.Warn().Err(err).Msg("[Metadata] parse failed") 429 return 430 } 431 432 rawProxy, chains := FetchRawProxyAdapter(proxy, metadata) 433 434 isRemote, err := resolveDNS(metadata, proxy, rawProxy) 435 if err != nil { 436 if isRemote { 437 log.Warn().Err(err). 438 Str("proxy", rawProxy.Name()). 439 Str("host", metadata.Host). 440 Msg("[UDP] remote resolve DNS failed") 441 } else { 442 log.Warn().Err(err). 443 Str("host", metadata.Host). 444 Msg("[UDP] resolve DNS failed") 445 } 446 return 447 } 448 449 ctx, cancel := context.WithTimeout(context.Background(), C.DefaultUDPTimeout) 450 defer cancel() 451 452 rawPc, err := rawProxy.ListenPacketContext(ctx, metadata) 453 if err != nil { 454 if rule == nil { 455 log.Warn(). 456 Err(err). 457 Str("proxy", rawProxy.Name()). 458 Any("rAddr", C.LogAddr{M: *metadata}). 459 Msg("[UDP] dial failed") 460 } else { 461 log.Warn(). 462 Err(err). 463 Str("proxy", rawProxy.Name()). 464 Any("rAddr", C.LogAddr{M: *metadata}). 465 Any("rule", rule.RuleType()). 466 Str("rulePayload", rule.Payload()). 467 Any("ruleGroup", rule.RuleGroups()). 468 Msg("[UDP] dial failed") 469 } 470 return 471 } 472 473 if len(chains) > 1 { 474 rawPc.SetChains(lo.Reverse(chains)) 475 } 476 477 pCtx.InjectPacketConn(rawPc) 478 pc := statistic.NewUDPTracker(rawPc, statistic.DefaultManager, metadata, rule) 479 480 switch true { 481 case metadata.SpecialProxy != "": 482 log.Info(). 483 EmbedObject(metadata). 484 Any("proxy", rawPc). 485 Msg("[UDP] tunnel connected") 486 case rule != nil: 487 log.Info(). 488 EmbedObject(metadata). 489 Any("mode", mode). 490 Any("rule", C.LogRule{R: rule}). 491 Any("proxy", rawPc). 492 Any("ruleGroup", rule.RuleGroups()). 493 Msg("[UDP] connected") 494 default: 495 log.Info().EmbedObject(metadata).Any("mode", mode).Any("proxy", rawPc).Msg("[UDP] connected") 496 } 497 498 oAddr := metadata.DstIP 499 go handleUDPToLocal(packet.UDPPacket, pc, key, rKey, oAddr, fAddr) 500 501 if rKey != "" { 502 addrTable.Set(rKey, oAddr) 503 } 504 505 natTable.Set(key, pc) 506 handle() 507 }() 508 } 509 510 func handleTCPConn(connCtx C.ConnContext) { 511 defer func(conn net.Conn) { 512 _ = conn.Close() 513 }(connCtx.Conn()) 514 515 metadata := connCtx.Metadata() 516 if !metadata.Valid() { 517 log.Warn().Msgf("[Metadata] not valid: %#v", metadata) 518 return 519 } 520 521 if err := preHandleMetadata(metadata); err != nil { 522 log.Debug().Err(err).Msg("[Metadata] prehandle failed") 523 return 524 } 525 526 log.Debug().EmbedObject(metadata).Any("inbound", metadata.Type).Msg("[TCP] accept connection") 527 528 proxy, rule, err := resolveMetadata(connCtx, metadata) 529 if err != nil { 530 log.Warn().Err(err).Msg("[Metadata] parse failed") 531 return 532 } 533 534 var ( 535 rawProxy C.Proxy 536 chains []string 537 538 isMitmOutbound = proxy == mitmProxy 539 ) 540 541 if !isMitmOutbound { 542 rawProxy, chains = FetchRawProxyAdapter(proxy, metadata) 543 isRemote, err2 := resolveDNS(metadata, proxy, rawProxy) 544 if err2 != nil { 545 if isRemote { 546 log.Warn().Err(err2). 547 Str("proxy", rawProxy.Name()). 548 Str("host", metadata.Host). 549 Msg("[TCP] remote resolve DNS failed") 550 } else { 551 log.Warn().Err(err2). 552 Str("host", metadata.Host). 553 Msg("[TCP] resolve DNS failed") 554 } 555 return 556 } 557 } else { 558 rawProxy = proxy 559 } 560 561 ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTCPTimeout) 562 defer cancel() 563 remoteConn, err := rawProxy.DialContext(ctx, metadata) 564 if err != nil { 565 if rule == nil { 566 log.Warn(). 567 Err(err). 568 Str("proxy", rawProxy.Name()). 569 Any("rAddr", C.LogAddr{M: *metadata}). 570 Msg("[TCP] dial failed") 571 } else { 572 log.Warn(). 573 Err(err). 574 Str("proxy", rawProxy.Name()). 575 Any("rAddr", C.LogAddr{M: *metadata}). 576 Any("rule", rule.RuleType()). 577 Str("rulePayload", rule.Payload()). 578 Any("ruleGroup", rule.RuleGroups()). 579 Msg("[TCP] dial failed") 580 } 581 return 582 } 583 584 if len(chains) > 1 { 585 remoteConn.SetChains(lo.Reverse(chains)) 586 } 587 588 if rawProxy.Name() != "REJECT" && !isMitmOutbound { 589 remoteConn = statistic.NewTCPTracker(remoteConn, statistic.DefaultManager, metadata, rule) 590 if sniffing { 591 remoteConn = statistic.NewSniffing(remoteConn, metadata, rule) 592 } 593 } 594 595 defer func(remoteConn C.Conn) { 596 _ = remoteConn.Close() 597 }(remoteConn) 598 599 switch { 600 case isMitmOutbound: 601 case metadata.SpecialProxy != "": 602 log.Info(). 603 EmbedObject(metadata). 604 Any("proxy", remoteConn). 605 Msg("[TCP] tunnel connected") 606 case rule != nil: 607 log.Info(). 608 EmbedObject(metadata). 609 Any("mode", mode). 610 Any("rule", C.LogRule{R: rule}). 611 Any("proxy", remoteConn). 612 Any("ruleGroup", rule.RuleGroups()). 613 Msg("[TCP] connected") 614 default: 615 log.Info(). 616 EmbedObject(metadata). 617 Any("mode", mode). 618 Any("proxy", remoteConn). 619 Msg("[TCP] connected") 620 } 621 622 handleSocket(connCtx, remoteConn) 623 } 624 625 func shouldResolveIP(rule C.Rule, metadata *C.Metadata) bool { 626 return rule.ShouldResolveIP() && metadata.Host != "" && !metadata.DstIP.IsValid() 627 } 628 629 func match(metadata *C.Metadata) (C.Proxy, C.Rule, error) { 630 configMux.RLock() 631 defer configMux.RUnlock() 632 633 var ( 634 resolved bool 635 processFound bool 636 ) 637 638 if node := resolver.DefaultHosts.Search(metadata.Host); node != nil { 639 metadata.DstIP = node.Data 640 resolved = true 641 } 642 643 adapter, rule := matchRule(rules, metadata, &resolved, &processFound) 644 645 if adapter != nil { 646 return adapter, rule, nil 647 } 648 649 if len(rules) == 0 { 650 return proxies["DIRECT"], nil, nil 651 } 652 653 return proxies["REJECT"], nil, nil 654 } 655 656 func matchRule(subRules []C.Rule, metadata *C.Metadata, resolved, processFound *bool) (C.Proxy, C.Rule) { 657 for _, rule := range subRules { 658 if !*resolved && shouldResolveIP(rule, metadata) { 659 rAddrs, err := resolver.LookupIP(context.Background(), metadata.Host) 660 if err != nil { 661 log.Debug(). 662 Err(err). 663 Str("host", metadata.Host). 664 Msg("[Matcher] resolve failed") 665 } else { 666 ip := rAddrs[0] 667 if l := len(rAddrs); l > 1 && metadata.NetWork != C.UDP { 668 ip = rAddrs[rand.IntN(l)] 669 } 670 log.Debug(). 671 Str("host", metadata.Host). 672 NetIPAddr("ip", ip). 673 Msg("[Matcher] resolve success") 674 675 metadata.DstIP = ip 676 } 677 *resolved = true 678 } 679 680 if !*processFound && rule.ShouldFindProcess() { 681 *processFound = true 682 683 if metadata.OriginDst.IsValid() { 684 path, err2 := P.FindProcessPath( 685 metadata.NetWork.String(), 686 netip.AddrPortFrom(metadata.SrcIP, uint16(metadata.SrcPort)), 687 metadata.OriginDst, 688 ) 689 690 if err2 != nil { 691 log.Debug(). 692 Err(err2). 693 Any("addr", C.LogAddr{M: *metadata, HostOnly: true}). 694 Msg("[Matcher] find process failed") 695 } else { 696 log.Debug(). 697 Any("addr", C.LogAddr{M: *metadata, HostOnly: true}). 698 Str("path", path). 699 Msg("[Matcher] find process success") 700 701 metadata.Process = filepath.Base(path) 702 metadata.ProcessPath = path 703 } 704 } 705 } 706 707 if rule.Match(metadata) { 708 if rule.RuleType() == C.Group { 709 adapter, subRule := matchRule(rule.SubRules(), metadata, resolved, processFound) 710 if adapter != nil { 711 return adapter, subRule 712 } 713 continue 714 } 715 716 adapter, ok := FindProxyByName(rule.Adapter()) 717 if !ok { 718 continue 719 } 720 721 extra := rule.RuleExtra() 722 if extra != nil { 723 if extra.NotMatchNetwork(metadata.NetWork) { 724 continue 725 } 726 727 if extra.NotMatchSourceIP(metadata.SrcIP) { 728 continue 729 } 730 731 if extra.NotMatchProcessName(metadata.Process) { 732 continue 733 } 734 } 735 736 if metadata.NetWork == C.UDP && !adapter.SupportUDP() { 737 if !UDPFallbackMatch.Load() { 738 policy := UDPFallbackPolicy.Load() 739 if policy != "" { 740 if adapter2, ok2 := FindProxyByName(policy); ok2 { 741 return adapter2, rule 742 } 743 log.Warn(). 744 Str("policy", policy). 745 Msg("[Matcher] UDP fallback policy not found, skip use policy") 746 } 747 } else { 748 log.Debug(). 749 Str("proxy", adapter.Name()). 750 Msg("[Matcher] UDP is not supported, skip match") 751 continue 752 } 753 } 754 755 return adapter, rule 756 } 757 } 758 759 return nil, nil 760 } 761 762 func matchScript(metadata *C.Metadata) (C.Proxy, error) { 763 configMux.RLock() 764 defer configMux.RUnlock() 765 766 if node := resolver.DefaultHosts.Search(metadata.Host); node != nil { 767 metadata.DstIP = node.Data 768 } 769 770 adapterName, err := scriptMainMatcher.Eval(metadata) 771 if err != nil { 772 return nil, err 773 } 774 775 adapter, ok := FindProxyByName(adapterName) 776 if !ok { 777 return nil, fmt.Errorf("proxy %s not found", adapterName) 778 } 779 780 if metadata.NetWork == C.UDP && !adapter.SupportUDP() { 781 if !UDPFallbackMatch.Load() { 782 policy := UDPFallbackPolicy.Load() 783 if policy != "" { 784 if adapter2, ok2 := FindProxyByName(policy); ok2 { 785 return adapter2, nil 786 } 787 log.Warn(). 788 Str("policy", policy). 789 Msg("[Matcher] UDP fallback policy not found, skip use policy") 790 } 791 } else { 792 log.Debug(). 793 Str("proxy", adapterName). 794 Msg("[Matcher] UDP is not supported, use `REJECT` policy") 795 return proxies["REJECT"], nil 796 } 797 } 798 799 return adapter, nil 800 }