Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(244)

Side by Side Diff: components/certificate_transparency/log_dns_client.cc

Issue 2331923003: Allow LogDnsClient queries to be rate-limited (Closed)
Patch Set: Addresses last of Ryan's comments Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/certificate_transparency/log_dns_client.h" 5 #include "components/certificate_transparency/log_dns_client.h"
6 6
7 #include <sstream>
8
9 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/format_macros.h"
10 #include "base/location.h" 9 #include "base/location.h"
11 #include "base/logging.h" 10 #include "base/logging.h"
12 #include "base/strings/string_number_conversions.h" 11 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/string_util.h" 12 #include "base/strings/string_util.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/threading/thread_task_runner_handle.h" 14 #include "base/threading/thread_task_runner_handle.h"
15 #include "base/time/time.h" 15 #include "base/time/time.h"
16 #include "components/base32/base32.h" 16 #include "components/base32/base32.h"
17 #include "crypto/sha2.h" 17 #include "crypto/sha2.h"
18 #include "net/base/net_errors.h" 18 #include "net/base/net_errors.h"
19 #include "net/cert/merkle_audit_proof.h" 19 #include "net/cert/merkle_audit_proof.h"
20 #include "net/dns/dns_client.h" 20 #include "net/dns/dns_client.h"
21 #include "net/dns/dns_config_service.h" 21 #include "net/dns/dns_config_service.h"
22 #include "net/dns/dns_protocol.h" 22 #include "net/dns/dns_protocol.h"
23 #include "net/dns/dns_response.h" 23 #include "net/dns/dns_response.h"
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
91 for (size_t i = 0; i < audit_path.size(); i += crypto::kSHA256Length) { 91 for (size_t i = 0; i < audit_path.size(); i += crypto::kSHA256Length) {
92 proof->nodes.push_back(audit_path.substr(i, crypto::kSHA256Length)); 92 proof->nodes.push_back(audit_path.substr(i, crypto::kSHA256Length));
93 } 93 }
94 94
95 return true; 95 return true;
96 } 96 }
97 97
98 } // namespace 98 } // namespace
99 99
100 LogDnsClient::LogDnsClient(std::unique_ptr<net::DnsClient> dns_client, 100 LogDnsClient::LogDnsClient(std::unique_ptr<net::DnsClient> dns_client,
101 const net::NetLogWithSource& net_log) 101 const net::NetLogWithSource& net_log,
102 size_t max_concurrent_queries)
102 : dns_client_(std::move(dns_client)), 103 : dns_client_(std::move(dns_client)),
103 net_log_(net_log), 104 net_log_(net_log),
105 max_concurrent_queries_(max_concurrent_queries),
104 weak_ptr_factory_(this) { 106 weak_ptr_factory_(this) {
105 CHECK(dns_client_); 107 CHECK(dns_client_);
106 net::NetworkChangeNotifier::AddDNSObserver(this); 108 net::NetworkChangeNotifier::AddDNSObserver(this);
107 UpdateDnsConfig(); 109 UpdateDnsConfig();
108 } 110 }
109 111
110 LogDnsClient::~LogDnsClient() { 112 LogDnsClient::~LogDnsClient() {
111 net::NetworkChangeNotifier::RemoveDNSObserver(this); 113 net::NetworkChangeNotifier::RemoveDNSObserver(this);
112 } 114 }
113 115
114 void LogDnsClient::OnDNSChanged() { 116 void LogDnsClient::OnDNSChanged() {
115 UpdateDnsConfig(); 117 UpdateDnsConfig();
116 } 118 }
117 119
118 void LogDnsClient::OnInitialDNSConfigRead() { 120 void LogDnsClient::OnInitialDNSConfigRead() {
119 UpdateDnsConfig(); 121 UpdateDnsConfig();
120 } 122 }
121 123
122 void LogDnsClient::QueryLeafIndex(base::StringPiece domain_for_log, 124 void LogDnsClient::QueryLeafIndex(base::StringPiece domain_for_log,
123 base::StringPiece leaf_hash, 125 base::StringPiece leaf_hash,
124 const LeafIndexCallback& callback) { 126 const LeafIndexCallback& callback) {
125 if (domain_for_log.empty() || leaf_hash.size() != crypto::kSHA256Length) { 127 if (domain_for_log.empty() || leaf_hash.size() != crypto::kSHA256Length) {
126 base::ThreadTaskRunnerHandle::Get()->PostTask( 128 base::ThreadTaskRunnerHandle::Get()->PostTask(
127 FROM_HERE, base::Bind(callback, net::Error::ERR_INVALID_ARGUMENT, 0)); 129 FROM_HERE, base::Bind(callback, net::Error::ERR_INVALID_ARGUMENT, 0));
128 return; 130 return;
129 } 131 }
130 132
133 if (HasMaxConcurrentQueriesInProgress()) {
134 base::ThreadTaskRunnerHandle::Get()->PostTask(
135 FROM_HERE,
136 base::Bind(callback, net::Error::ERR_TEMPORARILY_THROTTLED, 0));
137 return;
138 }
139
131 std::string encoded_leaf_hash = 140 std::string encoded_leaf_hash =
132 base32::Base32Encode(leaf_hash, base32::Base32EncodePolicy::OMIT_PADDING); 141 base32::Base32Encode(leaf_hash, base32::Base32EncodePolicy::OMIT_PADDING);
133 DCHECK_EQ(encoded_leaf_hash.size(), 52u); 142 DCHECK_EQ(encoded_leaf_hash.size(), 52u);
134 143
135 net::DnsTransactionFactory* factory = dns_client_->GetTransactionFactory(); 144 net::DnsTransactionFactory* factory = dns_client_->GetTransactionFactory();
136 if (factory == nullptr) { 145 if (factory == nullptr) {
137 base::ThreadTaskRunnerHandle::Get()->PostTask( 146 base::ThreadTaskRunnerHandle::Get()->PostTask(
138 FROM_HERE, 147 FROM_HERE,
139 base::Bind(callback, net::Error::ERR_NAME_RESOLUTION_FAILED, 0)); 148 base::Bind(callback, net::Error::ERR_NAME_RESOLUTION_FAILED, 0));
140 return; 149 return;
141 } 150 }
142 151
143 std::ostringstream qname; 152 std::string qname = base::StringPrintf(
144 qname << encoded_leaf_hash << ".hash." << domain_for_log << "."; 153 "%s.hash.%s.", encoded_leaf_hash.c_str(), domain_for_log.data());
145 154
146 net::DnsTransactionFactory::CallbackType transaction_callback = base::Bind( 155 net::DnsTransactionFactory::CallbackType transaction_callback = base::Bind(
147 &LogDnsClient::QueryLeafIndexComplete, weak_ptr_factory_.GetWeakPtr()); 156 &LogDnsClient::QueryLeafIndexComplete, weak_ptr_factory_.GetWeakPtr());
148 157
149 std::unique_ptr<net::DnsTransaction> dns_transaction = 158 std::unique_ptr<net::DnsTransaction> dns_transaction =
150 factory->CreateTransaction(qname.str(), net::dns_protocol::kTypeTXT, 159 factory->CreateTransaction(qname, net::dns_protocol::kTypeTXT,
151 transaction_callback, net_log_); 160 transaction_callback, net_log_);
152 161
153 dns_transaction->Start(); 162 dns_transaction->Start();
154 leaf_index_queries_.push_back({std::move(dns_transaction), callback}); 163 leaf_index_queries_.push_back({std::move(dns_transaction), callback});
155 } 164 }
156 165
157 // The performance of this could be improved by sending all of the expected 166 // The performance of this could be improved by sending all of the expected
158 // queries up front. Each response can contain a maximum of 7 audit path nodes, 167 // queries up front. Each response can contain a maximum of 7 audit path nodes,
159 // so for an audit proof of size 20, it could send 3 queries (for nodes 0-6, 168 // so for an audit proof of size 20, it could send 3 queries (for nodes 0-6,
160 // 7-13 and 14-19) immediately. Currently, it sends only the first and then, 169 // 7-13 and 14-19) immediately. Currently, it sends only the first and then,
161 // based on the number of nodes received, sends the next query. The complexity 170 // based on the number of nodes received, sends the next query. The complexity
162 // of the code would increase though, as it would need to detect gaps in the 171 // of the code would increase though, as it would need to detect gaps in the
163 // audit proof caused by the server not responding with the anticipated number 172 // audit proof caused by the server not responding with the anticipated number
164 // of nodes. Ownership of the proof would need to change, as it would be shared 173 // of nodes. Ownership of the proof would need to change, as it would be shared
165 // between simultaneous DNS transactions. 174 // between simultaneous DNS transactions. Throttling of queries would also need
175 // to take into account this increase in parallelism.
166 void LogDnsClient::QueryAuditProof(base::StringPiece domain_for_log, 176 void LogDnsClient::QueryAuditProof(base::StringPiece domain_for_log,
167 uint64_t leaf_index, 177 uint64_t leaf_index,
168 uint64_t tree_size, 178 uint64_t tree_size,
169 const AuditProofCallback& callback) { 179 const AuditProofCallback& callback) {
170 if (domain_for_log.empty() || leaf_index >= tree_size) { 180 if (domain_for_log.empty() || leaf_index >= tree_size) {
171 base::ThreadTaskRunnerHandle::Get()->PostTask( 181 base::ThreadTaskRunnerHandle::Get()->PostTask(
172 FROM_HERE, 182 FROM_HERE,
173 base::Bind(callback, net::Error::ERR_INVALID_ARGUMENT, nullptr)); 183 base::Bind(callback, net::Error::ERR_INVALID_ARGUMENT, nullptr));
174 return; 184 return;
175 } 185 }
176 186
187 if (HasMaxConcurrentQueriesInProgress()) {
188 base::ThreadTaskRunnerHandle::Get()->PostTask(
189 FROM_HERE,
190 base::Bind(callback, net::Error::ERR_TEMPORARILY_THROTTLED, nullptr));
191 return;
192 }
193
177 std::unique_ptr<net::ct::MerkleAuditProof> proof( 194 std::unique_ptr<net::ct::MerkleAuditProof> proof(
178 new net::ct::MerkleAuditProof); 195 new net::ct::MerkleAuditProof);
179 proof->leaf_index = leaf_index; 196 proof->leaf_index = leaf_index;
180 // TODO(robpercival): Once a "tree_size" field is added to MerkleAuditProof, 197 // TODO(robpercival): Once a "tree_size" field is added to MerkleAuditProof,
181 // pass |tree_size| to QueryAuditProofNodes using that. 198 // pass |tree_size| to QueryAuditProofNodes using that.
182 199
183 // Query for the first batch of audit proof nodes (i.e. starting from 0). 200 // Query for the first batch of audit proof nodes (i.e. starting from 0).
184 QueryAuditProofNodes(std::move(proof), domain_for_log, tree_size, 0, 201 QueryAuditProofNodes(std::move(proof), domain_for_log, tree_size, 0,
185 callback); 202 callback);
186 } 203 }
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
238 net::ct::CalculateAuditPathLength(proof->leaf_index, tree_size)); 255 net::ct::CalculateAuditPathLength(proof->leaf_index, tree_size));
239 256
240 net::DnsTransactionFactory* factory = dns_client_->GetTransactionFactory(); 257 net::DnsTransactionFactory* factory = dns_client_->GetTransactionFactory();
241 if (factory == nullptr) { 258 if (factory == nullptr) {
242 base::ThreadTaskRunnerHandle::Get()->PostTask( 259 base::ThreadTaskRunnerHandle::Get()->PostTask(
243 FROM_HERE, 260 FROM_HERE,
244 base::Bind(callback, net::Error::ERR_NAME_RESOLUTION_FAILED, nullptr)); 261 base::Bind(callback, net::Error::ERR_NAME_RESOLUTION_FAILED, nullptr));
245 return; 262 return;
246 } 263 }
247 264
248 std::ostringstream qname; 265 std::string qname = base::StringPrintf(
249 qname << node_index << "." << proof->leaf_index << "." << tree_size 266 "%" PRIu64 ".%" PRIu64 ".%" PRIu64 ".tree.%s.", node_index,
250 << ".tree." << domain_for_log << "."; 267 proof->leaf_index, tree_size, domain_for_log.data());
251 268
252 net::DnsTransactionFactory::CallbackType transaction_callback = 269 net::DnsTransactionFactory::CallbackType transaction_callback =
253 base::Bind(&LogDnsClient::QueryAuditProofNodesComplete, 270 base::Bind(&LogDnsClient::QueryAuditProofNodesComplete,
254 weak_ptr_factory_.GetWeakPtr(), base::Passed(std::move(proof)), 271 weak_ptr_factory_.GetWeakPtr(), base::Passed(std::move(proof)),
255 domain_for_log, tree_size); 272 domain_for_log, tree_size);
256 273
257 std::unique_ptr<net::DnsTransaction> dns_transaction = 274 std::unique_ptr<net::DnsTransaction> dns_transaction =
258 factory->CreateTransaction(qname.str(), net::dns_protocol::kTypeTXT, 275 factory->CreateTransaction(qname, net::dns_protocol::kTypeTXT,
259 transaction_callback, net_log_); 276 transaction_callback, net_log_);
260 dns_transaction->Start(); 277 dns_transaction->Start();
261 audit_proof_queries_.push_back({std::move(dns_transaction), callback}); 278 audit_proof_queries_.push_back({std::move(dns_transaction), callback});
262 } 279 }
263 280
264 void LogDnsClient::QueryAuditProofNodesComplete( 281 void LogDnsClient::QueryAuditProofNodesComplete(
265 std::unique_ptr<net::ct::MerkleAuditProof> proof, 282 std::unique_ptr<net::ct::MerkleAuditProof> proof,
266 base::StringPiece domain_for_log, 283 base::StringPiece domain_for_log,
267 uint64_t tree_size, 284 uint64_t tree_size,
268 net::DnsTransaction* transaction, 285 net::DnsTransaction* transaction,
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
313 QueryAuditProofNodes(std::move(proof), domain_for_log, tree_size, 330 QueryAuditProofNodes(std::move(proof), domain_for_log, tree_size,
314 audit_path_nodes_received, query.callback); 331 audit_path_nodes_received, query.callback);
315 return; 332 return;
316 } 333 }
317 334
318 base::ThreadTaskRunnerHandle::Get()->PostTask( 335 base::ThreadTaskRunnerHandle::Get()->PostTask(
319 FROM_HERE, 336 FROM_HERE,
320 base::Bind(query.callback, net::OK, base::Passed(std::move(proof)))); 337 base::Bind(query.callback, net::OK, base::Passed(std::move(proof))));
321 } 338 }
322 339
340 bool LogDnsClient::HasMaxConcurrentQueriesInProgress() const {
341 const size_t queries_in_progress =
342 leaf_index_queries_.size() + audit_proof_queries_.size();
343
344 return max_concurrent_queries_ != 0 &&
345 queries_in_progress >= max_concurrent_queries_;
346 }
347
323 void LogDnsClient::UpdateDnsConfig() { 348 void LogDnsClient::UpdateDnsConfig() {
324 net::DnsConfig config; 349 net::DnsConfig config;
325 net::NetworkChangeNotifier::GetDnsConfig(&config); 350 net::NetworkChangeNotifier::GetDnsConfig(&config);
326 if (config.IsValid()) 351 if (config.IsValid())
327 dns_client_->SetConfig(config); 352 dns_client_->SetConfig(config);
328 } 353 }
329 354
330 } // namespace certificate_transparency 355 } // namespace certificate_transparency
OLDNEW
« no previous file with comments | « components/certificate_transparency/log_dns_client.h ('k') | components/certificate_transparency/log_dns_client_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698