1 // Copyright 2018 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 "chrome/browser/chromeos/smb_client/discovery/netbios_host_locator.h"
6
7 #include "base/bind.h"
8 #include "base/test/simple_test_tick_clock.h"
9 #include "base/test/test_mock_time_task_runner.h"
10 #include "base/timer/timer.h"
11 #include "chrome/browser/chromeos/smb_client/discovery/fake_netbios_client.h"
12 #include "chrome/browser/chromeos/smb_client/smb_constants.h"
13 #include "chromeos/dbus/fake_smb_provider_client.h"
14 #include "net/base/ip_endpoint.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16
17 namespace chromeos {
18 namespace smb_client {
19 namespace {
20
21 // Helper method to create a NetworkInterface for testing.
CreateNetworkInterface(const net::IPAddress & address,uint32_t prefix_length,net::NetworkChangeNotifier::ConnectionType type)22 net::NetworkInterface CreateNetworkInterface(
23 const net::IPAddress& address,
24 uint32_t prefix_length,
25 net::NetworkChangeNotifier::ConnectionType type) {
26 net::NetworkInterface interface;
27 interface.address = address;
28 interface.prefix_length = prefix_length;
29 interface.type = type;
30 return interface;
31 }
32
CreateValidInterface()33 net::NetworkInterface CreateValidInterface() {
34 return CreateNetworkInterface(net::IPAddress::IPv4Localhost(), 0,
35 net::NetworkChangeNotifier::CONNECTION_WIFI);
36 }
37
GenerateInvalidInterface()38 net::NetworkInterface GenerateInvalidInterface() {
39 return CreateNetworkInterface(net::IPAddress::IPv4Localhost(), 0,
40 net::NetworkChangeNotifier::CONNECTION_3G);
41 }
42
GenerateInvalidInterfaceList(size_t num)43 net::NetworkInterfaceList GenerateInvalidInterfaceList(size_t num) {
44 return net::NetworkInterfaceList(num, GenerateInvalidInterface());
45 }
46
ExpectNoResults(bool success,const HostMap & hosts)47 void ExpectNoResults(bool success, const HostMap& hosts) {
48 EXPECT_TRUE(success);
49 EXPECT_TRUE(hosts.empty());
50 }
51
ExpectResultsEqual(const HostMap & expected,bool success,const HostMap & actual)52 void ExpectResultsEqual(const HostMap& expected,
53 bool success,
54 const HostMap& actual) {
55 EXPECT_TRUE(success);
56 EXPECT_EQ(expected, actual);
57 }
58
ExpectFailure(bool success,const HostMap & hosts)59 void ExpectFailure(bool success, const HostMap& hosts) {
60 EXPECT_FALSE(success);
61 EXPECT_TRUE(hosts.empty());
62 }
63
64 } // namespace
65
66 class NetBiosHostLocatorTest : public testing::Test {
67 public:
NetBiosHostLocatorTest()68 NetBiosHostLocatorTest() {
69 // Fake SmbProviderClient that simulates the parsing of NetBios response
70 // packets.
71 fake_provider_client_ = std::make_unique<FakeSmbProviderClient>();
72 // Bound function to get interfaces. For testing we generate a valid
73 // interface for each NetBiosClient in the test so that the correct number
74 // of NetBiosClients are created.
75 get_interfaces_ =
76 base::BindRepeating(&NetBiosHostLocatorTest::GenerateValidInterfaces,
77 base::Unretained(this));
78 // NetBiosClientFactory. Creates a FakeNetBiosClient using the fake response
79 // data in |clients_data_|, if any exists.
80 client_factory_ = base::BindRepeating(
81 &NetBiosHostLocatorTest::NetBiosClientFactory, base::Unretained(this));
82
83 // Set up taskrunner and timer.
84 task_runner_ = base::MakeRefCounted<base::TestMockTimeTaskRunner>();
85 timer_ =
86 std::make_unique<base::OneShotTimer>(task_runner_->GetMockTickClock());
87 timer_->SetTaskRunner(task_runner_);
88
89 // Callback used for setting |has_returned_|.
90 set_true_on_returned_callback_ = base::BindOnce(
91 &NetBiosHostLocatorTest::SetTrueOnReturned, base::Unretained(this));
92 }
93
94 ~NetBiosHostLocatorTest() override = default;
95
96 protected:
97 using Packet = std::vector<uint8_t>;
98 using Hostnames = std::vector<std::string>;
99
100 // Adds the data for one NetBiosClient. The NetBiosClient will return an
101 // <IPEndpoint, packet>, for each response and this packet can be parsed by
102 // FakeSmbProviderClient returning the hostnames. A |packet_id| is used to
103 // correlate the packet that will be returned by the FakeNetBiosClient and
104 // the Hostnames that the FakeSmbProviderClient should return.
AddNetBiosClient(const std::map<net::IPEndPoint,Hostnames> & responses)105 void AddNetBiosClient(const std::map<net::IPEndPoint, Hostnames>& responses) {
106 std::map<net::IPEndPoint, Packet> client_data;
107 for (const auto& kv : responses) {
108 client_data[kv.first] = Packet{packet_id_};
109 fake_provider_client_->AddNetBiosPacketParsingForTesting(packet_id_,
110 kv.second);
111 ++packet_id_;
112 }
113 clients_data_.push_back(std::move(client_data));
114 }
115
116 bool has_returned_ = false;
117 FindHostsCallback set_true_on_returned_callback_;
118 scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
119 std::unique_ptr<base::OneShotTimer> timer_;
120 NetBiosHostLocator::GetInterfacesFunction get_interfaces_;
121 NetBiosHostLocator::NetBiosClientFactory client_factory_;
122 std::unique_ptr<FakeSmbProviderClient> fake_provider_client_;
123 std::unique_ptr<NetBiosHostLocator> host_locator_;
124
125 private:
126 // Creates valid interfaces such that there is one valid interface for each
127 // NetBios Client that needs to be created.
GenerateValidInterfaces()128 net::NetworkInterfaceList GenerateValidInterfaces() {
129 return net::NetworkInterfaceList(clients_data_.size(),
130 CreateValidInterface());
131 }
132
133 // Factory Function for FakeNetBiosClient. Returns a pointer to a
134 // FakeNetBiosClient preloaded with corresponding data from |clients_data|.
NetBiosClientFactory()135 std::unique_ptr<NetBiosClientInterface> NetBiosClientFactory() {
136 if (current_client < clients_data_.size()) {
137 return std::make_unique<FakeNetBiosClient>(
138 clients_data_[current_client++]);
139 }
140 return std::make_unique<FakeNetBiosClient>();
141 }
142
143 // Callback for FindHosts that sets |has_returned_| to true when called.
SetTrueOnReturned(bool success,const HostMap & results)144 void SetTrueOnReturned(bool success, const HostMap& results) {
145 DCHECK(!has_returned_);
146 has_returned_ = true;
147 }
148
149 uint8_t packet_id_ = 0;
150 uint8_t current_client = 0;
151 // Each entry in the vector represents on Netbios Client that can be created.
152 // Each entry in the map represents an IP, packet pair that should be returned
153 // by that NetBiosClient.
154 std::vector<std::map<net::IPEndPoint, Packet>> clients_data_;
155
156 DISALLOW_COPY_AND_ASSIGN(NetBiosHostLocatorTest);
157 };
158
159 // Calculate broadcast address correctly calculates the broadcast address
160 // of a NetworkInterface.
TEST_F(NetBiosHostLocatorTest,CalculateBroadcastAddress)161 TEST_F(NetBiosHostLocatorTest, CalculateBroadcastAddress) {
162 const net::NetworkInterface interface = CreateNetworkInterface(
163 net::IPAddress(192, 168, 50, 152), 24 /* prefix_length */,
164 net::NetworkChangeNotifier::CONNECTION_WIFI);
165
166 EXPECT_EQ(net::IPAddress(192, 168, 50, 255),
167 CalculateBroadcastAddress(interface));
168 }
169
170 // ShouldUseInterface returns true for Wifi and Ethernet interfaces but false
171 // for other types of interfaces.
TEST_F(NetBiosHostLocatorTest,ShouldUseWifiAndEthernetInterfaces)172 TEST_F(NetBiosHostLocatorTest, ShouldUseWifiAndEthernetInterfaces) {
173 const net::NetworkInterface interface_wifi = CreateNetworkInterface(
174 net::IPAddress::IPv4Localhost(), 24 /* prefix_length */,
175 net::NetworkChangeNotifier::CONNECTION_WIFI);
176
177 const net::NetworkInterface interface_ethernet = CreateNetworkInterface(
178 net::IPAddress::IPv4Localhost(), 24 /* prefix_length */,
179 net::NetworkChangeNotifier::CONNECTION_WIFI);
180
181 const net::NetworkInterface interface_bluetooth = CreateNetworkInterface(
182 net::IPAddress::IPv4Localhost(), 24 /* prefix_length */,
183 net::NetworkChangeNotifier::CONNECTION_BLUETOOTH);
184
185 EXPECT_TRUE(ShouldUseInterface(interface_wifi));
186 EXPECT_TRUE(ShouldUseInterface(interface_ethernet));
187 EXPECT_FALSE(ShouldUseInterface(interface_bluetooth));
188 }
189
190 // ShouldUseInterface returns true for IPv4 interfaces but false for IPv6
191 // interfaces.
TEST_F(NetBiosHostLocatorTest,OnlyProcessIPv4Interfaces)192 TEST_F(NetBiosHostLocatorTest, OnlyProcessIPv4Interfaces) {
193 const net::NetworkInterface interface_ipv4 = CreateNetworkInterface(
194 net::IPAddress::IPv4Localhost(), 24 /* prefix_length */,
195 net::NetworkChangeNotifier::CONNECTION_WIFI);
196
197 const net::NetworkInterface interface_ipv6 = CreateNetworkInterface(
198 net::IPAddress::IPv6Localhost(), 24 /* prefix_length */,
199 net::NetworkChangeNotifier::CONNECTION_WIFI);
200
201 EXPECT_TRUE(ShouldUseInterface(interface_ipv4));
202 EXPECT_FALSE(ShouldUseInterface(interface_ipv6));
203 }
204
205 // One interface that receives no responses properly returns no results.
TEST_F(NetBiosHostLocatorTest,OneInterfaceNoResults)206 TEST_F(NetBiosHostLocatorTest, OneInterfaceNoResults) {
207 // Add the entry for a NetBios Client that returns no packets.
208 AddNetBiosClient(std::map<net::IPEndPoint, Hostnames>());
209
210 host_locator_ = std::make_unique<NetBiosHostLocator>(
211 get_interfaces_, client_factory_, fake_provider_client_.get(),
212 std::move(timer_));
213
214 host_locator_->FindHosts(base::BindOnce(&ExpectNoResults));
215 task_runner_->FastForwardBy(
216 base::TimeDelta::FromSeconds(kNetBiosDiscoveryTimeoutSeconds));
217 }
218
219 // Two interfaces that receive no responses properly return no results.
TEST_F(NetBiosHostLocatorTest,MultipleInterfacesNoResults)220 TEST_F(NetBiosHostLocatorTest, MultipleInterfacesNoResults) {
221 // Create two NetBiosClients that don't return any packets.
222 AddNetBiosClient(std::map<net::IPEndPoint, Hostnames>());
223 AddNetBiosClient(std::map<net::IPEndPoint, Hostnames>());
224
225 host_locator_ = std::make_unique<NetBiosHostLocator>(
226 get_interfaces_, client_factory_, fake_provider_client_.get(),
227 std::move(timer_));
228
229 host_locator_->FindHosts(base::BindOnce(&ExpectNoResults));
230
231 // Fast forward timer so that callback fires.
232 task_runner_->FastForwardBy(
233 base::TimeDelta::FromSeconds(kNetBiosDiscoveryTimeoutSeconds));
234 }
235
236 // One interface that recieves responses from two different ip addresses
237 // returns the correct results.
TEST_F(NetBiosHostLocatorTest,OneInterfaceWithResults)238 TEST_F(NetBiosHostLocatorTest, OneInterfaceWithResults) {
239 // Build data for a NetBiosClient
240 const net::IPEndPoint source_ip_1(net::IPAddress(1, 2, 3, 4), 137);
241 const Hostnames hostnames_1 = {"hostname1", "HOSTNAME_2"};
242
243 const net::IPEndPoint source_ip_2(net::IPAddress(2, 4, 6, 8), 137);
244 const Hostnames hostnames_2 = {"host.name.3"};
245
246 std::map<net::IPEndPoint, Hostnames> netbios_client_1;
247 netbios_client_1[source_ip_1] = hostnames_1;
248 netbios_client_1[source_ip_2] = hostnames_2;
249
250 // Build the map of expected results.
251 HostMap expected_results;
252 expected_results[hostnames_1[0]] = source_ip_1.address();
253 expected_results[hostnames_1[1]] = source_ip_1.address();
254 expected_results[hostnames_2[0]] = source_ip_2.address();
255
256 // Add the entry for a NetBios Client that returns packets.
257 AddNetBiosClient(netbios_client_1);
258
259 host_locator_ = std::make_unique<NetBiosHostLocator>(
260 get_interfaces_, client_factory_, fake_provider_client_.get(),
261 std::move(timer_));
262
263 host_locator_->FindHosts(
264 base::BindOnce(&ExpectResultsEqual, expected_results));
265 task_runner_->FastForwardBy(
266 base::TimeDelta::FromSeconds(kNetBiosDiscoveryTimeoutSeconds));
267 }
268
269 // Two interfaces that each receive responses from multiple ip addresses
270 // correctly returns results.
TEST_F(NetBiosHostLocatorTest,MultipleInterfacesWithResults)271 TEST_F(NetBiosHostLocatorTest, MultipleInterfacesWithResults) {
272 // Build data for the first NetBiosClient
273 const net::IPEndPoint source_ip_1(net::IPAddress(1, 2, 3, 4), 137);
274 const Hostnames hostnames_1 = {"hostname1", "HOSTNAME_2"};
275
276 const net::IPEndPoint source_ip_2(net::IPAddress(2, 4, 6, 8), 137);
277 const Hostnames hostnames_2 = {"host.name.3"};
278
279 std::map<net::IPEndPoint, Hostnames> netbios_client_1;
280 netbios_client_1[source_ip_1] = hostnames_1;
281 netbios_client_1[source_ip_2] = hostnames_2;
282
283 // Build data for the second NetBiosClient
284 const net::IPEndPoint source_ip_3(net::IPAddress(1, 3, 5, 9), 137);
285 const Hostnames hostnames_3 = {"host name 4"};
286
287 const net::IPEndPoint source_ip_4(net::IPAddress(2, 4, 8, 16), 137);
288 const Hostnames hostnames_4 = {"hOsTnAmE-5"};
289
290 std::map<net::IPEndPoint, Hostnames> netbios_client_2;
291 netbios_client_2[source_ip_3] = hostnames_3;
292 netbios_client_2[source_ip_4] = hostnames_4;
293
294 // Build the map of expected results.
295 HostMap expected_results;
296 expected_results[hostnames_1[0]] = source_ip_1.address();
297 expected_results[hostnames_1[1]] = source_ip_1.address();
298 expected_results[hostnames_2[0]] = source_ip_2.address();
299 expected_results[hostnames_3[0]] = source_ip_3.address();
300 expected_results[hostnames_4[0]] = source_ip_4.address();
301
302 // Add the entry for a NetBios Clients that return packets.
303 AddNetBiosClient(netbios_client_1);
304 AddNetBiosClient(netbios_client_2);
305
306 host_locator_ = std::make_unique<NetBiosHostLocator>(
307 get_interfaces_, client_factory_, fake_provider_client_.get(),
308 std::move(timer_));
309
310 host_locator_->FindHosts(
311 base::BindOnce(&ExpectResultsEqual, expected_results));
312 task_runner_->FastForwardBy(
313 base::TimeDelta::FromSeconds(kNetBiosDiscoveryTimeoutSeconds));
314 }
315
316 // Results are not duplicated when multiple interfaces receive the same response
317 // from one source.
TEST_F(NetBiosHostLocatorTest,MultipleInterfacesWithDuplicateResults)318 TEST_F(NetBiosHostLocatorTest, MultipleInterfacesWithDuplicateResults) {
319 // Build data for the first NetBiosClient.
320 const net::IPEndPoint source_ip_1(net::IPAddress(1, 2, 3, 4), 137);
321 const Hostnames hostnames_1 = {"hostname1", "HOSTNAME_2"};
322
323 const net::IPEndPoint source_ip_2(net::IPAddress(2, 4, 6, 8), 137);
324 const Hostnames hostnames_2 = {"host.name.3"};
325
326 std::map<net::IPEndPoint, Hostnames> netbios_client_1;
327 netbios_client_1[source_ip_1] = hostnames_1;
328 netbios_client_1[source_ip_2] = hostnames_2;
329
330 // Build data for the second NetBiosClient which also recieves the response
331 // from |source_ip_2|.
332 const net::IPEndPoint source_ip_4(net::IPAddress(2, 4, 8, 16), 137);
333 const Hostnames hostnames_4 = {"hOsTnAmE-5"};
334
335 std::map<net::IPEndPoint, Hostnames> netbios_client_2;
336 netbios_client_2[source_ip_2] = hostnames_2;
337 netbios_client_2[source_ip_4] = hostnames_4;
338
339 // Build the map of expected results.
340 HostMap expected_results;
341 expected_results[hostnames_1[0]] = source_ip_1.address();
342 expected_results[hostnames_1[1]] = source_ip_1.address();
343 expected_results[hostnames_2[0]] = source_ip_2.address();
344 expected_results[hostnames_4[0]] = source_ip_4.address();
345
346 // Add the entry for a NetBios Clients that return packets.
347 AddNetBiosClient(netbios_client_1);
348 AddNetBiosClient(netbios_client_2);
349
350 host_locator_ = std::make_unique<NetBiosHostLocator>(
351 get_interfaces_, client_factory_, fake_provider_client_.get(),
352 std::move(timer_));
353
354 host_locator_->FindHosts(
355 base::BindOnce(&ExpectResultsEqual, expected_results));
356 task_runner_->FastForwardBy(
357 base::TimeDelta::FromSeconds(kNetBiosDiscoveryTimeoutSeconds));
358 }
359
TEST_F(NetBiosHostLocatorTest,ResultsNotReturnedUntilTimer)360 TEST_F(NetBiosHostLocatorTest, ResultsNotReturnedUntilTimer) {
361 // Build data for a NetBiosClient
362 const net::IPEndPoint source_ip_1(net::IPAddress(1, 2, 3, 4), 137);
363 const Hostnames hostnames_1 = {"hostname1", "HOSTNAME_2"};
364
365 const net::IPEndPoint source_ip_2(net::IPAddress(2, 4, 6, 8), 137);
366 const Hostnames hostnames_2 = {"host.name.3"};
367
368 std::map<net::IPEndPoint, Hostnames> netbios_client_1;
369 netbios_client_1[source_ip_1] = hostnames_1;
370 netbios_client_1[source_ip_2] = hostnames_2;
371
372 // Build the map of expected results.
373 HostMap expected_results;
374 expected_results[hostnames_1[0]] = source_ip_1.address();
375 expected_results[hostnames_1[1]] = source_ip_1.address();
376 expected_results[hostnames_2[0]] = source_ip_2.address();
377
378 // Add the entry for a NetBios Client that returns packets.
379 AddNetBiosClient(netbios_client_1);
380
381 host_locator_ = std::make_unique<NetBiosHostLocator>(
382 get_interfaces_, client_factory_, fake_provider_client_.get(),
383 std::move(timer_));
384
385 host_locator_->FindHosts(std::move(set_true_on_returned_callback_));
386 task_runner_->FastForwardBy(
387 base::TimeDelta::FromSeconds(kNetBiosDiscoveryTimeoutSeconds) -
388 base::TimeDelta::FromMilliseconds(1));
389 EXPECT_FALSE(has_returned_);
390 task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(1));
391 EXPECT_TRUE(has_returned_);
392 }
393
TEST_F(NetBiosHostLocatorTest,NoValidInterfacesReturnsNoResults)394 TEST_F(NetBiosHostLocatorTest, NoValidInterfacesReturnsNoResults) {
395 auto get_invalid_interfaces_ =
396 base::BindRepeating(&GenerateInvalidInterfaceList, 3 /* num */);
397
398 host_locator_ = std::make_unique<NetBiosHostLocator>(
399 get_invalid_interfaces_, client_factory_, fake_provider_client_.get(),
400 std::move(timer_));
401
402 host_locator_->FindHosts(base::BindOnce(&ExpectFailure));
403 }
404
TEST_F(NetBiosHostLocatorTest,SecondIPUsedForResults)405 TEST_F(NetBiosHostLocatorTest, SecondIPUsedForResults) {
406 const std::string duplicate_hostname = "duplicate";
407
408 // Build data for the first NetBiosClient.
409 const net::IPEndPoint source_ip_1(net::IPAddress(1, 2, 3, 4), 137);
410 const Hostnames hostnames_1 = {duplicate_hostname};
411
412 std::map<net::IPEndPoint, Hostnames> netbios_client_1;
413 netbios_client_1[source_ip_1] = hostnames_1;
414
415 // Build data for the second NetBiosClient which also recieves the response
416 // from |source_ip_2|.
417 const net::IPEndPoint source_ip_2(net::IPAddress(2, 4, 8, 16), 137);
418 const Hostnames hostnames_2 = {duplicate_hostname};
419
420 std::map<net::IPEndPoint, Hostnames> netbios_client_2;
421 netbios_client_2[source_ip_2] = hostnames_2;
422
423 // Build the map of expected results.
424 HostMap expected_results;
425 expected_results[duplicate_hostname] = source_ip_2.address();
426
427 // Add the entry for a NetBios Clients that return packets.
428 AddNetBiosClient(netbios_client_1);
429 AddNetBiosClient(netbios_client_2);
430
431 host_locator_ = std::make_unique<NetBiosHostLocator>(
432 get_interfaces_, client_factory_, fake_provider_client_.get(),
433 std::move(timer_));
434
435 host_locator_->FindHosts(
436 base::BindOnce(&ExpectResultsEqual, expected_results));
437 task_runner_->FastForwardBy(
438 base::TimeDelta::FromSeconds(kNetBiosDiscoveryTimeoutSeconds));
439 }
440
441 } // namespace smb_client
442 } // namespace chromeos
443