route.go 21 KB

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