route.go 25 KB

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