dialer.go 6.3 KB

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