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.
4
5#include <map>
6#include <queue>
7#include <string>
8
9#include "base/bind.h"
10#include "base/callback.h"
11#include "base/logging.h"
12#include "base/memory/scoped_ptr.h"
13#include "base/message_loop/message_loop.h"
14#include "base/time/time.h"
15#include "chrome/browser/safe_browsing/client_side_detection_service.h"
16#include "chrome/common/safe_browsing/client_model.pb.h"
17#include "chrome/common/safe_browsing/csd.pb.h"
18#include "content/public/test/test_browser_thread.h"
19#include "crypto/sha2.h"
20#include "net/url_request/test_url_fetcher_factory.h"
21#include "net/url_request/url_request_status.h"
22#include "testing/gmock/include/gmock/gmock.h"
23#include "testing/gtest/include/gtest/gtest.h"
24#include "url/gurl.h"
25
26using ::testing::_;
27using ::testing::Invoke;
28using ::testing::Mock;
29using ::testing::StrictMock;
30using content::BrowserThread;
31
32namespace safe_browsing {
33namespace {
34class MockClientSideDetectionService : public ClientSideDetectionService {
35 public:
36  MockClientSideDetectionService() : ClientSideDetectionService(NULL) {}
37  virtual ~MockClientSideDetectionService() {}
38
39  MOCK_METHOD1(EndFetchModel, void(ClientModelStatus));
40  MOCK_METHOD1(ScheduleFetchModel, void(int64));
41
42  void Schedule(int64) {
43    // Ignore the delay when testing.
44    StartFetchModel();
45  }
46
47  void Disable(int) {
48    // Ignore the status.
49    SetEnabledAndRefreshState(false);
50  }
51
52 private:
53  DISALLOW_COPY_AND_ASSIGN(MockClientSideDetectionService);
54};
55
56ACTION(QuitCurrentMessageLoop) {
57  base::MessageLoop::current()->Quit();
58}
59
60}  // namespace
61
62class ClientSideDetectionServiceTest : public testing::Test {
63 protected:
64  virtual void SetUp() {
65    file_thread_.reset(new content::TestBrowserThread(BrowserThread::FILE,
66                                                      &msg_loop_));
67
68    factory_.reset(new net::FakeURLFetcherFactory(NULL));
69
70    browser_thread_.reset(new content::TestBrowserThread(BrowserThread::UI,
71                                                         &msg_loop_));
72  }
73
74  virtual void TearDown() {
75    msg_loop_.RunUntilIdle();
76    csd_service_.reset();
77    file_thread_.reset();
78    browser_thread_.reset();
79  }
80
81  bool SendClientReportPhishingRequest(const GURL& phishing_url,
82                                       float score) {
83    ClientPhishingRequest* request = new ClientPhishingRequest();
84    request->set_url(phishing_url.spec());
85    request->set_client_score(score);
86    request->set_is_phishing(true);  // client thinks the URL is phishing.
87    csd_service_->SendClientReportPhishingRequest(
88        request,
89        base::Bind(&ClientSideDetectionServiceTest::SendRequestDone,
90                   base::Unretained(this)));
91    phishing_url_ = phishing_url;
92    msg_loop_.Run();  // Waits until callback is called.
93    return is_phishing_;
94  }
95
96  bool SendClientReportMalwareRequest(const GURL& url) {
97    scoped_ptr<ClientMalwareRequest> request(new ClientMalwareRequest());
98    request->set_url(url.spec());
99    csd_service_->SendClientReportMalwareRequest(
100        request.release(),
101        base::Bind(&ClientSideDetectionServiceTest::SendMalwareRequestDone,
102                   base::Unretained(this)));
103    phishing_url_ = url;
104    msg_loop_.Run();  // Waits until callback is called.
105    return is_malware_;
106  }
107
108  void SetModelFetchResponse(std::string response_data, bool success) {
109    factory_->SetFakeResponse(ClientSideDetectionService::kClientModelUrl,
110                              response_data, success);
111  }
112
113  void SetClientReportPhishingResponse(std::string response_data,
114                                       bool success) {
115    factory_->SetFakeResponse(
116        ClientSideDetectionService::GetClientReportUrl(
117            ClientSideDetectionService::kClientReportPhishingUrl),
118        response_data, success);
119  }
120
121  void SetClientReportMalwareResponse(std::string response_data,
122                                      bool success) {
123    factory_->SetFakeResponse(
124        ClientSideDetectionService::GetClientReportUrl(
125            ClientSideDetectionService::kClientReportMalwareUrl),
126        response_data, success);
127  }
128
129  int GetNumReports(std::queue<base::Time>* report_times) {
130    return csd_service_->GetNumReports(report_times);
131  }
132
133  std::queue<base::Time>& GetPhishingReportTimes() {
134    return csd_service_->phishing_report_times_;
135  }
136
137  std::queue<base::Time>& GetMalwareReportTimes() {
138    return csd_service_->malware_report_times_;
139  }
140
141  void SetCache(const GURL& gurl, bool is_phishing, base::Time time) {
142    csd_service_->cache_[gurl] =
143        make_linked_ptr(new ClientSideDetectionService::CacheState(is_phishing,
144                                                                   time));
145  }
146
147  void TestCache() {
148    ClientSideDetectionService::PhishingCache& cache = csd_service_->cache_;
149    base::Time now = base::Time::Now();
150    base::Time time =
151        now - base::TimeDelta::FromDays(
152            ClientSideDetectionService::kNegativeCacheIntervalDays) +
153        base::TimeDelta::FromMinutes(5);
154    cache[GURL("http://first.url.com/")] =
155        make_linked_ptr(new ClientSideDetectionService::CacheState(false,
156                                                                   time));
157
158    time =
159        now - base::TimeDelta::FromDays(
160            ClientSideDetectionService::kNegativeCacheIntervalDays) -
161        base::TimeDelta::FromHours(1);
162    cache[GURL("http://second.url.com/")] =
163        make_linked_ptr(new ClientSideDetectionService::CacheState(false,
164                                                                   time));
165
166    time =
167        now - base::TimeDelta::FromMinutes(
168            ClientSideDetectionService::kPositiveCacheIntervalMinutes) -
169        base::TimeDelta::FromMinutes(5);
170    cache[GURL("http://third.url.com/")] =
171        make_linked_ptr(new ClientSideDetectionService::CacheState(true, time));
172
173    time =
174        now - base::TimeDelta::FromMinutes(
175            ClientSideDetectionService::kPositiveCacheIntervalMinutes) +
176        base::TimeDelta::FromMinutes(5);
177    cache[GURL("http://fourth.url.com/")] =
178        make_linked_ptr(new ClientSideDetectionService::CacheState(true, time));
179
180    csd_service_->UpdateCache();
181
182    // 3 elements should be in the cache, the first, third, and fourth.
183    EXPECT_EQ(3U, cache.size());
184    EXPECT_TRUE(cache.find(GURL("http://first.url.com/")) != cache.end());
185    EXPECT_TRUE(cache.find(GURL("http://third.url.com/")) != cache.end());
186    EXPECT_TRUE(cache.find(GURL("http://fourth.url.com/")) != cache.end());
187
188    // While 3 elements remain, only the first and the fourth are actually
189    // valid.
190    bool is_phishing;
191    EXPECT_TRUE(csd_service_->GetValidCachedResult(
192        GURL("http://first.url.com"), &is_phishing));
193    EXPECT_FALSE(is_phishing);
194    EXPECT_FALSE(csd_service_->GetValidCachedResult(
195        GURL("http://third.url.com"), &is_phishing));
196    EXPECT_TRUE(csd_service_->GetValidCachedResult(
197        GURL("http://fourth.url.com"), &is_phishing));
198    EXPECT_TRUE(is_phishing);
199  }
200
201  void AddFeature(const std::string& name, double value,
202                  ClientPhishingRequest* request) {
203    ClientPhishingRequest_Feature* feature = request->add_feature_map();
204    feature->set_name(name);
205    feature->set_value(value);
206  }
207
208  void AddNonModelFeature(const std::string& name, double value,
209                          ClientPhishingRequest* request) {
210    ClientPhishingRequest_Feature* feature =
211        request->add_non_model_feature_map();
212    feature->set_name(name);
213    feature->set_value(value);
214  }
215
216 protected:
217  scoped_ptr<ClientSideDetectionService> csd_service_;
218  scoped_ptr<net::FakeURLFetcherFactory> factory_;
219  base::MessageLoop msg_loop_;
220
221 private:
222  void SendRequestDone(GURL phishing_url, bool is_phishing) {
223    ASSERT_EQ(phishing_url, phishing_url_);
224    is_phishing_ = is_phishing;
225    msg_loop_.Quit();
226  }
227
228  void SendMalwareRequestDone(GURL url, bool is_malware) {
229    ASSERT_EQ(phishing_url_, url);
230    is_malware_ = is_malware;
231    msg_loop_.Quit();
232  }
233  scoped_ptr<content::TestBrowserThread> browser_thread_;
234  scoped_ptr<content::TestBrowserThread> file_thread_;
235
236  GURL phishing_url_;
237  bool is_phishing_;
238  bool is_malware_;
239};
240
241TEST_F(ClientSideDetectionServiceTest, FetchModelTest) {
242  // We don't want to use a real service class here because we can't call
243  // the real EndFetchModel.  It would reschedule a reload which might
244  // make the test flaky.
245  MockClientSideDetectionService service;
246  EXPECT_CALL(service, ScheduleFetchModel(_)).Times(1);
247  service.SetEnabledAndRefreshState(true);
248
249  // The model fetch failed.
250  SetModelFetchResponse("blamodel", false /* failure */);
251  EXPECT_CALL(service, EndFetchModel(
252      ClientSideDetectionService::MODEL_FETCH_FAILED))
253      .WillOnce(QuitCurrentMessageLoop());
254  service.StartFetchModel();
255  msg_loop_.Run();  // EndFetchModel will quit the message loop.
256  Mock::VerifyAndClearExpectations(&service);
257
258  // Empty model file.
259  SetModelFetchResponse(std::string(), true /* success */);
260  EXPECT_CALL(service, EndFetchModel(ClientSideDetectionService::MODEL_EMPTY))
261      .WillOnce(QuitCurrentMessageLoop());
262  service.StartFetchModel();
263  msg_loop_.Run();  // EndFetchModel will quit the message loop.
264  Mock::VerifyAndClearExpectations(&service);
265
266  // Model is too large.
267  SetModelFetchResponse(
268      std::string(ClientSideDetectionService::kMaxModelSizeBytes + 1, 'x'),
269      true /* success */);
270  EXPECT_CALL(service, EndFetchModel(
271      ClientSideDetectionService::MODEL_TOO_LARGE))
272      .WillOnce(QuitCurrentMessageLoop());
273  service.StartFetchModel();
274  msg_loop_.Run();  // EndFetchModel will quit the message loop.
275  Mock::VerifyAndClearExpectations(&service);
276
277  // Unable to parse the model file.
278  SetModelFetchResponse("Invalid model file", true /* success */);
279  EXPECT_CALL(service, EndFetchModel(
280      ClientSideDetectionService::MODEL_PARSE_ERROR))
281      .WillOnce(QuitCurrentMessageLoop());
282  service.StartFetchModel();
283  msg_loop_.Run();  // EndFetchModel will quit the message loop.
284  Mock::VerifyAndClearExpectations(&service);
285
286  // Model that is missing some required fields (missing the version field).
287  ClientSideModel model;
288  model.set_max_words_per_term(4);
289  SetModelFetchResponse(model.SerializePartialAsString(), true /* success */);
290  EXPECT_CALL(service, EndFetchModel(
291      ClientSideDetectionService::MODEL_MISSING_FIELDS))
292      .WillOnce(QuitCurrentMessageLoop());
293  service.StartFetchModel();
294  msg_loop_.Run();  // EndFetchModel will quit the message loop.
295  Mock::VerifyAndClearExpectations(&service);
296
297  // Model that points to hashes that don't exist.
298  model.set_version(10);
299  model.add_hashes("bla");
300  model.add_page_term(1);  // Should be 0 instead of 1.
301  SetModelFetchResponse(model.SerializePartialAsString(), true /* success */);
302  EXPECT_CALL(service, EndFetchModel(
303      ClientSideDetectionService::MODEL_BAD_HASH_IDS))
304      .WillOnce(QuitCurrentMessageLoop());
305  service.StartFetchModel();
306  msg_loop_.Run();  // EndFetchModel will quit the message loop.
307  Mock::VerifyAndClearExpectations(&service);
308  model.set_page_term(0, 0);
309
310  // Model version number is wrong.
311  model.set_version(-1);
312  SetModelFetchResponse(model.SerializeAsString(), true /* success */);
313  EXPECT_CALL(service, EndFetchModel(
314      ClientSideDetectionService::MODEL_INVALID_VERSION_NUMBER))
315      .WillOnce(QuitCurrentMessageLoop());
316  service.StartFetchModel();
317  msg_loop_.Run();  // EndFetchModel will quit the message loop.
318  Mock::VerifyAndClearExpectations(&service);
319
320  // Normal model.
321  model.set_version(10);
322  SetModelFetchResponse(model.SerializeAsString(), true /* success */);
323  EXPECT_CALL(service, EndFetchModel(
324      ClientSideDetectionService::MODEL_SUCCESS))
325      .WillOnce(QuitCurrentMessageLoop());
326  service.StartFetchModel();
327  msg_loop_.Run();  // EndFetchModel will quit the message loop.
328  Mock::VerifyAndClearExpectations(&service);
329
330  // Model version number is decreasing.  Set the model version number of the
331  // model that is currently loaded in the service object to 11.
332  service.model_.reset(new ClientSideModel(model));
333  service.model_->set_version(11);
334  SetModelFetchResponse(model.SerializeAsString(), true /* success */);
335  EXPECT_CALL(service, EndFetchModel(
336      ClientSideDetectionService::MODEL_INVALID_VERSION_NUMBER))
337      .WillOnce(QuitCurrentMessageLoop());
338  service.StartFetchModel();
339  msg_loop_.Run();  // EndFetchModel will quit the message loop.
340  Mock::VerifyAndClearExpectations(&service);
341
342  // Model version hasn't changed since the last reload.
343  service.model_->set_version(10);
344  SetModelFetchResponse(model.SerializeAsString(), true /* success */);
345  EXPECT_CALL(service, EndFetchModel(
346      ClientSideDetectionService::MODEL_NOT_CHANGED))
347      .WillOnce(QuitCurrentMessageLoop());
348  service.StartFetchModel();
349  msg_loop_.Run();  // EndFetchModel will quit the message loop.
350  Mock::VerifyAndClearExpectations(&service);
351}
352
353TEST_F(ClientSideDetectionServiceTest, ServiceObjectDeletedBeforeCallbackDone) {
354  SetModelFetchResponse("bogus model", true /* success */);
355  csd_service_.reset(ClientSideDetectionService::Create(NULL));
356  csd_service_->SetEnabledAndRefreshState(true);
357  EXPECT_TRUE(csd_service_.get() != NULL);
358  // We delete the client-side detection service class even though the callbacks
359  // haven't run yet.
360  csd_service_.reset();
361  // Waiting for the callbacks to run should not crash even if the service
362  // object is gone.
363  msg_loop_.RunUntilIdle();
364}
365
366TEST_F(ClientSideDetectionServiceTest, SendClientReportPhishingRequest) {
367  SetModelFetchResponse("bogus model", true /* success */);
368  csd_service_.reset(ClientSideDetectionService::Create(NULL));
369  csd_service_->SetEnabledAndRefreshState(true);
370
371  GURL url("http://a.com/");
372  float score = 0.4f;  // Some random client score.
373
374  base::Time before = base::Time::Now();
375
376  // Invalid response body from the server.
377  SetClientReportPhishingResponse("invalid proto response", true /* success */);
378  EXPECT_FALSE(SendClientReportPhishingRequest(url, score));
379
380  // Normal behavior.
381  ClientPhishingResponse response;
382  response.set_phishy(true);
383  SetClientReportPhishingResponse(response.SerializeAsString(),
384                                  true /* success */);
385  EXPECT_TRUE(SendClientReportPhishingRequest(url, score));
386
387  // This request will fail
388  GURL second_url("http://b.com/");
389  response.set_phishy(false);
390  SetClientReportPhishingResponse(response.SerializeAsString(),
391                                  false /* success */);
392  EXPECT_FALSE(SendClientReportPhishingRequest(second_url, score));
393
394  base::Time after = base::Time::Now();
395
396  // Check that we have recorded all 3 requests within the correct time range.
397  std::queue<base::Time>& report_times = GetPhishingReportTimes();
398  EXPECT_EQ(3U, report_times.size());
399  while (!report_times.empty()) {
400    base::Time time = report_times.back();
401    report_times.pop();
402    EXPECT_LE(before, time);
403    EXPECT_GE(after, time);
404  }
405
406  // Only the first url should be in the cache.
407  bool is_phishing;
408  EXPECT_TRUE(csd_service_->IsInCache(url));
409  EXPECT_TRUE(csd_service_->GetValidCachedResult(url, &is_phishing));
410  EXPECT_TRUE(is_phishing);
411  EXPECT_FALSE(csd_service_->IsInCache(second_url));
412}
413
414TEST_F(ClientSideDetectionServiceTest, SendClientReportMalwareRequest) {
415  SetModelFetchResponse("bogus model", true /* success */);
416  csd_service_.reset(ClientSideDetectionService::Create(NULL));
417  csd_service_->SetEnabledAndRefreshState(true);
418  GURL url("http://a.com/");
419
420  base::Time before = base::Time::Now();
421
422  // Invalid response body from the server.
423  SetClientReportMalwareResponse("invalid proto response", true /* success */);
424  EXPECT_FALSE(SendClientReportMalwareRequest(url));
425
426  // Normal behavior.
427  ClientMalwareResponse response;
428  response.set_blacklist(true);
429  SetClientReportMalwareResponse(response.SerializeAsString(), true);
430  EXPECT_TRUE(SendClientReportMalwareRequest(url));
431
432  // This request will fail
433  response.set_blacklist(false);
434  SetClientReportMalwareResponse(response.SerializeAsString(),
435                                 false /* success */);
436  EXPECT_FALSE(SendClientReportMalwareRequest(url));
437
438  // server blacklist decision is false, and response is succesful
439  response.set_blacklist(false);
440  SetClientReportMalwareResponse(response.SerializeAsString(), true);
441  EXPECT_FALSE(SendClientReportMalwareRequest(url));
442
443  // Check that we have recorded all 4 requests within the correct time range.
444  base::Time after = base::Time::Now();
445  std::queue<base::Time>& report_times = GetMalwareReportTimes();
446  EXPECT_EQ(4U, report_times.size());
447
448  // Another normal behavior will fail because of the limit is hit
449  response.set_blacklist(true);
450  SetClientReportMalwareResponse(response.SerializeAsString(), true);
451  EXPECT_FALSE(SendClientReportMalwareRequest(url));
452
453  report_times = GetMalwareReportTimes();
454  EXPECT_EQ(4U, report_times.size());
455  while (!report_times.empty()) {
456    base::Time time = report_times.back();
457    report_times.pop();
458    EXPECT_LE(before, time);
459    EXPECT_GE(after, time);
460  }
461}
462
463TEST_F(ClientSideDetectionServiceTest, GetNumReportTest) {
464  SetModelFetchResponse("bogus model", true /* success */);
465  csd_service_.reset(ClientSideDetectionService::Create(NULL));
466
467  std::queue<base::Time>& report_times = GetPhishingReportTimes();
468  base::Time now = base::Time::Now();
469  base::TimeDelta twenty_five_hours = base::TimeDelta::FromHours(25);
470  report_times.push(now - twenty_five_hours);
471  report_times.push(now - twenty_five_hours);
472  report_times.push(now);
473  report_times.push(now);
474
475  EXPECT_EQ(2, GetNumReports(&report_times));
476}
477
478TEST_F(ClientSideDetectionServiceTest, CacheTest) {
479  SetModelFetchResponse("bogus model", true /* success */);
480  csd_service_.reset(ClientSideDetectionService::Create(NULL));
481
482  TestCache();
483}
484
485TEST_F(ClientSideDetectionServiceTest, IsPrivateIPAddress) {
486  SetModelFetchResponse("bogus model", true /* success */);
487  csd_service_.reset(ClientSideDetectionService::Create(NULL));
488
489  EXPECT_TRUE(csd_service_->IsPrivateIPAddress("10.1.2.3"));
490  EXPECT_TRUE(csd_service_->IsPrivateIPAddress("127.0.0.1"));
491  EXPECT_TRUE(csd_service_->IsPrivateIPAddress("172.24.3.4"));
492  EXPECT_TRUE(csd_service_->IsPrivateIPAddress("192.168.1.1"));
493  EXPECT_TRUE(csd_service_->IsPrivateIPAddress("fc00::"));
494  EXPECT_TRUE(csd_service_->IsPrivateIPAddress("fec0::"));
495  EXPECT_TRUE(csd_service_->IsPrivateIPAddress("fec0:1:2::3"));
496  EXPECT_TRUE(csd_service_->IsPrivateIPAddress("::1"));
497
498  EXPECT_FALSE(csd_service_->IsPrivateIPAddress("1.2.3.4"));
499  EXPECT_FALSE(csd_service_->IsPrivateIPAddress("200.1.1.1"));
500  EXPECT_FALSE(csd_service_->IsPrivateIPAddress("2001:0db8:ac10:fe01::"));
501
502  // If the address can't be parsed, the default is true.
503  EXPECT_TRUE(csd_service_->IsPrivateIPAddress("blah"));
504}
505
506TEST_F(ClientSideDetectionServiceTest, SetBadSubnets) {
507  ClientSideModel model;
508  ClientSideDetectionService::BadSubnetMap bad_subnets;
509  ClientSideDetectionService::SetBadSubnets(model, &bad_subnets);
510  EXPECT_EQ(0U, bad_subnets.size());
511
512  // Bad subnets are skipped.
513  ClientSideModel::IPSubnet* subnet = model.add_bad_subnet();
514  subnet->set_prefix(std::string(crypto::kSHA256Length, '.'));
515  subnet->set_size(130);  // Invalid size.
516
517  subnet = model.add_bad_subnet();
518  subnet->set_prefix(std::string(crypto::kSHA256Length, '.'));
519  subnet->set_size(-1);  // Invalid size.
520
521  subnet = model.add_bad_subnet();
522  subnet->set_prefix(std::string(16, '.'));  // Invalid len.
523  subnet->set_size(64);
524
525  ClientSideDetectionService::SetBadSubnets(model, &bad_subnets);
526  EXPECT_EQ(0U, bad_subnets.size());
527
528  subnet = model.add_bad_subnet();
529  subnet->set_prefix(std::string(crypto::kSHA256Length, '.'));
530  subnet->set_size(64);
531
532  subnet = model.add_bad_subnet();
533  subnet->set_prefix(std::string(crypto::kSHA256Length, ','));
534  subnet->set_size(64);
535
536  subnet = model.add_bad_subnet();
537  subnet->set_prefix(std::string(crypto::kSHA256Length, '.'));
538  subnet->set_size(128);
539
540  subnet = model.add_bad_subnet();
541  subnet->set_prefix(std::string(crypto::kSHA256Length, '.'));
542  subnet->set_size(100);
543
544  ClientSideDetectionService::SetBadSubnets(model, &bad_subnets);
545  EXPECT_EQ(3U, bad_subnets.size());
546  ClientSideDetectionService::BadSubnetMap::const_iterator it;
547  std::string mask = std::string(8, '\xFF') + std::string(8, '\x00');
548  EXPECT_TRUE(bad_subnets.count(mask));
549  EXPECT_TRUE(bad_subnets[mask].count(std::string(crypto::kSHA256Length, '.')));
550  EXPECT_TRUE(bad_subnets[mask].count(std::string(crypto::kSHA256Length, ',')));
551
552  mask = std::string(16, '\xFF');
553  EXPECT_TRUE(bad_subnets.count(mask));
554  EXPECT_TRUE(bad_subnets[mask].count(std::string(crypto::kSHA256Length, '.')));
555
556  mask = std::string(12, '\xFF') + "\xF0" + std::string(3, '\x00');
557  EXPECT_TRUE(bad_subnets.count(mask));
558  EXPECT_TRUE(bad_subnets[mask].count(std::string(crypto::kSHA256Length, '.')));
559}
560
561TEST_F(ClientSideDetectionServiceTest, IsBadIpAddress) {
562  ClientSideModel model;
563  // IPv6 exact match for: 2620:0:1000:3103:21a:a0ff:fe10:786e.
564  ClientSideModel::IPSubnet* subnet = model.add_bad_subnet();
565  subnet->set_prefix(crypto::SHA256HashString(std::string(
566      "\x26\x20\x00\x00\x10\x00\x31\x03\x02\x1a\xa0\xff\xfe\x10\x78\x6e", 16)));
567  subnet->set_size(128);
568
569  // IPv6 prefix match for: fe80::21a:a0ff:fe10:786e/64.
570  subnet = model.add_bad_subnet();
571  subnet->set_prefix(crypto::SHA256HashString(std::string(
572      "\xfe\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16)));
573  subnet->set_size(64);
574
575  // IPv4 exact match for ::ffff:192.0.2.128.
576  subnet = model.add_bad_subnet();
577  subnet->set_prefix(crypto::SHA256HashString(std::string(
578      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xc0\x00\x02\x80", 16)));
579  subnet->set_size(128);
580
581  // IPv4 prefix match (/8) for ::ffff:192.1.1.0.
582  subnet = model.add_bad_subnet();
583  subnet->set_prefix(crypto::SHA256HashString(std::string(
584      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xc0\x01\x01\x00", 16)));
585  subnet->set_size(120);
586
587  // IPv4 prefix match (/9) for ::ffff:192.1.122.0.
588  subnet = model.add_bad_subnet();
589  subnet->set_prefix(crypto::SHA256HashString(std::string(
590      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xc0\x01\x7a\x00", 16)));
591  subnet->set_size(119);
592
593  // IPv4 prefix match (/15) for ::ffff:192.1.128.0.
594  subnet = model.add_bad_subnet();
595  subnet->set_prefix(crypto::SHA256HashString(std::string(
596      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xc0\x01\x80\x00", 16)));
597  subnet->set_size(113);
598
599  csd_service_.reset(ClientSideDetectionService::Create(NULL));
600  ClientSideDetectionService::SetBadSubnets(
601      model, &(csd_service_->bad_subnets_));
602  EXPECT_FALSE(csd_service_->IsBadIpAddress("blabla"));
603  EXPECT_FALSE(csd_service_->IsBadIpAddress(std::string()));
604
605  EXPECT_TRUE(csd_service_->IsBadIpAddress(
606      "2620:0:1000:3103:21a:a0ff:fe10:786e"));
607  EXPECT_FALSE(csd_service_->IsBadIpAddress(
608      "2620:0:1000:3103:21a:a0ff:fe10:786f"));
609
610  EXPECT_TRUE(csd_service_->IsBadIpAddress("fe80::21a:a0ff:fe10:786e"));
611  EXPECT_TRUE(csd_service_->IsBadIpAddress("fe80::31a:a0ff:fe10:786e"));
612  EXPECT_TRUE(csd_service_->IsBadIpAddress("fe80::21a:a0ff:fe10:786f"));
613  EXPECT_FALSE(csd_service_->IsBadIpAddress("fe81::21a:a0ff:fe10:786e"));
614
615  EXPECT_TRUE(csd_service_->IsBadIpAddress("192.0.2.128"));
616  EXPECT_TRUE(csd_service_->IsBadIpAddress("::ffff:192.0.2.128"));
617  EXPECT_FALSE(csd_service_->IsBadIpAddress("192.0.2.129"));
618
619  EXPECT_TRUE(csd_service_->IsBadIpAddress("192.1.1.0"));
620  EXPECT_TRUE(csd_service_->IsBadIpAddress("192.1.1.255"));
621  EXPECT_TRUE(csd_service_->IsBadIpAddress("192.1.1.10"));
622  EXPECT_TRUE(csd_service_->IsBadIpAddress("::ffff:192.1.1.2"));
623
624  EXPECT_FALSE(csd_service_->IsBadIpAddress("192.1.121.255"));
625  EXPECT_TRUE(csd_service_->IsBadIpAddress("192.1.122.0"));
626  EXPECT_TRUE(csd_service_->IsBadIpAddress("::ffff:192.1.122.1"));
627  EXPECT_TRUE(csd_service_->IsBadIpAddress("192.1.122.255"));
628  EXPECT_TRUE(csd_service_->IsBadIpAddress("192.1.123.0"));
629  EXPECT_TRUE(csd_service_->IsBadIpAddress("192.1.123.255"));
630  EXPECT_FALSE(csd_service_->IsBadIpAddress("192.1.124.0"));
631
632  EXPECT_FALSE(csd_service_->IsBadIpAddress("192.1.127.255"));
633  EXPECT_TRUE(csd_service_->IsBadIpAddress("192.1.128.0"));
634  EXPECT_TRUE(csd_service_->IsBadIpAddress("::ffff:192.1.128.1"));
635  EXPECT_TRUE(csd_service_->IsBadIpAddress("192.1.128.255"));
636  EXPECT_TRUE(csd_service_->IsBadIpAddress("192.1.255.0"));
637  EXPECT_TRUE(csd_service_->IsBadIpAddress("192.1.255.255"));
638  EXPECT_FALSE(csd_service_->IsBadIpAddress("192.2.0.0"));
639}
640
641TEST_F(ClientSideDetectionServiceTest, ModelHasValidHashIds) {
642  ClientSideModel model;
643  EXPECT_TRUE(ClientSideDetectionService::ModelHasValidHashIds(model));
644  model.add_hashes("bla");
645  EXPECT_TRUE(ClientSideDetectionService::ModelHasValidHashIds(model));
646  model.add_page_term(0);
647  EXPECT_TRUE(ClientSideDetectionService::ModelHasValidHashIds(model));
648
649  model.add_page_term(-1);
650  EXPECT_FALSE(ClientSideDetectionService::ModelHasValidHashIds(model));
651  model.set_page_term(1, 1);
652  EXPECT_FALSE(ClientSideDetectionService::ModelHasValidHashIds(model));
653  model.set_page_term(1, 0);
654  EXPECT_TRUE(ClientSideDetectionService::ModelHasValidHashIds(model));
655
656  // Test bad rules.
657  model.add_hashes("blu");
658  ClientSideModel::Rule* rule = model.add_rule();
659  rule->add_feature(0);
660  rule->add_feature(1);
661  rule->set_weight(0.1f);
662  EXPECT_TRUE(ClientSideDetectionService::ModelHasValidHashIds(model));
663
664  rule = model.add_rule();
665  rule->add_feature(0);
666  rule->add_feature(1);
667  rule->add_feature(-1);
668  rule->set_weight(0.2f);
669  EXPECT_FALSE(ClientSideDetectionService::ModelHasValidHashIds(model));
670
671  rule->set_feature(2, 2);
672  EXPECT_FALSE(ClientSideDetectionService::ModelHasValidHashIds(model));
673
674  rule->set_feature(2, 1);
675  EXPECT_TRUE(ClientSideDetectionService::ModelHasValidHashIds(model));
676}
677
678TEST_F(ClientSideDetectionServiceTest, SetEnabledAndRefreshState) {
679  // Check that the model isn't downloaded until the service is enabled.
680  csd_service_.reset(ClientSideDetectionService::Create(NULL));
681  EXPECT_FALSE(csd_service_->enabled());
682  EXPECT_TRUE(csd_service_->model_fetcher_.get() == NULL);
683
684  // Use a MockClientSideDetectionService for the rest of the test, to avoid
685  // the scheduling delay.
686  MockClientSideDetectionService* service =
687      new StrictMock<MockClientSideDetectionService>();
688  csd_service_.reset(service);
689  EXPECT_FALSE(csd_service_->enabled());
690  EXPECT_TRUE(csd_service_->model_fetcher_.get() == NULL);
691  // No calls expected yet.
692  Mock::VerifyAndClearExpectations(service);
693
694  ClientSideModel model;
695  model.set_version(10);
696  model.set_max_words_per_term(4);
697  SetModelFetchResponse(model.SerializeAsString(), true /* success */);
698  EXPECT_CALL(*service, ScheduleFetchModel(_))
699      .WillOnce(Invoke(service, &MockClientSideDetectionService::Schedule));
700  EXPECT_CALL(*service, EndFetchModel(
701      ClientSideDetectionService::MODEL_SUCCESS))
702      .WillOnce(QuitCurrentMessageLoop());
703  csd_service_->SetEnabledAndRefreshState(true);
704  EXPECT_TRUE(csd_service_->model_fetcher_.get() != NULL);
705  msg_loop_.Run();  // EndFetchModel will quit the message loop.
706  Mock::VerifyAndClearExpectations(service);
707
708  // Check that enabling again doesn't request the model.
709  csd_service_->SetEnabledAndRefreshState(true);
710  // No calls expected.
711  Mock::VerifyAndClearExpectations(service);
712
713  // Check that disabling the service cancels pending requests.
714  EXPECT_CALL(*service, ScheduleFetchModel(_))
715      .WillOnce(Invoke(service, &MockClientSideDetectionService::Schedule));
716  csd_service_->SetEnabledAndRefreshState(false);
717  csd_service_->SetEnabledAndRefreshState(true);
718  Mock::VerifyAndClearExpectations(service);
719  EXPECT_TRUE(csd_service_->model_fetcher_.get() != NULL);
720  csd_service_->SetEnabledAndRefreshState(false);
721  EXPECT_TRUE(csd_service_->model_fetcher_.get() == NULL);
722  msg_loop_.RunUntilIdle();
723  // No calls expected.
724  Mock::VerifyAndClearExpectations(service);
725
726  // Requests always return false when the service is disabled.
727  ClientPhishingResponse response;
728  response.set_phishy(true);
729  SetClientReportPhishingResponse(response.SerializeAsString(),
730                                  true /* success */);
731  EXPECT_FALSE(SendClientReportPhishingRequest(GURL("http://a.com/"), 0.4f));
732
733  // Pending requests also return false if the service is disabled before they
734  // report back.
735  EXPECT_CALL(*service, ScheduleFetchModel(_))
736      .WillOnce(Invoke(service, &MockClientSideDetectionService::Schedule));
737  EXPECT_CALL(*service, EndFetchModel(
738      ClientSideDetectionService::MODEL_NOT_CHANGED))
739      .WillOnce(Invoke(service, &MockClientSideDetectionService::Disable));
740  csd_service_->SetEnabledAndRefreshState(true);
741  EXPECT_FALSE(SendClientReportPhishingRequest(GURL("http://a.com/"), 0.4f));
742  Mock::VerifyAndClearExpectations(service);
743}
744}  // namespace safe_browsing
745