1 // Copyright (c) 2012 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.
5 #include "net/socket/socks_client_socket.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "net/base/address_list.h"
9 #include "net/base/test_completion_callback.h"
10 #include "net/base/winsock_init.h"
11 #include "net/dns/host_resolver.h"
12 #include "net/dns/mock_host_resolver.h"
13 #include "net/log/net_log.h"
14 #include "net/log/test_net_log.h"
15 #include "net/log/test_net_log_entry.h"
16 #include "net/log/test_net_log_util.h"
17 #include "net/socket/client_socket_factory.h"
18 #include "net/socket/socket_test_util.h"
19 #include "net/socket/tcp_client_socket.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21 #include "testing/platform_test.h"
23 //-----------------------------------------------------------------------------
27 const char kSOCKSOkRequest
[] = { 0x04, 0x01, 0x00, 0x50, 127, 0, 0, 1, 0 };
28 const char kSOCKSOkReply
[] = { 0x00, 0x5A, 0x00, 0x00, 0, 0, 0, 0 };
30 class SOCKSClientSocketTest
: public PlatformTest
{
32 SOCKSClientSocketTest();
33 // Create a SOCKSClientSocket on top of a MockSocket.
34 scoped_ptr
<SOCKSClientSocket
> BuildMockSocket(
35 MockRead reads
[], size_t reads_count
,
36 MockWrite writes
[], size_t writes_count
,
37 HostResolver
* host_resolver
,
38 const std::string
& hostname
, int port
,
40 void SetUp() override
;
43 scoped_ptr
<SOCKSClientSocket
> user_sock_
;
44 AddressList address_list_
;
45 // Filled in by BuildMockSocket() and owned by its return value
46 // (which |user_sock| is set to).
47 StreamSocket
* tcp_sock_
;
48 TestCompletionCallback callback_
;
49 scoped_ptr
<MockHostResolver
> host_resolver_
;
50 scoped_ptr
<SocketDataProvider
> data_
;
53 SOCKSClientSocketTest::SOCKSClientSocketTest()
54 : host_resolver_(new MockHostResolver
) {
57 // Set up platform before every test case
58 void SOCKSClientSocketTest::SetUp() {
59 PlatformTest::SetUp();
62 scoped_ptr
<SOCKSClientSocket
> SOCKSClientSocketTest::BuildMockSocket(
67 HostResolver
* host_resolver
,
68 const std::string
& hostname
,
72 TestCompletionCallback callback
;
73 data_
.reset(new StaticSocketDataProvider(reads
, reads_count
,
74 writes
, writes_count
));
75 tcp_sock_
= new MockTCPClientSocket(address_list_
, net_log
, data_
.get());
77 int rv
= tcp_sock_
->Connect(callback
.callback());
78 EXPECT_EQ(ERR_IO_PENDING
, rv
);
79 rv
= callback
.WaitForResult();
81 EXPECT_TRUE(tcp_sock_
->IsConnected());
83 scoped_ptr
<ClientSocketHandle
> connection(new ClientSocketHandle
);
84 // |connection| takes ownership of |tcp_sock_|, but keep a
85 // non-owning pointer to it.
86 connection
->SetSocket(scoped_ptr
<StreamSocket
>(tcp_sock_
));
87 return scoped_ptr
<SOCKSClientSocket
>(new SOCKSClientSocket(
89 HostResolver::RequestInfo(HostPortPair(hostname
, port
)),
94 // Implementation of HostResolver that never completes its resolve request.
95 // We use this in the test "DisconnectWhileHostResolveInProgress" to make
96 // sure that the outstanding resolve request gets cancelled.
97 class HangingHostResolverWithCancel
: public HostResolver
{
99 HangingHostResolverWithCancel() : outstanding_request_(NULL
) {}
101 int Resolve(const RequestInfo
& info
,
102 RequestPriority priority
,
103 AddressList
* addresses
,
104 const CompletionCallback
& callback
,
105 RequestHandle
* out_req
,
106 const BoundNetLog
& net_log
) override
{
108 DCHECK_EQ(false, callback
.is_null());
109 EXPECT_FALSE(HasOutstandingRequest());
110 outstanding_request_
= reinterpret_cast<RequestHandle
>(1);
111 *out_req
= outstanding_request_
;
112 return ERR_IO_PENDING
;
115 int ResolveFromCache(const RequestInfo
& info
,
116 AddressList
* addresses
,
117 const BoundNetLog
& net_log
) override
{
119 return ERR_UNEXPECTED
;
122 void CancelRequest(RequestHandle req
) override
{
123 EXPECT_TRUE(HasOutstandingRequest());
124 EXPECT_EQ(outstanding_request_
, req
);
125 outstanding_request_
= NULL
;
128 bool HasOutstandingRequest() {
129 return outstanding_request_
!= NULL
;
133 RequestHandle outstanding_request_
;
135 DISALLOW_COPY_AND_ASSIGN(HangingHostResolverWithCancel
);
138 // Tests a complete handshake and the disconnection.
139 TEST_F(SOCKSClientSocketTest
, CompleteHandshake
) {
140 const std::string payload_write
= "random data";
141 const std::string payload_read
= "moar random data";
143 MockWrite data_writes
[] = {
144 MockWrite(ASYNC
, kSOCKSOkRequest
, arraysize(kSOCKSOkRequest
)),
145 MockWrite(ASYNC
, payload_write
.data(), payload_write
.size()) };
146 MockRead data_reads
[] = {
147 MockRead(ASYNC
, kSOCKSOkReply
, arraysize(kSOCKSOkReply
)),
148 MockRead(ASYNC
, payload_read
.data(), payload_read
.size()) };
151 user_sock_
= BuildMockSocket(data_reads
, arraysize(data_reads
),
152 data_writes
, arraysize(data_writes
),
153 host_resolver_
.get(),
157 // At this state the TCP connection is completed but not the SOCKS handshake.
158 EXPECT_TRUE(tcp_sock_
->IsConnected());
159 EXPECT_FALSE(user_sock_
->IsConnected());
161 int rv
= user_sock_
->Connect(callback_
.callback());
162 EXPECT_EQ(ERR_IO_PENDING
, rv
);
164 TestNetLogEntry::List entries
;
165 log
.GetEntries(&entries
);
167 LogContainsBeginEvent(entries
, 0, NetLog::TYPE_SOCKS_CONNECT
));
168 EXPECT_FALSE(user_sock_
->IsConnected());
170 rv
= callback_
.WaitForResult();
172 EXPECT_TRUE(user_sock_
->IsConnected());
173 log
.GetEntries(&entries
);
174 EXPECT_TRUE(LogContainsEndEvent(
175 entries
, -1, NetLog::TYPE_SOCKS_CONNECT
));
177 scoped_refptr
<IOBuffer
> buffer(new IOBuffer(payload_write
.size()));
178 memcpy(buffer
->data(), payload_write
.data(), payload_write
.size());
179 rv
= user_sock_
->Write(
180 buffer
.get(), payload_write
.size(), callback_
.callback());
181 EXPECT_EQ(ERR_IO_PENDING
, rv
);
182 rv
= callback_
.WaitForResult();
183 EXPECT_EQ(static_cast<int>(payload_write
.size()), rv
);
185 buffer
= new IOBuffer(payload_read
.size());
187 user_sock_
->Read(buffer
.get(), payload_read
.size(), callback_
.callback());
188 EXPECT_EQ(ERR_IO_PENDING
, rv
);
189 rv
= callback_
.WaitForResult();
190 EXPECT_EQ(static_cast<int>(payload_read
.size()), rv
);
191 EXPECT_EQ(payload_read
, std::string(buffer
->data(), payload_read
.size()));
193 user_sock_
->Disconnect();
194 EXPECT_FALSE(tcp_sock_
->IsConnected());
195 EXPECT_FALSE(user_sock_
->IsConnected());
198 // List of responses from the socks server and the errors they should
199 // throw up are tested here.
200 TEST_F(SOCKSClientSocketTest
, HandshakeFailures
) {
202 const char fail_reply
[8];
205 // Failure of the server response code
207 { 0x01, 0x5A, 0x00, 0x00, 0, 0, 0, 0 },
208 ERR_SOCKS_CONNECTION_FAILED
,
210 // Failure of the null byte
212 { 0x00, 0x5B, 0x00, 0x00, 0, 0, 0, 0 },
213 ERR_SOCKS_CONNECTION_FAILED
,
217 //---------------------------------------
219 for (size_t i
= 0; i
< arraysize(tests
); ++i
) {
220 MockWrite data_writes
[] = {
221 MockWrite(SYNCHRONOUS
, kSOCKSOkRequest
, arraysize(kSOCKSOkRequest
)) };
222 MockRead data_reads
[] = {
223 MockRead(SYNCHRONOUS
, tests
[i
].fail_reply
,
224 arraysize(tests
[i
].fail_reply
)) };
227 user_sock_
= BuildMockSocket(data_reads
, arraysize(data_reads
),
228 data_writes
, arraysize(data_writes
),
229 host_resolver_
.get(),
233 int rv
= user_sock_
->Connect(callback_
.callback());
234 EXPECT_EQ(ERR_IO_PENDING
, rv
);
236 TestNetLogEntry::List entries
;
237 log
.GetEntries(&entries
);
238 EXPECT_TRUE(LogContainsBeginEvent(
239 entries
, 0, NetLog::TYPE_SOCKS_CONNECT
));
241 rv
= callback_
.WaitForResult();
242 EXPECT_EQ(tests
[i
].fail_code
, rv
);
243 EXPECT_FALSE(user_sock_
->IsConnected());
244 EXPECT_TRUE(tcp_sock_
->IsConnected());
245 log
.GetEntries(&entries
);
246 EXPECT_TRUE(LogContainsEndEvent(
247 entries
, -1, NetLog::TYPE_SOCKS_CONNECT
));
251 // Tests scenario when the server sends the handshake response in
252 // more than one packet.
253 TEST_F(SOCKSClientSocketTest
, PartialServerReads
) {
254 const char kSOCKSPartialReply1
[] = { 0x00 };
255 const char kSOCKSPartialReply2
[] = { 0x5A, 0x00, 0x00, 0, 0, 0, 0 };
257 MockWrite data_writes
[] = {
258 MockWrite(ASYNC
, kSOCKSOkRequest
, arraysize(kSOCKSOkRequest
)) };
259 MockRead data_reads
[] = {
260 MockRead(ASYNC
, kSOCKSPartialReply1
, arraysize(kSOCKSPartialReply1
)),
261 MockRead(ASYNC
, kSOCKSPartialReply2
, arraysize(kSOCKSPartialReply2
)) };
264 user_sock_
= BuildMockSocket(data_reads
, arraysize(data_reads
),
265 data_writes
, arraysize(data_writes
),
266 host_resolver_
.get(),
270 int rv
= user_sock_
->Connect(callback_
.callback());
271 EXPECT_EQ(ERR_IO_PENDING
, rv
);
272 TestNetLogEntry::List entries
;
273 log
.GetEntries(&entries
);
274 EXPECT_TRUE(LogContainsBeginEvent(
275 entries
, 0, NetLog::TYPE_SOCKS_CONNECT
));
277 rv
= callback_
.WaitForResult();
279 EXPECT_TRUE(user_sock_
->IsConnected());
280 log
.GetEntries(&entries
);
281 EXPECT_TRUE(LogContainsEndEvent(
282 entries
, -1, NetLog::TYPE_SOCKS_CONNECT
));
285 // Tests scenario when the client sends the handshake request in
286 // more than one packet.
287 TEST_F(SOCKSClientSocketTest
, PartialClientWrites
) {
288 const char kSOCKSPartialRequest1
[] = { 0x04, 0x01 };
289 const char kSOCKSPartialRequest2
[] = { 0x00, 0x50, 127, 0, 0, 1, 0 };
291 MockWrite data_writes
[] = {
292 MockWrite(ASYNC
, kSOCKSPartialRequest1
, arraysize(kSOCKSPartialRequest1
)),
293 // simulate some empty writes
296 MockWrite(ASYNC
, kSOCKSPartialRequest2
, arraysize(kSOCKSPartialRequest2
)),
298 MockRead data_reads
[] = {
299 MockRead(ASYNC
, kSOCKSOkReply
, arraysize(kSOCKSOkReply
)) };
302 user_sock_
= BuildMockSocket(data_reads
, arraysize(data_reads
),
303 data_writes
, arraysize(data_writes
),
304 host_resolver_
.get(),
308 int rv
= user_sock_
->Connect(callback_
.callback());
309 EXPECT_EQ(ERR_IO_PENDING
, rv
);
310 TestNetLogEntry::List entries
;
311 log
.GetEntries(&entries
);
312 EXPECT_TRUE(LogContainsBeginEvent(
313 entries
, 0, NetLog::TYPE_SOCKS_CONNECT
));
315 rv
= callback_
.WaitForResult();
317 EXPECT_TRUE(user_sock_
->IsConnected());
318 log
.GetEntries(&entries
);
319 EXPECT_TRUE(LogContainsEndEvent(
320 entries
, -1, NetLog::TYPE_SOCKS_CONNECT
));
323 // Tests the case when the server sends a smaller sized handshake data
324 // and closes the connection.
325 TEST_F(SOCKSClientSocketTest
, FailedSocketRead
) {
326 MockWrite data_writes
[] = {
327 MockWrite(ASYNC
, kSOCKSOkRequest
, arraysize(kSOCKSOkRequest
)) };
328 MockRead data_reads
[] = {
329 MockRead(ASYNC
, kSOCKSOkReply
, arraysize(kSOCKSOkReply
) - 2),
330 // close connection unexpectedly
331 MockRead(SYNCHRONOUS
, 0) };
334 user_sock_
= BuildMockSocket(data_reads
, arraysize(data_reads
),
335 data_writes
, arraysize(data_writes
),
336 host_resolver_
.get(),
340 int rv
= user_sock_
->Connect(callback_
.callback());
341 EXPECT_EQ(ERR_IO_PENDING
, rv
);
342 TestNetLogEntry::List entries
;
343 log
.GetEntries(&entries
);
344 EXPECT_TRUE(LogContainsBeginEvent(
345 entries
, 0, NetLog::TYPE_SOCKS_CONNECT
));
347 rv
= callback_
.WaitForResult();
348 EXPECT_EQ(ERR_CONNECTION_CLOSED
, rv
);
349 EXPECT_FALSE(user_sock_
->IsConnected());
350 log
.GetEntries(&entries
);
351 EXPECT_TRUE(LogContainsEndEvent(
352 entries
, -1, NetLog::TYPE_SOCKS_CONNECT
));
355 // Tries to connect to an unknown hostname. Should fail rather than
356 // falling back to SOCKS4a.
357 TEST_F(SOCKSClientSocketTest
, FailedDNS
) {
358 const char hostname
[] = "unresolved.ipv4.address";
360 host_resolver_
->rules()->AddSimulatedFailure(hostname
);
364 user_sock_
= BuildMockSocket(NULL
, 0,
366 host_resolver_
.get(),
370 int rv
= user_sock_
->Connect(callback_
.callback());
371 EXPECT_EQ(ERR_IO_PENDING
, rv
);
372 TestNetLogEntry::List entries
;
373 log
.GetEntries(&entries
);
374 EXPECT_TRUE(LogContainsBeginEvent(
375 entries
, 0, NetLog::TYPE_SOCKS_CONNECT
));
377 rv
= callback_
.WaitForResult();
378 EXPECT_EQ(ERR_NAME_NOT_RESOLVED
, rv
);
379 EXPECT_FALSE(user_sock_
->IsConnected());
380 log
.GetEntries(&entries
);
381 EXPECT_TRUE(LogContainsEndEvent(
382 entries
, -1, NetLog::TYPE_SOCKS_CONNECT
));
385 // Calls Disconnect() while a host resolve is in progress. The outstanding host
386 // resolve should be cancelled.
387 TEST_F(SOCKSClientSocketTest
, DisconnectWhileHostResolveInProgress
) {
388 scoped_ptr
<HangingHostResolverWithCancel
> hanging_resolver(
389 new HangingHostResolverWithCancel());
391 // Doesn't matter what the socket data is, we will never use it -- garbage.
392 MockWrite data_writes
[] = { MockWrite(SYNCHRONOUS
, "", 0) };
393 MockRead data_reads
[] = { MockRead(SYNCHRONOUS
, "", 0) };
395 user_sock_
= BuildMockSocket(data_reads
, arraysize(data_reads
),
396 data_writes
, arraysize(data_writes
),
397 hanging_resolver
.get(),
401 // Start connecting (will get stuck waiting for the host to resolve).
402 int rv
= user_sock_
->Connect(callback_
.callback());
403 EXPECT_EQ(ERR_IO_PENDING
, rv
);
405 EXPECT_FALSE(user_sock_
->IsConnected());
406 EXPECT_FALSE(user_sock_
->IsConnectedAndIdle());
408 // The host resolver should have received the resolve request.
409 EXPECT_TRUE(hanging_resolver
->HasOutstandingRequest());
411 // Disconnect the SOCKS socket -- this should cancel the outstanding resolve.
412 user_sock_
->Disconnect();
414 EXPECT_FALSE(hanging_resolver
->HasOutstandingRequest());
416 EXPECT_FALSE(user_sock_
->IsConnected());
417 EXPECT_FALSE(user_sock_
->IsConnectedAndIdle());
420 // Tries to connect to an IPv6 IP. Should fail, as SOCKS4 does not support
422 TEST_F(SOCKSClientSocketTest
, NoIPv6
) {
423 const char kHostName
[] = "::1";
425 user_sock_
= BuildMockSocket(NULL
, 0,
427 host_resolver_
.get(),
431 EXPECT_EQ(ERR_NAME_NOT_RESOLVED
,
432 callback_
.GetResult(user_sock_
->Connect(callback_
.callback())));
435 // Same as above, but with a real resolver, to protect against regressions.
436 TEST_F(SOCKSClientSocketTest
, NoIPv6RealResolver
) {
437 const char kHostName
[] = "::1";
439 scoped_ptr
<HostResolver
> host_resolver(
440 HostResolver::CreateSystemResolver(HostResolver::Options(), NULL
));
442 user_sock_
= BuildMockSocket(NULL
, 0,
448 EXPECT_EQ(ERR_NAME_NOT_RESOLVED
,
449 callback_
.GetResult(user_sock_
->Connect(callback_
.callback())));