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

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

Issue 2369373002: LogDnsClient now returns some errors synchronously (Closed)
Patch Set: Addresses Eran'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 "base/bind.h" 7 #include "base/bind.h"
8 #include "base/format_macros.h" 8 #include "base/format_macros.h"
9 #include "base/location.h" 9 #include "base/location.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/strings/string_number_conversions.h" 11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_util.h" 12 #include "base/strings/string_util.h"
13 #include "base/strings/stringprintf.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"
19 #include "net/cert/merkle_audit_proof.h" 18 #include "net/cert/merkle_audit_proof.h"
20 #include "net/dns/dns_client.h" 19 #include "net/dns/dns_client.h"
21 #include "net/dns/dns_config_service.h" 20 #include "net/dns/dns_config_service.h"
22 #include "net/dns/dns_protocol.h" 21 #include "net/dns/dns_protocol.h"
23 #include "net/dns/dns_response.h" 22 #include "net/dns/dns_response.h"
24 #include "net/dns/dns_transaction.h" 23 #include "net/dns/dns_transaction.h"
25 #include "net/dns/record_parsed.h" 24 #include "net/dns/record_parsed.h"
26 #include "net/dns/record_rdata.h" 25 #include "net/dns/record_rdata.h"
27 26
28 namespace certificate_transparency { 27 namespace certificate_transparency {
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
80 } 79 }
81 80
82 } // namespace 81 } // namespace
83 82
84 // Encapsulates the state machine required to get an audit proof from a Merkle 83 // Encapsulates the state machine required to get an audit proof from a Merkle
85 // leaf hash. This requires a DNS request to obtain the leaf index, then a 84 // leaf hash. This requires a DNS request to obtain the leaf index, then a
86 // series of DNS requests to get the nodes of the proof. 85 // series of DNS requests to get the nodes of the proof.
87 class LogDnsClient::AuditProofQuery { 86 class LogDnsClient::AuditProofQuery {
88 public: 87 public:
89 using CompletionCallback = 88 using CompletionCallback =
90 base::Callback<void(int net_error, AuditProofQuery* query)>; 89 base::Callback<void(net::Error result, AuditProofQuery* query)>;
91 90
92 // The LogDnsClient is guaranteed to outlive the AuditProofQuery, so it's safe 91 // The LogDnsClient is guaranteed to outlive the AuditProofQuery, so it's safe
93 // to leave ownership of |dns_client| with LogDnsClient. 92 // to leave ownership of |dns_client| with LogDnsClient.
94 AuditProofQuery(net::DnsClient* dns_client, 93 AuditProofQuery(net::DnsClient* dns_client,
Ryan Sleevi 2016/10/03 23:38:47 The choice to integrate both the definition and th
Rob Percival 2016/10/04 18:35:39 Done.
95 const std::string& domain_for_log, 94 const std::string& domain_for_log,
96 uint64_t tree_size, 95 uint64_t tree_size,
97 const net::NetLogWithSource& net_log) 96 const net::NetLogWithSource& net_log)
98 : domain_for_log_(domain_for_log), 97 : next_state_(State::NONE),
98 domain_for_log_(domain_for_log),
99 tree_size_(tree_size), 99 tree_size_(tree_size),
100 dns_client_(dns_client), 100 dns_client_(dns_client),
101 net_log_(net_log), 101 net_log_(net_log),
102 weak_ptr_factory_(this) { 102 weak_ptr_factory_(this) {
103 DCHECK(dns_client_); 103 DCHECK(dns_client_);
104 DCHECK(!domain_for_log_.empty()); 104 DCHECK(!domain_for_log_.empty());
105 } 105 }
106 106
107 // Start the query. 107 // Start the query.
108 void Start(base::StringPiece leaf_hash, CompletionCallback callback) { 108 net::Error Start(base::StringPiece leaf_hash, CompletionCallback callback) {
109 current_dns_transaction_.reset(); 109 // It should not already be in progress.
110 DCHECK_EQ(State::NONE, next_state_);
111 // Start a new audit proof.
Ryan Sleevi 2016/10/03 23:38:47 I appreciate the commenting, but this one seems ov
Rob Percival 2016/10/04 18:35:39 Done.
110 proof_.reset(new net::ct::MerkleAuditProof); 112 proof_.reset(new net::ct::MerkleAuditProof);
113 // The leaf hash will be used during the REQUEST_LEAF_INDEX state.
Ryan Sleevi 2016/10/03 23:38:47 I appreciate the commenting, but this one seems ov
Rob Percival 2016/10/04 18:35:40 Done.
114 leaf_hash.CopyToString(&leaf_hash_);
115 // The callback will be used during the REQUEST_AUDIT_PROOF_NODES_COMPLETE
116 // state.
Ryan Sleevi 2016/10/03 23:38:47 I appreciate the commenting, but this one seems ov
Rob Percival 2016/10/04 18:35:40 Done.
111 callback_ = callback; 117 callback_ = callback;
112 QueryLeafIndex(leaf_hash); 118 // The first step in the query is to request the leaf index corresponding to
113 } 119 // |leaf_hash| from the CT log.
114 120 next_state_ = State::REQUEST_LEAF_INDEX;
121 // Begin the state machine.
122 return DoLoop(net::OK);
123 }
124
125 // Take the audit proof obtained by the query.
126 // Should only be called once the CompletionCallback is invoked.
115 std::unique_ptr<net::ct::MerkleAuditProof> TakeProof() { 127 std::unique_ptr<net::ct::MerkleAuditProof> TakeProof() {
116 return std::move(proof_); 128 return std::move(proof_);
117 } 129 }
118 130
119 private: 131 private:
120 void QueryLeafIndex(base::StringPiece leaf_hash) { 132 enum class State {
Ryan Sleevi 2016/10/03 23:38:47 I believe this may be the first use of enum class
Rob Percival 2016/10/04 18:35:39 Looks like it's been done a few times before (http
133 NONE,
134 REQUEST_LEAF_INDEX,
135 REQUEST_LEAF_INDEX_COMPLETE,
136 REQUEST_AUDIT_PROOF_NODES,
137 REQUEST_AUDIT_PROOF_NODES_COMPLETE,
138 };
139
140 net::Error DoLoop(net::Error result) {
141 CHECK_NE(State::NONE, next_state_);
142 do {
143 State state = next_state_;
144 next_state_ = State::NONE;
145 switch (state) {
146 case State::REQUEST_LEAF_INDEX:
147 result = RequestLeafIndex();
148 break;
149 case State::REQUEST_LEAF_INDEX_COMPLETE:
150 result = RequestLeafIndexComplete(result);
151 break;
152 case State::REQUEST_AUDIT_PROOF_NODES:
153 result = RequestAuditProofNodes();
154 break;
155 case State::REQUEST_AUDIT_PROOF_NODES_COMPLETE:
156 result = RequestAuditProofNodesComplete(result);
157 break;
158 case State::NONE:
159 NOTREACHED();
160 break;
161 }
162 } while (result != net::ERR_IO_PENDING && next_state_ != State::NONE);
163
164 return result;
165 }
166
167 // When a DnsTransaction completes, store the response and resume the state
168 // machine. It is safe to store a pointer to |response| because |transaction|
169 // is kept alive in |current_dns_transaction_|.
170 void OnDnsTransactionComplete(net::DnsTransaction* transaction,
171 int net_error,
172 const net::DnsResponse* response) {
173 DCHECK_EQ(current_dns_transaction_.get(), transaction);
Ryan Sleevi 2016/10/03 23:38:47 Is the .get() necessary? operator== is supposed to
Rob Percival 2016/10/04 18:35:39 Yes, as unique_ptr doesn't have an operator== over
174 last_dns_response_ = response;
175 net::Error result = DoLoop(static_cast<net::Error>(net_error));
176
177 // If DoLoop() indicates that I/O is pending, don't invoke the completion
178 // callback. OnDnsTransactionComplete() will be invoked again once the I/O
179 // is complete, and can invoke the completion callback then if appropriate.
180 if (result != net::ERR_IO_PENDING) {
181 base::ThreadTaskRunnerHandle::Get()->PostTask(
182 FROM_HERE, base::Bind(callback_, result, base::Unretained(this)));
Ryan Sleevi 2016/10/03 23:38:47 Why do you PostTask yield here? This is generally
Rob Percival 2016/10/04 18:35:39 It's safe because the callback will only be invoke
183 }
184 }
185
186 // Requests the leaf index for the CT log entry with |leaf_hash_|.
187 net::Error RequestLeafIndex() {
121 std::string encoded_leaf_hash = base32::Base32Encode( 188 std::string encoded_leaf_hash = base32::Base32Encode(
122 leaf_hash, base32::Base32EncodePolicy::OMIT_PADDING); 189 leaf_hash_, base32::Base32EncodePolicy::OMIT_PADDING);
123 DCHECK_EQ(encoded_leaf_hash.size(), 52u); 190 DCHECK_EQ(encoded_leaf_hash.size(), 52u);
124 191
125 std::string qname = base::StringPrintf( 192 std::string qname = base::StringPrintf(
126 "%s.hash.%s.", encoded_leaf_hash.c_str(), domain_for_log_.data()); 193 "%s.hash.%s.", encoded_leaf_hash.c_str(), domain_for_log_.c_str());
127 194
128 net::DnsTransactionFactory* factory = dns_client_->GetTransactionFactory(); 195 if (!StartDnsTransaction(qname)) {
129 if (factory == nullptr) { 196 return net::ERR_NAME_RESOLUTION_FAILED;
130 base::ThreadTaskRunnerHandle::Get()->PostTask( 197 }
131 FROM_HERE, 198
132 base::Bind(callback_, net::Error::ERR_NAME_RESOLUTION_FAILED, 199 next_state_ = State::REQUEST_LEAF_INDEX_COMPLETE;
133 base::Unretained(this))); 200 return net::ERR_IO_PENDING;
134 return; 201 }
135 } 202
136 203 // Stores the received leaf index in |proof_->leaf_index|.
137 net::DnsTransactionFactory::CallbackType transaction_callback = 204 // If successful, the audit proof nodes will be requested next.
138 base::Bind(&LogDnsClient::AuditProofQuery::QueryLeafIndexComplete, 205 net::Error RequestLeafIndexComplete(net::Error result) {
139 weak_ptr_factory_.GetWeakPtr()); 206 if (result != net::OK) {
140 207 return result;
141 current_dns_transaction_ = factory->CreateTransaction( 208 }
142 qname, net::dns_protocol::kTypeTXT, transaction_callback, net_log_); 209
143 210 DCHECK(last_dns_response_);
144 current_dns_transaction_->Start(); 211 if (!ParseLeafIndex(*last_dns_response_, &proof_->leaf_index)) {
145 } 212 return net::ERR_DNS_MALFORMED_RESPONSE;
146
147 void QueryLeafIndexComplete(net::DnsTransaction* transaction,
148 int net_error,
149 const net::DnsResponse* response) {
150 // If we've received no response but no net::error either (shouldn't
151 // happen),
152 // report the response as invalid.
153 if (response == nullptr && net_error == net::OK) {
154 net_error = net::ERR_INVALID_RESPONSE;
155 }
156
157 if (net_error != net::OK) {
158 base::ThreadTaskRunnerHandle::Get()->PostTask(
159 FROM_HERE, base::Bind(callback_, net_error, base::Unretained(this)));
160 return;
161 }
162
163 if (!ParseLeafIndex(*response, &proof_->leaf_index)) {
164 base::ThreadTaskRunnerHandle::Get()->PostTask(
165 FROM_HERE, base::Bind(callback_, net::ERR_DNS_MALFORMED_RESPONSE,
166 base::Unretained(this)));
167 return;
168 } 213 }
169 214
170 // Reject leaf index if it is out-of-range. 215 // Reject leaf index if it is out-of-range.
171 // This indicates either: 216 // This indicates either:
172 // a) the wrong tree_size was provided. 217 // a) the wrong tree_size was provided.
173 // b) the wrong leaf hash was provided. 218 // b) the wrong leaf hash was provided.
174 // c) there is a bug server-side. 219 // c) there is a bug server-side.
175 // The first two are more likely, so return ERR_INVALID_ARGUMENT. 220 // The first two are more likely, so return ERR_INVALID_ARGUMENT.
176 if (proof_->leaf_index >= tree_size_) { 221 if (proof_->leaf_index >= tree_size_) {
177 base::ThreadTaskRunnerHandle::Get()->PostTask( 222 return net::ERR_INVALID_ARGUMENT;
178 FROM_HERE, base::Bind(callback_, net::ERR_INVALID_ARGUMENT, 223 }
179 base::Unretained(this))); 224
180 return; 225 next_state_ = State::REQUEST_AUDIT_PROOF_NODES;
181 } 226 return net::OK;
182 227 }
183 // QueryAuditProof for the first batch of audit proof_ nodes (i.e. starting 228
184 // from 0). 229 // Requests the next batch of audit proof nodes from a CT log.
185 QueryAuditProofNodes(0 /* start node index */); 230 // The index of the first node required is determined by looking at how many
186 } 231 // nodes are already in |proof_->nodes|.
187 232 // The CT log may return up to 7 nodes - this is the maximum allowed by the
188 // Queries a CT log to retrieve part of an audit |proof|. The |node_index| 233 // CT-over-DNS draft RFC, as a TXT RDATA string can have a maximum length of
189 // indicates which node of the audit proof/ should be requested. The CT log 234 // 255 bytes and each node is 32 bytes long (a SHA-256 hash).
190 // may return up to 7 nodes, starting from |node_index| (this is the maximum 235 //
191 // that will fit in a DNS UDP packet). The nodes will be appended to 236 // The performance of this could be improved by sending all of the expected
192 // |proof->nodes|. 237 // requests up front. Each response can contain a maximum of 7 audit path
193 void QueryAuditProofNodes(uint64_t node_index) { 238 // nodes, so for an audit proof of size 20, it could send 3 queries (for nodes
239 // 0-6, 7-13 and 14-19) immediately. Currently, it sends only the first and
240 // then, based on the number of nodes received, sends the next query.
241 // The complexity of the code would increase though, as it would need to
242 // detect gaps in the audit proof caused by the server not responding with the
243 // anticipated number of nodes. It would also undermine LogDnsClient's ability
244 // to rate-limit DNS requests.
Ryan Sleevi 2016/10/03 23:38:47 This last comment is not obvious about why this is
Rob Percival 2016/10/04 18:35:40 If AuditProofQuery could perform parallel DNS requ
245 net::Error RequestAuditProofNodes() {
194 DCHECK_LT(proof_->leaf_index, tree_size_); 246 DCHECK_LT(proof_->leaf_index, tree_size_);
195 DCHECK_LT(node_index, net::ct::CalculateAuditPathLength(proof_->leaf_index, 247 DCHECK_LT(proof_->nodes.size(), net::ct::CalculateAuditPathLength(
196 tree_size_)); 248 proof_->leaf_index, tree_size_));
Ryan Sleevi 2016/10/03 23:38:47 Are these DCHECKs guarding against programmer erro
Rob Percival 2016/10/04 18:35:40 These variables are validated as soon as they are
197 249
198 std::string qname = base::StringPrintf( 250 std::string qname = base::StringPrintf(
199 "%" PRIu64 ".%" PRIu64 ".%" PRIu64 ".tree.%s.", node_index, 251 "%zu.%" PRIu64 ".%" PRIu64 ".tree.%s.", proof_->nodes.size(),
200 proof_->leaf_index, tree_size_, domain_for_log_.data()); 252 proof_->leaf_index, tree_size_, domain_for_log_.c_str());
201 253
202 net::DnsTransactionFactory* factory = dns_client_->GetTransactionFactory(); 254 if (!StartDnsTransaction(qname)) {
203 if (factory == nullptr) { 255 return net::ERR_NAME_RESOLUTION_FAILED;
204 base::ThreadTaskRunnerHandle::Get()->PostTask( 256 }
205 FROM_HERE, 257
206 base::Bind(callback_, net::Error::ERR_NAME_RESOLUTION_FAILED, 258 next_state_ = State::REQUEST_AUDIT_PROOF_NODES_COMPLETE;
207 base::Unretained(this))); 259 return net::ERR_IO_PENDING;
208 return; 260 }
209 } 261
210 262 // Appends the received audit proof nodes to |proof_->nodes|.
211 net::DnsTransactionFactory::CallbackType transaction_callback = 263 // If any nodes are missing, another request will follow this one.
212 base::Bind(&LogDnsClient::AuditProofQuery::QueryAuditProofNodesComplete, 264 net::Error RequestAuditProofNodesComplete(net::Error result) {
213 weak_ptr_factory_.GetWeakPtr()); 265 if (result != net::OK) {
214 266 return result;
215 current_dns_transaction_ = factory->CreateTransaction(
216 qname, net::dns_protocol::kTypeTXT, transaction_callback, net_log_);
217 current_dns_transaction_->Start();
218 }
219
220 void QueryAuditProofNodesComplete(net::DnsTransaction* transaction,
221 int net_error,
222 const net::DnsResponse* response) {
223 // If we receive no response but no net::error either (shouldn't happen),
224 // report the response as invalid.
225 if (response == nullptr && net_error == net::OK) {
226 net_error = net::ERR_INVALID_RESPONSE;
227 }
228
229 if (net_error != net::OK) {
230 base::ThreadTaskRunnerHandle::Get()->PostTask(
231 FROM_HERE, base::Bind(callback_, net_error, base::Unretained(this)));
232 return;
233 } 267 }
234 268
235 const uint64_t audit_path_length = 269 const uint64_t audit_path_length =
236 net::ct::CalculateAuditPathLength(proof_->leaf_index, tree_size_); 270 net::ct::CalculateAuditPathLength(proof_->leaf_index, tree_size_);
271
237 // The calculated |audit_path_length| can't ever be greater than 64, so 272 // The calculated |audit_path_length| can't ever be greater than 64, so
238 // deriving the amount of memory to reserve from the untrusted |leaf_index| 273 // deriving the amount of memory to reserve from the untrusted |leaf_index|
239 // is safe. 274 // is safe.
240 proof_->nodes.reserve(audit_path_length); 275 proof_->nodes.reserve(audit_path_length);
241 276
242 if (!ParseAuditPath(*response, proof_.get())) { 277 DCHECK(last_dns_response_);
243 base::ThreadTaskRunnerHandle::Get()->PostTask( 278 if (!ParseAuditPath(*last_dns_response_, proof_.get())) {
244 FROM_HERE, base::Bind(callback_, net::ERR_DNS_MALFORMED_RESPONSE, 279 return net::ERR_DNS_MALFORMED_RESPONSE;
245 base::Unretained(this))); 280 }
246 return; 281
247 } 282 // If we don't have all of the proof nodes yet, request more.
Ryan Sleevi 2016/10/03 23:38:47 // Keep requesting more proof nodes until all of t
Rob Percival 2016/10/04 18:35:39 Done.
248 283 if (proof_->nodes.size() < audit_path_length) {
249 const uint64_t audit_path_nodes_received = proof_->nodes.size(); 284 next_state_ = State::REQUEST_AUDIT_PROOF_NODES;
250 if (audit_path_nodes_received < audit_path_length) { 285 }
251 QueryAuditProofNodes(audit_path_nodes_received); 286
252 return; 287 return net::OK;
253 } 288 }
254 289
255 base::ThreadTaskRunnerHandle::Get()->PostTask( 290 bool StartDnsTransaction(const std::string& qname) {
256 FROM_HERE, base::Bind(callback_, net::OK, base::Unretained(this))); 291 net::DnsTransactionFactory* factory = dns_client_->GetTransactionFactory();
257 } 292 if (factory == nullptr) {
258 293 return false;
294 }
295
296 current_dns_transaction_ = factory->CreateTransaction(
297 qname, net::dns_protocol::kTypeTXT,
298 base::Bind(&LogDnsClient::AuditProofQuery::OnDnsTransactionComplete,
299 weak_ptr_factory_.GetWeakPtr()),
300 net_log_);
301
302 current_dns_transaction_->Start();
303 return true;
304 }
305
306 // The next state that this query will enter.
307 State next_state_;
308 // The DNS domain of the CT log that is being queried.
259 std::string domain_for_log_; 309 std::string domain_for_log_;
310 // The Merkle leaf hash of the CT log entry an audit proof is required for.
311 std::string leaf_hash_;
312 // The size of the CT log's tree, from which the proof is requested.
260 // TODO(robpercival): Remove |tree_size| once |proof_| has a tree_size member. 313 // TODO(robpercival): Remove |tree_size| once |proof_| has a tree_size member.
261 uint64_t tree_size_; 314 uint64_t tree_size_;
315 // The audit proof. It will be null until the query is started and incomplete
316 // until the query is finished.
262 std::unique_ptr<net::ct::MerkleAuditProof> proof_; 317 std::unique_ptr<net::ct::MerkleAuditProof> proof_;
318 // The callback to invoke when the query is complete.
263 CompletionCallback callback_; 319 CompletionCallback callback_;
320 // The DnsClient to use for sending DNS requests to the CT log.
264 net::DnsClient* dns_client_; 321 net::DnsClient* dns_client_;
322 // The most recent DNS request. Null if no DNS requests have been made.
265 std::unique_ptr<net::DnsTransaction> current_dns_transaction_; 323 std::unique_ptr<net::DnsTransaction> current_dns_transaction_;
324 // The most recent DNS response. Only valid so long as the corresponding DNS
325 // request is stored in |current_dns_transaction_|.
326 const net::DnsResponse* last_dns_response_;
327 // The NetLog that DNS transactions will log to.
266 net::NetLogWithSource net_log_; 328 net::NetLogWithSource net_log_;
329 // Produces WeakPtrs to |this| for binding callbacks.
267 base::WeakPtrFactory<AuditProofQuery> weak_ptr_factory_; 330 base::WeakPtrFactory<AuditProofQuery> weak_ptr_factory_;
268 }; 331 };
269 332
270 LogDnsClient::LogDnsClient(std::unique_ptr<net::DnsClient> dns_client, 333 LogDnsClient::LogDnsClient(std::unique_ptr<net::DnsClient> dns_client,
271 const net::NetLogWithSource& net_log, 334 const net::NetLogWithSource& net_log,
272 size_t max_concurrent_queries) 335 size_t max_concurrent_queries)
273 : dns_client_(std::move(dns_client)), 336 : dns_client_(std::move(dns_client)),
274 net_log_(net_log), 337 net_log_(net_log),
275 max_concurrent_queries_(max_concurrent_queries), 338 max_concurrent_queries_(max_concurrent_queries),
276 weak_ptr_factory_(this) { 339 weak_ptr_factory_(this) {
277 CHECK(dns_client_); 340 CHECK(dns_client_);
278 net::NetworkChangeNotifier::AddDNSObserver(this); 341 net::NetworkChangeNotifier::AddDNSObserver(this);
279 UpdateDnsConfig(); 342 UpdateDnsConfig();
280 } 343 }
281 344
282 LogDnsClient::~LogDnsClient() { 345 LogDnsClient::~LogDnsClient() {
283 net::NetworkChangeNotifier::RemoveDNSObserver(this); 346 net::NetworkChangeNotifier::RemoveDNSObserver(this);
284 } 347 }
285 348
286 void LogDnsClient::OnDNSChanged() { 349 void LogDnsClient::OnDNSChanged() {
287 UpdateDnsConfig(); 350 UpdateDnsConfig();
288 } 351 }
289 352
290 void LogDnsClient::OnInitialDNSConfigRead() { 353 void LogDnsClient::OnInitialDNSConfigRead() {
291 UpdateDnsConfig(); 354 UpdateDnsConfig();
292 } 355 }
293 356
294 // The performance of this could be improved by sending all of the expected 357 net::Error LogDnsClient::QueryAuditProof(base::StringPiece domain_for_log,
295 // queries up front. Each response can contain a maximum of 7 audit path nodes, 358 base::StringPiece leaf_hash,
296 // so for an audit proof of size 20, it could send 3 queries (for nodes 0-6, 359 uint64_t tree_size,
297 // 7-13 and 14-19) immediately. Currently, it sends only the first and then, 360 const AuditProofCallback& callback) {
298 // based on the number of nodes received, sends the next query. The complexity
299 // of the code would increase though, as it would need to detect gaps in the
300 // audit proof caused by the server not responding with the anticipated number
301 // of nodes. Ownership of the proof would need to change, as it would be shared
302 // between simultaneous DNS transactions. Throttling of queries would also need
303 // to take into account this increase in parallelism.
304 void LogDnsClient::QueryAuditProof(const std::string& domain_for_log,
305 base::StringPiece leaf_hash,
306 uint64_t tree_size,
307 const AuditProofCallback& callback) {
308 if (domain_for_log.empty() || leaf_hash.size() != crypto::kSHA256Length) { 361 if (domain_for_log.empty() || leaf_hash.size() != crypto::kSHA256Length) {
309 base::ThreadTaskRunnerHandle::Get()->PostTask( 362 return net::ERR_INVALID_ARGUMENT;
310 FROM_HERE,
311 base::Bind(callback, net::Error::ERR_INVALID_ARGUMENT, nullptr));
312 return;
313 } 363 }
314 364
315 if (HasMaxConcurrentQueriesInProgress()) { 365 if (HasMaxConcurrentQueriesInProgress()) {
316 base::ThreadTaskRunnerHandle::Get()->PostTask( 366 return net::ERR_TEMPORARILY_THROTTLED;
317 FROM_HERE,
318 base::Bind(callback, net::Error::ERR_TEMPORARILY_THROTTLED, nullptr));
319 return;
320 } 367 }
321 368
322 audit_proof_queries_.emplace_back(new AuditProofQuery( 369 AuditProofQuery* query = new AuditProofQuery(
323 dns_client_.get(), domain_for_log, tree_size, net_log_)); 370 dns_client_.get(), domain_for_log.as_string(), tree_size, net_log_);
371 // Transfers ownership of |query| to |audit_proof_queries_|.
372 audit_proof_queries_.emplace_back(query);
324 373
325 AuditProofQuery::CompletionCallback internal_callback = 374 AuditProofQuery::CompletionCallback internal_callback =
326 base::Bind(&LogDnsClient::QueryAuditProofComplete, 375 base::Bind(&LogDnsClient::QueryAuditProofComplete,
327 weak_ptr_factory_.GetWeakPtr(), callback); 376 weak_ptr_factory_.GetWeakPtr(), callback);
328 377
329 audit_proof_queries_.back()->Start(leaf_hash, internal_callback); 378 return query->Start(leaf_hash, internal_callback);
330 } 379 }
331 380
332 void LogDnsClient::QueryAuditProofComplete(const AuditProofCallback& callback, 381 void LogDnsClient::QueryAuditProofComplete(const AuditProofCallback& callback,
333 int result, 382 net::Error result,
334 AuditProofQuery* query) { 383 AuditProofQuery* query) {
335 DCHECK(query); 384 DCHECK(query);
336 385
337 std::unique_ptr<net::ct::MerkleAuditProof> proof; 386 std::unique_ptr<net::ct::MerkleAuditProof> proof;
338 if (result == net::OK) { 387 if (result == net::OK) {
339 proof = query->TakeProof(); 388 proof = query->TakeProof();
340 } 389 }
341 390
342 // Finished with the query - destroy it. Do this before invoking |callback| 391 // Finished with the query - destroy it. Do this before invoking |callback|
343 // in case it wants to perform another query and |audit_proof_queries_| is 392 // in case it wants to perform another query and |audit_proof_queries_| is
344 // already at its limit (as specified by |max_concurrent_queries_|. 393 // already at its limit (as specified by |max_concurrent_queries_|).
345 auto query_iterator = 394 auto query_iterator =
346 std::find_if(audit_proof_queries_.begin(), audit_proof_queries_.end(), 395 std::find_if(audit_proof_queries_.begin(), audit_proof_queries_.end(),
347 [query](const std::unique_ptr<AuditProofQuery>& p) { 396 [query](const std::unique_ptr<AuditProofQuery>& p) {
348 return p.get() == query; 397 return p.get() == query;
349 }); 398 });
350 DCHECK(query_iterator != audit_proof_queries_.end()); 399 DCHECK(query_iterator != audit_proof_queries_.end());
351 audit_proof_queries_.erase(query_iterator); 400 audit_proof_queries_.erase(query_iterator);
352 401
353 base::ThreadTaskRunnerHandle::Get()->PostTask( 402 base::ThreadTaskRunnerHandle::Get()->PostTask(
354 FROM_HERE, base::Bind(callback, result, base::Passed(&proof))); 403 FROM_HERE, base::Bind(callback, result, base::Passed(&proof)));
355 } 404 }
356 405
357 bool LogDnsClient::HasMaxConcurrentQueriesInProgress() const { 406 bool LogDnsClient::HasMaxConcurrentQueriesInProgress() const {
358 return max_concurrent_queries_ != 0 && 407 return max_concurrent_queries_ != 0 &&
359 audit_proof_queries_.size() >= max_concurrent_queries_; 408 audit_proof_queries_.size() >= max_concurrent_queries_;
360 } 409 }
361 410
362 void LogDnsClient::UpdateDnsConfig() { 411 void LogDnsClient::UpdateDnsConfig() {
363 net::DnsConfig config; 412 net::DnsConfig config;
364 net::NetworkChangeNotifier::GetDnsConfig(&config); 413 net::NetworkChangeNotifier::GetDnsConfig(&config);
365 if (config.IsValid()) 414 if (config.IsValid())
366 dns_client_->SetConfig(config); 415 dns_client_->SetConfig(config);
367 } 416 }
368 417
369 } // namespace certificate_transparency 418 } // namespace certificate_transparency
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698