blob: 32c4e3bce3749e5dc7bc5ad5ce8b4ab8679c783c [file] [log] [blame]
[email protected]a2006ece2010-04-23 16:44:021// Copyright (c) 2010 The Chromium Authors. All rights reserved.
[email protected]3cd17242009-06-23 02:59:022// 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_client_socket.h"
6
7#include "base/basictypes.h"
[email protected]3cd17242009-06-23 02:59:028#include "base/compiler_specific.h"
9#include "base/trace_event.h"
10#include "net/base/io_buffer.h"
[email protected]9e743cd2010-03-16 07:03:5311#include "net/base/net_log.h"
[email protected]3cd17242009-06-23 02:59:0212#include "net/base/net_util.h"
[email protected]a540c2d2009-12-12 00:47:3713#include "net/base/sys_addrinfo.h"
[email protected]a796bcec2010-03-22 17:17:2614#include "net/socket/client_socket_handle.h"
[email protected]3cd17242009-06-23 02:59:0215
16namespace net {
17
18// Every SOCKS server requests a user-id from the client. It is optional
19// and we send an empty string.
20static const char kEmptyUserId[] = "";
21
22// The SOCKS4a implementation suggests to use an invalid IP in case the DNS
23// resolution at client fails.
24static const uint8 kInvalidIp[] = { 0, 0, 0, 127 };
25
26// For SOCKS4, the client sends 8 bytes plus the size of the user-id.
27// For SOCKS4A, this increases to accomodate the unresolved hostname.
[email protected]76a51ac82009-06-28 07:58:5828static const unsigned int kWriteHeaderSize = 8;
[email protected]3cd17242009-06-23 02:59:0229
30// For SOCKS4 and SOCKS4a, the server sends 8 bytes for acknowledgement.
[email protected]76a51ac82009-06-28 07:58:5831static const unsigned int kReadHeaderSize = 8;
[email protected]3cd17242009-06-23 02:59:0232
33// Server Response codes for SOCKS.
34static const uint8 kServerResponseOk = 0x5A;
35static const uint8 kServerResponseRejected = 0x5B;
36static const uint8 kServerResponseNotReachable = 0x5C;
37static const uint8 kServerResponseMismatchedUserId = 0x5D;
38
39static const uint8 kSOCKSVersion4 = 0x04;
40static const uint8 kSOCKSStreamRequest = 0x01;
41
42// A struct holding the essential details of the SOCKS4/4a Server Request.
43// The port in the header is stored in network byte order.
44struct SOCKS4ServerRequest {
45 uint8 version;
46 uint8 command;
47 uint16 nw_port;
48 uint8 ip[4];
49};
50COMPILE_ASSERT(sizeof(SOCKS4ServerRequest) == kWriteHeaderSize,
51 socks4_server_request_struct_wrong_size);
52
53// A struct holding details of the SOCKS4/4a Server Response.
54struct SOCKS4ServerResponse {
55 uint8 reserved_null;
56 uint8 code;
57 uint16 port;
58 uint8 ip[4];
59};
60COMPILE_ASSERT(sizeof(SOCKS4ServerResponse) == kReadHeaderSize,
61 socks4_server_response_struct_wrong_size);
62
[email protected]a796bcec2010-03-22 17:17:2663SOCKSClientSocket::SOCKSClientSocket(ClientSocketHandle* transport_socket,
[email protected]3cd17242009-06-23 02:59:0264 const HostResolver::RequestInfo& req_info,
65 HostResolver* host_resolver)
66 : ALLOW_THIS_IN_INITIALIZER_LIST(
67 io_callback_(this, &SOCKSClientSocket::OnIOComplete)),
68 transport_(transport_socket),
69 next_state_(STATE_NONE),
70 socks_version_(kSOCKS4Unresolved),
71 user_callback_(NULL),
[email protected]3cd17242009-06-23 02:59:0272 completed_handshake_(false),
73 bytes_sent_(0),
74 bytes_received_(0),
[email protected]76a51ac82009-06-28 07:58:5875 host_resolver_(host_resolver),
[email protected]a2006ece2010-04-23 16:44:0276 host_request_info_(req_info),
77 net_log_(transport_socket->socket()->NetLog()) {
[email protected]3cd17242009-06-23 02:59:0278}
79
[email protected]a796bcec2010-03-22 17:17:2680SOCKSClientSocket::SOCKSClientSocket(ClientSocket* transport_socket,
81 const HostResolver::RequestInfo& req_info,
82 HostResolver* host_resolver)
83 : ALLOW_THIS_IN_INITIALIZER_LIST(
84 io_callback_(this, &SOCKSClientSocket::OnIOComplete)),
85 transport_(new ClientSocketHandle()),
86 next_state_(STATE_NONE),
87 socks_version_(kSOCKS4Unresolved),
88 user_callback_(NULL),
89 completed_handshake_(false),
90 bytes_sent_(0),
91 bytes_received_(0),
92 host_resolver_(host_resolver),
[email protected]a2006ece2010-04-23 16:44:0293 host_request_info_(req_info),
94 net_log_(transport_socket->NetLog()) {
[email protected]a796bcec2010-03-22 17:17:2695 transport_->set_socket(transport_socket);
96}
97
[email protected]3cd17242009-06-23 02:59:0298SOCKSClientSocket::~SOCKSClientSocket() {
99 Disconnect();
100}
101
[email protected]a2006ece2010-04-23 16:44:02102int SOCKSClientSocket::Connect(CompletionCallback* callback) {
[email protected]3cd17242009-06-23 02:59:02103 DCHECK(transport_.get());
[email protected]a796bcec2010-03-22 17:17:26104 DCHECK(transport_->socket());
105 DCHECK(transport_->socket()->IsConnected());
[email protected]3cd17242009-06-23 02:59:02106 DCHECK_EQ(STATE_NONE, next_state_);
107 DCHECK(!user_callback_);
108
109 // If already connected, then just return OK.
110 if (completed_handshake_)
111 return OK;
112
113 next_state_ = STATE_RESOLVE_HOST;
[email protected]5a05c47a2009-11-02 23:25:19114
[email protected]ec11be62010-04-28 19:28:09115 net_log_.BeginEvent(NetLog::TYPE_SOCKS_CONNECT, NULL);
[email protected]3cd17242009-06-23 02:59:02116
117 int rv = DoLoop(OK);
[email protected]5a05c47a2009-11-02 23:25:19118 if (rv == ERR_IO_PENDING) {
[email protected]3cd17242009-06-23 02:59:02119 user_callback_ = callback;
[email protected]5a05c47a2009-11-02 23:25:19120 } else {
[email protected]ec11be62010-04-28 19:28:09121 net_log_.EndEvent(NetLog::TYPE_SOCKS_CONNECT, NULL);
[email protected]5a05c47a2009-11-02 23:25:19122 }
[email protected]3cd17242009-06-23 02:59:02123 return rv;
124}
125
126void SOCKSClientSocket::Disconnect() {
127 completed_handshake_ = false;
[email protected]16a02742010-01-07 22:50:10128 host_resolver_.Cancel();
[email protected]a796bcec2010-03-22 17:17:26129 transport_->socket()->Disconnect();
[email protected]16a02742010-01-07 22:50:10130
131 // Reset other states to make sure they aren't mistakenly used later.
132 // These are the states initialized by Connect().
133 next_state_ = STATE_NONE;
134 user_callback_ = NULL;
[email protected]3cd17242009-06-23 02:59:02135}
136
137bool SOCKSClientSocket::IsConnected() const {
[email protected]a796bcec2010-03-22 17:17:26138 return completed_handshake_ && transport_->socket()->IsConnected();
[email protected]3cd17242009-06-23 02:59:02139}
140
141bool SOCKSClientSocket::IsConnectedAndIdle() const {
[email protected]a796bcec2010-03-22 17:17:26142 return completed_handshake_ && transport_->socket()->IsConnectedAndIdle();
[email protected]3cd17242009-06-23 02:59:02143}
144
145// Read is called by the transport layer above to read. This can only be done
146// if the SOCKS handshake is complete.
147int SOCKSClientSocket::Read(IOBuffer* buf, int buf_len,
148 CompletionCallback* callback) {
149 DCHECK(completed_handshake_);
150 DCHECK_EQ(STATE_NONE, next_state_);
151 DCHECK(!user_callback_);
152
[email protected]a796bcec2010-03-22 17:17:26153 return transport_->socket()->Read(buf, buf_len, callback);
[email protected]3cd17242009-06-23 02:59:02154}
155
156// Write is called by the transport layer. This can only be done if the
157// SOCKS handshake is complete.
158int SOCKSClientSocket::Write(IOBuffer* buf, int buf_len,
159 CompletionCallback* callback) {
160 DCHECK(completed_handshake_);
161 DCHECK_EQ(STATE_NONE, next_state_);
162 DCHECK(!user_callback_);
163
[email protected]a796bcec2010-03-22 17:17:26164 return transport_->socket()->Write(buf, buf_len, callback);
[email protected]3cd17242009-06-23 02:59:02165}
166
[email protected]d3f66572009-09-09 22:38:04167bool SOCKSClientSocket::SetReceiveBufferSize(int32 size) {
[email protected]a796bcec2010-03-22 17:17:26168 return transport_->socket()->SetReceiveBufferSize(size);
[email protected]d3f66572009-09-09 22:38:04169}
170
171bool SOCKSClientSocket::SetSendBufferSize(int32 size) {
[email protected]a796bcec2010-03-22 17:17:26172 return transport_->socket()->SetSendBufferSize(size);
[email protected]d3f66572009-09-09 22:38:04173}
174
[email protected]3cd17242009-06-23 02:59:02175void SOCKSClientSocket::DoCallback(int result) {
176 DCHECK_NE(ERR_IO_PENDING, result);
177 DCHECK(user_callback_);
178
179 // Since Run() may result in Read being called,
180 // clear user_callback_ up front.
181 CompletionCallback* c = user_callback_;
182 user_callback_ = NULL;
183 DLOG(INFO) << "Finished setting up SOCKS handshake";
184 c->Run(result);
185}
186
187void SOCKSClientSocket::OnIOComplete(int result) {
188 DCHECK_NE(STATE_NONE, next_state_);
189 int rv = DoLoop(result);
[email protected]5a05c47a2009-11-02 23:25:19190 if (rv != ERR_IO_PENDING) {
[email protected]ec11be62010-04-28 19:28:09191 net_log_.EndEvent(NetLog::TYPE_SOCKS_CONNECT, NULL);
[email protected]3cd17242009-06-23 02:59:02192 DoCallback(rv);
[email protected]5a05c47a2009-11-02 23:25:19193 }
[email protected]3cd17242009-06-23 02:59:02194}
195
196int SOCKSClientSocket::DoLoop(int last_io_result) {
197 DCHECK_NE(next_state_, STATE_NONE);
198 int rv = last_io_result;
199 do {
200 State state = next_state_;
201 next_state_ = STATE_NONE;
202 switch (state) {
203 case STATE_RESOLVE_HOST:
204 DCHECK_EQ(OK, rv);
205 rv = DoResolveHost();
206 break;
207 case STATE_RESOLVE_HOST_COMPLETE:
208 rv = DoResolveHostComplete(rv);
209 break;
210 case STATE_HANDSHAKE_WRITE:
211 DCHECK_EQ(OK, rv);
212 rv = DoHandshakeWrite();
213 break;
214 case STATE_HANDSHAKE_WRITE_COMPLETE:
215 rv = DoHandshakeWriteComplete(rv);
216 break;
217 case STATE_HANDSHAKE_READ:
218 DCHECK_EQ(OK, rv);
219 rv = DoHandshakeRead();
220 break;
221 case STATE_HANDSHAKE_READ_COMPLETE:
222 rv = DoHandshakeReadComplete(rv);
223 break;
224 default:
225 NOTREACHED() << "bad state";
226 rv = ERR_UNEXPECTED;
227 break;
228 }
229 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
230 return rv;
231}
232
233int SOCKSClientSocket::DoResolveHost() {
234 DCHECK_EQ(kSOCKS4Unresolved, socks_version_);
235
236 next_state_ = STATE_RESOLVE_HOST_COMPLETE;
[email protected]ec08bb22009-08-12 00:25:12237 return host_resolver_.Resolve(
[email protected]9e743cd2010-03-16 07:03:53238 host_request_info_, &addresses_, &io_callback_, net_log_);
[email protected]3cd17242009-06-23 02:59:02239}
240
241int SOCKSClientSocket::DoResolveHostComplete(int result) {
242 DCHECK_EQ(kSOCKS4Unresolved, socks_version_);
243
244 bool ok = (result == OK);
245 next_state_ = STATE_HANDSHAKE_WRITE;
246 if (ok) {
247 DCHECK(addresses_.head());
248
249 // If the host is resolved to an IPv6 address, we revert to SOCKS4a
250 // since IPv6 is unsupported by SOCKS4/4a protocol.
251 struct sockaddr *host_info = addresses_.head()->ai_addr;
252 if (host_info->sa_family == AF_INET) {
253 DLOG(INFO) << "Resolved host. Using SOCKS4 to communicate";
254 socks_version_ = kSOCKS4;
255 } else {
256 DLOG(INFO) << "Resolved host but to IPv6. Using SOCKS4a to communicate";
257 socks_version_ = kSOCKS4a;
258 }
259 } else {
260 DLOG(INFO) << "Could not resolve host. Using SOCKS4a to communicate";
261 socks_version_ = kSOCKS4a;
262 }
263
264 // Even if DNS resolution fails, we send OK since the server
265 // resolves the domain.
266 return OK;
267}
268
269// Builds the buffer that is to be sent to the server.
270// We check whether the SOCKS proxy is 4 or 4A.
271// In case it is 4A, the record size increases by size of the hostname.
[email protected]76a51ac82009-06-28 07:58:58272const std::string SOCKSClientSocket::BuildHandshakeWriteBuffer() const {
[email protected]3cd17242009-06-23 02:59:02273 DCHECK_NE(kSOCKS4Unresolved, socks_version_);
274
[email protected]76a51ac82009-06-28 07:58:58275 SOCKS4ServerRequest request;
276 request.version = kSOCKSVersion4;
277 request.command = kSOCKSStreamRequest;
278 request.nw_port = htons(host_request_info_.port());
[email protected]3cd17242009-06-23 02:59:02279
280 if (socks_version_ == kSOCKS4) {
281 const struct addrinfo* ai = addresses_.head();
282 DCHECK(ai);
283 // If the sockaddr is IPv6, we have already marked the version to socks4a
284 // and so this step does not get hit.
[email protected]76a51ac82009-06-28 07:58:58285 struct sockaddr_in* ipv4_host =
[email protected]3cd17242009-06-23 02:59:02286 reinterpret_cast<struct sockaddr_in*>(ai->ai_addr);
[email protected]76a51ac82009-06-28 07:58:58287 memcpy(&request.ip, &(ipv4_host->sin_addr), sizeof(ipv4_host->sin_addr));
[email protected]3cd17242009-06-23 02:59:02288
289 DLOG(INFO) << "Resolved Host is : " << NetAddressToString(ai);
290 } else if (socks_version_ == kSOCKS4a) {
291 // invalid IP of the form 0.0.0.127
[email protected]76a51ac82009-06-28 07:58:58292 memcpy(&request.ip, kInvalidIp, arraysize(kInvalidIp));
[email protected]3cd17242009-06-23 02:59:02293 } else {
294 NOTREACHED();
295 }
296
[email protected]76a51ac82009-06-28 07:58:58297 std::string handshake_data(reinterpret_cast<char*>(&request),
298 sizeof(request));
299 handshake_data.append(kEmptyUserId, arraysize(kEmptyUserId));
[email protected]3cd17242009-06-23 02:59:02300
[email protected]76a51ac82009-06-28 07:58:58301 // In case we are passing the domain also, pass the hostname
302 // terminated with a null character.
[email protected]3cd17242009-06-23 02:59:02303 if (socks_version_ == kSOCKS4a) {
[email protected]76a51ac82009-06-28 07:58:58304 handshake_data.append(host_request_info_.hostname());
305 handshake_data.push_back('\0');
[email protected]3cd17242009-06-23 02:59:02306 }
[email protected]76a51ac82009-06-28 07:58:58307
308 return handshake_data;
[email protected]3cd17242009-06-23 02:59:02309}
310
311// Writes the SOCKS handshake data to the underlying socket connection.
312int SOCKSClientSocket::DoHandshakeWrite() {
313 next_state_ = STATE_HANDSHAKE_WRITE_COMPLETE;
314
[email protected]76a51ac82009-06-28 07:58:58315 if (buffer_.empty()) {
316 buffer_ = BuildHandshakeWriteBuffer();
[email protected]3cd17242009-06-23 02:59:02317 bytes_sent_ = 0;
318 }
319
[email protected]76a51ac82009-06-28 07:58:58320 int handshake_buf_len = buffer_.size() - bytes_sent_;
321 DCHECK_GT(handshake_buf_len, 0);
322 handshake_buf_ = new IOBuffer(handshake_buf_len);
323 memcpy(handshake_buf_->data(), &buffer_[bytes_sent_],
324 handshake_buf_len);
[email protected]a796bcec2010-03-22 17:17:26325 return transport_->socket()->Write(handshake_buf_, handshake_buf_len,
326 &io_callback_);
[email protected]3cd17242009-06-23 02:59:02327}
328
329int SOCKSClientSocket::DoHandshakeWriteComplete(int result) {
330 DCHECK_NE(kSOCKS4Unresolved, socks_version_);
331
332 if (result < 0)
333 return result;
334
[email protected]76a51ac82009-06-28 07:58:58335 // We ignore the case when result is 0, since the underlying Write
336 // may return spurious writes while waiting on the socket.
337
[email protected]3cd17242009-06-23 02:59:02338 bytes_sent_ += result;
[email protected]76a51ac82009-06-28 07:58:58339 if (bytes_sent_ == buffer_.size()) {
[email protected]3cd17242009-06-23 02:59:02340 next_state_ = STATE_HANDSHAKE_READ;
[email protected]76a51ac82009-06-28 07:58:58341 buffer_.clear();
342 } else if (bytes_sent_ < buffer_.size()) {
[email protected]3cd17242009-06-23 02:59:02343 next_state_ = STATE_HANDSHAKE_WRITE;
344 } else {
345 return ERR_UNEXPECTED;
346 }
347
348 return OK;
349}
350
351int SOCKSClientSocket::DoHandshakeRead() {
352 DCHECK_NE(kSOCKS4Unresolved, socks_version_);
353
354 next_state_ = STATE_HANDSHAKE_READ_COMPLETE;
355
[email protected]76a51ac82009-06-28 07:58:58356 if (buffer_.empty()) {
[email protected]3cd17242009-06-23 02:59:02357 bytes_received_ = 0;
358 }
359
[email protected]76a51ac82009-06-28 07:58:58360 int handshake_buf_len = kReadHeaderSize - bytes_received_;
361 handshake_buf_ = new IOBuffer(handshake_buf_len);
[email protected]a796bcec2010-03-22 17:17:26362 return transport_->socket()->Read(handshake_buf_, handshake_buf_len,
363 &io_callback_);
[email protected]3cd17242009-06-23 02:59:02364}
365
366int SOCKSClientSocket::DoHandshakeReadComplete(int result) {
367 DCHECK_NE(kSOCKS4Unresolved, socks_version_);
368
369 if (result < 0)
370 return result;
[email protected]76a51ac82009-06-28 07:58:58371
372 // The underlying socket closed unexpectedly.
373 if (result == 0)
374 return ERR_CONNECTION_CLOSED;
375
[email protected]d5a309592010-02-05 02:22:52376 if (bytes_received_ + result > kReadHeaderSize) {
[email protected]9e743cd2010-03-16 07:03:53377 // TODO(eroman): Describe failure in NetLog.
[email protected]d5a309592010-02-05 02:22:52378 return ERR_SOCKS_CONNECTION_FAILED;
379 }
[email protected]3cd17242009-06-23 02:59:02380
[email protected]76a51ac82009-06-28 07:58:58381 buffer_.append(handshake_buf_->data(), result);
[email protected]3cd17242009-06-23 02:59:02382 bytes_received_ += result;
[email protected]76a51ac82009-06-28 07:58:58383 if (bytes_received_ < kReadHeaderSize) {
[email protected]3cd17242009-06-23 02:59:02384 next_state_ = STATE_HANDSHAKE_READ;
385 return OK;
386 }
387
[email protected]76a51ac82009-06-28 07:58:58388 const SOCKS4ServerResponse* response =
389 reinterpret_cast<const SOCKS4ServerResponse*>(buffer_.data());
[email protected]3cd17242009-06-23 02:59:02390
391 if (response->reserved_null != 0x00) {
392 LOG(ERROR) << "Unknown response from SOCKS server.";
[email protected]d5a309592010-02-05 02:22:52393 return ERR_SOCKS_CONNECTION_FAILED;
[email protected]3cd17242009-06-23 02:59:02394 }
395
[email protected]3cd17242009-06-23 02:59:02396 switch (response->code) {
397 case kServerResponseOk:
398 completed_handshake_ = true;
399 return OK;
400 case kServerResponseRejected:
401 LOG(ERROR) << "SOCKS request rejected or failed";
[email protected]d5a309592010-02-05 02:22:52402 return ERR_SOCKS_CONNECTION_FAILED;
[email protected]3cd17242009-06-23 02:59:02403 case kServerResponseNotReachable:
404 LOG(ERROR) << "SOCKS request failed because client is not running "
405 << "identd (or not reachable from the server)";
[email protected]d5a309592010-02-05 02:22:52406 return ERR_SOCKS_CONNECTION_HOST_UNREACHABLE;
[email protected]3cd17242009-06-23 02:59:02407 case kServerResponseMismatchedUserId:
408 LOG(ERROR) << "SOCKS request failed because client's identd could "
409 << "not confirm the user ID string in the request";
[email protected]d5a309592010-02-05 02:22:52410 return ERR_SOCKS_CONNECTION_FAILED;
[email protected]3cd17242009-06-23 02:59:02411 default:
412 LOG(ERROR) << "SOCKS server sent unknown response";
[email protected]d5a309592010-02-05 02:22:52413 return ERR_SOCKS_CONNECTION_FAILED;
[email protected]3cd17242009-06-23 02:59:02414 }
415
416 // Note: we ignore the last 6 bytes as specified by the SOCKS protocol
417}
418
[email protected]ac9eec62010-02-20 18:50:38419int SOCKSClientSocket::GetPeerAddress(AddressList* address) const {
[email protected]a796bcec2010-03-22 17:17:26420 return transport_->socket()->GetPeerAddress(address);
[email protected]3cd17242009-06-23 02:59:02421}
[email protected]3cd17242009-06-23 02:59:02422
423} // namespace net