route.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  1. package route
  2. import (
  3. "context"
  4. "errors"
  5. "net"
  6. "net/netip"
  7. "os"
  8. "os/user"
  9. "strings"
  10. "syscall"
  11. "time"
  12. "github.com/sagernet/sing-box/adapter"
  13. "github.com/sagernet/sing-box/common/conntrack"
  14. "github.com/sagernet/sing-box/common/process"
  15. "github.com/sagernet/sing-box/common/sniff"
  16. C "github.com/sagernet/sing-box/constant"
  17. "github.com/sagernet/sing-box/option"
  18. "github.com/sagernet/sing-box/outbound"
  19. "github.com/sagernet/sing-box/route/rule"
  20. "github.com/sagernet/sing-dns"
  21. "github.com/sagernet/sing-mux"
  22. "github.com/sagernet/sing-tun"
  23. "github.com/sagernet/sing-vmess"
  24. "github.com/sagernet/sing/common"
  25. "github.com/sagernet/sing/common/buf"
  26. "github.com/sagernet/sing/common/bufio"
  27. "github.com/sagernet/sing/common/bufio/deadline"
  28. E "github.com/sagernet/sing/common/exceptions"
  29. F "github.com/sagernet/sing/common/format"
  30. M "github.com/sagernet/sing/common/metadata"
  31. N "github.com/sagernet/sing/common/network"
  32. "github.com/sagernet/sing/common/uot"
  33. )
  34. // Deprecated: use RouteConnectionEx instead.
  35. func (r *Router) RouteConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
  36. return r.routeConnection(ctx, conn, metadata, nil)
  37. }
  38. func (r *Router) RouteConnectionEx(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) {
  39. err := r.routeConnection(ctx, conn, metadata, onClose)
  40. if err != nil {
  41. N.CloseOnHandshakeFailure(conn, onClose, err)
  42. if E.IsClosedOrCanceled(err) {
  43. r.logger.DebugContext(ctx, "connection closed: ", err)
  44. } else {
  45. r.logger.ErrorContext(ctx, err)
  46. }
  47. }
  48. }
  49. func (r *Router) routeConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) error {
  50. if r.pauseManager.IsDevicePaused() {
  51. return E.New("reject connection to ", metadata.Destination, " while device paused")
  52. }
  53. if metadata.InboundDetour != "" {
  54. if metadata.LastInbound == metadata.InboundDetour {
  55. return E.New("routing loop on detour: ", metadata.InboundDetour)
  56. }
  57. detour := r.inboundByTag[metadata.InboundDetour]
  58. if detour == nil {
  59. return E.New("inbound detour not found: ", metadata.InboundDetour)
  60. }
  61. injectable, isInjectable := detour.(adapter.TCPInjectableInbound)
  62. if !isInjectable {
  63. return E.New("inbound detour is not TCP injectable: ", metadata.InboundDetour)
  64. }
  65. metadata.LastInbound = metadata.Inbound
  66. metadata.Inbound = metadata.InboundDetour
  67. metadata.InboundDetour = ""
  68. injectable.NewConnectionEx(ctx, conn, metadata, onClose)
  69. return nil
  70. }
  71. conntrack.KillerCheck()
  72. metadata.Network = N.NetworkTCP
  73. switch metadata.Destination.Fqdn {
  74. case mux.Destination.Fqdn:
  75. return E.New("global multiplex is deprecated since sing-box v1.7.0, enable multiplex in inbound options instead.")
  76. case vmess.MuxDestination.Fqdn:
  77. return E.New("global multiplex (v2ray legacy) not supported since sing-box v1.7.0.")
  78. case uot.MagicAddress:
  79. return E.New("global UoT not supported since sing-box v1.7.0.")
  80. case uot.LegacyMagicAddress:
  81. return E.New("global UoT (legacy) not supported since sing-box v1.7.0.")
  82. }
  83. if deadline.NeedAdditionalReadDeadline(conn) {
  84. conn = deadline.NewConn(conn)
  85. }
  86. selectedRule, _, buffers, err := r.matchRule(ctx, &metadata, conn, nil, -1)
  87. if err != nil {
  88. return err
  89. }
  90. var selectedOutbound adapter.Outbound
  91. var selectReturn bool
  92. if selectedRule != nil {
  93. switch action := selectedRule.Action().(type) {
  94. case *rule.RuleActionRoute:
  95. var loaded bool
  96. selectedOutbound, loaded = r.Outbound(action.Outbound)
  97. if !loaded {
  98. buf.ReleaseMulti(buffers)
  99. return E.New("outbound not found: ", action.Outbound)
  100. }
  101. case *rule.RuleActionReturn:
  102. selectReturn = true
  103. case *rule.RuleActionReject:
  104. buf.ReleaseMulti(buffers)
  105. var rejectErr error
  106. switch action.Method {
  107. case C.RuleActionRejectMethodDefault:
  108. rejectErr = os.ErrClosed
  109. case C.RuleActionRejectMethodPortUnreachable:
  110. rejectErr = syscall.ECONNREFUSED
  111. case C.RuleActionRejectMethodDrop:
  112. rejectErr = tun.ErrDrop
  113. }
  114. N.CloseOnHandshakeFailure(conn, onClose, rejectErr)
  115. return nil
  116. }
  117. }
  118. if selectedRule == nil || selectReturn {
  119. if r.defaultOutboundForConnection == nil {
  120. buf.ReleaseMulti(buffers)
  121. return E.New("missing default outbound with TCP support")
  122. }
  123. selectedOutbound = r.defaultOutboundForConnection
  124. }
  125. if !common.Contains(selectedOutbound.Network(), N.NetworkTCP) {
  126. buf.ReleaseMulti(buffers)
  127. return E.New("TCP is not supported by outbound: ", selectedOutbound.Tag())
  128. }
  129. for _, buffer := range buffers {
  130. conn = bufio.NewCachedConn(conn, buffer)
  131. }
  132. if r.clashServer != nil {
  133. trackerConn, tracker := r.clashServer.RoutedConnection(ctx, conn, metadata, selectedRule)
  134. defer tracker.Leave()
  135. conn = trackerConn
  136. }
  137. if r.v2rayServer != nil {
  138. if statsService := r.v2rayServer.StatsService(); statsService != nil {
  139. conn = statsService.RoutedConnection(metadata.Inbound, selectedOutbound.Tag(), metadata.User, conn)
  140. }
  141. }
  142. legacyOutbound, isLegacy := selectedOutbound.(adapter.ConnectionHandler)
  143. if isLegacy {
  144. err = legacyOutbound.NewConnection(ctx, conn, metadata)
  145. if err != nil {
  146. conn.Close()
  147. if onClose != nil {
  148. onClose(err)
  149. }
  150. return E.Cause(err, "outbound/", selectedOutbound.Type(), "[", selectedOutbound.Tag(), "]")
  151. } else {
  152. if onClose != nil {
  153. onClose(nil)
  154. }
  155. }
  156. return nil
  157. }
  158. // TODO
  159. err = outbound.NewConnection(ctx, selectedOutbound, conn, metadata)
  160. if err != nil {
  161. conn.Close()
  162. if onClose != nil {
  163. onClose(err)
  164. }
  165. return E.Cause(err, "outbound/", selectedOutbound.Type(), "[", selectedOutbound.Tag(), "]")
  166. } else {
  167. if onClose != nil {
  168. onClose(nil)
  169. }
  170. }
  171. return nil
  172. }
  173. func (r *Router) RoutePacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
  174. err := r.routePacketConnection(ctx, conn, metadata, nil)
  175. if err != nil {
  176. conn.Close()
  177. if E.IsClosedOrCanceled(err) {
  178. r.logger.DebugContext(ctx, "connection closed: ", err)
  179. } else {
  180. r.logger.ErrorContext(ctx, err)
  181. }
  182. }
  183. return nil
  184. }
  185. func (r *Router) RoutePacketConnectionEx(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) {
  186. err := r.routePacketConnection(ctx, conn, metadata, onClose)
  187. if err != nil {
  188. N.CloseOnHandshakeFailure(conn, onClose, err)
  189. if E.IsClosedOrCanceled(err) {
  190. r.logger.DebugContext(ctx, "connection closed: ", err)
  191. } else {
  192. r.logger.ErrorContext(ctx, err)
  193. }
  194. } else if onClose != nil {
  195. onClose(nil)
  196. }
  197. }
  198. func (r *Router) routePacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) error {
  199. if r.pauseManager.IsDevicePaused() {
  200. return E.New("reject packet connection to ", metadata.Destination, " while device paused")
  201. }
  202. if metadata.InboundDetour != "" {
  203. if metadata.LastInbound == metadata.InboundDetour {
  204. return E.New("routing loop on detour: ", metadata.InboundDetour)
  205. }
  206. detour := r.inboundByTag[metadata.InboundDetour]
  207. if detour == nil {
  208. return E.New("inbound detour not found: ", metadata.InboundDetour)
  209. }
  210. injectable, isInjectable := detour.(adapter.UDPInjectableInbound)
  211. if !isInjectable {
  212. return E.New("inbound detour is not UDP injectable: ", metadata.InboundDetour)
  213. }
  214. metadata.LastInbound = metadata.Inbound
  215. metadata.Inbound = metadata.InboundDetour
  216. metadata.InboundDetour = ""
  217. injectable.NewPacketConnectionEx(ctx, conn, metadata, onClose)
  218. return nil
  219. }
  220. conntrack.KillerCheck()
  221. // TODO: move to UoT
  222. metadata.Network = N.NetworkUDP
  223. // Currently we don't have deadline usages for UDP connections
  224. /*if deadline.NeedAdditionalReadDeadline(conn) {
  225. conn = deadline.NewPacketConn(bufio.NewNetPacketConn(conn))
  226. }*/
  227. selectedRule, _, buffers, err := r.matchRule(ctx, &metadata, nil, conn, -1)
  228. if err != nil {
  229. return err
  230. }
  231. var selectedOutbound adapter.Outbound
  232. var selectReturn bool
  233. if selectedRule != nil {
  234. switch action := selectedRule.Action().(type) {
  235. case *rule.RuleActionRoute:
  236. var loaded bool
  237. selectedOutbound, loaded = r.Outbound(action.Outbound)
  238. if !loaded {
  239. buf.ReleaseMulti(buffers)
  240. return E.New("outbound not found: ", action.Outbound)
  241. }
  242. metadata.UDPDisableDomainUnmapping = action.UDPDisableDomainUnmapping
  243. case *rule.RuleActionReturn:
  244. selectReturn = true
  245. case *rule.RuleActionReject:
  246. buf.ReleaseMulti(buffers)
  247. N.CloseOnHandshakeFailure(conn, onClose, syscall.ECONNREFUSED)
  248. return nil
  249. }
  250. }
  251. if selectedRule == nil || selectReturn {
  252. if r.defaultOutboundForPacketConnection == nil {
  253. buf.ReleaseMulti(buffers)
  254. return E.New("missing default outbound with UDP support")
  255. }
  256. selectedOutbound = r.defaultOutboundForPacketConnection
  257. }
  258. if !common.Contains(selectedOutbound.Network(), N.NetworkUDP) {
  259. buf.ReleaseMulti(buffers)
  260. return E.New("UDP is not supported by outbound: ", selectedOutbound.Tag())
  261. }
  262. for _, buffer := range buffers {
  263. // TODO: check if metadata.Destination == packet destination
  264. conn = bufio.NewCachedPacketConn(conn, buffer, metadata.Destination)
  265. }
  266. if r.clashServer != nil {
  267. trackerConn, tracker := r.clashServer.RoutedPacketConnection(ctx, conn, metadata, selectedRule)
  268. defer tracker.Leave()
  269. conn = trackerConn
  270. }
  271. if r.v2rayServer != nil {
  272. if statsService := r.v2rayServer.StatsService(); statsService != nil {
  273. conn = statsService.RoutedPacketConnection(metadata.Inbound, selectedOutbound.Tag(), metadata.User, conn)
  274. }
  275. }
  276. if metadata.FakeIP {
  277. conn = bufio.NewNATPacketConn(bufio.NewNetPacketConn(conn), metadata.OriginDestination, metadata.Destination)
  278. }
  279. legacyOutbound, isLegacy := selectedOutbound.(adapter.PacketConnectionHandler)
  280. if isLegacy {
  281. err = legacyOutbound.NewPacketConnection(ctx, conn, metadata)
  282. N.CloseOnHandshakeFailure(conn, onClose, err)
  283. if err != nil {
  284. return E.Cause(err, "outbound/", selectedOutbound.Type(), "[", selectedOutbound.Tag(), "]")
  285. }
  286. return nil
  287. }
  288. // TODO
  289. err = outbound.NewPacketConnection(ctx, selectedOutbound, conn, metadata)
  290. N.CloseOnHandshakeFailure(conn, onClose, err)
  291. if err != nil {
  292. return E.Cause(err, "outbound/", selectedOutbound.Type(), "[", selectedOutbound.Tag(), "]")
  293. }
  294. return nil
  295. }
  296. func (r *Router) matchRule(
  297. ctx context.Context, metadata *adapter.InboundContext,
  298. inputConn net.Conn, inputPacketConn N.PacketConn, ruleIndex int,
  299. ) (selectedRule adapter.Rule, selectedRuleIndex int, buffers []*buf.Buffer, fatalErr error) {
  300. if r.processSearcher != nil && metadata.ProcessInfo == nil {
  301. var originDestination netip.AddrPort
  302. if metadata.OriginDestination.IsValid() {
  303. originDestination = metadata.OriginDestination.AddrPort()
  304. } else if metadata.Destination.IsIP() {
  305. originDestination = metadata.Destination.AddrPort()
  306. }
  307. processInfo, fErr := process.FindProcessInfo(r.processSearcher, ctx, metadata.Network, metadata.Source.AddrPort(), originDestination)
  308. if fErr != nil {
  309. r.logger.InfoContext(ctx, "failed to search process: ", fErr)
  310. } else {
  311. if processInfo.ProcessPath != "" {
  312. r.logger.InfoContext(ctx, "found process path: ", processInfo.ProcessPath)
  313. } else if processInfo.PackageName != "" {
  314. r.logger.InfoContext(ctx, "found package name: ", processInfo.PackageName)
  315. } else if processInfo.UserId != -1 {
  316. if /*needUserName &&*/ true {
  317. osUser, _ := user.LookupId(F.ToString(processInfo.UserId))
  318. if osUser != nil {
  319. processInfo.User = osUser.Username
  320. }
  321. }
  322. if processInfo.User != "" {
  323. r.logger.InfoContext(ctx, "found user: ", processInfo.User)
  324. } else {
  325. r.logger.InfoContext(ctx, "found user id: ", processInfo.UserId)
  326. }
  327. }
  328. metadata.ProcessInfo = processInfo
  329. }
  330. }
  331. if r.fakeIPStore != nil && r.fakeIPStore.Contains(metadata.Destination.Addr) {
  332. domain, loaded := r.fakeIPStore.Lookup(metadata.Destination.Addr)
  333. if !loaded {
  334. fatalErr = E.New("missing fakeip record, try to configure experimental.cache_file")
  335. return
  336. }
  337. metadata.OriginDestination = metadata.Destination
  338. metadata.Destination = M.Socksaddr{
  339. Fqdn: domain,
  340. Port: metadata.Destination.Port,
  341. }
  342. metadata.FakeIP = true
  343. r.logger.DebugContext(ctx, "found fakeip domain: ", domain)
  344. }
  345. if r.dnsReverseMapping != nil && metadata.Domain == "" {
  346. domain, loaded := r.dnsReverseMapping.Query(metadata.Destination.Addr)
  347. if loaded {
  348. metadata.Domain = domain
  349. r.logger.DebugContext(ctx, "found reserve mapped domain: ", metadata.Domain)
  350. }
  351. }
  352. if metadata.Destination.IsIPv4() {
  353. metadata.IPVersion = 4
  354. } else if metadata.Destination.IsIPv6() {
  355. metadata.IPVersion = 6
  356. }
  357. //nolint:staticcheck
  358. if metadata.InboundOptions != common.DefaultValue[option.InboundOptions]() {
  359. if metadata.InboundOptions.SniffEnabled {
  360. newBuffers, newErr := r.actionSniff(ctx, metadata, &rule.RuleActionSniff{
  361. OverrideDestination: metadata.InboundOptions.SniffOverrideDestination,
  362. Timeout: time.Duration(metadata.InboundOptions.SniffTimeout),
  363. }, inputConn, inputPacketConn)
  364. if newErr != nil {
  365. fatalErr = newErr
  366. return
  367. }
  368. buffers = append(buffers, newBuffers...)
  369. }
  370. if dns.DomainStrategy(metadata.InboundOptions.DomainStrategy) != dns.DomainStrategyAsIS {
  371. fatalErr = r.actionResolve(ctx, metadata, &rule.RuleActionResolve{
  372. Strategy: dns.DomainStrategy(metadata.InboundOptions.DomainStrategy),
  373. })
  374. if fatalErr != nil {
  375. return
  376. }
  377. }
  378. if metadata.InboundOptions.UDPDisableDomainUnmapping {
  379. metadata.UDPDisableDomainUnmapping = true
  380. }
  381. metadata.InboundOptions = option.InboundOptions{}
  382. }
  383. match:
  384. for ruleIndex < len(r.rules) {
  385. rules := r.rules
  386. if ruleIndex != -1 {
  387. rules = rules[ruleIndex+1:]
  388. }
  389. var (
  390. currentRule adapter.Rule
  391. currentRuleIndex int
  392. matched bool
  393. )
  394. for currentRuleIndex, currentRule = range rules {
  395. if currentRule.Match(metadata) {
  396. matched = true
  397. break
  398. }
  399. }
  400. if !matched {
  401. break
  402. }
  403. r.logger.DebugContext(ctx, "match[", currentRuleIndex, "] ", currentRule, " => ", currentRule.Action())
  404. switch action := currentRule.Action().(type) {
  405. case *rule.RuleActionSniff:
  406. newBuffers, newErr := r.actionSniff(ctx, metadata, action, inputConn, inputPacketConn)
  407. if newErr != nil {
  408. fatalErr = newErr
  409. return
  410. }
  411. buffers = append(buffers, newBuffers...)
  412. case *rule.RuleActionResolve:
  413. fatalErr = r.actionResolve(ctx, metadata, action)
  414. if fatalErr != nil {
  415. return
  416. }
  417. default:
  418. selectedRule = currentRule
  419. selectedRuleIndex = currentRuleIndex
  420. break match
  421. }
  422. ruleIndex = currentRuleIndex
  423. }
  424. if metadata.Destination.Addr.IsUnspecified() {
  425. newBuffers, newErr := r.actionSniff(ctx, metadata, &rule.RuleActionSniff{}, inputConn, inputPacketConn)
  426. if newErr != nil {
  427. fatalErr = newErr
  428. return
  429. }
  430. buffers = append(buffers, newBuffers...)
  431. }
  432. return
  433. }
  434. func (r *Router) actionSniff(
  435. ctx context.Context, metadata *adapter.InboundContext, action *rule.RuleActionSniff,
  436. inputConn net.Conn, inputPacketConn N.PacketConn,
  437. ) (buffers []*buf.Buffer, fatalErr error) {
  438. if sniff.Skip(metadata) {
  439. return
  440. } else if inputConn != nil && len(action.StreamSniffers) > 0 {
  441. buffer := buf.NewPacket()
  442. err := sniff.PeekStream(
  443. ctx,
  444. metadata,
  445. inputConn,
  446. buffer,
  447. action.Timeout,
  448. action.StreamSniffers...,
  449. )
  450. if err == nil {
  451. //goland:noinspection GoDeprecation
  452. if action.OverrideDestination && M.IsDomainName(metadata.Domain) {
  453. metadata.Destination = M.Socksaddr{
  454. Fqdn: metadata.Domain,
  455. Port: metadata.Destination.Port,
  456. }
  457. }
  458. if metadata.Domain != "" && metadata.Client != "" {
  459. r.logger.DebugContext(ctx, "sniffed protocol: ", metadata.Protocol, ", domain: ", metadata.Domain, ", client: ", metadata.Client)
  460. } else if metadata.Domain != "" {
  461. r.logger.DebugContext(ctx, "sniffed protocol: ", metadata.Protocol, ", domain: ", metadata.Domain)
  462. } else {
  463. r.logger.DebugContext(ctx, "sniffed protocol: ", metadata.Protocol)
  464. }
  465. }
  466. if !buffer.IsEmpty() {
  467. buffers = append(buffers, buffer)
  468. } else {
  469. buffer.Release()
  470. }
  471. } else if inputPacketConn != nil && len(action.PacketSniffers) > 0 {
  472. for {
  473. var (
  474. buffer = buf.NewPacket()
  475. destination M.Socksaddr
  476. done = make(chan struct{})
  477. err error
  478. )
  479. go func() {
  480. sniffTimeout := C.ReadPayloadTimeout
  481. if action.Timeout > 0 {
  482. sniffTimeout = action.Timeout
  483. }
  484. inputPacketConn.SetReadDeadline(time.Now().Add(sniffTimeout))
  485. destination, err = inputPacketConn.ReadPacket(buffer)
  486. inputPacketConn.SetReadDeadline(time.Time{})
  487. close(done)
  488. }()
  489. select {
  490. case <-done:
  491. case <-ctx.Done():
  492. inputPacketConn.Close()
  493. fatalErr = ctx.Err()
  494. return
  495. }
  496. if err != nil {
  497. buffer.Release()
  498. if !errors.Is(err, os.ErrDeadlineExceeded) {
  499. fatalErr = err
  500. return
  501. }
  502. } else {
  503. // TODO: maybe always override destination
  504. if metadata.Destination.Addr.IsUnspecified() {
  505. metadata.Destination = destination
  506. }
  507. if len(buffers) > 0 {
  508. err = sniff.PeekPacket(
  509. ctx,
  510. metadata,
  511. buffer.Bytes(),
  512. sniff.QUICClientHello,
  513. )
  514. } else {
  515. err = sniff.PeekPacket(
  516. ctx, metadata,
  517. buffer.Bytes(),
  518. action.PacketSniffers...,
  519. )
  520. }
  521. buffers = append(buffers, buffer)
  522. if E.IsMulti(err, sniff.ErrClientHelloFragmented) && len(buffers) == 0 {
  523. r.logger.DebugContext(ctx, "attempt to sniff fragmented QUIC client hello")
  524. continue
  525. }
  526. if metadata.Protocol != "" {
  527. //goland:noinspection GoDeprecation
  528. if action.OverrideDestination && M.IsDomainName(metadata.Domain) {
  529. metadata.Destination = M.Socksaddr{
  530. Fqdn: metadata.Domain,
  531. Port: metadata.Destination.Port,
  532. }
  533. }
  534. if metadata.Domain != "" && metadata.Client != "" {
  535. r.logger.DebugContext(ctx, "sniffed packet protocol: ", metadata.Protocol, ", domain: ", metadata.Domain, ", client: ", metadata.Client)
  536. } else if metadata.Domain != "" {
  537. r.logger.DebugContext(ctx, "sniffed packet protocol: ", metadata.Protocol, ", domain: ", metadata.Domain)
  538. } else if metadata.Client != "" {
  539. r.logger.DebugContext(ctx, "sniffed packet protocol: ", metadata.Protocol, ", client: ", metadata.Client)
  540. } else {
  541. r.logger.DebugContext(ctx, "sniffed packet protocol: ", metadata.Protocol)
  542. }
  543. }
  544. }
  545. break
  546. }
  547. }
  548. return
  549. }
  550. func (r *Router) actionResolve(ctx context.Context, metadata *adapter.InboundContext, action *rule.RuleActionResolve) error {
  551. if metadata.Destination.IsFqdn() {
  552. // TODO: check if WithContext is necessary
  553. addresses, err := r.Lookup(adapter.WithContext(ctx, metadata), metadata.Destination.Fqdn, action.Strategy)
  554. if err != nil {
  555. return err
  556. }
  557. metadata.DestinationAddresses = addresses
  558. r.dnsLogger.DebugContext(ctx, "resolved [", strings.Join(F.MapToString(metadata.DestinationAddresses), " "), "]")
  559. if metadata.Destination.IsIPv4() {
  560. metadata.IPVersion = 4
  561. } else if metadata.Destination.IsIPv6() {
  562. metadata.IPVersion = 6
  563. }
  564. }
  565. return nil
  566. }