route.go 26 KB

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