Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(265)

Side by Side Diff: net/socket/socks_client_socket.cc

Issue 113811: Adding socks4 support for chromium. tested for windows and linux.... (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: final patch Created 11 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « net/socket/socks_client_socket.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
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/socks_client_socket.h"
6
7 #include "base/basictypes.h"
8 #include "build/build_config.h"
9 #if defined(OS_WIN)
10 #include <ws2tcpip.h>
11 #else
12 #include <netdb.h>
13 #endif
14 #include "base/compiler_specific.h"
15 #include "base/trace_event.h"
16 #include "net/base/io_buffer.h"
17 #include "net/base/net_util.h"
18
19 namespace net {
20
21 // Every SOCKS server requests a user-id from the client. It is optional
22 // and we send an empty string.
23 static const char kEmptyUserId[] = "";
24
25 // The SOCKS4a implementation suggests to use an invalid IP in case the DNS
26 // resolution at client fails.
27 static const uint8 kInvalidIp[] = { 0, 0, 0, 127 };
28
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.
31 static const int kWriteHeaderSize = 8;
32
33 // For SOCKS4 and SOCKS4a, the server sends 8 bytes for acknowledgement.
34 static const int kReadHeaderSize = 8;
35
36 // Server Response codes for SOCKS.
37 static const uint8 kServerResponseOk = 0x5A;
38 static const uint8 kServerResponseRejected = 0x5B;
39 static const uint8 kServerResponseNotReachable = 0x5C;
40 static const uint8 kServerResponseMismatchedUserId = 0x5D;
41
42 static const uint8 kSOCKSVersion4 = 0x04;
43 static const uint8 kSOCKSStreamRequest = 0x01;
44
45 // A struct holding the essential details of the SOCKS4/4a Server Request.
46 // The port in the header is stored in network byte order.
47 struct SOCKS4ServerRequest {
48 uint8 version;
49 uint8 command;
50 uint16 nw_port;
51 uint8 ip[4];
52 };
53 COMPILE_ASSERT(sizeof(SOCKS4ServerRequest) == kWriteHeaderSize,
54 socks4_server_request_struct_wrong_size);
55
56 // A struct holding details of the SOCKS4/4a Server Response.
57 struct SOCKS4ServerResponse {
58 uint8 reserved_null;
59 uint8 code;
60 uint16 port;
61 uint8 ip[4];
62 };
63 COMPILE_ASSERT(sizeof(SOCKS4ServerResponse) == kReadHeaderSize,
64 socks4_server_response_struct_wrong_size);
65
66 SOCKSClientSocket::SOCKSClientSocket(ClientSocket* transport_socket,
67 const HostResolver::RequestInfo& req_info,
68 HostResolver* host_resolver)
69 : ALLOW_THIS_IN_INITIALIZER_LIST(
70 io_callback_(this, &SOCKSClientSocket::OnIOComplete)),
71 transport_(transport_socket),
72 next_state_(STATE_NONE),
73 socks_version_(kSOCKS4Unresolved),
74 user_callback_(NULL),
75 handshake_buf_len_(0),
76 buffer_(NULL),
77 buffer_len_(0),
78 completed_handshake_(false),
79 bytes_sent_(0),
80 bytes_received_(0),
81 resolver_(host_resolver),
82 host_request_info_(req_info) {
83 }
84
85 SOCKSClientSocket::~SOCKSClientSocket() {
86 Disconnect();
87 }
88
89 int SOCKSClientSocket::Connect(CompletionCallback* callback) {
90 DCHECK(transport_.get());
91 DCHECK(transport_->IsConnected());
92 DCHECK_EQ(STATE_NONE, next_state_);
93 DCHECK(!user_callback_);
94
95 // If already connected, then just return OK.
96 if (completed_handshake_)
97 return OK;
98
99 next_state_ = STATE_RESOLVE_HOST;
100
101 int rv = DoLoop(OK);
102 if (rv == ERR_IO_PENDING)
103 user_callback_ = callback;
104 return rv;
105 }
106
107 void SOCKSClientSocket::Disconnect() {
108 completed_handshake_ = false;
109 transport_->Disconnect();
110 }
111
112 bool SOCKSClientSocket::IsConnected() const {
113 return completed_handshake_ && transport_->IsConnected();
114 }
115
116 bool SOCKSClientSocket::IsConnectedAndIdle() const {
117 return completed_handshake_ && transport_->IsConnectedAndIdle();
118 }
119
120 // Read is called by the transport layer above to read. This can only be done
121 // if the SOCKS handshake is complete.
122 int SOCKSClientSocket::Read(IOBuffer* buf, int buf_len,
123 CompletionCallback* callback) {
124 DCHECK(completed_handshake_);
125 DCHECK_EQ(STATE_NONE, next_state_);
126 DCHECK(!user_callback_);
127
128 return transport_->Read(buf, buf_len, callback);
129 }
130
131 // Write is called by the transport layer. This can only be done if the
132 // SOCKS handshake is complete.
133 int SOCKSClientSocket::Write(IOBuffer* buf, int buf_len,
134 CompletionCallback* callback) {
135 DCHECK(completed_handshake_);
136 DCHECK_EQ(STATE_NONE, next_state_);
137 DCHECK(!user_callback_);
138
139 return transport_->Write(buf, buf_len, callback);
140 }
141
142 void SOCKSClientSocket::DoCallback(int result) {
143 DCHECK_NE(ERR_IO_PENDING, result);
144 DCHECK(user_callback_);
145
146 // Since Run() may result in Read being called,
147 // clear user_callback_ up front.
148 CompletionCallback* c = user_callback_;
149 user_callback_ = NULL;
150 DLOG(INFO) << "Finished setting up SOCKS handshake";
151 c->Run(result);
152 }
153
154 void SOCKSClientSocket::OnIOComplete(int result) {
155 DCHECK_NE(STATE_NONE, next_state_);
156 int rv = DoLoop(result);
157 if (rv != ERR_IO_PENDING)
158 DoCallback(rv);
159 }
160
161 int SOCKSClientSocket::DoLoop(int last_io_result) {
162 DCHECK_NE(next_state_, STATE_NONE);
163 int rv = last_io_result;
164 do {
165 State state = next_state_;
166 next_state_ = STATE_NONE;
167 switch (state) {
168 case STATE_RESOLVE_HOST:
169 DCHECK_EQ(OK, rv);
170 rv = DoResolveHost();
171 break;
172 case STATE_RESOLVE_HOST_COMPLETE:
173 rv = DoResolveHostComplete(rv);
174 break;
175 case STATE_HANDSHAKE_WRITE:
176 DCHECK_EQ(OK, rv);
177 rv = DoHandshakeWrite();
178 break;
179 case STATE_HANDSHAKE_WRITE_COMPLETE:
180 rv = DoHandshakeWriteComplete(rv);
181 break;
182 case STATE_HANDSHAKE_READ:
183 DCHECK_EQ(OK, rv);
184 rv = DoHandshakeRead();
185 break;
186 case STATE_HANDSHAKE_READ_COMPLETE:
187 rv = DoHandshakeReadComplete(rv);
188 break;
189 default:
190 NOTREACHED() << "bad state";
191 rv = ERR_UNEXPECTED;
192 break;
193 }
194 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
195 return rv;
196 }
197
198 int SOCKSClientSocket::DoResolveHost() {
199 DCHECK_EQ(kSOCKS4Unresolved, socks_version_);
200
201 next_state_ = STATE_RESOLVE_HOST_COMPLETE;
202 return resolver_.Resolve(host_request_info_, &addresses_, &io_callback_);
203 }
204
205 int SOCKSClientSocket::DoResolveHostComplete(int result) {
206 DCHECK_EQ(kSOCKS4Unresolved, socks_version_);
207
208 bool ok = (result == OK);
209 next_state_ = STATE_HANDSHAKE_WRITE;
210 if (ok) {
211 DCHECK(addresses_.head());
212
213 // If the host is resolved to an IPv6 address, we revert to SOCKS4a
214 // since IPv6 is unsupported by SOCKS4/4a protocol.
215 struct sockaddr *host_info = addresses_.head()->ai_addr;
216 if (host_info->sa_family == AF_INET) {
217 DLOG(INFO) << "Resolved host. Using SOCKS4 to communicate";
218 socks_version_ = kSOCKS4;
219 } else {
220 DLOG(INFO) << "Resolved host but to IPv6. Using SOCKS4a to communicate";
221 socks_version_ = kSOCKS4a;
222 }
223 } else {
224 DLOG(INFO) << "Could not resolve host. Using SOCKS4a to communicate";
225 socks_version_ = kSOCKS4a;
226 }
227
228 // Even if DNS resolution fails, we send OK since the server
229 // resolves the domain.
230 return OK;
231 }
232
233 // Builds the buffer that is to be sent to the server.
234 // We check whether the SOCKS proxy is 4 or 4A.
235 // In case it is 4A, the record size increases by size of the hostname.
236 void SOCKSClientSocket::BuildHandshakeWriteBuffer() {
237 DCHECK_NE(kSOCKS4Unresolved, socks_version_);
238
239 int record_size = kWriteHeaderSize + arraysize(kEmptyUserId);
240 if (socks_version_ == kSOCKS4a) {
241 record_size += host_request_info_.hostname().size() + 1;
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());
253
254 if (socks_version_ == kSOCKS4) {
255 const struct addrinfo* ai = addresses_.head();
256 DCHECK(ai);
257 // If the sockaddr is IPv6, we have already marked the version to socks4a
258 // and so this step does not get hit.
259 struct sockaddr_in *ipv4_host =
260 reinterpret_cast<struct sockaddr_in*>(ai->ai_addr);
261 memcpy(&request->ip, &(ipv4_host->sin_addr), sizeof(ipv4_host->sin_addr));
262
263 DLOG(INFO) << "Resolved Host is : " << NetAddressToString(ai);
264 } else if (socks_version_ == kSOCKS4a) {
265 // invalid IP of the form 0.0.0.127
266 memcpy(&request->ip, kInvalidIp, arraysize(kInvalidIp));
267 } else {
268 NOTREACHED();
269 }
270
271 memcpy(&buffer_[kWriteHeaderSize], kEmptyUserId, arraysize(kEmptyUserId));
272
273 if (socks_version_ == kSOCKS4a) {
274 memcpy(&buffer_[kWriteHeaderSize + arraysize(kEmptyUserId)],
275 host_request_info_.hostname().c_str(),
276 host_request_info_.hostname().size() + 1);
277 }
278 }
279
280 // Writes the SOCKS handshake data to the underlying socket connection.
281 int SOCKSClientSocket::DoHandshakeWrite() {
282 next_state_ = STATE_HANDSHAKE_WRITE_COMPLETE;
283
284 if (!buffer_.get()) {
285 BuildHandshakeWriteBuffer();
286 bytes_sent_ = 0;
287 }
288
289 handshake_buf_len_ = buffer_len_ - bytes_sent_;
290 DCHECK_GT(handshake_buf_len_, 0);
291 handshake_buf_ = new IOBuffer(handshake_buf_len_);
292 memcpy(handshake_buf_.get()->data(), &buffer_[bytes_sent_],
293 handshake_buf_len_);
294 return transport_->Write(handshake_buf_, handshake_buf_len_, &io_callback_);
295 }
296
297 int SOCKSClientSocket::DoHandshakeWriteComplete(int result) {
298 DCHECK_NE(kSOCKS4Unresolved, socks_version_);
299
300 if (result < 0)
301 return result;
302
303 bytes_sent_ += result;
304 if (bytes_sent_ == buffer_len_) {
305 next_state_ = STATE_HANDSHAKE_READ;
306 buffer_.reset(NULL);
307 } else if (bytes_sent_ < buffer_len_) {
308 next_state_ = STATE_HANDSHAKE_WRITE;
309 } else {
310 return ERR_UNEXPECTED;
311 }
312
313 return OK;
314 }
315
316 int SOCKSClientSocket::DoHandshakeRead() {
317 DCHECK_NE(kSOCKS4Unresolved, socks_version_);
318
319 next_state_ = STATE_HANDSHAKE_READ_COMPLETE;
320
321 if (!buffer_.get()) {
322 buffer_.reset(new char[kReadHeaderSize]);
323 buffer_len_ = kReadHeaderSize;
324 bytes_received_ = 0;
325 }
326
327 handshake_buf_len_ = buffer_len_ - bytes_received_;
328 handshake_buf_ = new IOBuffer(handshake_buf_len_);
329 return transport_->Read(handshake_buf_, handshake_buf_len_, &io_callback_);
330 }
331
332 int SOCKSClientSocket::DoHandshakeReadComplete(int result) {
333 DCHECK_NE(kSOCKS4Unresolved, socks_version_);
334
335 if (result < 0)
336 return result;
337 if (bytes_received_ + result > buffer_len_)
338 return ERR_INVALID_RESPONSE;
339
340 memcpy(buffer_.get() + bytes_received_, handshake_buf_->data(), result);
341 bytes_received_ += result;
342 if (bytes_received_ < buffer_len_) {
343 next_state_ = STATE_HANDSHAKE_READ;
344 return OK;
345 }
346
347 SOCKS4ServerResponse* response =
348 reinterpret_cast<SOCKS4ServerResponse*>(buffer_.get());
349
350 if (response->reserved_null != 0x00) {
351 LOG(ERROR) << "Unknown response from SOCKS server.";
352 return ERR_INVALID_RESPONSE;
353 }
354
355 // TODO(arindam): Add SOCKS specific failure codes in net_error_list.h
356 switch (response->code) {
357 case kServerResponseOk:
358 completed_handshake_ = true;
359 return OK;
360 case kServerResponseRejected:
361 LOG(ERROR) << "SOCKS request rejected or failed";
362 return ERR_FAILED;
363 case kServerResponseNotReachable:
364 LOG(ERROR) << "SOCKS request failed because client is not running "
365 << "identd (or not reachable from the server)";
366 return ERR_NAME_NOT_RESOLVED;
367 case kServerResponseMismatchedUserId:
368 LOG(ERROR) << "SOCKS request failed because client's identd could "
369 << "not confirm the user ID string in the request";
370 return ERR_FAILED;
371 default:
372 LOG(ERROR) << "SOCKS server sent unknown response";
373 return ERR_INVALID_RESPONSE;
374 }
375
376 // Note: we ignore the last 6 bytes as specified by the SOCKS protocol
377 }
378
379 #if defined(OS_LINUX)
380 // Identical to posix system call getpeername().
381 // Needed by ssl_client_socket_nss.
382 int SOCKSClientSocket::GetPeerName(struct sockaddr *name, socklen_t *namelen) {
383 // Default implementation just permits some unit tests to link.
384 NOTREACHED();
385 return ERR_UNEXPECTED;
386 }
387 #endif
388
389 } // namespace net
390
OLDNEW
« no previous file with comments | « net/socket/socks_client_socket.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698