socks5_client_socket.cc revision e14dcc5a172cad1c4716af7ab94121a73c0c698e
1// Copyright (c) 2010 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
5#include "net/socket/socks5_client_socket.h"
6
7#include "base/basictypes.h"
8#include "base/compiler_specific.h"
9#include "base/debug/trace_event.h"
10#include "base/format_macros.h"
11#include "base/string_util.h"
12#include "net/base/io_buffer.h"
13#include "net/base/net_log.h"
14#include "net/base/net_util.h"
15#include "net/base/sys_addrinfo.h"
16#include "net/socket/client_socket_handle.h"
17
18namespace net {
19
20const unsigned int SOCKS5ClientSocket::kGreetReadHeaderSize = 2;
21const unsigned int SOCKS5ClientSocket::kWriteHeaderSize = 10;
22const unsigned int SOCKS5ClientSocket::kReadHeaderSize = 5;
23const uint8 SOCKS5ClientSocket::kSOCKS5Version = 0x05;
24const uint8 SOCKS5ClientSocket::kTunnelCommand = 0x01;
25const uint8 SOCKS5ClientSocket::kNullByte = 0x00;
26
27COMPILE_ASSERT(sizeof(struct in_addr) == 4, incorrect_system_size_of_IPv4);
28COMPILE_ASSERT(sizeof(struct in6_addr) == 16, incorrect_system_size_of_IPv6);
29
30SOCKS5ClientSocket::SOCKS5ClientSocket(
31    ClientSocketHandle* transport_socket,
32    const HostResolver::RequestInfo& req_info)
33    : ALLOW_THIS_IN_INITIALIZER_LIST(
34          io_callback_(this, &SOCKS5ClientSocket::OnIOComplete)),
35      transport_(transport_socket),
36      next_state_(STATE_NONE),
37      user_callback_(NULL),
38      completed_handshake_(false),
39      bytes_sent_(0),
40      bytes_received_(0),
41      read_header_size(kReadHeaderSize),
42      host_request_info_(req_info),
43      net_log_(transport_socket->socket()->NetLog()) {
44}
45
46SOCKS5ClientSocket::SOCKS5ClientSocket(
47    ClientSocket* transport_socket,
48    const HostResolver::RequestInfo& req_info)
49    : ALLOW_THIS_IN_INITIALIZER_LIST(
50          io_callback_(this, &SOCKS5ClientSocket::OnIOComplete)),
51      transport_(new ClientSocketHandle()),
52      next_state_(STATE_NONE),
53      user_callback_(NULL),
54      completed_handshake_(false),
55      bytes_sent_(0),
56      bytes_received_(0),
57      read_header_size(kReadHeaderSize),
58      host_request_info_(req_info),
59      net_log_(transport_socket->NetLog()) {
60  transport_->set_socket(transport_socket);
61}
62
63SOCKS5ClientSocket::~SOCKS5ClientSocket() {
64  Disconnect();
65}
66
67#ifdef ANDROID
68// TODO(kristianm): Find out if Connect should block
69#endif
70int SOCKS5ClientSocket::Connect(CompletionCallback* callback
71#ifdef ANDROID
72                                , bool wait_for_connect
73                                , bool valid_uid
74                                , uid_t calling_uid
75#endif
76                               ) {
77  DCHECK(transport_.get());
78  DCHECK(transport_->socket());
79  DCHECK_EQ(STATE_NONE, next_state_);
80  DCHECK(!user_callback_);
81
82  // If already connected, then just return OK.
83  if (completed_handshake_)
84    return OK;
85
86  net_log_.BeginEvent(NetLog::TYPE_SOCKS5_CONNECT, NULL);
87
88  next_state_ = STATE_GREET_WRITE;
89  buffer_.clear();
90
91  int rv = DoLoop(OK);
92  if (rv == ERR_IO_PENDING) {
93    user_callback_ = callback;
94  } else {
95    net_log_.EndEventWithNetErrorCode(NetLog::TYPE_SOCKS5_CONNECT, rv);
96  }
97  return rv;
98}
99
100void SOCKS5ClientSocket::Disconnect() {
101  completed_handshake_ = false;
102  transport_->socket()->Disconnect();
103
104  // Reset other states to make sure they aren't mistakenly used later.
105  // These are the states initialized by Connect().
106  next_state_ = STATE_NONE;
107  user_callback_ = NULL;
108}
109
110bool SOCKS5ClientSocket::IsConnected() const {
111  return completed_handshake_ && transport_->socket()->IsConnected();
112}
113
114bool SOCKS5ClientSocket::IsConnectedAndIdle() const {
115  return completed_handshake_ && transport_->socket()->IsConnectedAndIdle();
116}
117
118const BoundNetLog& SOCKS5ClientSocket::NetLog() const {
119  return net_log_;
120}
121
122void SOCKS5ClientSocket::SetSubresourceSpeculation() {
123  if (transport_.get() && transport_->socket()) {
124    transport_->socket()->SetSubresourceSpeculation();
125  } else {
126    NOTREACHED();
127  }
128}
129
130void SOCKS5ClientSocket::SetOmniboxSpeculation() {
131  if (transport_.get() && transport_->socket()) {
132    transport_->socket()->SetOmniboxSpeculation();
133  } else {
134    NOTREACHED();
135  }
136}
137
138bool SOCKS5ClientSocket::WasEverUsed() const {
139  if (transport_.get() && transport_->socket()) {
140    return transport_->socket()->WasEverUsed();
141  }
142  NOTREACHED();
143  return false;
144}
145
146bool SOCKS5ClientSocket::UsingTCPFastOpen() const {
147  if (transport_.get() && transport_->socket()) {
148    return transport_->socket()->UsingTCPFastOpen();
149  }
150  NOTREACHED();
151  return false;
152}
153
154// Read is called by the transport layer above to read. This can only be done
155// if the SOCKS handshake is complete.
156int SOCKS5ClientSocket::Read(IOBuffer* buf, int buf_len,
157                             CompletionCallback* callback) {
158  DCHECK(completed_handshake_);
159  DCHECK_EQ(STATE_NONE, next_state_);
160  DCHECK(!user_callback_);
161
162  return transport_->socket()->Read(buf, buf_len, callback);
163}
164
165// Write is called by the transport layer. This can only be done if the
166// SOCKS handshake is complete.
167int SOCKS5ClientSocket::Write(IOBuffer* buf, int buf_len,
168                             CompletionCallback* callback) {
169  DCHECK(completed_handshake_);
170  DCHECK_EQ(STATE_NONE, next_state_);
171  DCHECK(!user_callback_);
172
173  return transport_->socket()->Write(buf, buf_len, callback);
174}
175
176bool SOCKS5ClientSocket::SetReceiveBufferSize(int32 size) {
177  return transport_->socket()->SetReceiveBufferSize(size);
178}
179
180bool SOCKS5ClientSocket::SetSendBufferSize(int32 size) {
181  return transport_->socket()->SetSendBufferSize(size);
182}
183
184void SOCKS5ClientSocket::DoCallback(int result) {
185  DCHECK_NE(ERR_IO_PENDING, result);
186  DCHECK(user_callback_);
187
188  // Since Run() may result in Read being called,
189  // clear user_callback_ up front.
190  CompletionCallback* c = user_callback_;
191  user_callback_ = NULL;
192  c->Run(result);
193}
194
195void SOCKS5ClientSocket::OnIOComplete(int result) {
196  DCHECK_NE(STATE_NONE, next_state_);
197  int rv = DoLoop(result);
198  if (rv != ERR_IO_PENDING) {
199    net_log_.EndEvent(NetLog::TYPE_SOCKS5_CONNECT, NULL);
200    DoCallback(rv);
201  }
202}
203
204int SOCKS5ClientSocket::DoLoop(int last_io_result) {
205  DCHECK_NE(next_state_, STATE_NONE);
206  int rv = last_io_result;
207  do {
208    State state = next_state_;
209    next_state_ = STATE_NONE;
210    switch (state) {
211      case STATE_GREET_WRITE:
212        DCHECK_EQ(OK, rv);
213        net_log_.BeginEvent(NetLog::TYPE_SOCKS5_GREET_WRITE, NULL);
214        rv = DoGreetWrite();
215        break;
216      case STATE_GREET_WRITE_COMPLETE:
217        rv = DoGreetWriteComplete(rv);
218        net_log_.EndEventWithNetErrorCode(NetLog::TYPE_SOCKS5_GREET_WRITE, rv);
219        break;
220      case STATE_GREET_READ:
221        DCHECK_EQ(OK, rv);
222        net_log_.BeginEvent(NetLog::TYPE_SOCKS5_GREET_READ, NULL);
223        rv = DoGreetRead();
224        break;
225      case STATE_GREET_READ_COMPLETE:
226        rv = DoGreetReadComplete(rv);
227        net_log_.EndEventWithNetErrorCode(NetLog::TYPE_SOCKS5_GREET_READ, rv);
228        break;
229      case STATE_HANDSHAKE_WRITE:
230        DCHECK_EQ(OK, rv);
231        net_log_.BeginEvent(NetLog::TYPE_SOCKS5_HANDSHAKE_WRITE, NULL);
232        rv = DoHandshakeWrite();
233        break;
234      case STATE_HANDSHAKE_WRITE_COMPLETE:
235        rv = DoHandshakeWriteComplete(rv);
236        net_log_.EndEventWithNetErrorCode(
237            NetLog::TYPE_SOCKS5_HANDSHAKE_WRITE, rv);
238        break;
239      case STATE_HANDSHAKE_READ:
240        DCHECK_EQ(OK, rv);
241        net_log_.BeginEvent(NetLog::TYPE_SOCKS5_HANDSHAKE_READ, NULL);
242        rv = DoHandshakeRead();
243        break;
244      case STATE_HANDSHAKE_READ_COMPLETE:
245        rv = DoHandshakeReadComplete(rv);
246        net_log_.EndEventWithNetErrorCode(
247            NetLog::TYPE_SOCKS5_HANDSHAKE_READ, rv);
248        break;
249      default:
250        NOTREACHED() << "bad state";
251        rv = ERR_UNEXPECTED;
252        break;
253    }
254  } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
255  return rv;
256}
257
258const char kSOCKS5GreetWriteData[] = { 0x05, 0x01, 0x00 };  // no authentication
259const char kSOCKS5GreetReadData[] = { 0x05, 0x00 };
260
261int SOCKS5ClientSocket::DoGreetWrite() {
262  // Since we only have 1 byte to send the hostname length in, if the
263  // URL has a hostname longer than 255 characters we can't send it.
264  if (0xFF < host_request_info_.hostname().size()) {
265    net_log_.AddEvent(NetLog::TYPE_SOCKS_HOSTNAME_TOO_BIG, NULL);
266    return ERR_SOCKS_CONNECTION_FAILED;
267  }
268
269  if (buffer_.empty()) {
270    buffer_ = std::string(kSOCKS5GreetWriteData,
271                          arraysize(kSOCKS5GreetWriteData));
272    bytes_sent_ = 0;
273  }
274
275  next_state_ = STATE_GREET_WRITE_COMPLETE;
276  size_t handshake_buf_len = buffer_.size() - bytes_sent_;
277  handshake_buf_ = new IOBuffer(handshake_buf_len);
278  memcpy(handshake_buf_->data(), &buffer_.data()[bytes_sent_],
279         handshake_buf_len);
280  return transport_->socket()->Write(handshake_buf_, handshake_buf_len,
281                                     &io_callback_);
282}
283
284int SOCKS5ClientSocket::DoGreetWriteComplete(int result) {
285  if (result < 0)
286    return result;
287
288  bytes_sent_ += result;
289  if (bytes_sent_ == buffer_.size()) {
290    buffer_.clear();
291    bytes_received_ = 0;
292    next_state_ = STATE_GREET_READ;
293  } else {
294    next_state_ = STATE_GREET_WRITE;
295  }
296  return OK;
297}
298
299int SOCKS5ClientSocket::DoGreetRead() {
300  next_state_ = STATE_GREET_READ_COMPLETE;
301  size_t handshake_buf_len = kGreetReadHeaderSize - bytes_received_;
302  handshake_buf_ = new IOBuffer(handshake_buf_len);
303  return transport_->socket()->Read(handshake_buf_, handshake_buf_len,
304                                    &io_callback_);
305}
306
307int SOCKS5ClientSocket::DoGreetReadComplete(int result) {
308  if (result < 0)
309    return result;
310
311  if (result == 0) {
312    net_log_.AddEvent(NetLog::TYPE_SOCKS_UNEXPECTEDLY_CLOSED_DURING_GREETING,
313                      NULL);
314    return ERR_SOCKS_CONNECTION_FAILED;
315  }
316
317  bytes_received_ += result;
318  buffer_.append(handshake_buf_->data(), result);
319  if (bytes_received_ < kGreetReadHeaderSize) {
320    next_state_ = STATE_GREET_READ;
321    return OK;
322  }
323
324  // Got the greet data.
325  if (buffer_[0] != kSOCKS5Version) {
326    net_log_.AddEvent(
327        NetLog::TYPE_SOCKS_UNEXPECTED_VERSION,
328        make_scoped_refptr(new NetLogIntegerParameter("version", buffer_[0])));
329    return ERR_SOCKS_CONNECTION_FAILED;
330  }
331  if (buffer_[1] != 0x00) {
332    net_log_.AddEvent(
333        NetLog::TYPE_SOCKS_UNEXPECTED_AUTH,
334        make_scoped_refptr(new NetLogIntegerParameter("method", buffer_[1])));
335    return ERR_SOCKS_CONNECTION_FAILED;
336  }
337
338  buffer_.clear();
339  next_state_ = STATE_HANDSHAKE_WRITE;
340  return OK;
341}
342
343int SOCKS5ClientSocket::BuildHandshakeWriteBuffer(std::string* handshake)
344    const {
345  DCHECK(handshake->empty());
346
347  handshake->push_back(kSOCKS5Version);
348  handshake->push_back(kTunnelCommand);  // Connect command
349  handshake->push_back(kNullByte);  // Reserved null
350
351  handshake->push_back(kEndPointDomain);  // The type of the address.
352
353  DCHECK_GE(static_cast<size_t>(0xFF), host_request_info_.hostname().size());
354
355  // First add the size of the hostname, followed by the hostname.
356  handshake->push_back(static_cast<unsigned char>(
357      host_request_info_.hostname().size()));
358  handshake->append(host_request_info_.hostname());
359
360  uint16 nw_port = htons(host_request_info_.port());
361  handshake->append(reinterpret_cast<char*>(&nw_port), sizeof(nw_port));
362  return OK;
363}
364
365// Writes the SOCKS handshake data to the underlying socket connection.
366int SOCKS5ClientSocket::DoHandshakeWrite() {
367  next_state_ = STATE_HANDSHAKE_WRITE_COMPLETE;
368
369  if (buffer_.empty()) {
370    int rv = BuildHandshakeWriteBuffer(&buffer_);
371    if (rv != OK)
372      return rv;
373    bytes_sent_ = 0;
374  }
375
376  int handshake_buf_len = buffer_.size() - bytes_sent_;
377  DCHECK_LT(0, handshake_buf_len);
378  handshake_buf_ = new IOBuffer(handshake_buf_len);
379  memcpy(handshake_buf_->data(), &buffer_[bytes_sent_],
380         handshake_buf_len);
381  return transport_->socket()->Write(handshake_buf_, handshake_buf_len,
382                                     &io_callback_);
383}
384
385int SOCKS5ClientSocket::DoHandshakeWriteComplete(int result) {
386  if (result < 0)
387    return result;
388
389  // We ignore the case when result is 0, since the underlying Write
390  // may return spurious writes while waiting on the socket.
391
392  bytes_sent_ += result;
393  if (bytes_sent_ == buffer_.size()) {
394    next_state_ = STATE_HANDSHAKE_READ;
395    buffer_.clear();
396  } else if (bytes_sent_ < buffer_.size()) {
397    next_state_ = STATE_HANDSHAKE_WRITE;
398  } else {
399    NOTREACHED();
400  }
401
402  return OK;
403}
404
405int SOCKS5ClientSocket::DoHandshakeRead() {
406  next_state_ = STATE_HANDSHAKE_READ_COMPLETE;
407
408  if (buffer_.empty()) {
409    bytes_received_ = 0;
410    read_header_size = kReadHeaderSize;
411  }
412
413  int handshake_buf_len = read_header_size - bytes_received_;
414  handshake_buf_ = new IOBuffer(handshake_buf_len);
415  return transport_->socket()->Read(handshake_buf_, handshake_buf_len,
416                                    &io_callback_);
417}
418
419int SOCKS5ClientSocket::DoHandshakeReadComplete(int result) {
420  if (result < 0)
421    return result;
422
423  // The underlying socket closed unexpectedly.
424  if (result == 0) {
425    net_log_.AddEvent(NetLog::TYPE_SOCKS_UNEXPECTEDLY_CLOSED_DURING_HANDSHAKE,
426                      NULL);
427    return ERR_SOCKS_CONNECTION_FAILED;
428  }
429
430  buffer_.append(handshake_buf_->data(), result);
431  bytes_received_ += result;
432
433  // When the first few bytes are read, check how many more are required
434  // and accordingly increase them
435  if (bytes_received_ == kReadHeaderSize) {
436    if (buffer_[0] != kSOCKS5Version || buffer_[2] != kNullByte) {
437      net_log_.AddEvent(
438          NetLog::TYPE_SOCKS_UNEXPECTED_VERSION,
439          make_scoped_refptr(
440              new NetLogIntegerParameter("version", buffer_[0])));
441      return ERR_SOCKS_CONNECTION_FAILED;
442    }
443    if (buffer_[1] != 0x00) {
444      net_log_.AddEvent(
445          NetLog::TYPE_SOCKS_SERVER_ERROR,
446          make_scoped_refptr(
447              new NetLogIntegerParameter("error_code", buffer_[1])));
448      return ERR_SOCKS_CONNECTION_FAILED;
449    }
450
451    // We check the type of IP/Domain the server returns and accordingly
452    // increase the size of the response. For domains, we need to read the
453    // size of the domain, so the initial request size is upto the domain
454    // size. Since for IPv4/IPv6 the size is fixed and hence no 'size' is
455    // read, we substract 1 byte from the additional request size.
456    SocksEndPointAddressType address_type =
457        static_cast<SocksEndPointAddressType>(buffer_[3]);
458    if (address_type == kEndPointDomain)
459      read_header_size += static_cast<uint8>(buffer_[4]);
460    else if (address_type == kEndPointResolvedIPv4)
461      read_header_size += sizeof(struct in_addr) - 1;
462    else if (address_type == kEndPointResolvedIPv6)
463      read_header_size += sizeof(struct in6_addr) - 1;
464    else {
465      net_log_.AddEvent(
466          NetLog::TYPE_SOCKS_UNKNOWN_ADDRESS_TYPE,
467          make_scoped_refptr(
468              new NetLogIntegerParameter("address_type", buffer_[3])));
469      return ERR_SOCKS_CONNECTION_FAILED;
470    }
471
472    read_header_size += 2;  // for the port.
473    next_state_ = STATE_HANDSHAKE_READ;
474    return OK;
475  }
476
477  // When the final bytes are read, setup handshake. We ignore the rest
478  // of the response since they represent the SOCKSv5 endpoint and have
479  // no use when doing a tunnel connection.
480  if (bytes_received_ == read_header_size) {
481    completed_handshake_ = true;
482    buffer_.clear();
483    next_state_ = STATE_NONE;
484    return OK;
485  }
486
487  next_state_ = STATE_HANDSHAKE_READ;
488  return OK;
489}
490
491int SOCKS5ClientSocket::GetPeerAddress(AddressList* address) const {
492  return transport_->socket()->GetPeerAddress(address);
493}
494
495int SOCKS5ClientSocket::GetLocalAddress(IPEndPoint* address) const {
496  return transport_->socket()->GetLocalAddress(address);
497}
498
499}  // namespace net
500