172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 24a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// Use of this source code is governed by a BSD-style license that can be 34a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// found in the LICENSE file. 44a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 54a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "chrome/browser/safe_browsing/client_side_detection_service.h" 64a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 74a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "base/command_line.h" 84a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "base/file_path.h" 94a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "base/file_util_proxy.h" 104a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "base/logging.h" 11ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/scoped_ptr.h" 124a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "base/message_loop.h" 1372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "base/metrics/histogram.h" 144a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "base/platform_file.h" 154a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "base/stl_util-inl.h" 164a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "base/task.h" 1772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "base/time.h" 184a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "chrome/common/net/http_return.h" 194a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "chrome/common/net/url_fetcher.h" 20ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/common/safe_browsing/csd.pb.h" 21dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/browser_thread.h" 224a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "googleurl/src/gurl.h" 234a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "net/base/load_flags.h" 24ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "net/url_request/url_request_context_getter.h" 254a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "net/url_request/url_request_status.h" 264a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 274a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochnamespace safe_browsing { 284a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 2972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenconst int ClientSideDetectionService::kMaxReportsPerInterval = 3; 3072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 3172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenconst base::TimeDelta ClientSideDetectionService::kReportsInterval = 3272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen base::TimeDelta::FromDays(1); 3372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenconst base::TimeDelta ClientSideDetectionService::kNegativeCacheInterval = 3472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen base::TimeDelta::FromDays(1); 3572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenconst base::TimeDelta ClientSideDetectionService::kPositiveCacheInterval = 3672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen base::TimeDelta::FromMinutes(30); 3772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 384a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochconst char ClientSideDetectionService::kClientReportPhishingUrl[] = 394a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch "https://sb-ssl.google.com/safebrowsing/clientreport/phishing"; 40ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Note: when updatng the model version, don't forget to change the filename 41ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// in chrome/common/chrome_constants.cc as well, or else existing users won't 42ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// download the new model. 43ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// 44ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// TODO(bryner): add version metadata so that clients can download new models 45ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// without needing a new model filename. 464a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochconst char ClientSideDetectionService::kClientModelUrl[] = 47ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen "https://ssl.gstatic.com/safebrowsing/csd/client_model_v1.pb"; 484a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 4921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenstruct ClientSideDetectionService::ClientReportInfo { 5021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen scoped_ptr<ClientReportPhishingRequestCallback> callback; 5121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen GURL phishing_url; 5221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}; 5321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 5472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenClientSideDetectionService::CacheState::CacheState(bool phish, base::Time time) 5572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen : is_phishing(phish), 5672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen timestamp(time) {} 5772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 584a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben MurdochClientSideDetectionService::ClientSideDetectionService( 594a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch const FilePath& model_path, 60ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen net::URLRequestContextGetter* request_context_getter) 614a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch : model_path_(model_path), 624a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch model_status_(UNKNOWN_STATUS), 634a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch model_file_(base::kInvalidPlatformFileValue), 644a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)), 654a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch ALLOW_THIS_IN_INITIALIZER_LIST(callback_factory_(this)), 66dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen request_context_getter_(request_context_getter) {} 674a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 684a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben MurdochClientSideDetectionService::~ClientSideDetectionService() { 694a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch method_factory_.RevokeAll(); 704a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch STLDeleteContainerPairPointers(client_phishing_reports_.begin(), 714a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch client_phishing_reports_.end()); 724a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch client_phishing_reports_.clear(); 734a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch STLDeleteElements(&open_callbacks_); 744a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch CloseModelFile(); 754a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch} 764a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 774a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch/* static */ 784a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben MurdochClientSideDetectionService* ClientSideDetectionService::Create( 794a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch const FilePath& model_path, 80ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen net::URLRequestContextGetter* request_context_getter) { 814a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 824a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch scoped_ptr<ClientSideDetectionService> service( 834a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch new ClientSideDetectionService(model_path, request_context_getter)); 84dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (!service->InitializePrivateNetworks()) { 85dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen UMA_HISTOGRAM_COUNTS("SBClientPhishing.InitPrivateNetworksFailed", 1); 86dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return NULL; 87dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 88dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 894a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // We try to open the model file right away and start fetching it if 904a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // it does not already exist on disk. 914a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch base::FileUtilProxy::CreateOrOpenCallback* cb = 924a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch service.get()->callback_factory_.NewCallback( 934a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch &ClientSideDetectionService::OpenModelFileDone); 944a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch if (!base::FileUtilProxy::CreateOrOpen( 954a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE), 964a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch model_path, 974a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ, 984a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch cb)) { 994a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch delete cb; 1004a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch return NULL; 1014a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } 102ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 103ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Delete the previous-version model file. 104ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // TODO(bryner): Remove this for M14. 105ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen base::FileUtilProxy::Delete( 106ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE), 107ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen model_path.DirName().AppendASCII("Safe Browsing Phishing Model"), 108ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen false /* not recursive */, 109ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen NULL /* not interested in result */); 1104a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch return service.release(); 1114a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch} 1124a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 1134a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochvoid ClientSideDetectionService::GetModelFile(OpenModelDoneCallback* callback) { 1144a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1154a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch MessageLoop::current()->PostTask( 1164a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch FROM_HERE, 1174a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch method_factory_.NewRunnableMethod( 1184a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch &ClientSideDetectionService::StartGetModelFile, callback)); 1194a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch} 1204a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 1214a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochvoid ClientSideDetectionService::SendClientReportPhishingRequest( 122ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ClientPhishingRequest* verdict, 1234a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch ClientReportPhishingRequestCallback* callback) { 1244a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1254a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch MessageLoop::current()->PostTask( 1264a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch FROM_HERE, 1274a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch method_factory_.NewRunnableMethod( 1284a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch &ClientSideDetectionService::StartClientReportPhishingRequest, 129ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen verdict, callback)); 1304a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch} 1314a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 132dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenbool ClientSideDetectionService::IsPrivateIPAddress( 133dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const std::string& ip_address) const { 134dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen net::IPAddressNumber ip_number; 135dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (!net::ParseIPLiteralToNumber(ip_address, &ip_number)) { 136dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen DLOG(WARNING) << "Unable to parse IP address: " << ip_address; 137dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // Err on the side of safety and assume this might be private. 138dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return true; 139dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 140dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 141dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen for (std::vector<AddressRange>::const_iterator it = 142dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen private_networks_.begin(); 143dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen it != private_networks_.end(); ++it) { 144dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (net::IPNumberMatchesPrefix(ip_number, it->first, it->second)) { 145dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return true; 146dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 147dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 148dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return false; 149dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen} 150dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 1514a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochvoid ClientSideDetectionService::OnURLFetchComplete( 1524a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch const URLFetcher* source, 1534a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch const GURL& url, 15472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const net::URLRequestStatus& status, 1554a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch int response_code, 1564a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch const ResponseCookies& cookies, 1574a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch const std::string& data) { 15872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (source == model_fetcher_.get()) { 1594a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch HandleModelResponse(source, url, status, response_code, cookies, data); 1604a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } else if (client_phishing_reports_.find(source) != 1614a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch client_phishing_reports_.end()) { 1624a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch HandlePhishingVerdict(source, url, status, response_code, cookies, data); 1634a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } else { 1644a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch NOTREACHED(); 1654a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } 16672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 16772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 1684a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochvoid ClientSideDetectionService::SetModelStatus(ModelStatus status) { 1694a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch DCHECK_NE(READY_STATUS, model_status_); 1704a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch model_status_ = status; 1714a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch if (READY_STATUS == status || ERROR_STATUS == status) { 1724a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch for (size_t i = 0; i < open_callbacks_.size(); ++i) { 1734a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch open_callbacks_[i]->Run(model_file_); 1744a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } 1754a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch STLDeleteElements(&open_callbacks_); 1764a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } else { 1774a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch NOTREACHED(); 1784a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } 1794a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch} 1804a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 1814a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochvoid ClientSideDetectionService::OpenModelFileDone( 1824a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch base::PlatformFileError error_code, 1834a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch base::PassPlatformFile file, 1844a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch bool created) { 1854a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch DCHECK(!created); 1864a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch if (base::PLATFORM_FILE_OK == error_code) { 1874a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // The model file already exists. There is no need to fetch the model. 1884a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch model_file_ = file.ReleaseValue(); 1894a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch SetModelStatus(READY_STATUS); 1904a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } else if (base::PLATFORM_FILE_ERROR_NOT_FOUND == error_code) { 1914a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // We need to fetch the model since it does not exist yet. 19272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen model_fetcher_.reset(URLFetcher::Create(0 /* ID is not used */, 19372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen GURL(kClientModelUrl), 19472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen URLFetcher::GET, 19572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen this)); 1964a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch model_fetcher_->set_request_context(request_context_getter_.get()); 1974a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch model_fetcher_->Start(); 1984a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } else { 1994a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // It is not clear what we should do in this case. For now we simply fail. 2004a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // Hopefully, we'll be able to read the model during the next browser 2014a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // restart. 2024a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch SetModelStatus(ERROR_STATUS); 2034a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } 2044a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch} 2054a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 2064a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochvoid ClientSideDetectionService::CreateModelFileDone( 2074a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch base::PlatformFileError error_code, 2084a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch base::PassPlatformFile file, 2094a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch bool created) { 2104a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch model_file_ = file.ReleaseValue(); 21172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen base::FileUtilProxy::WriteCallback* cb = callback_factory_.NewCallback( 2124a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch &ClientSideDetectionService::WriteModelFileDone); 2134a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch if (!created || 2144a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch base::PLATFORM_FILE_OK != error_code || 2154a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch !base::FileUtilProxy::Write( 2164a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE), 2174a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch model_file_, 2184a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 0 /* offset */, tmp_model_string_->data(), tmp_model_string_->size(), 2194a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch cb)) { 2204a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch delete cb; 2214a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // An error occurred somewhere. We close the model file if necessary and 2224a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // then run all the pending callbacks giving them an invalid model file. 2234a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch CloseModelFile(); 2244a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch SetModelStatus(ERROR_STATUS); 2254a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } 2264a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch} 2274a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 2284a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochvoid ClientSideDetectionService::WriteModelFileDone( 2294a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch base::PlatformFileError error_code, 2304a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch int bytes_written) { 2314a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch if (base::PLATFORM_FILE_OK == error_code) { 2324a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch SetModelStatus(READY_STATUS); 2334a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } else { 2344a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // TODO(noelutz): maybe we should retry writing the model since we 2354a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // did already fetch the model? 2364a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch CloseModelFile(); 2374a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch SetModelStatus(ERROR_STATUS); 2384a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } 2394a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // Delete the model string that we kept around while we were writing the 2404a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // string to disk - we don't need it anymore. 2414a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch tmp_model_string_.reset(); 2424a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch} 2434a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 2444a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochvoid ClientSideDetectionService::CloseModelFile() { 2454a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch if (model_file_ != base::kInvalidPlatformFileValue) { 2464a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch base::FileUtilProxy::Close( 2474a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE), 2484a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch model_file_, 2494a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch NULL); 2504a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } 2514a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch model_file_ = base::kInvalidPlatformFileValue; 2524a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch} 2534a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 2544a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochvoid ClientSideDetectionService::StartGetModelFile( 2554a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch OpenModelDoneCallback* callback) { 2564a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 2574a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch if (UNKNOWN_STATUS == model_status_) { 2584a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // Store the callback which will be called once we know the status of the 2594a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // model file. 2604a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch open_callbacks_.push_back(callback); 2614a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } else { 2624a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // The model is either in READY or ERROR state which means we can 2634a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // call the callback right away. 2644a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch callback->Run(model_file_); 2654a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch delete callback; 2664a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } 2674a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch} 2684a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 2694a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochvoid ClientSideDetectionService::StartClientReportPhishingRequest( 270ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ClientPhishingRequest* verdict, 2714a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch ClientReportPhishingRequestCallback* callback) { 2724a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 273ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen scoped_ptr<ClientPhishingRequest> request(verdict); 2744a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch scoped_ptr<ClientReportPhishingRequestCallback> cb(callback); 27572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 2764a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch std::string request_data; 277ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!request->SerializeToString(&request_data)) { 27872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen UMA_HISTOGRAM_COUNTS("SBClientPhishing.RequestNotSerialized", 1); 27972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen VLOG(1) << "Unable to serialize the CSD request. Proto file changed?"; 280ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen cb->Run(GURL(request->url()), false); 2814a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch return; 2824a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } 2834a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 2844a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch URLFetcher* fetcher = URLFetcher::Create(0 /* ID is not used */, 2854a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch GURL(kClientReportPhishingUrl), 2864a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch URLFetcher::POST, 2874a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch this); 2884a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 2894a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // Remember which callback and URL correspond to the current fetcher object. 2904a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch ClientReportInfo* info = new ClientReportInfo; 2914a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch info->callback.swap(cb); // takes ownership of the callback. 292ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen info->phishing_url = GURL(request->url()); 2934a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch client_phishing_reports_[fetcher] = info; 2944a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 2954a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch fetcher->set_load_flags(net::LOAD_DISABLE_CACHE); 2964a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch fetcher->set_request_context(request_context_getter_.get()); 2974a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch fetcher->set_upload_data("application/octet-stream", request_data); 2984a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch fetcher->Start(); 29972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 30072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Record that we made a request 30172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen phishing_report_times_.push(base::Time::Now()); 3024a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch} 3034a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 3044a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochvoid ClientSideDetectionService::HandleModelResponse( 3054a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch const URLFetcher* source, 3064a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch const GURL& url, 30772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const net::URLRequestStatus& status, 3084a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch int response_code, 3094a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch const ResponseCookies& cookies, 3104a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch const std::string& data) { 3114a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch if (status.is_success() && RC_REQUEST_OK == response_code) { 3124a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // Copy the model because it has to be accessible after this function 3134a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // returns. Once we have written the model to a file we will delete the 3144a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // temporary model string. TODO(noelutz): don't store the model to disk if 3154a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // it's invalid. 3164a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch tmp_model_string_.reset(new std::string(data)); 3174a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch base::FileUtilProxy::CreateOrOpenCallback* cb = 3184a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch callback_factory_.NewCallback( 3194a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch &ClientSideDetectionService::CreateModelFileDone); 3204a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch if (!base::FileUtilProxy::CreateOrOpen( 3214a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE), 3224a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch model_path_, 3234a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch base::PLATFORM_FILE_CREATE_ALWAYS | 3244a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch base::PLATFORM_FILE_WRITE | 3254a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch base::PLATFORM_FILE_READ, 3264a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch cb)) { 3274a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch delete cb; 3284a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch SetModelStatus(ERROR_STATUS); 3294a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } 3304a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } else { 3314a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch SetModelStatus(ERROR_STATUS); 3324a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } 3334a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch} 3344a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 3354a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochvoid ClientSideDetectionService::HandlePhishingVerdict( 3364a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch const URLFetcher* source, 3374a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch const GURL& url, 33872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const net::URLRequestStatus& status, 3394a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch int response_code, 3404a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch const ResponseCookies& cookies, 3414a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch const std::string& data) { 3424a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch ClientPhishingResponse response; 3434a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch scoped_ptr<ClientReportInfo> info(client_phishing_reports_[source]); 34472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (status.is_success() && RC_REQUEST_OK == response_code && 3454a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch response.ParseFromString(data)) { 34672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Cache response, possibly flushing an old one. 34772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen cache_[info->phishing_url] = 34872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen make_linked_ptr(new CacheState(response.phishy(), base::Time::Now())); 3494a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch info->callback->Run(info->phishing_url, response.phishy()); 3504a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } else { 3514a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch DLOG(ERROR) << "Unable to get the server verdict for URL: " 352dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen << info->phishing_url << " status: " << status.status() << " " 353dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen << "response_code:" << response_code; 3544a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch info->callback->Run(info->phishing_url, false); 3554a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } 3564a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch client_phishing_reports_.erase(source); 35772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen delete source; 35872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 35972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 360ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool ClientSideDetectionService::IsInCache(const GURL& url) { 361ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen UpdateCache(); 362ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 363ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return cache_.find(url) != cache_.end(); 364ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 365ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 366ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool ClientSideDetectionService::GetValidCachedResult(const GURL& url, 367ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bool* is_phishing) { 36872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen UpdateCache(); 36972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 37072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen PhishingCache::iterator it = cache_.find(url); 37172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (it == cache_.end()) { 37272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return false; 37372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 37472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 37572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // We still need to check if the result is valid. 37672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const CacheState& cache_state = *it->second; 37772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (cache_state.is_phishing ? 37872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen cache_state.timestamp > base::Time::Now() - kPositiveCacheInterval : 37972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen cache_state.timestamp > base::Time::Now() - kNegativeCacheInterval) { 38072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen *is_phishing = cache_state.is_phishing; 38172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return true; 38272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 38372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return false; 38472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 38572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 38672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid ClientSideDetectionService::UpdateCache() { 38772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Since we limit the number of requests but allow pass-through for cache 38872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // refreshes, we don't want to remove elements from the cache if they 38972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // could be used for this purpose even if we will not use the entry to 39072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // satisfy the request from the cache. 39172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen base::TimeDelta positive_cache_interval = 39272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen std::max(kPositiveCacheInterval, kReportsInterval); 39372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen base::TimeDelta negative_cache_interval = 39472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen std::max(kNegativeCacheInterval, kReportsInterval); 39572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 39672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Remove elements from the cache that will no longer be used. 39772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen for (PhishingCache::iterator it = cache_.begin(); it != cache_.end();) { 39872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const CacheState& cache_state = *it->second; 39972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (cache_state.is_phishing ? 40072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen cache_state.timestamp > base::Time::Now() - positive_cache_interval : 40172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen cache_state.timestamp > base::Time::Now() - negative_cache_interval) { 40272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ++it; 40372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } else { 40472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen cache_.erase(it++); 40572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 40672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 40772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 40872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 409ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool ClientSideDetectionService::OverReportLimit() { 410ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return GetNumReports() > kMaxReportsPerInterval; 411ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 412ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 41372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenint ClientSideDetectionService::GetNumReports() { 41472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen base::Time cutoff = base::Time::Now() - kReportsInterval; 41572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 41672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Erase items older than cutoff because we will never care about them again. 41772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen while (!phishing_report_times_.empty() && 41872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen phishing_report_times_.front() < cutoff) { 41972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen phishing_report_times_.pop(); 42072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 42172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 42272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Return the number of elements that are above the cutoff. 42372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return phishing_report_times_.size(); 4244a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch} 4254a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 426dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenbool ClientSideDetectionService::InitializePrivateNetworks() { 427dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen static const char* const kPrivateNetworks[] = { 428dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen "10.0.0.0/8", 429dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen "127.0.0.0/8", 430dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen "172.16.0.0/12", 431dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen "192.168.0.0/16", 432dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // IPv6 address ranges 433dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen "fc00::/7", 434dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen "fec0::/10", 435dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen "::1/128", 436dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen }; 437dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 438dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen for (size_t i = 0; i < arraysize(kPrivateNetworks); ++i) { 439dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen net::IPAddressNumber ip_number; 440dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen size_t prefix_length; 441dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (net::ParseCIDRBlock(kPrivateNetworks[i], &ip_number, &prefix_length)) { 442dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen private_networks_.push_back(std::make_pair(ip_number, prefix_length)); 443dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } else { 444dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen DLOG(FATAL) << "Unable to parse IP address range: " 445dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen << kPrivateNetworks[i]; 446dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return false; 447dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 448dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 449dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return true; 450dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen} 451dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 4524a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch} // namespace safe_browsing 453