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