OLD | NEW |
---|---|
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 Loading... | |
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, |
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. | |
110 proof_.reset(new net::ct::MerkleAuditProof); | 112 proof_.reset(new net::ct::MerkleAuditProof); |
113 // The leaf hash and callback will be used later. | |
Eran Messeri
2016/09/30 09:26:51
nit: Explain when later is.
Rob Percival
2016/09/30 12:03:21
Done.
| |
114 leaf_hash.CopyToString(&leaf_hash_); | |
111 callback_ = callback; | 115 callback_ = callback; |
112 QueryLeafIndex(leaf_hash); | 116 // The first step in the query is to request the leaf index corresponding to |
113 } | 117 // |leaf_hash| from the CT log. |
114 | 118 next_state_ = State::REQUEST_LEAF_INDEX; |
119 // Begin the state machine. | |
120 return DoLoop(net::OK); | |
121 } | |
122 | |
123 // Take the audit proof obtained by the query. | |
124 // Should only be called once the CompletionCallback is invoked. | |
115 std::unique_ptr<net::ct::MerkleAuditProof> TakeProof() { | 125 std::unique_ptr<net::ct::MerkleAuditProof> TakeProof() { |
116 return std::move(proof_); | 126 return std::move(proof_); |
117 } | 127 } |
118 | 128 |
119 private: | 129 private: |
120 void QueryLeafIndex(base::StringPiece leaf_hash) { | 130 enum class State { |
131 NONE, | |
132 REQUEST_LEAF_INDEX, | |
133 REQUEST_LEAF_INDEX_COMPLETE, | |
134 REQUEST_AUDIT_PROOF_NODES, | |
135 REQUEST_AUDIT_PROOF_NODES_COMPLETE, | |
136 }; | |
137 | |
138 net::Error DoLoop(net::Error result) { | |
139 CHECK_NE(State::NONE, next_state_); | |
140 do { | |
141 State state = next_state_; | |
142 next_state_ = State::NONE; | |
143 switch (state) { | |
144 case State::REQUEST_LEAF_INDEX: | |
145 result = RequestLeafIndex(); | |
146 break; | |
147 case State::REQUEST_LEAF_INDEX_COMPLETE: | |
148 result = RequestLeafIndexComplete(result); | |
149 break; | |
150 case State::REQUEST_AUDIT_PROOF_NODES: | |
151 result = RequestAuditProofNodes(); | |
152 break; | |
153 case State::REQUEST_AUDIT_PROOF_NODES_COMPLETE: | |
154 result = RequestAuditProofNodesComplete(result); | |
155 break; | |
156 case State::NONE: | |
157 NOTREACHED(); | |
158 break; | |
159 } | |
160 } while (result != net::ERR_IO_PENDING && next_state_ != State::NONE); | |
161 | |
162 return result; | |
163 } | |
164 | |
165 // When a DnsTransaction completes, store the response and resume the state | |
166 // machine. It is safe to store a pointer to |response| because |transaction| | |
167 // is kept alive in |current_dns_transaction_|. | |
Eran Messeri
2016/09/30 09:26:51
Would it be appropriate , then, to add a DCHECK_EQ
Rob Percival
2016/09/30 12:03:21
Done.
| |
168 void OnDnsTransactionComplete(net::DnsTransaction* transaction, | |
169 int net_error, | |
170 const net::DnsResponse* response) { | |
171 last_dns_response_ = response; | |
172 net::Error result = DoLoop(static_cast<net::Error>(net_error)); | |
173 | |
174 // If DoLoop() indicates that I/O is pending, don't invoke the completion | |
175 // callback. OnDnsTransactionComplete() will be invoked again once the I/O | |
176 // is complete, and can invoke the completion callback then if appropriate. | |
177 if (result != net::ERR_IO_PENDING) { | |
178 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
179 FROM_HERE, base::Bind(callback_, result, base::Unretained(this))); | |
180 } | |
181 } | |
182 | |
183 // Requests the leaf index for the CT log entry with |leaf_hash_|. | |
184 net::Error RequestLeafIndex() { | |
121 std::string encoded_leaf_hash = base32::Base32Encode( | 185 std::string encoded_leaf_hash = base32::Base32Encode( |
122 leaf_hash, base32::Base32EncodePolicy::OMIT_PADDING); | 186 leaf_hash_, base32::Base32EncodePolicy::OMIT_PADDING); |
123 DCHECK_EQ(encoded_leaf_hash.size(), 52u); | 187 DCHECK_EQ(encoded_leaf_hash.size(), 52u); |
124 | 188 |
125 std::string qname = base::StringPrintf( | 189 std::string qname = base::StringPrintf( |
126 "%s.hash.%s.", encoded_leaf_hash.c_str(), domain_for_log_.data()); | 190 "%s.hash.%s.", encoded_leaf_hash.c_str(), domain_for_log_.c_str()); |
127 | 191 |
128 net::DnsTransactionFactory* factory = dns_client_->GetTransactionFactory(); | 192 if (!StartDnsTransaction(qname)) { |
129 if (factory == nullptr) { | 193 return net::ERR_NAME_RESOLUTION_FAILED; |
130 base::ThreadTaskRunnerHandle::Get()->PostTask( | 194 } |
131 FROM_HERE, | 195 |
132 base::Bind(callback_, net::Error::ERR_NAME_RESOLUTION_FAILED, | 196 next_state_ = State::REQUEST_LEAF_INDEX_COMPLETE; |
133 base::Unretained(this))); | 197 return net::ERR_IO_PENDING; |
134 return; | 198 } |
135 } | 199 |
136 | 200 // Stores the received leaf index in |proof_->leaf_index|. |
137 net::DnsTransactionFactory::CallbackType transaction_callback = | 201 // If successful, the audit proof nodes will be requested next. |
138 base::Bind(&LogDnsClient::AuditProofQuery::QueryLeafIndexComplete, | 202 net::Error RequestLeafIndexComplete(net::Error result) { |
139 weak_ptr_factory_.GetWeakPtr()); | 203 if (result != net::OK) { |
140 | 204 return result; |
141 current_dns_transaction_ = factory->CreateTransaction( | 205 } |
142 qname, net::dns_protocol::kTypeTXT, transaction_callback, net_log_); | 206 |
143 | 207 DCHECK(last_dns_response_); |
144 current_dns_transaction_->Start(); | 208 if (!ParseLeafIndex(*last_dns_response_, &proof_->leaf_index)) { |
145 } | 209 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 } | 210 } |
169 | 211 |
170 // Reject leaf index if it is out-of-range. | 212 // Reject leaf index if it is out-of-range. |
171 // This indicates either: | 213 // This indicates either: |
172 // a) the wrong tree_size was provided. | 214 // a) the wrong tree_size was provided. |
173 // b) the wrong leaf hash was provided. | 215 // b) the wrong leaf hash was provided. |
174 // c) there is a bug server-side. | 216 // c) there is a bug server-side. |
175 // The first two are more likely, so return ERR_INVALID_ARGUMENT. | 217 // The first two are more likely, so return ERR_INVALID_ARGUMENT. |
176 if (proof_->leaf_index >= tree_size_) { | 218 if (proof_->leaf_index >= tree_size_) { |
177 base::ThreadTaskRunnerHandle::Get()->PostTask( | 219 return net::ERR_INVALID_ARGUMENT; |
178 FROM_HERE, base::Bind(callback_, net::ERR_INVALID_ARGUMENT, | 220 } |
179 base::Unretained(this))); | 221 |
180 return; | 222 next_state_ = State::REQUEST_AUDIT_PROOF_NODES; |
181 } | 223 return net::OK; |
182 | 224 } |
183 // QueryAuditProof for the first batch of audit proof_ nodes (i.e. starting | 225 |
184 // from 0). | 226 // Requests the next batch of audit proof nodes from a CT log. |
185 QueryAuditProofNodes(0 /* start node index */); | 227 // The index of the first node required is determined by looking at how many |
186 } | 228 // nodes are already in |proof_->nodes|. |
187 | 229 // 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| | 230 // 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 | 231 // 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 | 232 // |
191 // that will fit in a DNS UDP packet). The nodes will be appended to | 233 // The performance of this could be improved by sending all of the expected |
192 // |proof->nodes|. | 234 // requests up front. Each response can contain a maximum of 7 audit path |
193 void QueryAuditProofNodes(uint64_t node_index) { | 235 // nodes, so for an audit proof of size 20, it could send 3 queries (for nodes |
236 // 0-6, 7-13 and 14-19) immediately. Currently, it sends only the first and | |
237 // then, based on the number of nodes received, sends the next query. | |
238 // The complexity of the code would increase though, as it would need to | |
239 // detect gaps in the audit proof caused by the server not responding with the | |
240 // anticipated number of nodes. It would also undermine LogDnsClient's ability | |
241 // to rate-limit DNS requests. | |
242 net::Error RequestAuditProofNodes() { | |
194 DCHECK_LT(proof_->leaf_index, tree_size_); | 243 DCHECK_LT(proof_->leaf_index, tree_size_); |
195 DCHECK_LT(node_index, net::ct::CalculateAuditPathLength(proof_->leaf_index, | 244 DCHECK_LT(proof_->nodes.size(), net::ct::CalculateAuditPathLength( |
196 tree_size_)); | 245 proof_->leaf_index, tree_size_)); |
197 | 246 |
198 std::string qname = base::StringPrintf( | 247 std::string qname = base::StringPrintf( |
199 "%" PRIu64 ".%" PRIu64 ".%" PRIu64 ".tree.%s.", node_index, | 248 "%zu.%" PRIu64 ".%" PRIu64 ".tree.%s.", proof_->nodes.size(), |
200 proof_->leaf_index, tree_size_, domain_for_log_.data()); | 249 proof_->leaf_index, tree_size_, domain_for_log_.c_str()); |
201 | 250 |
202 net::DnsTransactionFactory* factory = dns_client_->GetTransactionFactory(); | 251 if (!StartDnsTransaction(qname)) { |
203 if (factory == nullptr) { | 252 return net::ERR_NAME_RESOLUTION_FAILED; |
204 base::ThreadTaskRunnerHandle::Get()->PostTask( | 253 } |
205 FROM_HERE, | 254 |
206 base::Bind(callback_, net::Error::ERR_NAME_RESOLUTION_FAILED, | 255 next_state_ = State::REQUEST_AUDIT_PROOF_NODES_COMPLETE; |
207 base::Unretained(this))); | 256 return net::ERR_IO_PENDING; |
208 return; | 257 } |
209 } | 258 |
210 | 259 // Appends the received audit proof nodes to |proof_->nodes|. |
211 net::DnsTransactionFactory::CallbackType transaction_callback = | 260 // If any nodes are missing, another request will follow this one. |
212 base::Bind(&LogDnsClient::AuditProofQuery::QueryAuditProofNodesComplete, | 261 net::Error RequestAuditProofNodesComplete(net::Error result) { |
213 weak_ptr_factory_.GetWeakPtr()); | 262 if (result != net::OK) { |
214 | 263 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 } | 264 } |
234 | 265 |
235 const uint64_t audit_path_length = | 266 const uint64_t audit_path_length = |
236 net::ct::CalculateAuditPathLength(proof_->leaf_index, tree_size_); | 267 net::ct::CalculateAuditPathLength(proof_->leaf_index, tree_size_); |
268 | |
237 // The calculated |audit_path_length| can't ever be greater than 64, so | 269 // 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| | 270 // deriving the amount of memory to reserve from the untrusted |leaf_index| |
239 // is safe. | 271 // is safe. |
240 proof_->nodes.reserve(audit_path_length); | 272 proof_->nodes.reserve(audit_path_length); |
241 | 273 |
242 if (!ParseAuditPath(*response, proof_.get())) { | 274 DCHECK(last_dns_response_); |
243 base::ThreadTaskRunnerHandle::Get()->PostTask( | 275 if (!ParseAuditPath(*last_dns_response_, proof_.get())) { |
244 FROM_HERE, base::Bind(callback_, net::ERR_DNS_MALFORMED_RESPONSE, | 276 return net::ERR_DNS_MALFORMED_RESPONSE; |
245 base::Unretained(this))); | 277 } |
246 return; | 278 |
247 } | 279 // If we don't have all of the proof nodes yet, request more. |
248 | 280 if (proof_->nodes.size() < audit_path_length) { |
249 const uint64_t audit_path_nodes_received = proof_->nodes.size(); | 281 next_state_ = State::REQUEST_AUDIT_PROOF_NODES; |
250 if (audit_path_nodes_received < audit_path_length) { | 282 } |
251 QueryAuditProofNodes(audit_path_nodes_received); | 283 |
252 return; | 284 return net::OK; |
253 } | 285 } |
254 | 286 |
255 base::ThreadTaskRunnerHandle::Get()->PostTask( | 287 bool StartDnsTransaction(const std::string& qname) { |
256 FROM_HERE, base::Bind(callback_, net::OK, base::Unretained(this))); | 288 net::DnsTransactionFactory* factory = dns_client_->GetTransactionFactory(); |
257 } | 289 if (factory == nullptr) { |
258 | 290 return false; |
291 } | |
292 | |
293 net::DnsTransactionFactory::CallbackType transaction_callback = | |
Eran Messeri
2016/09/30 09:26:51
inline transaction_callback creation/use.
Rob Percival
2016/09/30 12:03:21
Done.
| |
294 base::Bind(&LogDnsClient::AuditProofQuery::OnDnsTransactionComplete, | |
295 weak_ptr_factory_.GetWeakPtr()); | |
296 | |
297 current_dns_transaction_ = factory->CreateTransaction( | |
298 qname, net::dns_protocol::kTypeTXT, transaction_callback, net_log_); | |
299 current_dns_transaction_->Start(); | |
300 return true; | |
301 } | |
302 | |
303 // The next state that this query will enter. | |
304 State next_state_; | |
305 // The DNS domain of the CT log that is being queried. | |
259 std::string domain_for_log_; | 306 std::string domain_for_log_; |
307 // The Merkle leaf hash of the CT log entry an audit proof is required for. | |
308 std::string leaf_hash_; | |
309 // 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. | 310 // TODO(robpercival): Remove |tree_size| once |proof_| has a tree_size member. |
261 uint64_t tree_size_; | 311 uint64_t tree_size_; |
312 // The audit proof. It will be null until the query is started and incomplete | |
313 // until the query is finished. | |
262 std::unique_ptr<net::ct::MerkleAuditProof> proof_; | 314 std::unique_ptr<net::ct::MerkleAuditProof> proof_; |
315 // The callback to invoke when the query is complete. | |
263 CompletionCallback callback_; | 316 CompletionCallback callback_; |
317 // The DnsClient to use for sending DNS requests to the CT log. | |
264 net::DnsClient* dns_client_; | 318 net::DnsClient* dns_client_; |
319 // The most recent DNS request. Null if no DNS requests have been made. | |
265 std::unique_ptr<net::DnsTransaction> current_dns_transaction_; | 320 std::unique_ptr<net::DnsTransaction> current_dns_transaction_; |
321 // The most recent DNS response. Only valid so long as the corresponding DNS | |
322 // request is stored in |current_dns_transaction_|. | |
323 const net::DnsResponse* last_dns_response_; | |
324 // The NetLog that DNS transactions will log to. | |
266 net::NetLogWithSource net_log_; | 325 net::NetLogWithSource net_log_; |
326 // Produces WeakPtrs to |this| for binding callbacks. | |
267 base::WeakPtrFactory<AuditProofQuery> weak_ptr_factory_; | 327 base::WeakPtrFactory<AuditProofQuery> weak_ptr_factory_; |
268 }; | 328 }; |
269 | 329 |
270 LogDnsClient::LogDnsClient(std::unique_ptr<net::DnsClient> dns_client, | 330 LogDnsClient::LogDnsClient(std::unique_ptr<net::DnsClient> dns_client, |
271 const net::NetLogWithSource& net_log, | 331 const net::NetLogWithSource& net_log, |
272 size_t max_concurrent_queries) | 332 size_t max_concurrent_queries) |
273 : dns_client_(std::move(dns_client)), | 333 : dns_client_(std::move(dns_client)), |
274 net_log_(net_log), | 334 net_log_(net_log), |
275 max_concurrent_queries_(max_concurrent_queries), | 335 max_concurrent_queries_(max_concurrent_queries), |
276 weak_ptr_factory_(this) { | 336 weak_ptr_factory_(this) { |
277 CHECK(dns_client_); | 337 CHECK(dns_client_); |
278 net::NetworkChangeNotifier::AddDNSObserver(this); | 338 net::NetworkChangeNotifier::AddDNSObserver(this); |
279 UpdateDnsConfig(); | 339 UpdateDnsConfig(); |
280 } | 340 } |
281 | 341 |
282 LogDnsClient::~LogDnsClient() { | 342 LogDnsClient::~LogDnsClient() { |
283 net::NetworkChangeNotifier::RemoveDNSObserver(this); | 343 net::NetworkChangeNotifier::RemoveDNSObserver(this); |
284 } | 344 } |
285 | 345 |
286 void LogDnsClient::OnDNSChanged() { | 346 void LogDnsClient::OnDNSChanged() { |
287 UpdateDnsConfig(); | 347 UpdateDnsConfig(); |
288 } | 348 } |
289 | 349 |
290 void LogDnsClient::OnInitialDNSConfigRead() { | 350 void LogDnsClient::OnInitialDNSConfigRead() { |
291 UpdateDnsConfig(); | 351 UpdateDnsConfig(); |
292 } | 352 } |
293 | 353 |
294 // The performance of this could be improved by sending all of the expected | 354 net::Error LogDnsClient::QueryAuditProof(base::StringPiece domain_for_log, |
295 // queries up front. Each response can contain a maximum of 7 audit path nodes, | 355 base::StringPiece leaf_hash, |
296 // so for an audit proof of size 20, it could send 3 queries (for nodes 0-6, | 356 uint64_t tree_size, |
297 // 7-13 and 14-19) immediately. Currently, it sends only the first and then, | 357 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) { | 358 if (domain_for_log.empty() || leaf_hash.size() != crypto::kSHA256Length) { |
309 base::ThreadTaskRunnerHandle::Get()->PostTask( | 359 return net::ERR_INVALID_ARGUMENT; |
310 FROM_HERE, | |
311 base::Bind(callback, net::Error::ERR_INVALID_ARGUMENT, nullptr)); | |
312 return; | |
313 } | 360 } |
314 | 361 |
315 if (HasMaxConcurrentQueriesInProgress()) { | 362 if (HasMaxConcurrentQueriesInProgress()) { |
316 base::ThreadTaskRunnerHandle::Get()->PostTask( | 363 return net::ERR_TEMPORARILY_THROTTLED; |
317 FROM_HERE, | |
318 base::Bind(callback, net::Error::ERR_TEMPORARILY_THROTTLED, nullptr)); | |
319 return; | |
320 } | 364 } |
321 | 365 |
322 audit_proof_queries_.emplace_back(new AuditProofQuery( | 366 AuditProofQuery* query = new AuditProofQuery( |
323 dns_client_.get(), domain_for_log, tree_size, net_log_)); | 367 dns_client_.get(), domain_for_log.as_string(), tree_size, net_log_); |
368 // Transfers ownership of |query| to |audit_proof_queries_|. | |
369 audit_proof_queries_.emplace_back(query); | |
324 | 370 |
325 AuditProofQuery::CompletionCallback internal_callback = | 371 AuditProofQuery::CompletionCallback internal_callback = |
326 base::Bind(&LogDnsClient::QueryAuditProofComplete, | 372 base::Bind(&LogDnsClient::QueryAuditProofComplete, |
327 weak_ptr_factory_.GetWeakPtr(), callback); | 373 weak_ptr_factory_.GetWeakPtr(), callback); |
328 | 374 |
329 audit_proof_queries_.back()->Start(leaf_hash, internal_callback); | 375 return query->Start(leaf_hash, internal_callback); |
330 } | 376 } |
331 | 377 |
332 void LogDnsClient::QueryAuditProofComplete(const AuditProofCallback& callback, | 378 void LogDnsClient::QueryAuditProofComplete(const AuditProofCallback& callback, |
333 int result, | 379 net::Error result, |
334 AuditProofQuery* query) { | 380 AuditProofQuery* query) { |
335 DCHECK(query); | 381 DCHECK(query); |
336 | 382 |
337 std::unique_ptr<net::ct::MerkleAuditProof> proof; | 383 std::unique_ptr<net::ct::MerkleAuditProof> proof; |
338 if (result == net::OK) { | 384 if (result == net::OK) { |
339 proof = query->TakeProof(); | 385 proof = query->TakeProof(); |
340 } | 386 } |
341 | 387 |
342 // Finished with the query - destroy it. Do this before invoking |callback| | 388 // 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 | 389 // in case it wants to perform another query and |audit_proof_queries_| is |
(...skipping 13 matching lines...) Expand all Loading... | |
357 } | 403 } |
358 | 404 |
359 void LogDnsClient::UpdateDnsConfig() { | 405 void LogDnsClient::UpdateDnsConfig() { |
360 net::DnsConfig config; | 406 net::DnsConfig config; |
361 net::NetworkChangeNotifier::GetDnsConfig(&config); | 407 net::NetworkChangeNotifier::GetDnsConfig(&config); |
362 if (config.IsValid()) | 408 if (config.IsValid()) |
363 dns_client_->SetConfig(config); | 409 dns_client_->SetConfig(config); |
364 } | 410 } |
365 | 411 |
366 } // namespace certificate_transparency | 412 } // namespace certificate_transparency |
OLD | NEW |