socks_connect_job.cc 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "net/socket/socks_connect_job.h"
  5. #include <memory>
  6. #include <utility>
  7. #include "base/bind.h"
  8. #include "net/base/net_errors.h"
  9. #include "net/log/net_log_source_type.h"
  10. #include "net/log/net_log_with_source.h"
  11. #include "net/socket/client_socket_factory.h"
  12. #include "net/socket/client_socket_handle.h"
  13. #include "net/socket/socks5_client_socket.h"
  14. #include "net/socket/socks_client_socket.h"
  15. #include "net/socket/transport_connect_job.h"
  16. namespace net {
  17. // SOCKSConnectJobs will time out if the SOCKS handshake takes longer than this.
  18. static constexpr base::TimeDelta kSOCKSConnectJobTimeout = base::Seconds(30);
  19. SOCKSSocketParams::SOCKSSocketParams(
  20. scoped_refptr<TransportSocketParams> proxy_server_params,
  21. bool socks_v5,
  22. const HostPortPair& host_port_pair,
  23. const NetworkIsolationKey& network_isolation_key,
  24. const NetworkTrafficAnnotationTag& traffic_annotation)
  25. : transport_params_(std::move(proxy_server_params)),
  26. destination_(host_port_pair),
  27. socks_v5_(socks_v5),
  28. network_isolation_key_(network_isolation_key),
  29. traffic_annotation_(traffic_annotation) {}
  30. SOCKSSocketParams::~SOCKSSocketParams() = default;
  31. std::unique_ptr<SOCKSConnectJob> SOCKSConnectJob::Factory::Create(
  32. RequestPriority priority,
  33. const SocketTag& socket_tag,
  34. const CommonConnectJobParams* common_connect_job_params,
  35. scoped_refptr<SOCKSSocketParams> socks_params,
  36. ConnectJob::Delegate* delegate,
  37. const NetLogWithSource* net_log) {
  38. return std::make_unique<SOCKSConnectJob>(
  39. priority, socket_tag, common_connect_job_params, std::move(socks_params),
  40. delegate, net_log);
  41. }
  42. SOCKSConnectJob::SOCKSConnectJob(
  43. RequestPriority priority,
  44. const SocketTag& socket_tag,
  45. const CommonConnectJobParams* common_connect_job_params,
  46. scoped_refptr<SOCKSSocketParams> socks_params,
  47. ConnectJob::Delegate* delegate,
  48. const NetLogWithSource* net_log)
  49. : ConnectJob(priority,
  50. socket_tag,
  51. base::TimeDelta(),
  52. common_connect_job_params,
  53. delegate,
  54. net_log,
  55. NetLogSourceType::SOCKS_CONNECT_JOB,
  56. NetLogEventType::SOCKS_CONNECT_JOB_CONNECT),
  57. socks_params_(std::move(socks_params)) {}
  58. SOCKSConnectJob::~SOCKSConnectJob() {
  59. // In the case the job was canceled, need to delete nested job first to
  60. // correctly order NetLog events.
  61. transport_connect_job_.reset();
  62. }
  63. LoadState SOCKSConnectJob::GetLoadState() const {
  64. switch (next_state_) {
  65. case STATE_TRANSPORT_CONNECT:
  66. return LOAD_STATE_IDLE;
  67. case STATE_TRANSPORT_CONNECT_COMPLETE:
  68. return transport_connect_job_->GetLoadState();
  69. case STATE_SOCKS_CONNECT:
  70. case STATE_SOCKS_CONNECT_COMPLETE:
  71. return LOAD_STATE_CONNECTING;
  72. default:
  73. NOTREACHED();
  74. return LOAD_STATE_IDLE;
  75. }
  76. }
  77. bool SOCKSConnectJob::HasEstablishedConnection() const {
  78. return next_state_ == STATE_SOCKS_CONNECT ||
  79. next_state_ == STATE_SOCKS_CONNECT_COMPLETE;
  80. }
  81. ResolveErrorInfo SOCKSConnectJob::GetResolveErrorInfo() const {
  82. return resolve_error_info_;
  83. }
  84. base::TimeDelta SOCKSConnectJob::HandshakeTimeoutForTesting() {
  85. return kSOCKSConnectJobTimeout;
  86. }
  87. void SOCKSConnectJob::OnIOComplete(int result) {
  88. int rv = DoLoop(result);
  89. if (rv != ERR_IO_PENDING)
  90. NotifyDelegateOfCompletion(rv); // Deletes |this|
  91. }
  92. void SOCKSConnectJob::OnConnectJobComplete(int result, ConnectJob* job) {
  93. DCHECK(transport_connect_job_);
  94. DCHECK_EQ(next_state_, STATE_TRANSPORT_CONNECT_COMPLETE);
  95. OnIOComplete(result);
  96. }
  97. void SOCKSConnectJob::OnNeedsProxyAuth(
  98. const HttpResponseInfo& response,
  99. HttpAuthController* auth_controller,
  100. base::OnceClosure restart_with_auth_callback,
  101. ConnectJob* job) {
  102. // A SOCKSConnectJob can't be on top of an HttpProxyConnectJob.
  103. NOTREACHED();
  104. }
  105. int SOCKSConnectJob::DoLoop(int result) {
  106. DCHECK_NE(next_state_, STATE_NONE);
  107. int rv = result;
  108. do {
  109. State state = next_state_;
  110. next_state_ = STATE_NONE;
  111. switch (state) {
  112. case STATE_TRANSPORT_CONNECT:
  113. DCHECK_EQ(OK, rv);
  114. rv = DoTransportConnect();
  115. break;
  116. case STATE_TRANSPORT_CONNECT_COMPLETE:
  117. rv = DoTransportConnectComplete(rv);
  118. break;
  119. case STATE_SOCKS_CONNECT:
  120. DCHECK_EQ(OK, rv);
  121. rv = DoSOCKSConnect();
  122. break;
  123. case STATE_SOCKS_CONNECT_COMPLETE:
  124. rv = DoSOCKSConnectComplete(rv);
  125. break;
  126. default:
  127. NOTREACHED() << "bad state";
  128. rv = ERR_FAILED;
  129. break;
  130. }
  131. } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
  132. return rv;
  133. }
  134. int SOCKSConnectJob::DoTransportConnect() {
  135. DCHECK(!transport_connect_job_);
  136. next_state_ = STATE_TRANSPORT_CONNECT_COMPLETE;
  137. transport_connect_job_ = std::make_unique<TransportConnectJob>(
  138. priority(), socket_tag(), common_connect_job_params(),
  139. socks_params_->transport_params(), this, &net_log());
  140. return transport_connect_job_->Connect();
  141. }
  142. int SOCKSConnectJob::DoTransportConnectComplete(int result) {
  143. resolve_error_info_ = transport_connect_job_->GetResolveErrorInfo();
  144. if (result != OK)
  145. return ERR_PROXY_CONNECTION_FAILED;
  146. // Start the timer to time allowed for SOCKS handshake.
  147. ResetTimer(kSOCKSConnectJobTimeout);
  148. next_state_ = STATE_SOCKS_CONNECT;
  149. return result;
  150. }
  151. int SOCKSConnectJob::DoSOCKSConnect() {
  152. next_state_ = STATE_SOCKS_CONNECT_COMPLETE;
  153. // Add a SOCKS connection on top of the tcp socket.
  154. if (socks_params_->is_socks_v5()) {
  155. socket_ = std::make_unique<SOCKS5ClientSocket>(
  156. transport_connect_job_->PassSocket(), socks_params_->destination(),
  157. socks_params_->traffic_annotation());
  158. } else {
  159. auto socks_socket = std::make_unique<SOCKSClientSocket>(
  160. transport_connect_job_->PassSocket(), socks_params_->destination(),
  161. socks_params_->network_isolation_key(), priority(), host_resolver(),
  162. socks_params_->transport_params()->secure_dns_policy(),
  163. socks_params_->traffic_annotation());
  164. socks_socket_ptr_ = socks_socket.get();
  165. socket_ = std::move(socks_socket);
  166. }
  167. transport_connect_job_.reset();
  168. return socket_->Connect(
  169. base::BindOnce(&SOCKSConnectJob::OnIOComplete, base::Unretained(this)));
  170. }
  171. int SOCKSConnectJob::DoSOCKSConnectComplete(int result) {
  172. if (!socks_params_->is_socks_v5())
  173. resolve_error_info_ = socks_socket_ptr_->GetResolveErrorInfo();
  174. if (result != OK) {
  175. socket_->Disconnect();
  176. return result;
  177. }
  178. SetSocket(std::move(socket_), absl::nullopt /* dns_aliases */);
  179. return result;
  180. }
  181. int SOCKSConnectJob::ConnectInternal() {
  182. next_state_ = STATE_TRANSPORT_CONNECT;
  183. return DoLoop(OK);
  184. }
  185. void SOCKSConnectJob::ChangePriorityInternal(RequestPriority priority) {
  186. // Currently doesn't change host resolution request priority for SOCKS4 case.
  187. if (transport_connect_job_)
  188. transport_connect_job_->ChangePriority(priority);
  189. }
  190. } // namespace net