141be673e93ed225b45479557b20ff19b3082bae8Richard Smith// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2859b6227694033dd6eaf3991a2b80877a406c382Richard Smith// Use of this source code is governed by a BSD-style license that can be
384ef8990b8f6b0f9ab57f8e2b7372dad5575364fRichard Smith// found in the LICENSE file.
403544fccd1782418c1bf2528111683e18f43b913Richard Smith
503544fccd1782418c1bf2528111683e18f43b913Richard Smith#include "net/socket/socks5_client_socket.h"
603544fccd1782418c1bf2528111683e18f43b913Richard Smith
703544fccd1782418c1bf2528111683e18f43b913Richard Smith#include <algorithm>
803544fccd1782418c1bf2528111683e18f43b913Richard Smith#include <iterator>
903544fccd1782418c1bf2528111683e18f43b913Richard Smith#include <map>
1003544fccd1782418c1bf2528111683e18f43b913Richard Smith
11193649c2a3ff0616777de934a2bf47eaeb4f1076Richard Smith#include "base/sys_byteorder.h"
12193649c2a3ff0616777de934a2bf47eaeb4f1076Richard Smith#include "net/base/address_list.h"
1303544fccd1782418c1bf2528111683e18f43b913Richard Smith#include "net/base/net_log.h"
1403544fccd1782418c1bf2528111683e18f43b913Richard Smith#include "net/base/net_log_unittest.h"
15d390de9c6312684c5e5b333f434199e193c7467aRichard Smith#include "net/base/test_completion_callback.h"
1684ef8990b8f6b0f9ab57f8e2b7372dad5575364fRichard Smith#include "net/base/winsock_init.h"
1784ef8990b8f6b0f9ab57f8e2b7372dad5575364fRichard Smith#include "net/dns/mock_host_resolver.h"
1884ef8990b8f6b0f9ab57f8e2b7372dad5575364fRichard Smith#include "net/socket/client_socket_factory.h"
1984ef8990b8f6b0f9ab57f8e2b7372dad5575364fRichard Smith#include "net/socket/socket_test_util.h"
2084ef8990b8f6b0f9ab57f8e2b7372dad5575364fRichard Smith#include "net/socket/tcp_client_socket.h"
2184ef8990b8f6b0f9ab57f8e2b7372dad5575364fRichard Smith#include "testing/gtest/include/gtest/gtest.h"
2284ef8990b8f6b0f9ab57f8e2b7372dad5575364fRichard Smith#include "testing/platform_test.h"
2384ef8990b8f6b0f9ab57f8e2b7372dad5575364fRichard Smith
2441be673e93ed225b45479557b20ff19b3082bae8Richard Smith//-----------------------------------------------------------------------------
25f64231e9f47234826fbcdc3b4fe0370ef6c9961dMichael Han
26651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesnamespace net {
27661a99690bc133bbaa029da925481d4a860dec90Richard Smith
28661a99690bc133bbaa029da925481d4a860dec90Richard Smithnamespace {
29661a99690bc133bbaa029da925481d4a860dec90Richard Smith
30661a99690bc133bbaa029da925481d4a860dec90Richard Smith// Base class to test SOCKS5ClientSocket
31661a99690bc133bbaa029da925481d4a860dec90Richard Smithclass SOCKS5ClientSocketTest : public PlatformTest {
32661a99690bc133bbaa029da925481d4a860dec90Richard Smith public:
33661a99690bc133bbaa029da925481d4a860dec90Richard Smith  SOCKS5ClientSocketTest();
34661a99690bc133bbaa029da925481d4a860dec90Richard Smith  // Create a SOCKSClientSocket on top of a MockSocket.
35661a99690bc133bbaa029da925481d4a860dec90Richard Smith  scoped_ptr<SOCKS5ClientSocket> BuildMockSocket(MockRead reads[],
36661a99690bc133bbaa029da925481d4a860dec90Richard Smith                                                 size_t reads_count,
37661a99690bc133bbaa029da925481d4a860dec90Richard Smith                                                 MockWrite writes[],
38661a99690bc133bbaa029da925481d4a860dec90Richard Smith                                                 size_t writes_count,
39661a99690bc133bbaa029da925481d4a860dec90Richard Smith                                                 const std::string& hostname,
40661a99690bc133bbaa029da925481d4a860dec90Richard Smith                                                 int port,
41661a99690bc133bbaa029da925481d4a860dec90Richard Smith                                                 NetLog* net_log);
42661a99690bc133bbaa029da925481d4a860dec90Richard Smith
437fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith  virtual void SetUp();
447fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith
457fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith protected:
467fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith  const uint16 kNwPort;
477fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith  CapturingNetLog net_log_;
487fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith  scoped_ptr<SOCKS5ClientSocket> user_sock_;
49b9c64d84ea3edd5e2fffb0a2e85ca1308be4f429Richard Smith  AddressList address_list_;
507fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith  // Filled in by BuildMockSocket() and owned by its return value
517fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith  // (which |user_sock| is set to).
5203544fccd1782418c1bf2528111683e18f43b913Richard Smith  StreamSocket* tcp_sock_;
5303544fccd1782418c1bf2528111683e18f43b913Richard Smith  TestCompletionCallback callback_;
5403544fccd1782418c1bf2528111683e18f43b913Richard Smith  scoped_ptr<MockHostResolver> host_resolver_;
5503544fccd1782418c1bf2528111683e18f43b913Richard Smith  scoped_ptr<SocketDataProvider> data_;
5603544fccd1782418c1bf2528111683e18f43b913Richard Smith
5703544fccd1782418c1bf2528111683e18f43b913Richard Smith private:
5803544fccd1782418c1bf2528111683e18f43b913Richard Smith  DISALLOW_COPY_AND_ASSIGN(SOCKS5ClientSocketTest);
5903544fccd1782418c1bf2528111683e18f43b913Richard Smith};
603e280b58db5e7dc2bab736fa65af2b8157916726Sebastian Redl
613e280b58db5e7dc2bab736fa65af2b8157916726Sebastian RedlSOCKS5ClientSocketTest::SOCKS5ClientSocketTest()
6256a04287a1c713870d1e03206cce785e985cc866Sebastian Redl  : kNwPort(base::HostToNet16(80)),
6356a04287a1c713870d1e03206cce785e985cc866Sebastian Redl    host_resolver_(new MockHostResolver) {
646dc00f6e98a00bd1c332927c3e04918d7e8b0d4fSebastian Redl}
656dc00f6e98a00bd1c332927c3e04918d7e8b0d4fSebastian Redl
666b13022faef260c8f49d04310f4a2c0a57f9103bRichard Smith// Set up platform before every test case
67dbe01bb024ce9407954275a5e3c7e1a7113ca9faRichard Smithvoid SOCKS5ClientSocketTest::SetUp() {
68dbe01bb024ce9407954275a5e3c7e1a7113ca9faRichard Smith  PlatformTest::SetUp();
6903544fccd1782418c1bf2528111683e18f43b913Richard Smith
7003544fccd1782418c1bf2528111683e18f43b913Richard Smith  // Resolve the "localhost" AddressList used by the TCP connection to connect.
7103544fccd1782418c1bf2528111683e18f43b913Richard Smith  HostResolver::RequestInfo info(HostPortPair("www.socks-proxy.com", 1080));
7203544fccd1782418c1bf2528111683e18f43b913Richard Smith  TestCompletionCallback callback;
7303544fccd1782418c1bf2528111683e18f43b913Richard Smith  int rv = host_resolver_->Resolve(info,
7403544fccd1782418c1bf2528111683e18f43b913Richard Smith                                   DEFAULT_PRIORITY,
7503544fccd1782418c1bf2528111683e18f43b913Richard Smith                                   &address_list_,
766242a45ca50586ed3f363d4ac7422e07092e4d96Richard Smith                                   callback.callback(),
776b13022faef260c8f49d04310f4a2c0a57f9103bRichard Smith                                   NULL,
787fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith                                   BoundNetLog());
79ca8937111cccdbf7d17c349487a332d6c7c97f91Sebastian Redl  ASSERT_EQ(ERR_IO_PENDING, rv);
80ca8937111cccdbf7d17c349487a332d6c7c97f91Sebastian Redl  rv = callback.WaitForResult();
81ca8937111cccdbf7d17c349487a332d6c7c97f91Sebastian Redl  ASSERT_EQ(OK, rv);
82ca8937111cccdbf7d17c349487a332d6c7c97f91Sebastian Redl}
837fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith
845cc2c6eb67b6e5361bbe96f79b519fd62ec666d6Richard Smithscoped_ptr<SOCKS5ClientSocket> SOCKS5ClientSocketTest::BuildMockSocket(
857fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith    MockRead reads[],
867fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith    size_t reads_count,
877fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith    MockWrite writes[],
887fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith    size_t writes_count,
897fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith    const std::string& hostname,
907fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith    int port,
917fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith    NetLog* net_log) {
927fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith  TestCompletionCallback callback;
937fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith  data_.reset(new StaticSocketDataProvider(reads, reads_count,
947fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith                                           writes, writes_count));
957fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith  tcp_sock_ = new MockTCPClientSocket(address_list_, net_log, data_.get());
967fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith
977fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith  int rv = tcp_sock_->Connect(callback.callback());
987fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith  EXPECT_EQ(ERR_IO_PENDING, rv);
997fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith  rv = callback.WaitForResult();
1007fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith  EXPECT_EQ(OK, rv);
1017fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith  EXPECT_TRUE(tcp_sock_->IsConnected());
1027fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith
1037fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith  scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle);
1047fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith  // |connection| takes ownership of |tcp_sock_|, but keep a
1057fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith  // non-owning pointer to it.
1067fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith  connection->SetSocket(scoped_ptr<StreamSocket>(tcp_sock_));
1077fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith  return scoped_ptr<SOCKS5ClientSocket>(new SOCKS5ClientSocket(
108193649c2a3ff0616777de934a2bf47eaeb4f1076Richard Smith      connection.Pass(),
109193649c2a3ff0616777de934a2bf47eaeb4f1076Richard Smith      HostResolver::RequestInfo(HostPortPair(hostname, port))));
110193649c2a3ff0616777de934a2bf47eaeb4f1076Richard Smith}
111193649c2a3ff0616777de934a2bf47eaeb4f1076Richard Smith
11225cf8abf30189323199b1424848b105940267c1bRichard Smith// Tests a complete SOCKS5 handshake and the disconnection.
113193649c2a3ff0616777de934a2bf47eaeb4f1076Richard SmithTEST_F(SOCKS5ClientSocketTest, CompleteHandshake) {
11425cf8abf30189323199b1424848b105940267c1bRichard Smith  const std::string payload_write = "random data";
1157fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith  const std::string payload_read = "moar random data";
1167fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith
1177fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith  const char kOkRequest[] = {
1187fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith    0x05,  // Version
1197fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith    0x01,  // Command (CONNECT)
1207fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith    0x00,  // Reserved.
1217fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith    0x03,  // Address type (DOMAINNAME).
1227fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith    0x09,  // Length of domain (9)
1237fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith    // Domain string:
1247fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith    'l', 'o', 'c', 'a', 'l', 'h', 'o', 's', 't',
1257fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith    0x00, 0x50,  // 16-bit port (80)
1267fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith  };
1277fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith
1287fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith  MockWrite data_writes[] = {
1297fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith      MockWrite(ASYNC, kSOCKS5GreetRequest, kSOCKS5GreetRequestLength),
1307fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith      MockWrite(ASYNC, kOkRequest, arraysize(kOkRequest)),
1317fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith      MockWrite(ASYNC, payload_write.data(), payload_write.size()) };
1327fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith  MockRead data_reads[] = {
133ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith      MockRead(ASYNC, kSOCKS5GreetResponse, kSOCKS5GreetResponseLength),
1347fe6208c3fa91f835813bb78236ef5c2bbf81053Richard Smith      MockRead(ASYNC, kSOCKS5OkResponse, kSOCKS5OkResponseLength),
1350aa86c0463a881be85fd34e04c7de3379997621dRichard Smith      MockRead(ASYNC, payload_read.data(), payload_read.size()) };
1360aa86c0463a881be85fd34e04c7de3379997621dRichard Smith
1370aa86c0463a881be85fd34e04c7de3379997621dRichard Smith  user_sock_ = BuildMockSocket(data_reads, arraysize(data_reads),
138841804baff6ea8ba1904a2ba81265aae1479e882Richard Smith                               data_writes, arraysize(data_writes),
139841804baff6ea8ba1904a2ba81265aae1479e882Richard Smith                               "localhost", 80, &net_log_);
140841804baff6ea8ba1904a2ba81265aae1479e882Richard Smith
141841804baff6ea8ba1904a2ba81265aae1479e882Richard Smith  // At this state the TCP connection is completed but not the SOCKS handshake.
142841804baff6ea8ba1904a2ba81265aae1479e882Richard Smith  EXPECT_TRUE(tcp_sock_->IsConnected());
143841804baff6ea8ba1904a2ba81265aae1479e882Richard Smith  EXPECT_FALSE(user_sock_->IsConnected());
14439304fad1c8a7b7e64121e9ae544b18e460b682cRichard Smith
145841804baff6ea8ba1904a2ba81265aae1479e882Richard Smith  int rv = user_sock_->Connect(callback_.callback());
146841804baff6ea8ba1904a2ba81265aae1479e882Richard Smith  EXPECT_EQ(ERR_IO_PENDING, rv);
147841804baff6ea8ba1904a2ba81265aae1479e882Richard Smith  EXPECT_FALSE(user_sock_->IsConnected());
148841804baff6ea8ba1904a2ba81265aae1479e882Richard Smith
149ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith  CapturingNetLog::CapturedEntryList net_log_entries;
150ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith  net_log_.GetEntries(&net_log_entries);
151ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith  EXPECT_TRUE(LogContainsBeginEvent(net_log_entries, 0,
152ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith                                    NetLog::TYPE_SOCKS5_CONNECT));
153ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith
154cbec59a267d8d6c402c6b0206e36dca091fc9ae4Richard Smith  rv = callback_.WaitForResult();
155ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith
156ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith  EXPECT_EQ(OK, rv);
157ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith  EXPECT_TRUE(user_sock_->IsConnected());
158ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith
159ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith  net_log_.GetEntries(&net_log_entries);
160ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith  EXPECT_TRUE(LogContainsEndEvent(net_log_entries, -1,
161ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith                                  NetLog::TYPE_SOCKS5_CONNECT));
162ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith
163ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith  scoped_refptr<IOBuffer> buffer(new IOBuffer(payload_write.size()));
164ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith  memcpy(buffer->data(), payload_write.data(), payload_write.size());
165ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith  rv = user_sock_->Write(
166ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith      buffer.get(), payload_write.size(), callback_.callback());
167ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith  EXPECT_EQ(ERR_IO_PENDING, rv);
168ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith  rv = callback_.WaitForResult();
169ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith  EXPECT_EQ(static_cast<int>(payload_write.size()), rv);
170ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith
171ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith  buffer = new IOBuffer(payload_read.size());
172ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith  rv =
173ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith      user_sock_->Read(buffer.get(), payload_read.size(), callback_.callback());
174ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith  EXPECT_EQ(ERR_IO_PENDING, rv);
175ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith  rv = callback_.WaitForResult();
176ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith  EXPECT_EQ(static_cast<int>(payload_read.size()), rv);
177ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith  EXPECT_EQ(payload_read, std::string(buffer->data(), payload_read.size()));
178ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith
179ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith  user_sock_->Disconnect();
180ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith  EXPECT_FALSE(tcp_sock_->IsConnected());
181ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith  EXPECT_FALSE(user_sock_->IsConnected());
182ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith}
183ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith
184ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith// Test that you can call Connect() again after having called Disconnect().
185ebaf0e6ab743394dda086a01b457838cb6e589a8Richard SmithTEST_F(SOCKS5ClientSocketTest, ConnectAndDisconnectTwice) {
186ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith  const std::string hostname = "my-host-name";
187ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith  const char kSOCKS5DomainRequest[] = {
188ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith      0x05,  // VER
189ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith      0x01,  // CMD
190ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith      0x00,  // RSV
191ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith      0x03,  // ATYPE
192ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith  };
193ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith
194ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith  std::string request(kSOCKS5DomainRequest, arraysize(kSOCKS5DomainRequest));
195ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith  request.push_back(hostname.size());
196ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith  request.append(hostname);
197ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith  request.append(reinterpret_cast<const char*>(&kNwPort), sizeof(kNwPort));
198ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith
199ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith  for (int i = 0; i < 2; ++i) {
200ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith    MockWrite data_writes[] = {
201ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith        MockWrite(SYNCHRONOUS, kSOCKS5GreetRequest, kSOCKS5GreetRequestLength),
202ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith        MockWrite(SYNCHRONOUS, request.data(), request.size())
203ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith    };
204ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith    MockRead data_reads[] = {
205ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith        MockRead(SYNCHRONOUS, kSOCKS5GreetResponse, kSOCKS5GreetResponseLength),
206ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith        MockRead(SYNCHRONOUS, kSOCKS5OkResponse, kSOCKS5OkResponseLength)
207ebaf0e6ab743394dda086a01b457838cb6e589a8Richard Smith    };
2086b13022faef260c8f49d04310f4a2c0a57f9103bRichard Smith
2096b13022faef260c8f49d04310f4a2c0a57f9103bRichard Smith    user_sock_ = BuildMockSocket(data_reads, arraysize(data_reads),
2106b13022faef260c8f49d04310f4a2c0a57f9103bRichard Smith                                 data_writes, arraysize(data_writes),
2116b13022faef260c8f49d04310f4a2c0a57f9103bRichard Smith                                 hostname, 80, NULL);
2126b13022faef260c8f49d04310f4a2c0a57f9103bRichard Smith
2136b13022faef260c8f49d04310f4a2c0a57f9103bRichard Smith    int rv = user_sock_->Connect(callback_.callback());
2146b13022faef260c8f49d04310f4a2c0a57f9103bRichard Smith    EXPECT_EQ(OK, rv);
2156b13022faef260c8f49d04310f4a2c0a57f9103bRichard Smith    EXPECT_TRUE(user_sock_->IsConnected());
2166b13022faef260c8f49d04310f4a2c0a57f9103bRichard Smith
2176b13022faef260c8f49d04310f4a2c0a57f9103bRichard Smith    user_sock_->Disconnect();
21877faa365cb2322cfc8edf58a4f5d68f2370cc39aRichard Smith    EXPECT_FALSE(user_sock_->IsConnected());
21977faa365cb2322cfc8edf58a4f5d68f2370cc39aRichard Smith  }
22077faa365cb2322cfc8edf58a4f5d68f2370cc39aRichard Smith}
22177faa365cb2322cfc8edf58a4f5d68f2370cc39aRichard Smith
222651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// Test that we fail trying to connect to a hosname longer than 255 bytes.
22377faa365cb2322cfc8edf58a4f5d68f2370cc39aRichard SmithTEST_F(SOCKS5ClientSocketTest, LargeHostNameFails) {
22477faa365cb2322cfc8edf58a4f5d68f2370cc39aRichard Smith  // Create a string of length 256, where each character is 'x'.
22577faa365cb2322cfc8edf58a4f5d68f2370cc39aRichard Smith  std::string large_host_name;
226651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  std::fill_n(std::back_inserter(large_host_name), 256, 'x');
22783da2e711902c4c54f5601c9000d646dfff06aeaRichard Smith
22883da2e711902c4c54f5601c9000d646dfff06aeaRichard Smith  // Create a SOCKS socket, with mock transport socket.
22983da2e711902c4c54f5601c9000d646dfff06aeaRichard Smith  MockWrite data_writes[] = {MockWrite()};
23083da2e711902c4c54f5601c9000d646dfff06aeaRichard Smith  MockRead data_reads[] = {MockRead()};
23183da2e711902c4c54f5601c9000d646dfff06aeaRichard Smith  user_sock_ = BuildMockSocket(data_reads, arraysize(data_reads),
23283da2e711902c4c54f5601c9000d646dfff06aeaRichard Smith                               data_writes, arraysize(data_writes),
23383da2e711902c4c54f5601c9000d646dfff06aeaRichard Smith                               large_host_name, 80, NULL);
23483da2e711902c4c54f5601c9000d646dfff06aeaRichard Smith
23583da2e711902c4c54f5601c9000d646dfff06aeaRichard Smith  // Try to connect -- should fail (without having read/written anything to
23683da2e711902c4c54f5601c9000d646dfff06aeaRichard Smith  // the transport socket first) because the hostname is too long.
23783da2e711902c4c54f5601c9000d646dfff06aeaRichard Smith  TestCompletionCallback callback;
23883da2e711902c4c54f5601c9000d646dfff06aeaRichard Smith  int rv = user_sock_->Connect(callback.callback());
23983da2e711902c4c54f5601c9000d646dfff06aeaRichard Smith  EXPECT_EQ(ERR_SOCKS_CONNECTION_FAILED, rv);
24083da2e711902c4c54f5601c9000d646dfff06aeaRichard Smith}
24183da2e711902c4c54f5601c9000d646dfff06aeaRichard Smith
24283da2e711902c4c54f5601c9000d646dfff06aeaRichard SmithTEST_F(SOCKS5ClientSocketTest, PartialReadWrites) {
2436c4c36c4ed1007143f5b8655eb68b313a7e12e76Richard Smith  const std::string hostname = "www.google.com";
2446c4c36c4ed1007143f5b8655eb68b313a7e12e76Richard Smith
24583da2e711902c4c54f5601c9000d646dfff06aeaRichard Smith  const char kOkRequest[] = {
24683da2e711902c4c54f5601c9000d646dfff06aeaRichard Smith    0x05,  // Version
24783da2e711902c4c54f5601c9000d646dfff06aeaRichard Smith    0x01,  // Command (CONNECT)
24883da2e711902c4c54f5601c9000d646dfff06aeaRichard Smith    0x00,  // Reserved.
24983da2e711902c4c54f5601c9000d646dfff06aeaRichard Smith    0x03,  // Address type (DOMAINNAME).
25083da2e711902c4c54f5601c9000d646dfff06aeaRichard Smith    0x0E,  // Length of domain (14)
25183da2e711902c4c54f5601c9000d646dfff06aeaRichard Smith    // Domain string:
252e7d7c39be90bf654a8da0f53f6682d965426d081Richard Smith    'w', 'w', 'w', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'c', 'o', 'm',
253e7d7c39be90bf654a8da0f53f6682d965426d081Richard Smith    0x00, 0x50,  // 16-bit port (80)
254e7d7c39be90bf654a8da0f53f6682d965426d081Richard Smith  };
255ac71351acdefc9de0c770c1d717e621ac9e684bfRichard Smith
256e7d7c39be90bf654a8da0f53f6682d965426d081Richard Smith  // Test for partial greet request write
257e7d7c39be90bf654a8da0f53f6682d965426d081Richard Smith  {
258ac71351acdefc9de0c770c1d717e621ac9e684bfRichard Smith    const char partial1[] = { 0x05, 0x01 };
259e7d7c39be90bf654a8da0f53f6682d965426d081Richard Smith    const char partial2[] = { 0x00 };
260e7d7c39be90bf654a8da0f53f6682d965426d081Richard Smith    MockWrite data_writes[] = {
261ac71351acdefc9de0c770c1d717e621ac9e684bfRichard Smith        MockWrite(ASYNC, arraysize(partial1)),
262e7d7c39be90bf654a8da0f53f6682d965426d081Richard Smith        MockWrite(ASYNC, partial2, arraysize(partial2)),
263e7d7c39be90bf654a8da0f53f6682d965426d081Richard Smith        MockWrite(ASYNC, kOkRequest, arraysize(kOkRequest)) };
264e7d7c39be90bf654a8da0f53f6682d965426d081Richard Smith    MockRead data_reads[] = {
265e7d7c39be90bf654a8da0f53f6682d965426d081Richard Smith        MockRead(ASYNC, kSOCKS5GreetResponse, kSOCKS5GreetResponseLength),
266e7d7c39be90bf654a8da0f53f6682d965426d081Richard Smith        MockRead(ASYNC, kSOCKS5OkResponse, kSOCKS5OkResponseLength) };
267e7d7c39be90bf654a8da0f53f6682d965426d081Richard Smith    user_sock_ = BuildMockSocket(data_reads, arraysize(data_reads),
268e7d7c39be90bf654a8da0f53f6682d965426d081Richard Smith                                 data_writes, arraysize(data_writes),
269e7d7c39be90bf654a8da0f53f6682d965426d081Richard Smith                                 hostname, 80, &net_log_);
270e7d7c39be90bf654a8da0f53f6682d965426d081Richard Smith    int rv = user_sock_->Connect(callback_.callback());
271e7d7c39be90bf654a8da0f53f6682d965426d081Richard Smith    EXPECT_EQ(ERR_IO_PENDING, rv);
272e7d7c39be90bf654a8da0f53f6682d965426d081Richard Smith
273e7d7c39be90bf654a8da0f53f6682d965426d081Richard Smith    CapturingNetLog::CapturedEntryList net_log_entries;
274e7d7c39be90bf654a8da0f53f6682d965426d081Richard Smith    net_log_.GetEntries(&net_log_entries);
275b9c64d84ea3edd5e2fffb0a2e85ca1308be4f429Richard Smith    EXPECT_TRUE(LogContainsBeginEvent(net_log_entries, 0,
276b9c64d84ea3edd5e2fffb0a2e85ca1308be4f429Richard Smith                NetLog::TYPE_SOCKS5_CONNECT));
277b9c64d84ea3edd5e2fffb0a2e85ca1308be4f429Richard Smith
278b9c64d84ea3edd5e2fffb0a2e85ca1308be4f429Richard Smith    rv = callback_.WaitForResult();
279b9c64d84ea3edd5e2fffb0a2e85ca1308be4f429Richard Smith    EXPECT_EQ(OK, rv);
280e7d7c39be90bf654a8da0f53f6682d965426d081Richard Smith    EXPECT_TRUE(user_sock_->IsConnected());
28195aafb2453e1fecec8dcfd9e125cd78277f45859Richard Smith
28295aafb2453e1fecec8dcfd9e125cd78277f45859Richard Smith    net_log_.GetEntries(&net_log_entries);
28395aafb2453e1fecec8dcfd9e125cd78277f45859Richard Smith    EXPECT_TRUE(LogContainsEndEvent(net_log_entries, -1,
28495aafb2453e1fecec8dcfd9e125cd78277f45859Richard Smith                NetLog::TYPE_SOCKS5_CONNECT));
28595aafb2453e1fecec8dcfd9e125cd78277f45859Richard Smith  }
28695aafb2453e1fecec8dcfd9e125cd78277f45859Richard Smith
2870e9e9814a7f8313c0c02b6afea71f0e4c411873eRichard Smith  // Test for partial greet response read
2880e9e9814a7f8313c0c02b6afea71f0e4c411873eRichard Smith  {
2890e9e9814a7f8313c0c02b6afea71f0e4c411873eRichard Smith    const char partial1[] = { 0x05 };
2900e9e9814a7f8313c0c02b6afea71f0e4c411873eRichard Smith    const char partial2[] = { 0x00 };
2910e9e9814a7f8313c0c02b6afea71f0e4c411873eRichard Smith    MockWrite data_writes[] = {
2920e9e9814a7f8313c0c02b6afea71f0e4c411873eRichard Smith        MockWrite(ASYNC, kSOCKS5GreetRequest, kSOCKS5GreetRequestLength),
2930e9e9814a7f8313c0c02b6afea71f0e4c411873eRichard Smith        MockWrite(ASYNC, kOkRequest, arraysize(kOkRequest)) };
2940e9e9814a7f8313c0c02b6afea71f0e4c411873eRichard Smith    MockRead data_reads[] = {
2950e9e9814a7f8313c0c02b6afea71f0e4c411873eRichard Smith        MockRead(ASYNC, partial1, arraysize(partial1)),
2960e9e9814a7f8313c0c02b6afea71f0e4c411873eRichard Smith        MockRead(ASYNC, partial2, arraysize(partial2)),
2970e9e9814a7f8313c0c02b6afea71f0e4c411873eRichard Smith        MockRead(ASYNC, kSOCKS5OkResponse, kSOCKS5OkResponseLength) };
2980e9e9814a7f8313c0c02b6afea71f0e4c411873eRichard Smith    user_sock_ = BuildMockSocket(data_reads, arraysize(data_reads),
2990e9e9814a7f8313c0c02b6afea71f0e4c411873eRichard Smith                                 data_writes, arraysize(data_writes),
3000e9e9814a7f8313c0c02b6afea71f0e4c411873eRichard Smith                                 hostname, 80, &net_log_);
3010e9e9814a7f8313c0c02b6afea71f0e4c411873eRichard Smith    int rv = user_sock_->Connect(callback_.callback());
3020e9e9814a7f8313c0c02b6afea71f0e4c411873eRichard Smith    EXPECT_EQ(ERR_IO_PENDING, rv);
3030e9e9814a7f8313c0c02b6afea71f0e4c411873eRichard Smith
304d390de9c6312684c5e5b333f434199e193c7467aRichard Smith    CapturingNetLog::CapturedEntryList net_log_entries;
305d390de9c6312684c5e5b333f434199e193c7467aRichard Smith    net_log_.GetEntries(&net_log_entries);
306d390de9c6312684c5e5b333f434199e193c7467aRichard Smith    EXPECT_TRUE(LogContainsBeginEvent(net_log_entries, 0,
307d390de9c6312684c5e5b333f434199e193c7467aRichard Smith                                      NetLog::TYPE_SOCKS5_CONNECT));
308d390de9c6312684c5e5b333f434199e193c7467aRichard Smith    rv = callback_.WaitForResult();
309d390de9c6312684c5e5b333f434199e193c7467aRichard Smith    EXPECT_EQ(OK, rv);
310d390de9c6312684c5e5b333f434199e193c7467aRichard Smith    EXPECT_TRUE(user_sock_->IsConnected());
311d390de9c6312684c5e5b333f434199e193c7467aRichard Smith    net_log_.GetEntries(&net_log_entries);
312d390de9c6312684c5e5b333f434199e193c7467aRichard Smith    EXPECT_TRUE(LogContainsEndEvent(net_log_entries, -1,
31326b75c07317a3b50a8a00a1623e3ef38af1d8349Richard Smith                                    NetLog::TYPE_SOCKS5_CONNECT));
31426b75c07317a3b50a8a00a1623e3ef38af1d8349Richard Smith  }
31526b75c07317a3b50a8a00a1623e3ef38af1d8349Richard Smith
31626b75c07317a3b50a8a00a1623e3ef38af1d8349Richard Smith  // Test for partial handshake request write.
31726b75c07317a3b50a8a00a1623e3ef38af1d8349Richard Smith  {
31826b75c07317a3b50a8a00a1623e3ef38af1d8349Richard Smith    const int kSplitPoint = 3;  // Break handshake write into two parts.
31926b75c07317a3b50a8a00a1623e3ef38af1d8349Richard Smith    MockWrite data_writes[] = {
320b4051e7047a0085f0679257386ff183aed3e5162Richard Smith        MockWrite(ASYNC, kSOCKS5GreetRequest, kSOCKS5GreetRequestLength),
321b4051e7047a0085f0679257386ff183aed3e5162Richard Smith        MockWrite(ASYNC, kOkRequest, kSplitPoint),
322b4051e7047a0085f0679257386ff183aed3e5162Richard Smith        MockWrite(ASYNC, kOkRequest + kSplitPoint,
323b4051e7047a0085f0679257386ff183aed3e5162Richard Smith                  arraysize(kOkRequest) - kSplitPoint)
324b4051e7047a0085f0679257386ff183aed3e5162Richard Smith    };
325b4051e7047a0085f0679257386ff183aed3e5162Richard Smith    MockRead data_reads[] = {
326b4051e7047a0085f0679257386ff183aed3e5162Richard Smith        MockRead(ASYNC, kSOCKS5GreetResponse, kSOCKS5GreetResponseLength),
327b4051e7047a0085f0679257386ff183aed3e5162Richard Smith        MockRead(ASYNC, kSOCKS5OkResponse, kSOCKS5OkResponseLength) };
32886e6fdcf1a04edc4c24f53f9dbacf7e1b52f306dRichard Smith    user_sock_ = BuildMockSocket(data_reads, arraysize(data_reads),
32986e6fdcf1a04edc4c24f53f9dbacf7e1b52f306dRichard Smith                                 data_writes, arraysize(data_writes),
33086e6fdcf1a04edc4c24f53f9dbacf7e1b52f306dRichard Smith                                 hostname, 80, &net_log_);
33186e6fdcf1a04edc4c24f53f9dbacf7e1b52f306dRichard Smith    int rv = user_sock_->Connect(callback_.callback());
33286e6fdcf1a04edc4c24f53f9dbacf7e1b52f306dRichard Smith    EXPECT_EQ(ERR_IO_PENDING, rv);
33386e6fdcf1a04edc4c24f53f9dbacf7e1b52f306dRichard Smith    CapturingNetLog::CapturedEntryList net_log_entries;
33486e6fdcf1a04edc4c24f53f9dbacf7e1b52f306dRichard Smith    net_log_.GetEntries(&net_log_entries);
33586e6fdcf1a04edc4c24f53f9dbacf7e1b52f306dRichard Smith    EXPECT_TRUE(LogContainsBeginEvent(net_log_entries, 0,
3362cd7f41f4eb2b02568664132253f8e1d9cf381ddBenjamin Kramer                                      NetLog::TYPE_SOCKS5_CONNECT));
3372cd7f41f4eb2b02568664132253f8e1d9cf381ddBenjamin Kramer    rv = callback_.WaitForResult();
3382cd7f41f4eb2b02568664132253f8e1d9cf381ddBenjamin Kramer    EXPECT_EQ(OK, rv);
339ac71351acdefc9de0c770c1d717e621ac9e684bfRichard Smith    EXPECT_TRUE(user_sock_->IsConnected());
340ac71351acdefc9de0c770c1d717e621ac9e684bfRichard Smith    net_log_.GetEntries(&net_log_entries);
3412cd7f41f4eb2b02568664132253f8e1d9cf381ddBenjamin Kramer    EXPECT_TRUE(LogContainsEndEvent(net_log_entries, -1,
3422cd7f41f4eb2b02568664132253f8e1d9cf381ddBenjamin Kramer                                    NetLog::TYPE_SOCKS5_CONNECT));
3432cd7f41f4eb2b02568664132253f8e1d9cf381ddBenjamin Kramer  }
3442cd7f41f4eb2b02568664132253f8e1d9cf381ddBenjamin Kramer
3452cd7f41f4eb2b02568664132253f8e1d9cf381ddBenjamin Kramer  // Test for partial handshake response read
3462cd7f41f4eb2b02568664132253f8e1d9cf381ddBenjamin Kramer  {
347e5e8f4d2db48ec21f537fd6452276c1fe26bc726Benjamin Kramer    const int kSplitPoint = 6;  // Break the handshake read into two parts.
348e5e8f4d2db48ec21f537fd6452276c1fe26bc726Benjamin Kramer    MockWrite data_writes[] = {
349e5e8f4d2db48ec21f537fd6452276c1fe26bc726Benjamin Kramer        MockWrite(ASYNC, kSOCKS5GreetRequest, kSOCKS5GreetRequestLength),
350ac71351acdefc9de0c770c1d717e621ac9e684bfRichard Smith        MockWrite(ASYNC, kOkRequest, arraysize(kOkRequest))
351ac71351acdefc9de0c770c1d717e621ac9e684bfRichard Smith    };
352e5e8f4d2db48ec21f537fd6452276c1fe26bc726Benjamin Kramer    MockRead data_reads[] = {
353e5e8f4d2db48ec21f537fd6452276c1fe26bc726Benjamin Kramer        MockRead(ASYNC, kSOCKS5GreetResponse, kSOCKS5GreetResponseLength),
354e5e8f4d2db48ec21f537fd6452276c1fe26bc726Benjamin Kramer        MockRead(ASYNC, kSOCKS5OkResponse, kSplitPoint),
355ac71351acdefc9de0c770c1d717e621ac9e684bfRichard Smith        MockRead(ASYNC, kSOCKS5OkResponse + kSplitPoint,
356e5e8f4d2db48ec21f537fd6452276c1fe26bc726Benjamin Kramer                 kSOCKS5OkResponseLength - kSplitPoint)
357e5e8f4d2db48ec21f537fd6452276c1fe26bc726Benjamin Kramer    };
358e5e8f4d2db48ec21f537fd6452276c1fe26bc726Benjamin Kramer
359e5e8f4d2db48ec21f537fd6452276c1fe26bc726Benjamin Kramer    user_sock_ = BuildMockSocket(data_reads, arraysize(data_reads),
360e5e8f4d2db48ec21f537fd6452276c1fe26bc726Benjamin Kramer                                 data_writes, arraysize(data_writes),
361e5e8f4d2db48ec21f537fd6452276c1fe26bc726Benjamin Kramer                                 hostname, 80, &net_log_);
362e5e8f4d2db48ec21f537fd6452276c1fe26bc726Benjamin Kramer    int rv = user_sock_->Connect(callback_.callback());
363ccc4f283cf0e892e19a097a2aa4ec4491682b15fDouglas Gregor    EXPECT_EQ(ERR_IO_PENDING, rv);
364ccc4f283cf0e892e19a097a2aa4ec4491682b15fDouglas Gregor    CapturingNetLog::CapturedEntryList net_log_entries;
365ac71351acdefc9de0c770c1d717e621ac9e684bfRichard Smith    net_log_.GetEntries(&net_log_entries);
366ccc4f283cf0e892e19a097a2aa4ec4491682b15fDouglas Gregor    EXPECT_TRUE(LogContainsBeginEvent(net_log_entries, 0,
367ac71351acdefc9de0c770c1d717e621ac9e684bfRichard Smith                                      NetLog::TYPE_SOCKS5_CONNECT));
368ccc4f283cf0e892e19a097a2aa4ec4491682b15fDouglas Gregor    rv = callback_.WaitForResult();
369ccc4f283cf0e892e19a097a2aa4ec4491682b15fDouglas Gregor    EXPECT_EQ(OK, rv);
370ccc4f283cf0e892e19a097a2aa4ec4491682b15fDouglas Gregor    EXPECT_TRUE(user_sock_->IsConnected());
371ccc4f283cf0e892e19a097a2aa4ec4491682b15fDouglas Gregor    net_log_.GetEntries(&net_log_entries);
372ccc4f283cf0e892e19a097a2aa4ec4491682b15fDouglas Gregor    EXPECT_TRUE(LogContainsEndEvent(net_log_entries, -1,
373ccc4f283cf0e892e19a097a2aa4ec4491682b15fDouglas Gregor                                    NetLog::TYPE_SOCKS5_CONNECT));
374ef4579cda09b73e3d4d98af48201da25adc29326Larisse Voufo  }
375ef4579cda09b73e3d4d98af48201da25adc29326Larisse Voufo}
376ef4579cda09b73e3d4d98af48201da25adc29326Larisse Voufo
377ef4579cda09b73e3d4d98af48201da25adc29326Larisse Voufo}  // namespace
378ef4579cda09b73e3d4d98af48201da25adc29326Larisse Voufo
379ef4579cda09b73e3d4d98af48201da25adc29326Larisse Voufo}  // namespace net
380ef4579cda09b73e3d4d98af48201da25adc29326Larisse Voufo