route.go 22 KB

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