dialer.go 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. package websocket
  2. import (
  3. "bytes"
  4. "context"
  5. "encoding/base64"
  6. "io"
  7. "net/http"
  8. "time"
  9. "github.com/gorilla/websocket"
  10. core "github.com/v2fly/v2ray-core/v5"
  11. "github.com/v2fly/v2ray-core/v5/common"
  12. "github.com/v2fly/v2ray-core/v5/common/net"
  13. "github.com/v2fly/v2ray-core/v5/common/session"
  14. "github.com/v2fly/v2ray-core/v5/features/extension"
  15. "github.com/v2fly/v2ray-core/v5/transport/internet"
  16. "github.com/v2fly/v2ray-core/v5/transport/internet/tls"
  17. )
  18. // Dial dials a WebSocket connection to the given destination.
  19. func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (internet.Connection, error) {
  20. newError("creating connection to ", dest).WriteToLog(session.ExportIDToError(ctx))
  21. conn, err := dialWebsocket(ctx, dest, streamSettings)
  22. if err != nil {
  23. return nil, newError("failed to dial WebSocket").Base(err)
  24. }
  25. return internet.Connection(conn), nil
  26. }
  27. func init() {
  28. common.Must(internet.RegisterTransportDialer(protocolName, Dial))
  29. }
  30. func dialWebsocket(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (net.Conn, error) {
  31. wsSettings := streamSettings.ProtocolSettings.(*Config)
  32. dialer := &websocket.Dialer{
  33. NetDial: func(network, addr string) (net.Conn, error) {
  34. return internet.DialSystem(ctx, dest, streamSettings.SocketSettings)
  35. },
  36. ReadBufferSize: 4 * 1024,
  37. WriteBufferSize: 4 * 1024,
  38. HandshakeTimeout: time.Second * 8,
  39. }
  40. protocol := "ws"
  41. if config := tls.ConfigFromStreamSettings(streamSettings); config != nil {
  42. protocol = "wss"
  43. dialer.TLSClientConfig = config.GetTLSConfig(tls.WithDestination(dest), tls.WithNextProto("http/1.1"))
  44. }
  45. host := dest.NetAddr()
  46. if (protocol == "ws" && dest.Port == 80) || (protocol == "wss" && dest.Port == 443) {
  47. host = dest.Address.String()
  48. }
  49. uri := protocol + "://" + host + wsSettings.GetNormalizedPath()
  50. if wsSettings.UseBrowserForwarding {
  51. var forwarder extension.BrowserForwarder
  52. err := core.RequireFeatures(ctx, func(Forwarder extension.BrowserForwarder) {
  53. forwarder = Forwarder
  54. })
  55. if err != nil {
  56. return nil, newError("cannot find browser forwarder service").Base(err)
  57. }
  58. if wsSettings.MaxEarlyData != 0 {
  59. return newRelayedConnectionWithDelayedDial(&dialerWithEarlyDataRelayed{
  60. forwarder: forwarder,
  61. uriBase: uri,
  62. config: wsSettings,
  63. }), nil
  64. }
  65. conn, err := forwarder.DialWebsocket(uri, nil)
  66. if err != nil {
  67. return nil, newError("cannot dial with browser forwarder service").Base(err)
  68. }
  69. return newRelayedConnection(conn), nil
  70. }
  71. if wsSettings.MaxEarlyData != 0 {
  72. return newConnectionWithDelayedDial(&dialerWithEarlyData{
  73. dialer: dialer,
  74. uriBase: uri,
  75. config: wsSettings,
  76. }), nil
  77. }
  78. conn, resp, err := dialer.Dial(uri, wsSettings.GetRequestHeader()) // nolint: bodyclose
  79. if err != nil {
  80. var reason string
  81. if resp != nil {
  82. reason = resp.Status
  83. }
  84. return nil, newError("failed to dial to (", uri, "): ", reason).Base(err)
  85. }
  86. return newConnection(conn, conn.RemoteAddr()), nil
  87. }
  88. type dialerWithEarlyData struct {
  89. dialer *websocket.Dialer
  90. uriBase string
  91. config *Config
  92. }
  93. func (d dialerWithEarlyData) Dial(earlyData []byte) (*websocket.Conn, error) {
  94. earlyDataBuf := bytes.NewBuffer(nil)
  95. base64EarlyDataEncoder := base64.NewEncoder(base64.RawURLEncoding, earlyDataBuf)
  96. earlydata := bytes.NewReader(earlyData)
  97. limitedEarlyDatareader := io.LimitReader(earlydata, int64(d.config.MaxEarlyData))
  98. n, encerr := io.Copy(base64EarlyDataEncoder, limitedEarlyDatareader)
  99. if encerr != nil {
  100. return nil, newError("websocket delayed dialer cannot encode early data").Base(encerr)
  101. }
  102. if errc := base64EarlyDataEncoder.Close(); errc != nil {
  103. return nil, newError("websocket delayed dialer cannot encode early data tail").Base(errc)
  104. }
  105. dialFunction := func() (*websocket.Conn, *http.Response, error) {
  106. return d.dialer.Dial(d.uriBase+earlyDataBuf.String(), d.config.GetRequestHeader())
  107. }
  108. if d.config.EarlyDataHeaderName != "" {
  109. dialFunction = func() (*websocket.Conn, *http.Response, error) {
  110. earlyDataStr := earlyDataBuf.String()
  111. currentHeader := d.config.GetRequestHeader()
  112. currentHeader.Set(d.config.EarlyDataHeaderName, earlyDataStr)
  113. return d.dialer.Dial(d.uriBase, currentHeader)
  114. }
  115. }
  116. conn, resp, err := dialFunction() // nolint: bodyclose
  117. if err != nil {
  118. var reason string
  119. if resp != nil {
  120. reason = resp.Status
  121. }
  122. return nil, newError("failed to dial to (", d.uriBase, ") with early data: ", reason).Base(err)
  123. }
  124. if n != int64(len(earlyData)) {
  125. if errWrite := conn.WriteMessage(websocket.BinaryMessage, earlyData[n:]); errWrite != nil {
  126. return nil, newError("failed to dial to (", d.uriBase, ") with early data as write of remainder early data failed: ").Base(err)
  127. }
  128. }
  129. return conn, nil
  130. }
  131. type dialerWithEarlyDataRelayed struct {
  132. forwarder extension.BrowserForwarder
  133. uriBase string
  134. config *Config
  135. }
  136. func (d dialerWithEarlyDataRelayed) Dial(earlyData []byte) (io.ReadWriteCloser, error) {
  137. earlyDataBuf := bytes.NewBuffer(nil)
  138. base64EarlyDataEncoder := base64.NewEncoder(base64.RawURLEncoding, earlyDataBuf)
  139. earlydata := bytes.NewReader(earlyData)
  140. limitedEarlyDatareader := io.LimitReader(earlydata, int64(d.config.MaxEarlyData))
  141. n, encerr := io.Copy(base64EarlyDataEncoder, limitedEarlyDatareader)
  142. if encerr != nil {
  143. return nil, newError("websocket delayed dialer cannot encode early data").Base(encerr)
  144. }
  145. if errc := base64EarlyDataEncoder.Close(); errc != nil {
  146. return nil, newError("websocket delayed dialer cannot encode early data tail").Base(errc)
  147. }
  148. dialFunction := func() (io.ReadWriteCloser, error) {
  149. return d.forwarder.DialWebsocket(d.uriBase+earlyDataBuf.String(), d.config.GetRequestHeader())
  150. }
  151. if d.config.EarlyDataHeaderName != "" {
  152. earlyDataStr := earlyDataBuf.String()
  153. currentHeader := d.config.GetRequestHeader()
  154. currentHeader.Set(d.config.EarlyDataHeaderName, earlyDataStr)
  155. return d.forwarder.DialWebsocket(d.uriBase, currentHeader)
  156. }
  157. conn, err := dialFunction()
  158. if err != nil {
  159. var reason string
  160. return nil, newError("failed to dial to (", d.uriBase, ") with early data: ", reason).Base(err)
  161. }
  162. if n != int64(len(earlyData)) {
  163. if _, errWrite := conn.Write(earlyData[n:]); errWrite != nil {
  164. return nil, newError("failed to dial to (", d.uriBase, ") with early data as write of remainder early data failed: ").Base(err)
  165. }
  166. }
  167. return conn, nil
  168. }