proxy.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. package outbound
  2. import (
  3. std_bufio "bufio"
  4. "context"
  5. "crypto/rand"
  6. "encoding/hex"
  7. "net"
  8. "github.com/sagernet/sing-box/adapter"
  9. "github.com/sagernet/sing-box/log"
  10. "github.com/sagernet/sing/common"
  11. "github.com/sagernet/sing/common/auth"
  12. "github.com/sagernet/sing/common/buf"
  13. "github.com/sagernet/sing/common/bufio"
  14. E "github.com/sagernet/sing/common/exceptions"
  15. M "github.com/sagernet/sing/common/metadata"
  16. N "github.com/sagernet/sing/common/network"
  17. "github.com/sagernet/sing/common/rw"
  18. "github.com/sagernet/sing/protocol/http"
  19. "github.com/sagernet/sing/protocol/socks"
  20. "github.com/sagernet/sing/protocol/socks/socks4"
  21. "github.com/sagernet/sing/protocol/socks/socks5"
  22. )
  23. type ProxyListener struct {
  24. ctx context.Context
  25. logger log.ContextLogger
  26. dialer N.Dialer
  27. tcpListener *net.TCPListener
  28. username string
  29. password string
  30. authenticator auth.Authenticator
  31. }
  32. func NewProxyListener(ctx context.Context, logger log.ContextLogger, dialer N.Dialer) *ProxyListener {
  33. var usernameB [64]byte
  34. var passwordB [64]byte
  35. rand.Read(usernameB[:])
  36. rand.Read(passwordB[:])
  37. username := hex.EncodeToString(usernameB[:])
  38. password := hex.EncodeToString(passwordB[:])
  39. return &ProxyListener{
  40. ctx: ctx,
  41. logger: logger,
  42. dialer: dialer,
  43. authenticator: auth.NewAuthenticator([]auth.User{{Username: username, Password: password}}),
  44. username: username,
  45. password: password,
  46. }
  47. }
  48. func (l *ProxyListener) Start() error {
  49. tcpListener, err := net.ListenTCP("tcp", &net.TCPAddr{
  50. IP: net.IPv4(127, 0, 0, 1),
  51. })
  52. if err != nil {
  53. return err
  54. }
  55. l.tcpListener = tcpListener
  56. go l.acceptLoop()
  57. return nil
  58. }
  59. func (l *ProxyListener) Port() uint16 {
  60. if l.tcpListener == nil {
  61. panic("start listener first")
  62. }
  63. return M.SocksaddrFromNet(l.tcpListener.Addr()).Port
  64. }
  65. func (l *ProxyListener) Username() string {
  66. return l.username
  67. }
  68. func (l *ProxyListener) Password() string {
  69. return l.password
  70. }
  71. func (l *ProxyListener) Close() error {
  72. return common.Close(l.tcpListener)
  73. }
  74. func (l *ProxyListener) acceptLoop() {
  75. for {
  76. tcpConn, err := l.tcpListener.AcceptTCP()
  77. if err != nil {
  78. return
  79. }
  80. ctx := log.ContextWithNewID(l.ctx)
  81. go func() {
  82. hErr := l.accept(ctx, tcpConn)
  83. if hErr != nil {
  84. if E.IsClosedOrCanceled(hErr) {
  85. l.logger.DebugContext(ctx, E.Cause(hErr, "proxy connection closed"))
  86. return
  87. }
  88. l.logger.ErrorContext(ctx, E.Cause(hErr, "proxy"))
  89. }
  90. }()
  91. }
  92. }
  93. func (l *ProxyListener) accept(ctx context.Context, conn *net.TCPConn) error {
  94. headerType, err := rw.ReadByte(conn)
  95. if err != nil {
  96. return err
  97. }
  98. switch headerType {
  99. case socks4.Version, socks5.Version:
  100. return socks.HandleConnection0(ctx, conn, headerType, l.authenticator, l, M.Metadata{})
  101. }
  102. reader := std_bufio.NewReader(bufio.NewCachedReader(conn, buf.As([]byte{headerType})))
  103. return http.HandleConnection(ctx, conn, reader, l.authenticator, l, M.Metadata{})
  104. }
  105. func (l *ProxyListener) NewConnection(ctx context.Context, conn net.Conn, upstreamMetadata M.Metadata) error {
  106. var metadata adapter.InboundContext
  107. metadata.Network = N.NetworkTCP
  108. metadata.Destination = upstreamMetadata.Destination
  109. l.logger.InfoContext(ctx, "proxy connection to ", metadata.Destination)
  110. return NewConnection(ctx, l.dialer, conn, metadata)
  111. }
  112. func (l *ProxyListener) NewPacketConnection(ctx context.Context, conn N.PacketConn, upstreamMetadata M.Metadata) error {
  113. var metadata adapter.InboundContext
  114. metadata.Network = N.NetworkUDP
  115. metadata.Destination = upstreamMetadata.Destination
  116. l.logger.InfoContext(ctx, "proxy packet connection to ", metadata.Destination)
  117. return NewPacketConnection(ctx, l.dialer, conn, metadata)
  118. }