dial.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. package route
  2. import (
  3. "context"
  4. "net"
  5. "github.com/sagernet/sing-box/adapter"
  6. "github.com/sagernet/sing-box/common/dialer"
  7. C "github.com/sagernet/sing-box/constant"
  8. R "github.com/sagernet/sing-box/route/rule"
  9. "github.com/sagernet/sing/common"
  10. "github.com/sagernet/sing/common/buf"
  11. "github.com/sagernet/sing/common/bufio"
  12. E "github.com/sagernet/sing/common/exceptions"
  13. N "github.com/sagernet/sing/common/network"
  14. )
  15. // DialRoutePacketConnection dials a routed connected UDP packet connection for metadata.
  16. func (r *Router) DialRoutePacketConnection(ctx context.Context, metadata adapter.InboundContext) (N.PacketConn, error) {
  17. metadata.Network = N.NetworkUDP
  18. metadata.UDPConnect = true
  19. ctx = adapter.WithContext(ctx, &metadata)
  20. selectedRule, selectedOutbound, err := r.selectRoutedOutbound(ctx, &metadata, N.NetworkUDP)
  21. if err != nil {
  22. return nil, err
  23. }
  24. var remoteConn net.Conn
  25. if len(metadata.DestinationAddresses) > 0 || metadata.Destination.IsIP() {
  26. remoteConn, err = dialer.DialSerialNetwork(
  27. ctx,
  28. selectedOutbound,
  29. N.NetworkUDP,
  30. metadata.Destination,
  31. metadata.DestinationAddresses,
  32. metadata.NetworkStrategy,
  33. metadata.NetworkType,
  34. metadata.FallbackNetworkType,
  35. metadata.FallbackDelay,
  36. )
  37. } else {
  38. remoteConn, err = selectedOutbound.DialContext(ctx, N.NetworkUDP, metadata.Destination)
  39. }
  40. if err != nil {
  41. return nil, err
  42. }
  43. var packetConn N.PacketConn = bufio.NewUnbindPacketConn(remoteConn)
  44. for _, tracker := range r.trackers {
  45. packetConn = tracker.RoutedPacketConnection(ctx, packetConn, metadata, selectedRule, selectedOutbound)
  46. }
  47. if metadata.FakeIP {
  48. packetConn = bufio.NewNATPacketConn(bufio.NewNetPacketConn(packetConn), metadata.OriginDestination, metadata.Destination)
  49. }
  50. return packetConn, nil
  51. }
  52. func (r *Router) selectRoutedOutbound(
  53. ctx context.Context,
  54. metadata *adapter.InboundContext,
  55. network string,
  56. ) (adapter.Rule, adapter.Outbound, error) {
  57. selectedRule, _, buffers, packetBuffers, err := r.matchRule(ctx, metadata, false, false, nil, nil)
  58. if len(buffers) > 0 {
  59. buf.ReleaseMulti(buffers)
  60. }
  61. if len(packetBuffers) > 0 {
  62. N.ReleaseMultiPacketBuffer(packetBuffers)
  63. }
  64. if err != nil {
  65. return nil, nil, err
  66. }
  67. var selectedOutbound adapter.Outbound
  68. if selectedRule != nil {
  69. switch action := selectedRule.Action().(type) {
  70. case *R.RuleActionRoute:
  71. var loaded bool
  72. selectedOutbound, loaded = r.outbound.Outbound(action.Outbound)
  73. if !loaded {
  74. return nil, nil, E.New("outbound not found: ", action.Outbound)
  75. }
  76. case *R.RuleActionBypass:
  77. if action.Outbound != "" {
  78. var loaded bool
  79. selectedOutbound, loaded = r.outbound.Outbound(action.Outbound)
  80. if !loaded {
  81. return nil, nil, E.New("outbound not found: ", action.Outbound)
  82. }
  83. }
  84. case *R.RuleActionReject:
  85. if action.Method == C.RuleActionRejectMethodReply {
  86. return nil, nil, E.New("reject method `reply` is not supported for dialed connections")
  87. }
  88. return nil, nil, action.Error(ctx)
  89. case *R.RuleActionHijackDNS:
  90. return nil, nil, E.New("DNS hijack is not supported for dialed connections")
  91. }
  92. }
  93. if selectedOutbound == nil {
  94. selectedOutbound = r.outbound.Default()
  95. }
  96. if !common.Contains(selectedOutbound.Network(), network) {
  97. return nil, nil, E.New(network, " is not supported by outbound: ", selectedOutbound.Tag())
  98. }
  99. return selectedRule, selectedOutbound, nil
  100. }