dialer.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. // +build !confonly
  2. package websocket
  3. import (
  4. "bytes"
  5. "context"
  6. "encoding/base64"
  7. "github.com/v2fly/v2ray-core/v4/features/extension"
  8. "io"
  9. "time"
  10. "github.com/gorilla/websocket"
  11. core "github.com/v2fly/v2ray-core/v4"
  12. "github.com/v2fly/v2ray-core/v4/common"
  13. "github.com/v2fly/v2ray-core/v4/common/net"
  14. "github.com/v2fly/v2ray-core/v4/common/session"
  15. "github.com/v2fly/v2ray-core/v4/transport/internet"
  16. "github.com/v2fly/v2ray-core/v4/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())
  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. conn, resp, err := d.dialer.Dial(d.uriBase+earlyDataBuf.String(), d.config.GetRequestHeader())
  106. if err != nil {
  107. var reason string
  108. if resp != nil {
  109. reason = resp.Status
  110. }
  111. return nil, newError("failed to dial to (", d.uriBase, ") with early data: ", reason).Base(err)
  112. }
  113. if n != int64(len(earlyData)) {
  114. if errWrite := conn.WriteMessage(websocket.BinaryMessage, earlyData[n:]); errWrite != nil {
  115. return nil, newError("failed to dial to (", d.uriBase, ") with early data as write of remainder early data failed: ").Base(err)
  116. }
  117. }
  118. return conn, nil
  119. }
  120. type dialerWithEarlyDataRelayed struct {
  121. forwarder extension.BrowserForwarder
  122. uriBase string
  123. config *Config
  124. }
  125. func (d dialerWithEarlyDataRelayed) Dial(earlyData []byte) (io.ReadWriteCloser, error) {
  126. earlyDataBuf := bytes.NewBuffer(nil)
  127. base64EarlyDataEncoder := base64.NewEncoder(base64.RawURLEncoding, earlyDataBuf)
  128. earlydata := bytes.NewReader(earlyData)
  129. limitedEarlyDatareader := io.LimitReader(earlydata, int64(d.config.MaxEarlyData))
  130. n, encerr := io.Copy(base64EarlyDataEncoder, limitedEarlyDatareader)
  131. if encerr != nil {
  132. return nil, newError("websocket delayed dialer cannot encode early data").Base(encerr)
  133. }
  134. if errc := base64EarlyDataEncoder.Close(); errc != nil {
  135. return nil, newError("websocket delayed dialer cannot encode early data tail").Base(errc)
  136. }
  137. conn, err := d.forwarder.DialWebsocket(d.uriBase+earlyDataBuf.String(), d.config.GetRequestHeader())
  138. if err != nil {
  139. var reason string
  140. return nil, newError("failed to dial to (", d.uriBase, ") with early data: ", reason).Base(err)
  141. }
  142. if n != int64(len(earlyData)) {
  143. if _, errWrite := conn.Write(earlyData[n:]); errWrite != nil {
  144. return nil, newError("failed to dial to (", d.uriBase, ") with early data as write of remainder early data failed: ").Base(err)
  145. }
  146. }
  147. return conn, nil
  148. }