| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 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 | 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/socks_client_socket.h" | 5 #include "net/socket/socks_client_socket.h" |
| 6 | 6 |
| 7 #include "base/basictypes.h" | 7 #include "base/basictypes.h" |
| 8 #include "build/build_config.h" | 8 #include "build/build_config.h" |
| 9 #if defined(OS_WIN) | 9 #if defined(OS_WIN) |
| 10 #include <ws2tcpip.h> | 10 #include <ws2tcpip.h> |
| (...skipping 10 matching lines...) Expand all Loading... |
| 21 // Every SOCKS server requests a user-id from the client. It is optional | 21 // Every SOCKS server requests a user-id from the client. It is optional |
| 22 // and we send an empty string. | 22 // and we send an empty string. |
| 23 static const char kEmptyUserId[] = ""; | 23 static const char kEmptyUserId[] = ""; |
| 24 | 24 |
| 25 // The SOCKS4a implementation suggests to use an invalid IP in case the DNS | 25 // The SOCKS4a implementation suggests to use an invalid IP in case the DNS |
| 26 // resolution at client fails. | 26 // resolution at client fails. |
| 27 static const uint8 kInvalidIp[] = { 0, 0, 0, 127 }; | 27 static const uint8 kInvalidIp[] = { 0, 0, 0, 127 }; |
| 28 | 28 |
| 29 // For SOCKS4, the client sends 8 bytes plus the size of the user-id. | 29 // For SOCKS4, the client sends 8 bytes plus the size of the user-id. |
| 30 // For SOCKS4A, this increases to accomodate the unresolved hostname. | 30 // For SOCKS4A, this increases to accomodate the unresolved hostname. |
| 31 static const unsigned int kWriteHeaderSize = 8; | 31 static const int kWriteHeaderSize = 8; |
| 32 | 32 |
| 33 // For SOCKS4 and SOCKS4a, the server sends 8 bytes for acknowledgement. | 33 // For SOCKS4 and SOCKS4a, the server sends 8 bytes for acknowledgement. |
| 34 static const unsigned int kReadHeaderSize = 8; | 34 static const int kReadHeaderSize = 8; |
| 35 | 35 |
| 36 // Server Response codes for SOCKS. | 36 // Server Response codes for SOCKS. |
| 37 static const uint8 kServerResponseOk = 0x5A; | 37 static const uint8 kServerResponseOk = 0x5A; |
| 38 static const uint8 kServerResponseRejected = 0x5B; | 38 static const uint8 kServerResponseRejected = 0x5B; |
| 39 static const uint8 kServerResponseNotReachable = 0x5C; | 39 static const uint8 kServerResponseNotReachable = 0x5C; |
| 40 static const uint8 kServerResponseMismatchedUserId = 0x5D; | 40 static const uint8 kServerResponseMismatchedUserId = 0x5D; |
| 41 | 41 |
| 42 static const uint8 kSOCKSVersion4 = 0x04; | 42 static const uint8 kSOCKSVersion4 = 0x04; |
| 43 static const uint8 kSOCKSStreamRequest = 0x01; | 43 static const uint8 kSOCKSStreamRequest = 0x01; |
| 44 | 44 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 65 | 65 |
| 66 SOCKSClientSocket::SOCKSClientSocket(ClientSocket* transport_socket, | 66 SOCKSClientSocket::SOCKSClientSocket(ClientSocket* transport_socket, |
| 67 const HostResolver::RequestInfo& req_info, | 67 const HostResolver::RequestInfo& req_info, |
| 68 HostResolver* host_resolver) | 68 HostResolver* host_resolver) |
| 69 : ALLOW_THIS_IN_INITIALIZER_LIST( | 69 : ALLOW_THIS_IN_INITIALIZER_LIST( |
| 70 io_callback_(this, &SOCKSClientSocket::OnIOComplete)), | 70 io_callback_(this, &SOCKSClientSocket::OnIOComplete)), |
| 71 transport_(transport_socket), | 71 transport_(transport_socket), |
| 72 next_state_(STATE_NONE), | 72 next_state_(STATE_NONE), |
| 73 socks_version_(kSOCKS4Unresolved), | 73 socks_version_(kSOCKS4Unresolved), |
| 74 user_callback_(NULL), | 74 user_callback_(NULL), |
| 75 handshake_buf_len_(0), |
| 76 buffer_(NULL), |
| 77 buffer_len_(0), |
| 75 completed_handshake_(false), | 78 completed_handshake_(false), |
| 76 bytes_sent_(0), | 79 bytes_sent_(0), |
| 77 bytes_received_(0), | 80 bytes_received_(0), |
| 78 resolver_(host_resolver), | 81 resolver_(host_resolver), |
| 79 host_request_info_(req_info) { | 82 host_request_info_(req_info) { |
| 80 } | 83 } |
| 81 | 84 |
| 82 SOCKSClientSocket::~SOCKSClientSocket() { | 85 SOCKSClientSocket::~SOCKSClientSocket() { |
| 83 Disconnect(); | 86 Disconnect(); |
| 84 } | 87 } |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 223 } | 226 } |
| 224 | 227 |
| 225 // Even if DNS resolution fails, we send OK since the server | 228 // Even if DNS resolution fails, we send OK since the server |
| 226 // resolves the domain. | 229 // resolves the domain. |
| 227 return OK; | 230 return OK; |
| 228 } | 231 } |
| 229 | 232 |
| 230 // Builds the buffer that is to be sent to the server. | 233 // Builds the buffer that is to be sent to the server. |
| 231 // We check whether the SOCKS proxy is 4 or 4A. | 234 // We check whether the SOCKS proxy is 4 or 4A. |
| 232 // In case it is 4A, the record size increases by size of the hostname. | 235 // In case it is 4A, the record size increases by size of the hostname. |
| 233 const std::string SOCKSClientSocket::BuildHandshakeWriteBuffer() const { | 236 void SOCKSClientSocket::BuildHandshakeWriteBuffer() { |
| 234 DCHECK_NE(kSOCKS4Unresolved, socks_version_); | 237 DCHECK_NE(kSOCKS4Unresolved, socks_version_); |
| 235 | 238 |
| 236 SOCKS4ServerRequest request; | 239 int record_size = kWriteHeaderSize + arraysize(kEmptyUserId); |
| 237 request.version = kSOCKSVersion4; | 240 if (socks_version_ == kSOCKS4a) { |
| 238 request.command = kSOCKSStreamRequest; | 241 record_size += host_request_info_.hostname().size() + 1; |
| 239 request.nw_port = htons(host_request_info_.port()); | 242 } |
| 243 |
| 244 buffer_len_ = record_size; |
| 245 buffer_.reset(new char[buffer_len_]); |
| 246 |
| 247 SOCKS4ServerRequest* request = |
| 248 reinterpret_cast<SOCKS4ServerRequest*>(buffer_.get()); |
| 249 |
| 250 request->version = kSOCKSVersion4; |
| 251 request->command = kSOCKSStreamRequest; |
| 252 request->nw_port = htons(host_request_info_.port()); |
| 240 | 253 |
| 241 if (socks_version_ == kSOCKS4) { | 254 if (socks_version_ == kSOCKS4) { |
| 242 const struct addrinfo* ai = addresses_.head(); | 255 const struct addrinfo* ai = addresses_.head(); |
| 243 DCHECK(ai); | 256 DCHECK(ai); |
| 244 // If the sockaddr is IPv6, we have already marked the version to socks4a | 257 // If the sockaddr is IPv6, we have already marked the version to socks4a |
| 245 // and so this step does not get hit. | 258 // and so this step does not get hit. |
| 246 struct sockaddr_in* ipv4_host = | 259 struct sockaddr_in *ipv4_host = |
| 247 reinterpret_cast<struct sockaddr_in*>(ai->ai_addr); | 260 reinterpret_cast<struct sockaddr_in*>(ai->ai_addr); |
| 248 memcpy(&request.ip, &(ipv4_host->sin_addr), sizeof(ipv4_host->sin_addr)); | 261 memcpy(&request->ip, &(ipv4_host->sin_addr), sizeof(ipv4_host->sin_addr)); |
| 249 | 262 |
| 250 DLOG(INFO) << "Resolved Host is : " << NetAddressToString(ai); | 263 DLOG(INFO) << "Resolved Host is : " << NetAddressToString(ai); |
| 251 } else if (socks_version_ == kSOCKS4a) { | 264 } else if (socks_version_ == kSOCKS4a) { |
| 252 // invalid IP of the form 0.0.0.127 | 265 // invalid IP of the form 0.0.0.127 |
| 253 memcpy(&request.ip, kInvalidIp, arraysize(kInvalidIp)); | 266 memcpy(&request->ip, kInvalidIp, arraysize(kInvalidIp)); |
| 254 } else { | 267 } else { |
| 255 NOTREACHED(); | 268 NOTREACHED(); |
| 256 } | 269 } |
| 257 | 270 |
| 258 std::string handshake_data(reinterpret_cast<char*>(&request), | 271 memcpy(&buffer_[kWriteHeaderSize], kEmptyUserId, arraysize(kEmptyUserId)); |
| 259 sizeof(request)); | |
| 260 handshake_data.append(kEmptyUserId, arraysize(kEmptyUserId)); | |
| 261 | 272 |
| 262 // In case we are passing the domain also, pass the hostname | |
| 263 // terminated with a null character. | |
| 264 if (socks_version_ == kSOCKS4a) { | 273 if (socks_version_ == kSOCKS4a) { |
| 265 handshake_data.append(host_request_info_.hostname()); | 274 memcpy(&buffer_[kWriteHeaderSize + arraysize(kEmptyUserId)], |
| 266 handshake_data.push_back('\0'); | 275 host_request_info_.hostname().c_str(), |
| 276 host_request_info_.hostname().size() + 1); |
| 267 } | 277 } |
| 268 | |
| 269 return handshake_data; | |
| 270 } | 278 } |
| 271 | 279 |
| 272 // Writes the SOCKS handshake data to the underlying socket connection. | 280 // Writes the SOCKS handshake data to the underlying socket connection. |
| 273 int SOCKSClientSocket::DoHandshakeWrite() { | 281 int SOCKSClientSocket::DoHandshakeWrite() { |
| 274 next_state_ = STATE_HANDSHAKE_WRITE_COMPLETE; | 282 next_state_ = STATE_HANDSHAKE_WRITE_COMPLETE; |
| 275 | 283 |
| 276 if (buffer_.empty()) { | 284 if (!buffer_.get()) { |
| 277 buffer_ = BuildHandshakeWriteBuffer(); | 285 BuildHandshakeWriteBuffer(); |
| 278 bytes_sent_ = 0; | 286 bytes_sent_ = 0; |
| 279 } | 287 } |
| 280 | 288 |
| 281 int handshake_buf_len = buffer_.size() - bytes_sent_; | 289 handshake_buf_len_ = buffer_len_ - bytes_sent_; |
| 282 DCHECK_GT(handshake_buf_len, 0); | 290 DCHECK_GT(handshake_buf_len_, 0); |
| 283 handshake_buf_ = new IOBuffer(handshake_buf_len); | 291 handshake_buf_ = new IOBuffer(handshake_buf_len_); |
| 284 memcpy(handshake_buf_->data(), &buffer_[bytes_sent_], | 292 memcpy(handshake_buf_.get()->data(), &buffer_[bytes_sent_], |
| 285 handshake_buf_len); | 293 handshake_buf_len_); |
| 286 return transport_->Write(handshake_buf_, handshake_buf_len, &io_callback_); | 294 return transport_->Write(handshake_buf_, handshake_buf_len_, &io_callback_); |
| 287 } | 295 } |
| 288 | 296 |
| 289 int SOCKSClientSocket::DoHandshakeWriteComplete(int result) { | 297 int SOCKSClientSocket::DoHandshakeWriteComplete(int result) { |
| 290 DCHECK_NE(kSOCKS4Unresolved, socks_version_); | 298 DCHECK_NE(kSOCKS4Unresolved, socks_version_); |
| 291 | 299 |
| 292 if (result < 0) | 300 if (result < 0) |
| 293 return result; | 301 return result; |
| 294 | 302 |
| 295 // We ignore the case when result is 0, since the underlying Write | |
| 296 // may return spurious writes while waiting on the socket. | |
| 297 | |
| 298 bytes_sent_ += result; | 303 bytes_sent_ += result; |
| 299 if (bytes_sent_ == buffer_.size()) { | 304 if (bytes_sent_ == buffer_len_) { |
| 300 next_state_ = STATE_HANDSHAKE_READ; | 305 next_state_ = STATE_HANDSHAKE_READ; |
| 301 buffer_.clear(); | 306 buffer_.reset(NULL); |
| 302 } else if (bytes_sent_ < buffer_.size()) { | 307 } else if (bytes_sent_ < buffer_len_) { |
| 303 next_state_ = STATE_HANDSHAKE_WRITE; | 308 next_state_ = STATE_HANDSHAKE_WRITE; |
| 304 } else { | 309 } else { |
| 305 return ERR_UNEXPECTED; | 310 return ERR_UNEXPECTED; |
| 306 } | 311 } |
| 307 | 312 |
| 308 return OK; | 313 return OK; |
| 309 } | 314 } |
| 310 | 315 |
| 311 int SOCKSClientSocket::DoHandshakeRead() { | 316 int SOCKSClientSocket::DoHandshakeRead() { |
| 312 DCHECK_NE(kSOCKS4Unresolved, socks_version_); | 317 DCHECK_NE(kSOCKS4Unresolved, socks_version_); |
| 313 | 318 |
| 314 next_state_ = STATE_HANDSHAKE_READ_COMPLETE; | 319 next_state_ = STATE_HANDSHAKE_READ_COMPLETE; |
| 315 | 320 |
| 316 if (buffer_.empty()) { | 321 if (!buffer_.get()) { |
| 322 buffer_.reset(new char[kReadHeaderSize]); |
| 323 buffer_len_ = kReadHeaderSize; |
| 317 bytes_received_ = 0; | 324 bytes_received_ = 0; |
| 318 } | 325 } |
| 319 | 326 |
| 320 int handshake_buf_len = kReadHeaderSize - bytes_received_; | 327 handshake_buf_len_ = buffer_len_ - bytes_received_; |
| 321 handshake_buf_ = new IOBuffer(handshake_buf_len); | 328 handshake_buf_ = new IOBuffer(handshake_buf_len_); |
| 322 return transport_->Read(handshake_buf_, handshake_buf_len, &io_callback_); | 329 return transport_->Read(handshake_buf_, handshake_buf_len_, &io_callback_); |
| 323 } | 330 } |
| 324 | 331 |
| 325 int SOCKSClientSocket::DoHandshakeReadComplete(int result) { | 332 int SOCKSClientSocket::DoHandshakeReadComplete(int result) { |
| 326 DCHECK_NE(kSOCKS4Unresolved, socks_version_); | 333 DCHECK_NE(kSOCKS4Unresolved, socks_version_); |
| 327 | 334 |
| 328 if (result < 0) | 335 if (result < 0) |
| 329 return result; | 336 return result; |
| 330 | 337 if (bytes_received_ + result > buffer_len_) |
| 331 // The underlying socket closed unexpectedly. | |
| 332 if (result == 0) | |
| 333 return ERR_CONNECTION_CLOSED; | |
| 334 | |
| 335 if (bytes_received_ + result > kReadHeaderSize) | |
| 336 return ERR_INVALID_RESPONSE; | 338 return ERR_INVALID_RESPONSE; |
| 337 | 339 |
| 338 buffer_.append(handshake_buf_->data(), result); | 340 memcpy(buffer_.get() + bytes_received_, handshake_buf_->data(), result); |
| 339 bytes_received_ += result; | 341 bytes_received_ += result; |
| 340 if (bytes_received_ < kReadHeaderSize) { | 342 if (bytes_received_ < buffer_len_) { |
| 341 next_state_ = STATE_HANDSHAKE_READ; | 343 next_state_ = STATE_HANDSHAKE_READ; |
| 342 return OK; | 344 return OK; |
| 343 } | 345 } |
| 344 | 346 |
| 345 const SOCKS4ServerResponse* response = | 347 SOCKS4ServerResponse* response = |
| 346 reinterpret_cast<const SOCKS4ServerResponse*>(buffer_.data()); | 348 reinterpret_cast<SOCKS4ServerResponse*>(buffer_.get()); |
| 347 | 349 |
| 348 if (response->reserved_null != 0x00) { | 350 if (response->reserved_null != 0x00) { |
| 349 LOG(ERROR) << "Unknown response from SOCKS server."; | 351 LOG(ERROR) << "Unknown response from SOCKS server."; |
| 350 return ERR_INVALID_RESPONSE; | 352 return ERR_INVALID_RESPONSE; |
| 351 } | 353 } |
| 352 | 354 |
| 353 // TODO(arindam): Add SOCKS specific failure codes in net_error_list.h | 355 // TODO(arindam): Add SOCKS specific failure codes in net_error_list.h |
| 354 switch (response->code) { | 356 switch (response->code) { |
| 355 case kServerResponseOk: | 357 case kServerResponseOk: |
| 356 completed_handshake_ = true; | 358 completed_handshake_ = true; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 379 // Needed by ssl_client_socket_nss. | 381 // Needed by ssl_client_socket_nss. |
| 380 int SOCKSClientSocket::GetPeerName(struct sockaddr *name, socklen_t *namelen) { | 382 int SOCKSClientSocket::GetPeerName(struct sockaddr *name, socklen_t *namelen) { |
| 381 // Default implementation just permits some unit tests to link. | 383 // Default implementation just permits some unit tests to link. |
| 382 NOTREACHED(); | 384 NOTREACHED(); |
| 383 return ERR_UNEXPECTED; | 385 return ERR_UNEXPECTED; |
| 384 } | 386 } |
| 385 #endif | 387 #endif |
| 386 | 388 |
| 387 } // namespace net | 389 } // namespace net |
| 388 | 390 |
| OLD | NEW |