listener.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. package listener
  2. import (
  3. "context"
  4. "net"
  5. "net/netip"
  6. "runtime"
  7. "strings"
  8. "sync/atomic"
  9. "github.com/sagernet/sing-box/adapter"
  10. "github.com/sagernet/sing-box/common/settings"
  11. "github.com/sagernet/sing-box/option"
  12. "github.com/sagernet/sing/common"
  13. E "github.com/sagernet/sing/common/exceptions"
  14. "github.com/sagernet/sing/common/logger"
  15. M "github.com/sagernet/sing/common/metadata"
  16. N "github.com/sagernet/sing/common/network"
  17. "github.com/vishvananda/netns"
  18. )
  19. type Listener struct {
  20. ctx context.Context
  21. logger logger.ContextLogger
  22. network []string
  23. listenOptions option.ListenOptions
  24. connHandler adapter.ConnectionHandlerEx
  25. packetHandler adapter.PacketHandlerEx
  26. oobPacketHandler adapter.OOBPacketHandlerEx
  27. threadUnsafePacketWriter bool
  28. disablePacketOutput bool
  29. setSystemProxy bool
  30. systemProxySOCKS bool
  31. tcpListener net.Listener
  32. systemProxy settings.SystemProxy
  33. udpConn *net.UDPConn
  34. udpAddr M.Socksaddr
  35. packetOutbound chan *N.PacketBuffer
  36. packetOutboundClosed chan struct{}
  37. shutdown atomic.Bool
  38. }
  39. type Options struct {
  40. Context context.Context
  41. Logger logger.ContextLogger
  42. Network []string
  43. Listen option.ListenOptions
  44. ConnectionHandler adapter.ConnectionHandlerEx
  45. PacketHandler adapter.PacketHandlerEx
  46. OOBPacketHandler adapter.OOBPacketHandlerEx
  47. ThreadUnsafePacketWriter bool
  48. DisablePacketOutput bool
  49. SetSystemProxy bool
  50. SystemProxySOCKS bool
  51. }
  52. func New(
  53. options Options,
  54. ) *Listener {
  55. return &Listener{
  56. ctx: options.Context,
  57. logger: options.Logger,
  58. network: options.Network,
  59. listenOptions: options.Listen,
  60. connHandler: options.ConnectionHandler,
  61. packetHandler: options.PacketHandler,
  62. oobPacketHandler: options.OOBPacketHandler,
  63. threadUnsafePacketWriter: options.ThreadUnsafePacketWriter,
  64. disablePacketOutput: options.DisablePacketOutput,
  65. setSystemProxy: options.SetSystemProxy,
  66. systemProxySOCKS: options.SystemProxySOCKS,
  67. }
  68. }
  69. func (l *Listener) Start() error {
  70. if common.Contains(l.network, N.NetworkTCP) {
  71. _, err := l.ListenTCP()
  72. if err != nil {
  73. return err
  74. }
  75. go l.loopTCPIn()
  76. }
  77. if common.Contains(l.network, N.NetworkUDP) {
  78. _, err := l.ListenUDP()
  79. if err != nil {
  80. return err
  81. }
  82. l.packetOutboundClosed = make(chan struct{})
  83. l.packetOutbound = make(chan *N.PacketBuffer, 64)
  84. go l.loopUDPIn()
  85. if !l.disablePacketOutput {
  86. go l.loopUDPOut()
  87. }
  88. }
  89. if l.setSystemProxy {
  90. listenPort := M.SocksaddrFromNet(l.tcpListener.Addr()).Port
  91. var listenAddrString string
  92. listenAddr := l.listenOptions.Listen.Build(netip.IPv4Unspecified())
  93. if listenAddr.IsUnspecified() {
  94. listenAddrString = "127.0.0.1"
  95. } else {
  96. listenAddrString = listenAddr.String()
  97. }
  98. systemProxy, err := settings.NewSystemProxy(l.ctx, M.ParseSocksaddrHostPort(listenAddrString, listenPort), l.systemProxySOCKS)
  99. if err != nil {
  100. return E.Cause(err, "initialize system proxy")
  101. }
  102. err = systemProxy.Enable()
  103. if err != nil {
  104. return E.Cause(err, "set system proxy")
  105. }
  106. l.systemProxy = systemProxy
  107. }
  108. return nil
  109. }
  110. func (l *Listener) Close() error {
  111. l.shutdown.Store(true)
  112. var err error
  113. if l.systemProxy != nil && l.systemProxy.IsEnabled() {
  114. err = l.systemProxy.Disable()
  115. }
  116. return E.Errors(err, common.Close(
  117. l.tcpListener,
  118. common.PtrOrNil(l.udpConn),
  119. ))
  120. }
  121. func (l *Listener) TCPListener() net.Listener {
  122. return l.tcpListener
  123. }
  124. func (l *Listener) UDPConn() *net.UDPConn {
  125. return l.udpConn
  126. }
  127. func (l *Listener) ListenOptions() option.ListenOptions {
  128. return l.listenOptions
  129. }
  130. func ListenNetworkNamespace[T any](nameOrPath string, block func() (T, error)) (T, error) {
  131. if nameOrPath != "" {
  132. runtime.LockOSThread()
  133. defer runtime.UnlockOSThread()
  134. currentNs, err := netns.Get()
  135. if err != nil {
  136. return common.DefaultValue[T](), E.Cause(err, "get current netns")
  137. }
  138. defer netns.Set(currentNs)
  139. var targetNs netns.NsHandle
  140. if strings.HasPrefix(nameOrPath, "/") {
  141. targetNs, err = netns.GetFromPath(nameOrPath)
  142. } else {
  143. targetNs, err = netns.GetFromName(nameOrPath)
  144. }
  145. if err != nil {
  146. return common.DefaultValue[T](), E.Cause(err, "get netns ", nameOrPath)
  147. }
  148. defer targetNs.Close()
  149. err = netns.Set(targetNs)
  150. if err != nil {
  151. return common.DefaultValue[T](), E.Cause(err, "set netns to ", nameOrPath)
  152. }
  153. }
  154. return block()
  155. }