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