client.go 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. package hysteria2
  2. import (
  3. "context"
  4. "io"
  5. "net"
  6. "net/http"
  7. "net/url"
  8. "os"
  9. "runtime"
  10. "sync"
  11. "time"
  12. "github.com/sagernet/quic-go"
  13. "github.com/sagernet/sing-box/common/qtls"
  14. "github.com/sagernet/sing-box/common/tls"
  15. "github.com/sagernet/sing-box/transport/hysteria2/congestion"
  16. "github.com/sagernet/sing-box/transport/hysteria2/internal/protocol"
  17. tuicCongestion "github.com/sagernet/sing-box/transport/tuic/congestion"
  18. "github.com/sagernet/sing/common/baderror"
  19. "github.com/sagernet/sing/common/bufio"
  20. E "github.com/sagernet/sing/common/exceptions"
  21. M "github.com/sagernet/sing/common/metadata"
  22. N "github.com/sagernet/sing/common/network"
  23. )
  24. const (
  25. defaultStreamReceiveWindow = 8388608 // 8MB
  26. defaultConnReceiveWindow = defaultStreamReceiveWindow * 5 / 2 // 20MB
  27. defaultMaxIdleTimeout = 30 * time.Second
  28. defaultKeepAlivePeriod = 10 * time.Second
  29. )
  30. type ClientOptions struct {
  31. Context context.Context
  32. Dialer N.Dialer
  33. ServerAddress M.Socksaddr
  34. SendBPS uint64
  35. ReceiveBPS uint64
  36. SalamanderPassword string
  37. Password string
  38. TLSConfig tls.Config
  39. UDPDisabled bool
  40. }
  41. type Client struct {
  42. ctx context.Context
  43. dialer N.Dialer
  44. serverAddr M.Socksaddr
  45. sendBPS uint64
  46. receiveBPS uint64
  47. salamanderPassword string
  48. password string
  49. tlsConfig tls.Config
  50. quicConfig *quic.Config
  51. udpDisabled bool
  52. connAccess sync.RWMutex
  53. conn *clientQUICConnection
  54. }
  55. func NewClient(options ClientOptions) (*Client, error) {
  56. quicConfig := &quic.Config{
  57. DisablePathMTUDiscovery: !(runtime.GOOS == "windows" || runtime.GOOS == "linux" || runtime.GOOS == "android" || runtime.GOOS == "darwin"),
  58. EnableDatagrams: true,
  59. InitialStreamReceiveWindow: defaultStreamReceiveWindow,
  60. MaxStreamReceiveWindow: defaultStreamReceiveWindow,
  61. InitialConnectionReceiveWindow: defaultConnReceiveWindow,
  62. MaxConnectionReceiveWindow: defaultConnReceiveWindow,
  63. MaxIdleTimeout: defaultMaxIdleTimeout,
  64. KeepAlivePeriod: defaultKeepAlivePeriod,
  65. }
  66. return &Client{
  67. ctx: options.Context,
  68. dialer: options.Dialer,
  69. serverAddr: options.ServerAddress,
  70. sendBPS: options.SendBPS,
  71. receiveBPS: options.ReceiveBPS,
  72. salamanderPassword: options.SalamanderPassword,
  73. password: options.Password,
  74. tlsConfig: options.TLSConfig,
  75. quicConfig: quicConfig,
  76. udpDisabled: options.UDPDisabled,
  77. }, nil
  78. }
  79. func (c *Client) offer(ctx context.Context) (*clientQUICConnection, error) {
  80. conn := c.conn
  81. if conn != nil && conn.active() {
  82. return conn, nil
  83. }
  84. c.connAccess.Lock()
  85. defer c.connAccess.Unlock()
  86. conn = c.conn
  87. if conn != nil && conn.active() {
  88. return conn, nil
  89. }
  90. conn, err := c.offerNew(ctx)
  91. if err != nil {
  92. return nil, err
  93. }
  94. return conn, nil
  95. }
  96. func (c *Client) offerNew(ctx context.Context) (*clientQUICConnection, error) {
  97. udpConn, err := c.dialer.DialContext(c.ctx, "udp", c.serverAddr)
  98. if err != nil {
  99. return nil, err
  100. }
  101. var packetConn net.PacketConn
  102. packetConn = bufio.NewUnbindPacketConn(udpConn)
  103. if c.salamanderPassword != "" {
  104. packetConn = NewSalamanderConn(packetConn, []byte(c.salamanderPassword))
  105. }
  106. var quicConn quic.EarlyConnection
  107. http3Transport, err := qtls.CreateTransport(packetConn, &quicConn, c.serverAddr, c.tlsConfig, c.quicConfig, true)
  108. if err != nil {
  109. udpConn.Close()
  110. return nil, err
  111. }
  112. request := &http.Request{
  113. Method: http.MethodPost,
  114. URL: &url.URL{
  115. Scheme: "https",
  116. Host: protocol.URLHost,
  117. Path: protocol.URLPath,
  118. },
  119. Header: make(http.Header),
  120. }
  121. protocol.AuthRequestToHeader(request.Header, protocol.AuthRequest{Auth: c.password, Rx: c.receiveBPS})
  122. response, err := http3Transport.RoundTrip(request.WithContext(ctx))
  123. if err != nil {
  124. if quicConn != nil {
  125. quicConn.CloseWithError(0, "")
  126. }
  127. udpConn.Close()
  128. return nil, err
  129. }
  130. if response.StatusCode != protocol.StatusAuthOK {
  131. if quicConn != nil {
  132. quicConn.CloseWithError(0, "")
  133. }
  134. udpConn.Close()
  135. return nil, E.New("authentication failed, status code: ", response.StatusCode)
  136. }
  137. response.Body.Close()
  138. authResponse := protocol.AuthResponseFromHeader(response.Header)
  139. actualTx := authResponse.Rx
  140. if actualTx == 0 || actualTx > c.sendBPS {
  141. actualTx = c.sendBPS
  142. }
  143. if !authResponse.RxAuto && actualTx > 0 {
  144. quicConn.SetCongestionControl(congestion.NewBrutalSender(actualTx))
  145. } else {
  146. quicConn.SetCongestionControl(tuicCongestion.NewBBRSender(
  147. tuicCongestion.DefaultClock{},
  148. tuicCongestion.GetInitialPacketSize(quicConn.RemoteAddr()),
  149. tuicCongestion.InitialCongestionWindow*tuicCongestion.InitialMaxDatagramSize,
  150. tuicCongestion.DefaultBBRMaxCongestionWindow*tuicCongestion.InitialMaxDatagramSize,
  151. ))
  152. }
  153. conn := &clientQUICConnection{
  154. quicConn: quicConn,
  155. rawConn: udpConn,
  156. connDone: make(chan struct{}),
  157. udpDisabled: c.udpDisabled || !authResponse.UDPEnabled,
  158. udpConnMap: make(map[uint32]*udpPacketConn),
  159. }
  160. if !c.udpDisabled {
  161. go c.loopMessages(conn)
  162. }
  163. c.conn = conn
  164. return conn, nil
  165. }
  166. func (c *Client) DialConn(ctx context.Context, destination M.Socksaddr) (net.Conn, error) {
  167. conn, err := c.offer(ctx)
  168. if err != nil {
  169. return nil, err
  170. }
  171. stream, err := conn.quicConn.OpenStream()
  172. if err != nil {
  173. return nil, err
  174. }
  175. return &clientConn{
  176. Stream: stream,
  177. destination: destination,
  178. }, nil
  179. }
  180. func (c *Client) ListenPacket(ctx context.Context) (net.PacketConn, error) {
  181. if c.udpDisabled {
  182. return nil, os.ErrInvalid
  183. }
  184. conn, err := c.offer(ctx)
  185. if err != nil {
  186. return nil, err
  187. }
  188. if conn.udpDisabled {
  189. return nil, E.New("UDP disabled by server")
  190. }
  191. var sessionID uint32
  192. clientPacketConn := newUDPPacketConn(ctx, conn.quicConn, func() {
  193. conn.udpAccess.Lock()
  194. delete(conn.udpConnMap, sessionID)
  195. conn.udpAccess.Unlock()
  196. })
  197. conn.udpAccess.Lock()
  198. sessionID = conn.udpSessionID
  199. conn.udpSessionID++
  200. conn.udpConnMap[sessionID] = clientPacketConn
  201. conn.udpAccess.Unlock()
  202. clientPacketConn.sessionID = sessionID
  203. return clientPacketConn, nil
  204. }
  205. func (c *Client) CloseWithError(err error) error {
  206. conn := c.conn
  207. if conn != nil {
  208. conn.closeWithError(err)
  209. }
  210. return nil
  211. }
  212. type clientQUICConnection struct {
  213. quicConn quic.Connection
  214. rawConn io.Closer
  215. closeOnce sync.Once
  216. connDone chan struct{}
  217. connErr error
  218. udpDisabled bool
  219. udpAccess sync.RWMutex
  220. udpConnMap map[uint32]*udpPacketConn
  221. udpSessionID uint32
  222. }
  223. func (c *clientQUICConnection) active() bool {
  224. select {
  225. case <-c.quicConn.Context().Done():
  226. return false
  227. default:
  228. }
  229. select {
  230. case <-c.connDone:
  231. return false
  232. default:
  233. }
  234. return true
  235. }
  236. func (c *clientQUICConnection) closeWithError(err error) {
  237. c.closeOnce.Do(func() {
  238. c.connErr = err
  239. close(c.connDone)
  240. c.quicConn.CloseWithError(0, "")
  241. })
  242. }
  243. type clientConn struct {
  244. quic.Stream
  245. destination M.Socksaddr
  246. requestWritten bool
  247. responseRead bool
  248. }
  249. func (c *clientConn) NeedHandshake() bool {
  250. return !c.requestWritten
  251. }
  252. func (c *clientConn) Read(p []byte) (n int, err error) {
  253. if c.responseRead {
  254. n, err = c.Stream.Read(p)
  255. return n, baderror.WrapQUIC(err)
  256. }
  257. status, errorMessage, err := protocol.ReadTCPResponse(c.Stream)
  258. if err != nil {
  259. return 0, baderror.WrapQUIC(err)
  260. }
  261. if !status {
  262. err = E.New("remote error: ", errorMessage)
  263. return
  264. }
  265. c.responseRead = true
  266. n, err = c.Stream.Read(p)
  267. return n, baderror.WrapQUIC(err)
  268. }
  269. func (c *clientConn) Write(p []byte) (n int, err error) {
  270. if !c.requestWritten {
  271. buffer := protocol.WriteTCPRequest(c.destination.String(), p)
  272. defer buffer.Release()
  273. _, err = c.Stream.Write(buffer.Bytes())
  274. if err != nil {
  275. return
  276. }
  277. c.requestWritten = true
  278. return len(p), nil
  279. }
  280. n, err = c.Stream.Write(p)
  281. return n, baderror.WrapQUIC(err)
  282. }
  283. func (c *clientConn) LocalAddr() net.Addr {
  284. return M.Socksaddr{}
  285. }
  286. func (c *clientConn) RemoteAddr() net.Addr {
  287. return M.Socksaddr{}
  288. }
  289. func (c *clientConn) Close() error {
  290. c.Stream.CancelRead(0)
  291. return c.Stream.Close()
  292. }