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