tunnel.go 17 KB

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