| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/socket/socks5_client_socket.h" | 5 #include "net/socket/socks5_client_socket.h" |
| 6 | 6 |
| 7 #include "base/basictypes.h" | 7 #include "base/basictypes.h" |
| 8 #include "base/compiler_specific.h" | 8 #include "base/compiler_specific.h" |
| 9 #include "base/format_macros.h" | 9 #include "base/format_macros.h" |
| 10 #include "base/string_util.h" | 10 #include "base/string_util.h" |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 68 DCHECK(transport_.get()); | 68 DCHECK(transport_.get()); |
| 69 DCHECK(transport_->socket()); | 69 DCHECK(transport_->socket()); |
| 70 DCHECK(transport_->socket()->IsConnected()); | 70 DCHECK(transport_->socket()->IsConnected()); |
| 71 DCHECK_EQ(STATE_NONE, next_state_); | 71 DCHECK_EQ(STATE_NONE, next_state_); |
| 72 DCHECK(!user_callback_); | 72 DCHECK(!user_callback_); |
| 73 | 73 |
| 74 // If already connected, then just return OK. | 74 // If already connected, then just return OK. |
| 75 if (completed_handshake_) | 75 if (completed_handshake_) |
| 76 return OK; | 76 return OK; |
| 77 | 77 |
| 78 net_log_.BeginEvent(NetLog::TYPE_SOCKS5_CONNECT); | 78 net_log_.BeginEvent(NetLog::TYPE_SOCKS5_CONNECT, NULL); |
| 79 | 79 |
| 80 next_state_ = STATE_GREET_WRITE; | 80 next_state_ = STATE_GREET_WRITE; |
| 81 buffer_.clear(); | 81 buffer_.clear(); |
| 82 | 82 |
| 83 int rv = DoLoop(OK); | 83 int rv = DoLoop(OK); |
| 84 if (rv == ERR_IO_PENDING) { | 84 if (rv == ERR_IO_PENDING) { |
| 85 user_callback_ = callback; | 85 user_callback_ = callback; |
| 86 } else { | 86 } else { |
| 87 net_log_.EndEvent(NetLog::TYPE_SOCKS5_CONNECT); | 87 net_log_.EndEvent(NetLog::TYPE_SOCKS5_CONNECT, NULL); |
| 88 } | 88 } |
| 89 return rv; | 89 return rv; |
| 90 } | 90 } |
| 91 | 91 |
| 92 void SOCKS5ClientSocket::Disconnect() { | 92 void SOCKS5ClientSocket::Disconnect() { |
| 93 completed_handshake_ = false; | 93 completed_handshake_ = false; |
| 94 transport_->socket()->Disconnect(); | 94 transport_->socket()->Disconnect(); |
| 95 | 95 |
| 96 // Reset other states to make sure they aren't mistakenly used later. | 96 // Reset other states to make sure they aren't mistakenly used later. |
| 97 // These are the states initialized by Connect(). | 97 // These are the states initialized by Connect(). |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 145 // clear user_callback_ up front. | 145 // clear user_callback_ up front. |
| 146 CompletionCallback* c = user_callback_; | 146 CompletionCallback* c = user_callback_; |
| 147 user_callback_ = NULL; | 147 user_callback_ = NULL; |
| 148 c->Run(result); | 148 c->Run(result); |
| 149 } | 149 } |
| 150 | 150 |
| 151 void SOCKS5ClientSocket::OnIOComplete(int result) { | 151 void SOCKS5ClientSocket::OnIOComplete(int result) { |
| 152 DCHECK_NE(STATE_NONE, next_state_); | 152 DCHECK_NE(STATE_NONE, next_state_); |
| 153 int rv = DoLoop(result); | 153 int rv = DoLoop(result); |
| 154 if (rv != ERR_IO_PENDING) { | 154 if (rv != ERR_IO_PENDING) { |
| 155 net_log_.EndEvent(NetLog::TYPE_SOCKS5_CONNECT); | 155 net_log_.EndEvent(NetLog::TYPE_SOCKS5_CONNECT, NULL); |
| 156 DoCallback(rv); | 156 DoCallback(rv); |
| 157 } | 157 } |
| 158 } | 158 } |
| 159 | 159 |
| 160 int SOCKS5ClientSocket::DoLoop(int last_io_result) { | 160 int SOCKS5ClientSocket::DoLoop(int last_io_result) { |
| 161 DCHECK_NE(next_state_, STATE_NONE); | 161 DCHECK_NE(next_state_, STATE_NONE); |
| 162 int rv = last_io_result; | 162 int rv = last_io_result; |
| 163 do { | 163 do { |
| 164 State state = next_state_; | 164 State state = next_state_; |
| 165 next_state_ = STATE_NONE; | 165 next_state_ = STATE_NONE; |
| 166 switch (state) { | 166 switch (state) { |
| 167 case STATE_GREET_WRITE: | 167 case STATE_GREET_WRITE: |
| 168 DCHECK_EQ(OK, rv); | 168 DCHECK_EQ(OK, rv); |
| 169 net_log_.BeginEvent(NetLog::TYPE_SOCKS5_GREET_WRITE); | 169 net_log_.BeginEvent(NetLog::TYPE_SOCKS5_GREET_WRITE, NULL); |
| 170 rv = DoGreetWrite(); | 170 rv = DoGreetWrite(); |
| 171 break; | 171 break; |
| 172 case STATE_GREET_WRITE_COMPLETE: | 172 case STATE_GREET_WRITE_COMPLETE: |
| 173 rv = DoGreetWriteComplete(rv); | 173 rv = DoGreetWriteComplete(rv); |
| 174 net_log_.EndEvent(NetLog::TYPE_SOCKS5_GREET_WRITE); | 174 net_log_.EndEvent(NetLog::TYPE_SOCKS5_GREET_WRITE, NULL); |
| 175 break; | 175 break; |
| 176 case STATE_GREET_READ: | 176 case STATE_GREET_READ: |
| 177 DCHECK_EQ(OK, rv); | 177 DCHECK_EQ(OK, rv); |
| 178 net_log_.BeginEvent(NetLog::TYPE_SOCKS5_GREET_READ); | 178 net_log_.BeginEvent(NetLog::TYPE_SOCKS5_GREET_READ, NULL); |
| 179 rv = DoGreetRead(); | 179 rv = DoGreetRead(); |
| 180 break; | 180 break; |
| 181 case STATE_GREET_READ_COMPLETE: | 181 case STATE_GREET_READ_COMPLETE: |
| 182 rv = DoGreetReadComplete(rv); | 182 rv = DoGreetReadComplete(rv); |
| 183 net_log_.EndEvent(NetLog::TYPE_SOCKS5_GREET_READ); | 183 net_log_.EndEvent(NetLog::TYPE_SOCKS5_GREET_READ, NULL); |
| 184 break; | 184 break; |
| 185 case STATE_HANDSHAKE_WRITE: | 185 case STATE_HANDSHAKE_WRITE: |
| 186 DCHECK_EQ(OK, rv); | 186 DCHECK_EQ(OK, rv); |
| 187 net_log_.BeginEvent(NetLog::TYPE_SOCKS5_HANDSHAKE_WRITE); | 187 net_log_.BeginEvent(NetLog::TYPE_SOCKS5_HANDSHAKE_WRITE, NULL); |
| 188 rv = DoHandshakeWrite(); | 188 rv = DoHandshakeWrite(); |
| 189 break; | 189 break; |
| 190 case STATE_HANDSHAKE_WRITE_COMPLETE: | 190 case STATE_HANDSHAKE_WRITE_COMPLETE: |
| 191 rv = DoHandshakeWriteComplete(rv); | 191 rv = DoHandshakeWriteComplete(rv); |
| 192 net_log_.EndEvent(NetLog::TYPE_SOCKS5_HANDSHAKE_WRITE); | 192 net_log_.EndEvent(NetLog::TYPE_SOCKS5_HANDSHAKE_WRITE, NULL); |
| 193 break; | 193 break; |
| 194 case STATE_HANDSHAKE_READ: | 194 case STATE_HANDSHAKE_READ: |
| 195 DCHECK_EQ(OK, rv); | 195 DCHECK_EQ(OK, rv); |
| 196 net_log_.BeginEvent(NetLog::TYPE_SOCKS5_HANDSHAKE_READ); | 196 net_log_.BeginEvent(NetLog::TYPE_SOCKS5_HANDSHAKE_READ, NULL); |
| 197 rv = DoHandshakeRead(); | 197 rv = DoHandshakeRead(); |
| 198 break; | 198 break; |
| 199 case STATE_HANDSHAKE_READ_COMPLETE: | 199 case STATE_HANDSHAKE_READ_COMPLETE: |
| 200 rv = DoHandshakeReadComplete(rv); | 200 rv = DoHandshakeReadComplete(rv); |
| 201 net_log_.EndEvent(NetLog::TYPE_SOCKS5_HANDSHAKE_READ); | 201 net_log_.EndEvent(NetLog::TYPE_SOCKS5_HANDSHAKE_READ, NULL); |
| 202 break; | 202 break; |
| 203 default: | 203 default: |
| 204 NOTREACHED() << "bad state"; | 204 NOTREACHED() << "bad state"; |
| 205 rv = ERR_UNEXPECTED; | 205 rv = ERR_UNEXPECTED; |
| 206 break; | 206 break; |
| 207 } | 207 } |
| 208 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); | 208 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); |
| 209 return rv; | 209 return rv; |
| 210 } | 210 } |
| 211 | 211 |
| 212 const char kSOCKS5GreetWriteData[] = { 0x05, 0x01, 0x00 }; // no authentication | 212 const char kSOCKS5GreetWriteData[] = { 0x05, 0x01, 0x00 }; // no authentication |
| 213 const char kSOCKS5GreetReadData[] = { 0x05, 0x00 }; | 213 const char kSOCKS5GreetReadData[] = { 0x05, 0x00 }; |
| 214 | 214 |
| 215 int SOCKS5ClientSocket::DoGreetWrite() { | 215 int SOCKS5ClientSocket::DoGreetWrite() { |
| 216 // Since we only have 1 byte to send the hostname length in, if the | 216 // Since we only have 1 byte to send the hostname length in, if the |
| 217 // URL has a hostname longer than 255 characters we can't send it. | 217 // URL has a hostname longer than 255 characters we can't send it. |
| 218 if (0xFF < host_request_info_.hostname().size()) { | 218 if (0xFF < host_request_info_.hostname().size()) { |
| 219 net_log_.AddEvent(NetLog::TYPE_SOCKS_HOSTNAME_TOO_BIG); | 219 net_log_.AddEvent(NetLog::TYPE_SOCKS_HOSTNAME_TOO_BIG, NULL); |
| 220 return ERR_SOCKS_CONNECTION_FAILED; | 220 return ERR_SOCKS_CONNECTION_FAILED; |
| 221 } | 221 } |
| 222 | 222 |
| 223 if (buffer_.empty()) { | 223 if (buffer_.empty()) { |
| 224 buffer_ = std::string(kSOCKS5GreetWriteData, | 224 buffer_ = std::string(kSOCKS5GreetWriteData, |
| 225 arraysize(kSOCKS5GreetWriteData)); | 225 arraysize(kSOCKS5GreetWriteData)); |
| 226 bytes_sent_ = 0; | 226 bytes_sent_ = 0; |
| 227 } | 227 } |
| 228 | 228 |
| 229 next_state_ = STATE_GREET_WRITE_COMPLETE; | 229 next_state_ = STATE_GREET_WRITE_COMPLETE; |
| (...skipping 26 matching lines...) Expand all Loading... |
| 256 handshake_buf_ = new IOBuffer(handshake_buf_len); | 256 handshake_buf_ = new IOBuffer(handshake_buf_len); |
| 257 return transport_->socket()->Read(handshake_buf_, handshake_buf_len, | 257 return transport_->socket()->Read(handshake_buf_, handshake_buf_len, |
| 258 &io_callback_); | 258 &io_callback_); |
| 259 } | 259 } |
| 260 | 260 |
| 261 int SOCKS5ClientSocket::DoGreetReadComplete(int result) { | 261 int SOCKS5ClientSocket::DoGreetReadComplete(int result) { |
| 262 if (result < 0) | 262 if (result < 0) |
| 263 return result; | 263 return result; |
| 264 | 264 |
| 265 if (result == 0) { | 265 if (result == 0) { |
| 266 net_log_.AddEvent(NetLog::TYPE_SOCKS_UNEXPECTEDLY_CLOSED_DURING_GREETING); | 266 net_log_.AddEvent(NetLog::TYPE_SOCKS_UNEXPECTEDLY_CLOSED_DURING_GREETING, |
| 267 NULL); |
| 267 return ERR_SOCKS_CONNECTION_FAILED; | 268 return ERR_SOCKS_CONNECTION_FAILED; |
| 268 } | 269 } |
| 269 | 270 |
| 270 bytes_received_ += result; | 271 bytes_received_ += result; |
| 271 buffer_.append(handshake_buf_->data(), result); | 272 buffer_.append(handshake_buf_->data(), result); |
| 272 if (bytes_received_ < kGreetReadHeaderSize) { | 273 if (bytes_received_ < kGreetReadHeaderSize) { |
| 273 next_state_ = STATE_GREET_READ; | 274 next_state_ = STATE_GREET_READ; |
| 274 return OK; | 275 return OK; |
| 275 } | 276 } |
| 276 | 277 |
| 277 // Got the greet data. | 278 // Got the greet data. |
| 278 if (buffer_[0] != kSOCKS5Version) { | 279 if (buffer_[0] != kSOCKS5Version) { |
| 279 net_log_.AddEventWithInteger(NetLog::TYPE_SOCKS_UNEXPECTED_VERSION, | 280 net_log_.AddEvent(NetLog::TYPE_SOCKS_UNEXPECTED_VERSION, |
| 280 "version", buffer_[0]); | 281 new NetLogIntegerParameter("version", buffer_[0])); |
| 281 return ERR_SOCKS_CONNECTION_FAILED; | 282 return ERR_SOCKS_CONNECTION_FAILED; |
| 282 } | 283 } |
| 283 if (buffer_[1] != 0x00) { | 284 if (buffer_[1] != 0x00) { |
| 284 net_log_.AddEventWithInteger(NetLog::TYPE_SOCKS_UNEXPECTED_AUTH, | 285 net_log_.AddEvent(NetLog::TYPE_SOCKS_UNEXPECTED_AUTH, |
| 285 "method", buffer_[1]); | 286 new NetLogIntegerParameter("method", buffer_[1])); |
| 286 return ERR_SOCKS_CONNECTION_FAILED; | 287 return ERR_SOCKS_CONNECTION_FAILED; |
| 287 } | 288 } |
| 288 | 289 |
| 289 buffer_.clear(); | 290 buffer_.clear(); |
| 290 next_state_ = STATE_HANDSHAKE_WRITE; | 291 next_state_ = STATE_HANDSHAKE_WRITE; |
| 291 return OK; | 292 return OK; |
| 292 } | 293 } |
| 293 | 294 |
| 294 int SOCKS5ClientSocket::BuildHandshakeWriteBuffer(std::string* handshake) | 295 int SOCKS5ClientSocket::BuildHandshakeWriteBuffer(std::string* handshake) |
| 295 const { | 296 const { |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 366 return transport_->socket()->Read(handshake_buf_, handshake_buf_len, | 367 return transport_->socket()->Read(handshake_buf_, handshake_buf_len, |
| 367 &io_callback_); | 368 &io_callback_); |
| 368 } | 369 } |
| 369 | 370 |
| 370 int SOCKS5ClientSocket::DoHandshakeReadComplete(int result) { | 371 int SOCKS5ClientSocket::DoHandshakeReadComplete(int result) { |
| 371 if (result < 0) | 372 if (result < 0) |
| 372 return result; | 373 return result; |
| 373 | 374 |
| 374 // The underlying socket closed unexpectedly. | 375 // The underlying socket closed unexpectedly. |
| 375 if (result == 0) { | 376 if (result == 0) { |
| 376 net_log_.AddEvent(NetLog::TYPE_SOCKS_UNEXPECTEDLY_CLOSED_DURING_HANDSHAKE); | 377 net_log_.AddEvent(NetLog::TYPE_SOCKS_UNEXPECTEDLY_CLOSED_DURING_HANDSHAKE, |
| 378 NULL); |
| 377 return ERR_SOCKS_CONNECTION_FAILED; | 379 return ERR_SOCKS_CONNECTION_FAILED; |
| 378 } | 380 } |
| 379 | 381 |
| 380 buffer_.append(handshake_buf_->data(), result); | 382 buffer_.append(handshake_buf_->data(), result); |
| 381 bytes_received_ += result; | 383 bytes_received_ += result; |
| 382 | 384 |
| 383 // When the first few bytes are read, check how many more are required | 385 // When the first few bytes are read, check how many more are required |
| 384 // and accordingly increase them | 386 // and accordingly increase them |
| 385 if (bytes_received_ == kReadHeaderSize) { | 387 if (bytes_received_ == kReadHeaderSize) { |
| 386 if (buffer_[0] != kSOCKS5Version || buffer_[2] != kNullByte) { | 388 if (buffer_[0] != kSOCKS5Version || buffer_[2] != kNullByte) { |
| 387 net_log_.AddEventWithInteger(NetLog::TYPE_SOCKS_UNEXPECTED_VERSION, | 389 net_log_.AddEvent(NetLog::TYPE_SOCKS_UNEXPECTED_VERSION, |
| 388 "version", buffer_[0]); | 390 new NetLogIntegerParameter("version", buffer_[0])); |
| 389 return ERR_SOCKS_CONNECTION_FAILED; | 391 return ERR_SOCKS_CONNECTION_FAILED; |
| 390 } | 392 } |
| 391 if (buffer_[1] != 0x00) { | 393 if (buffer_[1] != 0x00) { |
| 392 net_log_.AddEventWithInteger(NetLog::TYPE_SOCKS_SERVER_ERROR, | 394 net_log_.AddEvent(NetLog::TYPE_SOCKS_SERVER_ERROR, |
| 393 "error_code", buffer_[1]); | 395 new NetLogIntegerParameter("error_code", buffer_[1])); |
| 394 return ERR_SOCKS_CONNECTION_FAILED; | 396 return ERR_SOCKS_CONNECTION_FAILED; |
| 395 } | 397 } |
| 396 | 398 |
| 397 // We check the type of IP/Domain the server returns and accordingly | 399 // We check the type of IP/Domain the server returns and accordingly |
| 398 // increase the size of the response. For domains, we need to read the | 400 // increase the size of the response. For domains, we need to read the |
| 399 // size of the domain, so the initial request size is upto the domain | 401 // size of the domain, so the initial request size is upto the domain |
| 400 // size. Since for IPv4/IPv6 the size is fixed and hence no 'size' is | 402 // size. Since for IPv4/IPv6 the size is fixed and hence no 'size' is |
| 401 // read, we substract 1 byte from the additional request size. | 403 // read, we substract 1 byte from the additional request size. |
| 402 SocksEndPointAddressType address_type = | 404 SocksEndPointAddressType address_type = |
| 403 static_cast<SocksEndPointAddressType>(buffer_[3]); | 405 static_cast<SocksEndPointAddressType>(buffer_[3]); |
| 404 if (address_type == kEndPointDomain) | 406 if (address_type == kEndPointDomain) |
| 405 read_header_size += static_cast<uint8>(buffer_[4]); | 407 read_header_size += static_cast<uint8>(buffer_[4]); |
| 406 else if (address_type == kEndPointResolvedIPv4) | 408 else if (address_type == kEndPointResolvedIPv4) |
| 407 read_header_size += sizeof(struct in_addr) - 1; | 409 read_header_size += sizeof(struct in_addr) - 1; |
| 408 else if (address_type == kEndPointResolvedIPv6) | 410 else if (address_type == kEndPointResolvedIPv6) |
| 409 read_header_size += sizeof(struct in6_addr) - 1; | 411 read_header_size += sizeof(struct in6_addr) - 1; |
| 410 else { | 412 else { |
| 411 net_log_.AddEventWithInteger(NetLog::TYPE_SOCKS_UNKNOWN_ADDRESS_TYPE, | 413 net_log_.AddEvent(NetLog::TYPE_SOCKS_UNKNOWN_ADDRESS_TYPE, |
| 412 "address_type", buffer_[3]); | 414 new NetLogIntegerParameter("address_type", buffer_[3])); |
| 413 return ERR_SOCKS_CONNECTION_FAILED; | 415 return ERR_SOCKS_CONNECTION_FAILED; |
| 414 } | 416 } |
| 415 | 417 |
| 416 read_header_size += 2; // for the port. | 418 read_header_size += 2; // for the port. |
| 417 next_state_ = STATE_HANDSHAKE_READ; | 419 next_state_ = STATE_HANDSHAKE_READ; |
| 418 return OK; | 420 return OK; |
| 419 } | 421 } |
| 420 | 422 |
| 421 // When the final bytes are read, setup handshake. We ignore the rest | 423 // When the final bytes are read, setup handshake. We ignore the rest |
| 422 // of the response since they represent the SOCKSv5 endpoint and have | 424 // of the response since they represent the SOCKSv5 endpoint and have |
| 423 // no use when doing a tunnel connection. | 425 // no use when doing a tunnel connection. |
| 424 if (bytes_received_ == read_header_size) { | 426 if (bytes_received_ == read_header_size) { |
| 425 completed_handshake_ = true; | 427 completed_handshake_ = true; |
| 426 buffer_.clear(); | 428 buffer_.clear(); |
| 427 next_state_ = STATE_NONE; | 429 next_state_ = STATE_NONE; |
| 428 return OK; | 430 return OK; |
| 429 } | 431 } |
| 430 | 432 |
| 431 next_state_ = STATE_HANDSHAKE_READ; | 433 next_state_ = STATE_HANDSHAKE_READ; |
| 432 return OK; | 434 return OK; |
| 433 } | 435 } |
| 434 | 436 |
| 435 int SOCKS5ClientSocket::GetPeerAddress(AddressList* address) const { | 437 int SOCKS5ClientSocket::GetPeerAddress(AddressList* address) const { |
| 436 return transport_->socket()->GetPeerAddress(address); | 438 return transport_->socket()->GetPeerAddress(address); |
| 437 } | 439 } |
| 438 | 440 |
| 439 } // namespace net | 441 } // namespace net |
| OLD | NEW |