default.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. package dialer
  2. import (
  3. "context"
  4. "net"
  5. "net/netip"
  6. "time"
  7. "github.com/sagernet/sing-box/adapter"
  8. "github.com/sagernet/sing-box/common/warning"
  9. C "github.com/sagernet/sing-box/constant"
  10. "github.com/sagernet/sing-box/option"
  11. "github.com/sagernet/sing/common/control"
  12. M "github.com/sagernet/sing/common/metadata"
  13. N "github.com/sagernet/sing/common/network"
  14. "github.com/database64128/tfo-go"
  15. )
  16. var warnBindInterfaceOnUnsupportedPlatform = warning.New(
  17. func() bool {
  18. return !(C.IsLinux || C.IsWindows || C.IsDarwin)
  19. },
  20. "outbound option `bind_interface` is only supported on Linux and Windows",
  21. )
  22. var warnRoutingMarkOnUnsupportedPlatform = warning.New(
  23. func() bool {
  24. return !C.IsLinux
  25. },
  26. "outbound option `routing_mark` is only supported on Linux",
  27. )
  28. var warnReuseAdderOnUnsupportedPlatform = warning.New(
  29. func() bool {
  30. return !(C.IsDarwin || C.IsDragonfly || C.IsFreebsd || C.IsLinux || C.IsNetbsd || C.IsOpenbsd || C.IsSolaris || C.IsWindows)
  31. },
  32. "outbound option `reuse_addr` is unsupported on current platform",
  33. )
  34. var warnProtectPathOnNonAndroid = warning.New(
  35. func() bool {
  36. return !C.IsAndroid
  37. },
  38. "outbound option `protect_path` is only supported on Android",
  39. )
  40. var warnTFOOnUnsupportedPlatform = warning.New(
  41. func() bool {
  42. return !(C.IsDarwin || C.IsFreebsd || C.IsLinux || C.IsWindows)
  43. },
  44. "outbound option `tcp_fast_open` is unsupported on current platform",
  45. )
  46. type DefaultDialer struct {
  47. dialer tfo.Dialer
  48. udpDialer net.Dialer
  49. udpListener net.ListenConfig
  50. bindUDPAddr string
  51. }
  52. func NewDefault(router adapter.Router, options option.DialerOptions) *DefaultDialer {
  53. var dialer net.Dialer
  54. var listener net.ListenConfig
  55. if options.BindInterface != "" {
  56. warnBindInterfaceOnUnsupportedPlatform.Check()
  57. bindFunc := skipIfPrivate(control.BindToInterface(router.InterfaceBindManager(), options.BindInterface))
  58. dialer.Control = control.Append(dialer.Control, bindFunc)
  59. listener.Control = control.Append(listener.Control, bindFunc)
  60. } else if router.AutoDetectInterface() {
  61. if C.IsWindows {
  62. bindFunc := skipIfPrivate(control.BindToInterfaceIndexFunc(func() int {
  63. return router.InterfaceMonitor().DefaultInterfaceIndex()
  64. }))
  65. dialer.Control = control.Append(dialer.Control, bindFunc)
  66. listener.Control = control.Append(listener.Control, bindFunc)
  67. } else {
  68. bindFunc := skipIfPrivate(control.BindToInterfaceFunc(router.InterfaceBindManager(), func() string {
  69. return router.InterfaceMonitor().DefaultInterfaceName()
  70. }))
  71. dialer.Control = control.Append(dialer.Control, bindFunc)
  72. listener.Control = control.Append(listener.Control, bindFunc)
  73. }
  74. } else if router.DefaultInterface() != "" {
  75. bindFunc := skipIfPrivate(control.BindToInterface(router.InterfaceBindManager(), router.DefaultInterface()))
  76. dialer.Control = control.Append(dialer.Control, bindFunc)
  77. listener.Control = control.Append(listener.Control, bindFunc)
  78. }
  79. if options.RoutingMark != 0 {
  80. warnRoutingMarkOnUnsupportedPlatform.Check()
  81. dialer.Control = control.Append(dialer.Control, control.RoutingMark(options.RoutingMark))
  82. listener.Control = control.Append(listener.Control, control.RoutingMark(options.RoutingMark))
  83. } else if router.DefaultMark() != 0 {
  84. dialer.Control = control.Append(dialer.Control, control.RoutingMark(router.DefaultMark()))
  85. listener.Control = control.Append(listener.Control, control.RoutingMark(router.DefaultMark()))
  86. }
  87. if options.ReuseAddr {
  88. warnReuseAdderOnUnsupportedPlatform.Check()
  89. listener.Control = control.Append(listener.Control, control.ReuseAddr())
  90. }
  91. if options.ProtectPath != "" {
  92. warnProtectPathOnNonAndroid.Check()
  93. dialer.Control = control.Append(dialer.Control, control.ProtectPath(options.ProtectPath))
  94. listener.Control = control.Append(listener.Control, control.ProtectPath(options.ProtectPath))
  95. }
  96. if options.ConnectTimeout != 0 {
  97. dialer.Timeout = time.Duration(options.ConnectTimeout)
  98. } else {
  99. dialer.Timeout = C.TCPTimeout
  100. }
  101. if options.TCPFastOpen {
  102. warnTFOOnUnsupportedPlatform.Check()
  103. }
  104. var bindUDPAddr string
  105. udpDialer := dialer
  106. bindAddress := netip.Addr(options.BindAddress)
  107. if bindAddress.IsValid() {
  108. dialer.LocalAddr = &net.TCPAddr{
  109. IP: bindAddress.AsSlice(),
  110. }
  111. udpDialer.LocalAddr = &net.UDPAddr{
  112. IP: bindAddress.AsSlice(),
  113. }
  114. bindUDPAddr = M.SocksaddrFrom(bindAddress, 0).String()
  115. }
  116. return &DefaultDialer{tfo.Dialer{Dialer: dialer, DisableTFO: !options.TCPFastOpen}, udpDialer, listener, bindUDPAddr}
  117. }
  118. func (d *DefaultDialer) DialContext(ctx context.Context, network string, address M.Socksaddr) (net.Conn, error) {
  119. switch N.NetworkName(network) {
  120. case N.NetworkUDP:
  121. return d.udpDialer.DialContext(ctx, network, address.String())
  122. }
  123. return d.dialer.DialContext(ctx, network, address.Unwrap().String())
  124. }
  125. func (d *DefaultDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
  126. return d.udpListener.ListenPacket(ctx, N.NetworkUDP, d.bindUDPAddr)
  127. }