route.go 21 KB

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