[go: nahoru, domu]

blob: 383092b0cb85257beaab670f2557ba85bba5356d [file] [log] [blame]
wez@chromium.org9eb7b112012-03-28 20:19:311// Copyright (c) 2012 The Chromium Authors. All rights reserved.
arindam@chromium.orge0c27be2009-07-15 13:09:352// 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/socks5_client_socket.h"
6
dchengc7eeda422015-12-26 03:56:487#include <utility>
8
davidben@chromium.org0dc88b32014-03-26 20:12:289#include "base/callback_helpers.h"
arindam@chromium.orge0c27be2009-07-15 13:09:3510#include "base/compiler_specific.h"
eroman@chromium.org38c70d35d2009-12-22 01:49:4011#include "base/format_macros.h"
Avi Drissman4365a4782018-12-28 19:26:2412#include "base/stl_util.h"
avi@chromium.orgfc9be5802013-06-11 10:56:5113#include "base/strings/string_util.h"
wez@chromium.org9eb7b112012-03-28 20:19:3114#include "base/sys_byteorder.h"
primiano4775e5012015-01-30 16:40:3115#include "base/trace_event/trace_event.h"
arindam@chromium.orge0c27be2009-07-15 13:09:3516#include "net/base/io_buffer.h"
eroman87c53d62015-04-02 06:51:0717#include "net/log/net_log.h"
mikecirone8b85c432016-09-08 19:11:0018#include "net/log/net_log_event_type.h"
vandebo@chromium.orga796bcec2010-03-22 17:17:2619#include "net/socket/client_socket_handle.h"
rhalavati@google.coma2b2cfc2017-12-06 09:06:0820#include "net/traffic_annotation/network_traffic_annotation.h"
arindam@chromium.orge0c27be2009-07-15 13:09:3521
22namespace net {
23
24const unsigned int SOCKS5ClientSocket::kGreetReadHeaderSize = 2;
25const unsigned int SOCKS5ClientSocket::kWriteHeaderSize = 10;
26const unsigned int SOCKS5ClientSocket::kReadHeaderSize = 5;
Avi Drissman13fc8932015-12-20 04:40:4627const uint8_t SOCKS5ClientSocket::kSOCKS5Version = 0x05;
28const uint8_t SOCKS5ClientSocket::kTunnelCommand = 0x01;
29const uint8_t SOCKS5ClientSocket::kNullByte = 0x00;
arindam@chromium.orge0c27be2009-07-15 13:09:3530
mostynb91e0da982015-01-20 19:17:2731static_assert(sizeof(struct in_addr) == 4, "incorrect system size of IPv4");
32static_assert(sizeof(struct in6_addr) == 16, "incorrect system size of IPv6");
arindam@chromium.orge0c27be2009-07-15 13:09:3533
vandebo@chromium.orga796bcec2010-03-22 17:17:2634SOCKS5ClientSocket::SOCKS5ClientSocket(
danakj655b66c2016-04-16 00:51:3835 std::unique_ptr<ClientSocketHandle> transport_socket,
rhalavati@google.com27fb73c2018-01-11 13:27:2436 const HostResolver::RequestInfo& req_info,
37 const NetworkTrafficAnnotationTag& traffic_annotation)
Bence Béky61f756c2018-04-25 14:17:5338 : io_callback_(base::BindRepeating(&SOCKS5ClientSocket::OnIOComplete,
39 base::Unretained(this))),
dchengc7eeda422015-12-26 03:56:4840 transport_(std::move(transport_socket)),
arindam@chromium.orge0c27be2009-07-15 13:09:3541 next_state_(STATE_NONE),
arindam@chromium.orge0c27be2009-07-15 13:09:3542 completed_handshake_(false),
43 bytes_sent_(0),
44 bytes_received_(0),
45 read_header_size(kReadHeaderSize),
davidben@chromium.org0dc88b32014-03-26 20:12:2846 was_ever_used_(false),
vandebo@chromium.orga2006ece2010-04-23 16:44:0247 host_request_info_(req_info),
rhalavati@google.com27fb73c2018-01-11 13:27:2448 net_log_(transport_->socket()->NetLog()),
49 traffic_annotation_(traffic_annotation) {}
arindam@chromium.orge0c27be2009-07-15 13:09:3550
51SOCKS5ClientSocket::~SOCKS5ClientSocket() {
52 Disconnect();
53}
54
Brad Lassey3a814172018-04-26 03:30:2155int SOCKS5ClientSocket::Connect(CompletionOnceCallback callback) {
arindam@chromium.orge0c27be2009-07-15 13:09:3556 DCHECK(transport_.get());
vandebo@chromium.orga796bcec2010-03-22 17:17:2657 DCHECK(transport_->socket());
arindam@chromium.orge0c27be2009-07-15 13:09:3558 DCHECK_EQ(STATE_NONE, next_state_);
ajwong@chromium.org83039bb2011-12-09 18:43:5559 DCHECK(user_callback_.is_null());
arindam@chromium.orge0c27be2009-07-15 13:09:3560
61 // If already connected, then just return OK.
62 if (completed_handshake_)
63 return OK;
64
mikecirone8b85c432016-09-08 19:11:0065 net_log_.BeginEvent(NetLogEventType::SOCKS5_CONNECT);
arindam@chromium.orge0c27be2009-07-15 13:09:3566
eroman@chromium.org20cbe23d2009-12-18 03:39:2167 next_state_ = STATE_GREET_WRITE;
68 buffer_.clear();
eroman@chromium.orgf209dba2009-12-18 00:24:3769
arindam@chromium.orge0c27be2009-07-15 13:09:3570 int rv = DoLoop(OK);
willchan@chromium.org5a05c47a2009-11-02 23:25:1971 if (rv == ERR_IO_PENDING) {
Brad Lassey3a814172018-04-26 03:30:2172 user_callback_ = std::move(callback);
willchan@chromium.org5a05c47a2009-11-02 23:25:1973 } else {
mikecirone8b85c432016-09-08 19:11:0074 net_log_.EndEventWithNetErrorCode(NetLogEventType::SOCKS5_CONNECT, rv);
willchan@chromium.org5a05c47a2009-11-02 23:25:1975 }
arindam@chromium.orge0c27be2009-07-15 13:09:3576 return rv;
77}
78
79void SOCKS5ClientSocket::Disconnect() {
80 completed_handshake_ = false;
vandebo@chromium.orga796bcec2010-03-22 17:17:2681 transport_->socket()->Disconnect();
eroman@chromium.org16a02742010-01-07 22:50:1082
83 // Reset other states to make sure they aren't mistakenly used later.
84 // These are the states initialized by Connect().
85 next_state_ = STATE_NONE;
jhawkins@chromium.orgdbf036f2011-12-06 23:33:2486 user_callback_.Reset();
arindam@chromium.orge0c27be2009-07-15 13:09:3587}
88
89bool SOCKS5ClientSocket::IsConnected() const {
vandebo@chromium.orga796bcec2010-03-22 17:17:2690 return completed_handshake_ && transport_->socket()->IsConnected();
arindam@chromium.orge0c27be2009-07-15 13:09:3591}
92
93bool SOCKS5ClientSocket::IsConnectedAndIdle() const {
vandebo@chromium.orga796bcec2010-03-22 17:17:2694 return completed_handshake_ && transport_->socket()->IsConnectedAndIdle();
arindam@chromium.orge0c27be2009-07-15 13:09:3595}
96
tfarina42834112016-09-22 13:38:2097const NetLogWithSource& SOCKS5ClientSocket::NetLog() const {
erg@google.come4be2dd2010-12-14 00:44:3998 return net_log_;
99}
100
willchan@chromium.org0f873e82010-09-02 16:09:01101bool SOCKS5ClientSocket::WasEverUsed() const {
davidben@chromium.org0dc88b32014-03-26 20:12:28102 return was_ever_used_;
willchan@chromium.org0f873e82010-09-02 16:09:01103}
104
tfarina2846404c2016-12-25 14:31:37105bool SOCKS5ClientSocket::WasAlpnNegotiated() const {
rch@chromium.org2d88e7d2012-07-19 17:55:17106 if (transport_.get() && transport_->socket()) {
tfarina2846404c2016-12-25 14:31:37107 return transport_->socket()->WasAlpnNegotiated();
rch@chromium.org2d88e7d2012-07-19 17:55:17108 }
109 NOTREACHED();
110 return false;
111}
112
rch@chromium.org33661e482012-04-03 16:16:26113NextProto SOCKS5ClientSocket::GetNegotiatedProtocol() const {
114 if (transport_.get() && transport_->socket()) {
115 return transport_->socket()->GetNegotiatedProtocol();
116 }
117 NOTREACHED();
118 return kProtoUnknown;
119}
120
rch@chromium.org2d88e7d2012-07-19 17:55:17121bool SOCKS5ClientSocket::GetSSLInfo(SSLInfo* ssl_info) {
122 if (transport_.get() && transport_->socket()) {
123 return transport_->socket()->GetSSLInfo(ssl_info);
124 }
125 NOTREACHED();
126 return false;
ttuttle23fdb7b2015-05-15 01:28:03127}
rch@chromium.org2d88e7d2012-07-19 17:55:17128
ttuttle23fdb7b2015-05-15 01:28:03129void SOCKS5ClientSocket::GetConnectionAttempts(ConnectionAttempts* out) const {
130 out->clear();
rch@chromium.org2d88e7d2012-07-19 17:55:17131}
132
tbansalf82cc8e2015-10-14 20:05:49133int64_t SOCKS5ClientSocket::GetTotalReceivedBytes() const {
134 return transport_->socket()->GetTotalReceivedBytes();
135}
136
Paul Jensen0f49dec2017-12-12 23:39:58137void SOCKS5ClientSocket::ApplySocketTag(const SocketTag& tag) {
138 return transport_->socket()->ApplySocketTag(tag);
139}
140
arindam@chromium.orge0c27be2009-07-15 13:09:35141// Read is called by the transport layer above to read. This can only be done
142// if the SOCKS handshake is complete.
Brad Lassey3a814172018-04-26 03:30:21143int SOCKS5ClientSocket::Read(IOBuffer* buf,
144 int buf_len,
145 CompletionOnceCallback callback) {
jhawkins@chromium.org3f55aa12011-12-07 02:03:33146 DCHECK(completed_handshake_);
147 DCHECK_EQ(STATE_NONE, next_state_);
ajwong@chromium.org83039bb2011-12-09 18:43:55148 DCHECK(user_callback_.is_null());
davidben@chromium.org0dc88b32014-03-26 20:12:28149 DCHECK(!callback.is_null());
arindam@chromium.orge0c27be2009-07-15 13:09:35150
davidben@chromium.org0dc88b32014-03-26 20:12:28151 int rv = transport_->socket()->Read(
152 buf, buf_len,
Brad Lassey3a814172018-04-26 03:30:21153 base::BindOnce(&SOCKS5ClientSocket::OnReadWriteComplete,
154 base::Unretained(this), std::move(callback)));
davidben@chromium.org0dc88b32014-03-26 20:12:28155 if (rv > 0)
156 was_ever_used_ = true;
157 return rv;
arindam@chromium.orge0c27be2009-07-15 13:09:35158}
159
160// Write is called by the transport layer. This can only be done if the
161// SOCKS handshake is complete.
rhalavati@google.coma2b2cfc2017-12-06 09:06:08162int SOCKS5ClientSocket::Write(
163 IOBuffer* buf,
164 int buf_len,
Brad Lassey3a814172018-04-26 03:30:21165 CompletionOnceCallback callback,
rhalavati@google.coma2b2cfc2017-12-06 09:06:08166 const NetworkTrafficAnnotationTag& traffic_annotation) {
arindam@chromium.orge0c27be2009-07-15 13:09:35167 DCHECK(completed_handshake_);
168 DCHECK_EQ(STATE_NONE, next_state_);
ajwong@chromium.org83039bb2011-12-09 18:43:55169 DCHECK(user_callback_.is_null());
davidben@chromium.org0dc88b32014-03-26 20:12:28170 DCHECK(!callback.is_null());
arindam@chromium.orge0c27be2009-07-15 13:09:35171
davidben@chromium.org0dc88b32014-03-26 20:12:28172 int rv = transport_->socket()->Write(
173 buf, buf_len,
Brad Lassey3a814172018-04-26 03:30:21174 base::BindOnce(&SOCKS5ClientSocket::OnReadWriteComplete,
175 base::Unretained(this), std::move(callback)),
rhalavati@google.coma2b2cfc2017-12-06 09:06:08176 traffic_annotation);
davidben@chromium.org0dc88b32014-03-26 20:12:28177 if (rv > 0)
178 was_ever_used_ = true;
179 return rv;
arindam@chromium.orge0c27be2009-07-15 13:09:35180}
181
Avi Drissman13fc8932015-12-20 04:40:46182int SOCKS5ClientSocket::SetReceiveBufferSize(int32_t size) {
vandebo@chromium.orga796bcec2010-03-22 17:17:26183 return transport_->socket()->SetReceiveBufferSize(size);
mbelshe@google.comd3f66572009-09-09 22:38:04184}
185
Avi Drissman13fc8932015-12-20 04:40:46186int SOCKS5ClientSocket::SetSendBufferSize(int32_t size) {
vandebo@chromium.orga796bcec2010-03-22 17:17:26187 return transport_->socket()->SetSendBufferSize(size);
mbelshe@google.comd3f66572009-09-09 22:38:04188}
189
arindam@chromium.orge0c27be2009-07-15 13:09:35190void SOCKS5ClientSocket::DoCallback(int result) {
191 DCHECK_NE(ERR_IO_PENDING, result);
ajwong@chromium.org83039bb2011-12-09 18:43:55192 DCHECK(!user_callback_.is_null());
arindam@chromium.orge0c27be2009-07-15 13:09:35193
194 // Since Run() may result in Read being called,
195 // clear user_callback_ up front.
Brad Lassey3a814172018-04-26 03:30:21196 std::move(user_callback_).Run(result);
arindam@chromium.orge0c27be2009-07-15 13:09:35197}
198
199void SOCKS5ClientSocket::OnIOComplete(int result) {
200 DCHECK_NE(STATE_NONE, next_state_);
201 int rv = DoLoop(result);
willchan@chromium.org5a05c47a2009-11-02 23:25:19202 if (rv != ERR_IO_PENDING) {
mikecirone8b85c432016-09-08 19:11:00203 net_log_.EndEvent(NetLogEventType::SOCKS5_CONNECT);
arindam@chromium.orge0c27be2009-07-15 13:09:35204 DoCallback(rv);
willchan@chromium.org5a05c47a2009-11-02 23:25:19205 }
arindam@chromium.orge0c27be2009-07-15 13:09:35206}
207
Brad Lassey3a814172018-04-26 03:30:21208void SOCKS5ClientSocket::OnReadWriteComplete(CompletionOnceCallback callback,
davidben@chromium.org0dc88b32014-03-26 20:12:28209 int result) {
210 DCHECK_NE(ERR_IO_PENDING, result);
211 DCHECK(!callback.is_null());
212
213 if (result > 0)
214 was_ever_used_ = true;
Brad Lassey3a814172018-04-26 03:30:21215 std::move(callback).Run(result);
davidben@chromium.org0dc88b32014-03-26 20:12:28216}
217
arindam@chromium.orge0c27be2009-07-15 13:09:35218int SOCKS5ClientSocket::DoLoop(int last_io_result) {
219 DCHECK_NE(next_state_, STATE_NONE);
220 int rv = last_io_result;
221 do {
222 State state = next_state_;
223 next_state_ = STATE_NONE;
224 switch (state) {
arindam@chromium.orge0c27be2009-07-15 13:09:35225 case STATE_GREET_WRITE:
226 DCHECK_EQ(OK, rv);
mikecirone8b85c432016-09-08 19:11:00227 net_log_.BeginEvent(NetLogEventType::SOCKS5_GREET_WRITE);
arindam@chromium.orge0c27be2009-07-15 13:09:35228 rv = DoGreetWrite();
229 break;
230 case STATE_GREET_WRITE_COMPLETE:
231 rv = DoGreetWriteComplete(rv);
mikecirone8b85c432016-09-08 19:11:00232 net_log_.EndEventWithNetErrorCode(NetLogEventType::SOCKS5_GREET_WRITE,
233 rv);
arindam@chromium.orge0c27be2009-07-15 13:09:35234 break;
235 case STATE_GREET_READ:
236 DCHECK_EQ(OK, rv);
mikecirone8b85c432016-09-08 19:11:00237 net_log_.BeginEvent(NetLogEventType::SOCKS5_GREET_READ);
arindam@chromium.orge0c27be2009-07-15 13:09:35238 rv = DoGreetRead();
239 break;
240 case STATE_GREET_READ_COMPLETE:
241 rv = DoGreetReadComplete(rv);
mikecirone8b85c432016-09-08 19:11:00242 net_log_.EndEventWithNetErrorCode(NetLogEventType::SOCKS5_GREET_READ,
243 rv);
arindam@chromium.orge0c27be2009-07-15 13:09:35244 break;
245 case STATE_HANDSHAKE_WRITE:
246 DCHECK_EQ(OK, rv);
mikecirone8b85c432016-09-08 19:11:00247 net_log_.BeginEvent(NetLogEventType::SOCKS5_HANDSHAKE_WRITE);
arindam@chromium.orge0c27be2009-07-15 13:09:35248 rv = DoHandshakeWrite();
249 break;
250 case STATE_HANDSHAKE_WRITE_COMPLETE:
251 rv = DoHandshakeWriteComplete(rv);
mmenke@chromium.orgd7fd1782011-02-08 19:16:43252 net_log_.EndEventWithNetErrorCode(
mikecirone8b85c432016-09-08 19:11:00253 NetLogEventType::SOCKS5_HANDSHAKE_WRITE, rv);
arindam@chromium.orge0c27be2009-07-15 13:09:35254 break;
255 case STATE_HANDSHAKE_READ:
256 DCHECK_EQ(OK, rv);
mikecirone8b85c432016-09-08 19:11:00257 net_log_.BeginEvent(NetLogEventType::SOCKS5_HANDSHAKE_READ);
arindam@chromium.orge0c27be2009-07-15 13:09:35258 rv = DoHandshakeRead();
259 break;
260 case STATE_HANDSHAKE_READ_COMPLETE:
261 rv = DoHandshakeReadComplete(rv);
mmenke@chromium.orgd7fd1782011-02-08 19:16:43262 net_log_.EndEventWithNetErrorCode(
mikecirone8b85c432016-09-08 19:11:00263 NetLogEventType::SOCKS5_HANDSHAKE_READ, rv);
arindam@chromium.orge0c27be2009-07-15 13:09:35264 break;
265 default:
266 NOTREACHED() << "bad state";
267 rv = ERR_UNEXPECTED;
268 break;
269 }
270 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
271 return rv;
272}
273
arindam@chromium.orge0c27be2009-07-15 13:09:35274const char kSOCKS5GreetWriteData[] = { 0x05, 0x01, 0x00 }; // no authentication
arindam@chromium.orge0c27be2009-07-15 13:09:35275
276int SOCKS5ClientSocket::DoGreetWrite() {
eroman@chromium.org866ba4c2009-12-18 23:43:43277 // Since we only have 1 byte to send the hostname length in, if the
278 // URL has a hostname longer than 255 characters we can't send it.
eroman@chromium.org38c70d35d2009-12-22 01:49:40279 if (0xFF < host_request_info_.hostname().size()) {
mikecirone8b85c432016-09-08 19:11:00280 net_log_.AddEvent(NetLogEventType::SOCKS_HOSTNAME_TOO_BIG);
eroman@chromium.orgd5a309592010-02-05 02:22:52281 return ERR_SOCKS_CONNECTION_FAILED;
eroman@chromium.org38c70d35d2009-12-22 01:49:40282 }
eroman@chromium.org866ba4c2009-12-18 23:43:43283
arindam@chromium.orge0c27be2009-07-15 13:09:35284 if (buffer_.empty()) {
Avi Drissman4365a4782018-12-28 19:26:24285 buffer_ =
286 std::string(kSOCKS5GreetWriteData, base::size(kSOCKS5GreetWriteData));
arindam@chromium.orge0c27be2009-07-15 13:09:35287 bytes_sent_ = 0;
288 }
289
290 next_state_ = STATE_GREET_WRITE_COMPLETE;
291 size_t handshake_buf_len = buffer_.size() - bytes_sent_;
Victor Costan9c7302b2018-08-27 16:39:44292 handshake_buf_ = base::MakeRefCounted<IOBuffer>(handshake_buf_len);
arindam@chromium.orge0c27be2009-07-15 13:09:35293 memcpy(handshake_buf_->data(), &buffer_.data()[bytes_sent_],
294 handshake_buf_len);
rhalavati@google.coma2b2cfc2017-12-06 09:06:08295 return transport_->socket()->Write(handshake_buf_.get(), handshake_buf_len,
rhalavati@google.com27fb73c2018-01-11 13:27:24296 io_callback_, traffic_annotation_);
arindam@chromium.orge0c27be2009-07-15 13:09:35297}
298
299int SOCKS5ClientSocket::DoGreetWriteComplete(int result) {
300 if (result < 0)
301 return result;
302
303 bytes_sent_ += result;
304 if (bytes_sent_ == buffer_.size()) {
305 buffer_.clear();
306 bytes_received_ = 0;
307 next_state_ = STATE_GREET_READ;
308 } else {
309 next_state_ = STATE_GREET_WRITE;
310 }
311 return OK;
312}
313
314int SOCKS5ClientSocket::DoGreetRead() {
315 next_state_ = STATE_GREET_READ_COMPLETE;
316 size_t handshake_buf_len = kGreetReadHeaderSize - bytes_received_;
Victor Costan9c7302b2018-08-27 16:39:44317 handshake_buf_ = base::MakeRefCounted<IOBuffer>(handshake_buf_len);
rsleevi@chromium.org90499482013-06-01 00:39:50318 return transport_->socket()
319 ->Read(handshake_buf_.get(), handshake_buf_len, io_callback_);
arindam@chromium.orge0c27be2009-07-15 13:09:35320}
321
322int SOCKS5ClientSocket::DoGreetReadComplete(int result) {
323 if (result < 0)
324 return result;
325
eroman@chromium.orgd5a309592010-02-05 02:22:52326 if (result == 0) {
mikecirone8b85c432016-09-08 19:11:00327 net_log_.AddEvent(
328 NetLogEventType::SOCKS_UNEXPECTEDLY_CLOSED_DURING_GREETING);
eroman@chromium.orgd5a309592010-02-05 02:22:52329 return ERR_SOCKS_CONNECTION_FAILED;
330 }
arindam@chromium.orge0c27be2009-07-15 13:09:35331
332 bytes_received_ += result;
333 buffer_.append(handshake_buf_->data(), result);
334 if (bytes_received_ < kGreetReadHeaderSize) {
335 next_state_ = STATE_GREET_READ;
336 return OK;
337 }
338
339 // Got the greet data.
eroman@chromium.org38c70d35d2009-12-22 01:49:40340 if (buffer_[0] != kSOCKS5Version) {
mikecirone8b85c432016-09-08 19:11:00341 net_log_.AddEvent(NetLogEventType::SOCKS_UNEXPECTED_VERSION,
tfarina5e24b242015-10-27 13:11:28342 NetLog::IntCallback("version", buffer_[0]));
eroman@chromium.orgd5a309592010-02-05 02:22:52343 return ERR_SOCKS_CONNECTION_FAILED;
eroman@chromium.org38c70d35d2009-12-22 01:49:40344 }
345 if (buffer_[1] != 0x00) {
mikecirone8b85c432016-09-08 19:11:00346 net_log_.AddEvent(NetLogEventType::SOCKS_UNEXPECTED_AUTH,
tfarina5e24b242015-10-27 13:11:28347 NetLog::IntCallback("method", buffer_[1]));
eroman@chromium.orgd5a309592010-02-05 02:22:52348 return ERR_SOCKS_CONNECTION_FAILED;
eroman@chromium.org38c70d35d2009-12-22 01:49:40349 }
arindam@chromium.orge0c27be2009-07-15 13:09:35350
351 buffer_.clear();
352 next_state_ = STATE_HANDSHAKE_WRITE;
353 return OK;
354}
355
356int SOCKS5ClientSocket::BuildHandshakeWriteBuffer(std::string* handshake)
357 const {
arindam@chromium.orge0c27be2009-07-15 13:09:35358 DCHECK(handshake->empty());
359
360 handshake->push_back(kSOCKS5Version);
361 handshake->push_back(kTunnelCommand); // Connect command
362 handshake->push_back(kNullByte); // Reserved null
363
eroman@chromium.org20cbe23d2009-12-18 03:39:21364 handshake->push_back(kEndPointDomain); // The type of the address.
arindam@chromium.orge0c27be2009-07-15 13:09:35365
eroman@chromium.org866ba4c2009-12-18 23:43:43366 DCHECK_GE(static_cast<size_t>(0xFF), host_request_info_.hostname().size());
arindam@chromium.orge0c27be2009-07-15 13:09:35367
eroman@chromium.org20cbe23d2009-12-18 03:39:21368 // First add the size of the hostname, followed by the hostname.
369 handshake->push_back(static_cast<unsigned char>(
370 host_request_info_.hostname().size()));
371 handshake->append(host_request_info_.hostname());
arindam@chromium.orge0c27be2009-07-15 13:09:35372
Avi Drissman13fc8932015-12-20 04:40:46373 uint16_t nw_port = base::HostToNet16(host_request_info_.port());
arindam@chromium.orge0c27be2009-07-15 13:09:35374 handshake->append(reinterpret_cast<char*>(&nw_port), sizeof(nw_port));
375 return OK;
376}
377
378// Writes the SOCKS handshake data to the underlying socket connection.
379int SOCKS5ClientSocket::DoHandshakeWrite() {
380 next_state_ = STATE_HANDSHAKE_WRITE_COMPLETE;
381
382 if (buffer_.empty()) {
383 int rv = BuildHandshakeWriteBuffer(&buffer_);
384 if (rv != OK)
385 return rv;
386 bytes_sent_ = 0;
387 }
388
389 int handshake_buf_len = buffer_.size() - bytes_sent_;
390 DCHECK_LT(0, handshake_buf_len);
Victor Costan9c7302b2018-08-27 16:39:44391 handshake_buf_ = base::MakeRefCounted<IOBuffer>(handshake_buf_len);
arindam@chromium.orge0c27be2009-07-15 13:09:35392 memcpy(handshake_buf_->data(), &buffer_[bytes_sent_],
393 handshake_buf_len);
rhalavati@google.coma2b2cfc2017-12-06 09:06:08394 return transport_->socket()->Write(handshake_buf_.get(), handshake_buf_len,
rhalavati@google.com27fb73c2018-01-11 13:27:24395 io_callback_, traffic_annotation_);
arindam@chromium.orge0c27be2009-07-15 13:09:35396}
397
398int SOCKS5ClientSocket::DoHandshakeWriteComplete(int result) {
arindam@chromium.orge0c27be2009-07-15 13:09:35399 if (result < 0)
400 return result;
401
402 // We ignore the case when result is 0, since the underlying Write
403 // may return spurious writes while waiting on the socket.
404
405 bytes_sent_ += result;
406 if (bytes_sent_ == buffer_.size()) {
407 next_state_ = STATE_HANDSHAKE_READ;
408 buffer_.clear();
409 } else if (bytes_sent_ < buffer_.size()) {
410 next_state_ = STATE_HANDSHAKE_WRITE;
411 } else {
412 NOTREACHED();
413 }
414
415 return OK;
416}
417
418int SOCKS5ClientSocket::DoHandshakeRead() {
arindam@chromium.orge0c27be2009-07-15 13:09:35419 next_state_ = STATE_HANDSHAKE_READ_COMPLETE;
420
421 if (buffer_.empty()) {
422 bytes_received_ = 0;
423 read_header_size = kReadHeaderSize;
424 }
425
426 int handshake_buf_len = read_header_size - bytes_received_;
Victor Costan9c7302b2018-08-27 16:39:44427 handshake_buf_ = base::MakeRefCounted<IOBuffer>(handshake_buf_len);
rsleevi@chromium.org90499482013-06-01 00:39:50428 return transport_->socket()
429 ->Read(handshake_buf_.get(), handshake_buf_len, io_callback_);
arindam@chromium.orge0c27be2009-07-15 13:09:35430}
431
432int SOCKS5ClientSocket::DoHandshakeReadComplete(int result) {
arindam@chromium.orge0c27be2009-07-15 13:09:35433 if (result < 0)
434 return result;
435
436 // The underlying socket closed unexpectedly.
eroman@chromium.orgd5a309592010-02-05 02:22:52437 if (result == 0) {
mikecirone8b85c432016-09-08 19:11:00438 net_log_.AddEvent(
439 NetLogEventType::SOCKS_UNEXPECTEDLY_CLOSED_DURING_HANDSHAKE);
eroman@chromium.orgd5a309592010-02-05 02:22:52440 return ERR_SOCKS_CONNECTION_FAILED;
441 }
arindam@chromium.orge0c27be2009-07-15 13:09:35442
443 buffer_.append(handshake_buf_->data(), result);
444 bytes_received_ += result;
445
446 // When the first few bytes are read, check how many more are required
447 // and accordingly increase them
448 if (bytes_received_ == kReadHeaderSize) {
eroman@chromium.org38c70d35d2009-12-22 01:49:40449 if (buffer_[0] != kSOCKS5Version || buffer_[2] != kNullByte) {
mikecirone8b85c432016-09-08 19:11:00450 net_log_.AddEvent(NetLogEventType::SOCKS_UNEXPECTED_VERSION,
tfarina5e24b242015-10-27 13:11:28451 NetLog::IntCallback("version", buffer_[0]));
eroman@chromium.orgd5a309592010-02-05 02:22:52452 return ERR_SOCKS_CONNECTION_FAILED;
eroman@chromium.org38c70d35d2009-12-22 01:49:40453 }
454 if (buffer_[1] != 0x00) {
mikecirone8b85c432016-09-08 19:11:00455 net_log_.AddEvent(NetLogEventType::SOCKS_SERVER_ERROR,
tfarina5e24b242015-10-27 13:11:28456 NetLog::IntCallback("error_code", buffer_[1]));
eroman@chromium.orgd5a309592010-02-05 02:22:52457 return ERR_SOCKS_CONNECTION_FAILED;
eroman@chromium.org38c70d35d2009-12-22 01:49:40458 }
arindam@chromium.orge0c27be2009-07-15 13:09:35459
460 // We check the type of IP/Domain the server returns and accordingly
461 // increase the size of the response. For domains, we need to read the
462 // size of the domain, so the initial request size is upto the domain
463 // size. Since for IPv4/IPv6 the size is fixed and hence no 'size' is
464 // read, we substract 1 byte from the additional request size.
465 SocksEndPointAddressType address_type =
466 static_cast<SocksEndPointAddressType>(buffer_[3]);
eroman@chromium.org20cbe23d2009-12-18 03:39:21467 if (address_type == kEndPointDomain)
Avi Drissman13fc8932015-12-20 04:40:46468 read_header_size += static_cast<uint8_t>(buffer_[4]);
arindam@chromium.orge0c27be2009-07-15 13:09:35469 else if (address_type == kEndPointResolvedIPv4)
470 read_header_size += sizeof(struct in_addr) - 1;
471 else if (address_type == kEndPointResolvedIPv6)
472 read_header_size += sizeof(struct in6_addr) - 1;
eroman@chromium.org38c70d35d2009-12-22 01:49:40473 else {
mikecirone8b85c432016-09-08 19:11:00474 net_log_.AddEvent(NetLogEventType::SOCKS_UNKNOWN_ADDRESS_TYPE,
tfarina5e24b242015-10-27 13:11:28475 NetLog::IntCallback("address_type", buffer_[3]));
eroman@chromium.orgd5a309592010-02-05 02:22:52476 return ERR_SOCKS_CONNECTION_FAILED;
eroman@chromium.org38c70d35d2009-12-22 01:49:40477 }
arindam@chromium.orge0c27be2009-07-15 13:09:35478
479 read_header_size += 2; // for the port.
480 next_state_ = STATE_HANDSHAKE_READ;
481 return OK;
482 }
483
484 // When the final bytes are read, setup handshake. We ignore the rest
485 // of the response since they represent the SOCKSv5 endpoint and have
486 // no use when doing a tunnel connection.
487 if (bytes_received_ == read_header_size) {
488 completed_handshake_ = true;
489 buffer_.clear();
490 next_state_ = STATE_NONE;
491 return OK;
492 }
493
494 next_state_ = STATE_HANDSHAKE_READ;
495 return OK;
496}
497
zhaoqin@chromium.orga3528692012-06-08 00:11:42498int SOCKS5ClientSocket::GetPeerAddress(IPEndPoint* address) const {
vandebo@chromium.orga796bcec2010-03-22 17:17:26499 return transport_->socket()->GetPeerAddress(address);
arindam@chromium.orge0c27be2009-07-15 13:09:35500}
arindam@chromium.orge0c27be2009-07-15 13:09:35501
sergeyu@chromium.orge7f74da2011-04-19 23:49:35502int SOCKS5ClientSocket::GetLocalAddress(IPEndPoint* address) const {
503 return transport_->socket()->GetLocalAddress(address);
504}
505
arindam@chromium.orge0c27be2009-07-15 13:09:35506} // namespace net