route.go 22 KB

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