Chromium Code Reviews| 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" |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 74 | 74 |
| 75 for (size_t i = 0; i < audit_path.size(); i += crypto::kSHA256Length) { | 75 for (size_t i = 0; i < audit_path.size(); i += crypto::kSHA256Length) { |
| 76 proof->nodes.push_back(audit_path.substr(i, crypto::kSHA256Length)); | 76 proof->nodes.push_back(audit_path.substr(i, crypto::kSHA256Length)); |
| 77 } | 77 } |
| 78 | 78 |
| 79 return true; | 79 return true; |
| 80 } | 80 } |
| 81 | 81 |
| 82 } // namespace | 82 } // namespace |
| 83 | 83 |
| 84 // 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 | |
| 86 // series of DNS requests to get the nodes of the proof. | |
| 87 class LogDnsClient::AuditProofQuery { | |
|
Ryan Sleevi
2016/10/03 23:51:07
See comments on the other CL about splitting defin
Rob Percival
2016/10/04 16:01:57
Done.
| |
| 88 public: | |
| 89 using CompletionCallback = | |
| 90 base::Callback<void(int net_error, AuditProofQuery* query)>; | |
| 91 | |
| 92 // The LogDnsClient is guaranteed to outlive the AuditProofQuery, so it's safe | |
| 93 // to leave ownership of |dns_client| with LogDnsClient. | |
| 94 AuditProofQuery(net::DnsClient* dns_client, | |
| 95 const std::string& domain_for_log, | |
| 96 uint64_t tree_size, | |
| 97 const net::NetLogWithSource& net_log) | |
| 98 : domain_for_log_(domain_for_log), | |
| 99 tree_size_(tree_size), | |
| 100 dns_client_(dns_client), | |
| 101 net_log_(net_log), | |
| 102 weak_ptr_factory_(this) { | |
| 103 DCHECK(dns_client_); | |
| 104 DCHECK(!domain_for_log_.empty()); | |
| 105 } | |
| 106 | |
| 107 // Start the query. | |
| 108 void Start(base::StringPiece leaf_hash, CompletionCallback callback) { | |
| 109 current_dns_transaction_.reset(); | |
| 110 proof_.reset(new net::ct::MerkleAuditProof); | |
|
Ryan Sleevi
2016/10/03 23:51:08
base::MakeUnique<> ?
Rob Percival
2016/10/04 16:01:57
Done.
| |
| 111 callback_ = callback; | |
| 112 QueryLeafIndex(leaf_hash); | |
| 113 } | |
| 114 | |
| 115 std::unique_ptr<net::ct::MerkleAuditProof> TakeProof() { | |
| 116 return std::move(proof_); | |
| 117 } | |
| 118 | |
| 119 private: | |
| 120 void QueryLeafIndex(base::StringPiece leaf_hash) { | |
| 121 std::string encoded_leaf_hash = base32::Base32Encode( | |
| 122 leaf_hash, base32::Base32EncodePolicy::OMIT_PADDING); | |
| 123 DCHECK_EQ(encoded_leaf_hash.size(), 52u); | |
| 124 | |
| 125 std::string qname = base::StringPrintf( | |
| 126 "%s.hash.%s.", encoded_leaf_hash.c_str(), domain_for_log_.data()); | |
| 127 | |
| 128 net::DnsTransactionFactory* factory = dns_client_->GetTransactionFactory(); | |
| 129 if (factory == nullptr) { | |
| 130 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
| 131 FROM_HERE, | |
| 132 base::Bind(callback_, net::Error::ERR_NAME_RESOLUTION_FAILED, | |
| 133 base::Unretained(this))); | |
| 134 return; | |
| 135 } | |
| 136 | |
| 137 net::DnsTransactionFactory::CallbackType transaction_callback = | |
| 138 base::Bind(&LogDnsClient::AuditProofQuery::QueryLeafIndexComplete, | |
| 139 weak_ptr_factory_.GetWeakPtr()); | |
| 140 | |
| 141 current_dns_transaction_ = factory->CreateTransaction( | |
| 142 qname, net::dns_protocol::kTypeTXT, transaction_callback, net_log_); | |
| 143 | |
| 144 current_dns_transaction_->Start(); | |
| 145 } | |
| 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 } | |
| 169 | |
| 170 // Reject leaf index if it is out-of-range. | |
| 171 // This indicates either: | |
| 172 // a) the wrong tree_size was provided. | |
| 173 // b) the wrong leaf hash was provided. | |
| 174 // c) there is a bug server-side. | |
| 175 // The first two are more likely, so return ERR_INVALID_ARGUMENT. | |
| 176 if (proof_->leaf_index >= tree_size_) { | |
| 177 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
| 178 FROM_HERE, base::Bind(callback_, net::ERR_INVALID_ARGUMENT, | |
| 179 base::Unretained(this))); | |
| 180 return; | |
| 181 } | |
| 182 | |
| 183 // QueryAuditProof for the first batch of audit proof_ nodes (i.e. starting | |
| 184 // from 0). | |
| 185 QueryAuditProofNodes(0 /* start node index */); | |
| 186 } | |
| 187 | |
| 188 // Queries a CT log to retrieve part of an audit |proof|. The |node_index| | |
| 189 // indicates which node of the audit proof/ should be requested. The CT log | |
| 190 // may return up to 7 nodes, starting from |node_index| (this is the maximum | |
| 191 // that will fit in a DNS UDP packet). The nodes will be appended to | |
| 192 // |proof->nodes|. | |
| 193 void QueryAuditProofNodes(uint64_t node_index) { | |
| 194 DCHECK_LT(proof_->leaf_index, tree_size_); | |
| 195 DCHECK_LT(node_index, net::ct::CalculateAuditPathLength(proof_->leaf_index, | |
| 196 tree_size_)); | |
| 197 | |
| 198 std::string qname = base::StringPrintf( | |
| 199 "%" PRIu64 ".%" PRIu64 ".%" PRIu64 ".tree.%s.", node_index, | |
| 200 proof_->leaf_index, tree_size_, domain_for_log_.data()); | |
| 201 | |
| 202 net::DnsTransactionFactory* factory = dns_client_->GetTransactionFactory(); | |
| 203 if (factory == nullptr) { | |
| 204 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
| 205 FROM_HERE, | |
| 206 base::Bind(callback_, net::Error::ERR_NAME_RESOLUTION_FAILED, | |
| 207 base::Unretained(this))); | |
| 208 return; | |
| 209 } | |
| 210 | |
| 211 net::DnsTransactionFactory::CallbackType transaction_callback = | |
| 212 base::Bind(&LogDnsClient::AuditProofQuery::QueryAuditProofNodesComplete, | |
| 213 weak_ptr_factory_.GetWeakPtr()); | |
| 214 | |
| 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 } | |
| 234 | |
| 235 const uint64_t audit_path_length = | |
| 236 net::ct::CalculateAuditPathLength(proof_->leaf_index, tree_size_); | |
| 237 // 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| | |
| 239 // is safe. | |
| 240 proof_->nodes.reserve(audit_path_length); | |
| 241 | |
| 242 if (!ParseAuditPath(*response, proof_.get())) { | |
| 243 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
| 244 FROM_HERE, base::Bind(callback_, net::ERR_DNS_MALFORMED_RESPONSE, | |
| 245 base::Unretained(this))); | |
| 246 return; | |
| 247 } | |
| 248 | |
| 249 const uint64_t audit_path_nodes_received = proof_->nodes.size(); | |
| 250 if (audit_path_nodes_received < audit_path_length) { | |
| 251 QueryAuditProofNodes(audit_path_nodes_received); | |
| 252 return; | |
| 253 } | |
| 254 | |
| 255 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
| 256 FROM_HERE, base::Bind(callback_, net::OK, base::Unretained(this))); | |
| 257 } | |
| 258 | |
| 259 std::string domain_for_log_; | |
| 260 // TODO(robpercival): Remove |tree_size| once |proof_| has a tree_size member. | |
| 261 uint64_t tree_size_; | |
| 262 std::unique_ptr<net::ct::MerkleAuditProof> proof_; | |
| 263 CompletionCallback callback_; | |
| 264 net::DnsClient* dns_client_; | |
| 265 std::unique_ptr<net::DnsTransaction> current_dns_transaction_; | |
| 266 net::NetLogWithSource net_log_; | |
| 267 base::WeakPtrFactory<AuditProofQuery> weak_ptr_factory_; | |
| 268 }; | |
| 269 | |
| 84 LogDnsClient::LogDnsClient(std::unique_ptr<net::DnsClient> dns_client, | 270 LogDnsClient::LogDnsClient(std::unique_ptr<net::DnsClient> dns_client, |
| 85 const net::NetLogWithSource& net_log, | 271 const net::NetLogWithSource& net_log, |
| 86 size_t max_concurrent_queries) | 272 size_t max_concurrent_queries) |
| 87 : dns_client_(std::move(dns_client)), | 273 : dns_client_(std::move(dns_client)), |
| 88 net_log_(net_log), | 274 net_log_(net_log), |
| 89 max_concurrent_queries_(max_concurrent_queries), | 275 max_concurrent_queries_(max_concurrent_queries), |
| 90 weak_ptr_factory_(this) { | 276 weak_ptr_factory_(this) { |
| 91 CHECK(dns_client_); | 277 CHECK(dns_client_); |
| 92 net::NetworkChangeNotifier::AddDNSObserver(this); | 278 net::NetworkChangeNotifier::AddDNSObserver(this); |
| 93 UpdateDnsConfig(); | 279 UpdateDnsConfig(); |
| 94 } | 280 } |
| 95 | 281 |
| 96 LogDnsClient::~LogDnsClient() { | 282 LogDnsClient::~LogDnsClient() { |
| 97 net::NetworkChangeNotifier::RemoveDNSObserver(this); | 283 net::NetworkChangeNotifier::RemoveDNSObserver(this); |
| 98 } | 284 } |
| 99 | 285 |
| 100 void LogDnsClient::OnDNSChanged() { | 286 void LogDnsClient::OnDNSChanged() { |
| 101 UpdateDnsConfig(); | 287 UpdateDnsConfig(); |
| 102 } | 288 } |
| 103 | 289 |
| 104 void LogDnsClient::OnInitialDNSConfigRead() { | 290 void LogDnsClient::OnInitialDNSConfigRead() { |
| 105 UpdateDnsConfig(); | 291 UpdateDnsConfig(); |
| 106 } | 292 } |
| 107 | 293 |
| 108 void LogDnsClient::QueryLeafIndex(base::StringPiece domain_for_log, | |
| 109 base::StringPiece leaf_hash, | |
| 110 const LeafIndexCallback& callback) { | |
| 111 if (domain_for_log.empty() || leaf_hash.size() != crypto::kSHA256Length) { | |
| 112 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
| 113 FROM_HERE, base::Bind(callback, net::Error::ERR_INVALID_ARGUMENT, 0)); | |
| 114 return; | |
| 115 } | |
| 116 | |
| 117 if (HasMaxConcurrentQueriesInProgress()) { | |
| 118 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
| 119 FROM_HERE, | |
| 120 base::Bind(callback, net::Error::ERR_TEMPORARILY_THROTTLED, 0)); | |
| 121 return; | |
| 122 } | |
| 123 | |
| 124 std::string encoded_leaf_hash = | |
| 125 base32::Base32Encode(leaf_hash, base32::Base32EncodePolicy::OMIT_PADDING); | |
| 126 DCHECK_EQ(encoded_leaf_hash.size(), 52u); | |
| 127 | |
| 128 net::DnsTransactionFactory* factory = dns_client_->GetTransactionFactory(); | |
| 129 if (factory == nullptr) { | |
| 130 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
| 131 FROM_HERE, | |
| 132 base::Bind(callback, net::Error::ERR_NAME_RESOLUTION_FAILED, 0)); | |
| 133 return; | |
| 134 } | |
| 135 | |
| 136 std::string qname = base::StringPrintf( | |
| 137 "%s.hash.%s.", encoded_leaf_hash.c_str(), domain_for_log.data()); | |
| 138 | |
| 139 net::DnsTransactionFactory::CallbackType transaction_callback = base::Bind( | |
| 140 &LogDnsClient::QueryLeafIndexComplete, weak_ptr_factory_.GetWeakPtr()); | |
| 141 | |
| 142 std::unique_ptr<net::DnsTransaction> dns_transaction = | |
| 143 factory->CreateTransaction(qname, net::dns_protocol::kTypeTXT, | |
| 144 transaction_callback, net_log_); | |
| 145 | |
| 146 dns_transaction->Start(); | |
| 147 leaf_index_queries_.push_back({std::move(dns_transaction), callback}); | |
| 148 } | |
| 149 | |
| 150 // The performance of this could be improved by sending all of the expected | 294 // The performance of this could be improved by sending all of the expected |
| 151 // queries up front. Each response can contain a maximum of 7 audit path nodes, | 295 // queries up front. Each response can contain a maximum of 7 audit path nodes, |
| 152 // so for an audit proof of size 20, it could send 3 queries (for nodes 0-6, | 296 // so for an audit proof of size 20, it could send 3 queries (for nodes 0-6, |
| 153 // 7-13 and 14-19) immediately. Currently, it sends only the first and then, | 297 // 7-13 and 14-19) immediately. Currently, it sends only the first and then, |
| 154 // based on the number of nodes received, sends the next query. The complexity | 298 // based on the number of nodes received, sends the next query. The complexity |
| 155 // of the code would increase though, as it would need to detect gaps in the | 299 // of the code would increase though, as it would need to detect gaps in the |
| 156 // audit proof caused by the server not responding with the anticipated number | 300 // audit proof caused by the server not responding with the anticipated number |
| 157 // of nodes. Ownership of the proof would need to change, as it would be shared | 301 // of nodes. Ownership of the proof would need to change, as it would be shared |
| 158 // between simultaneous DNS transactions. Throttling of queries would also need | 302 // between simultaneous DNS transactions. Throttling of queries would also need |
| 159 // to take into account this increase in parallelism. | 303 // to take into account this increase in parallelism. |
| 160 void LogDnsClient::QueryAuditProof(base::StringPiece domain_for_log, | 304 void LogDnsClient::QueryAuditProof(const std::string& domain_for_log, |
| 161 uint64_t leaf_index, | 305 base::StringPiece leaf_hash, |
| 162 uint64_t tree_size, | 306 uint64_t tree_size, |
| 163 const AuditProofCallback& callback) { | 307 const AuditProofCallback& callback) { |
| 164 if (domain_for_log.empty() || leaf_index >= tree_size) { | 308 if (domain_for_log.empty() || leaf_hash.size() != crypto::kSHA256Length) { |
| 165 base::ThreadTaskRunnerHandle::Get()->PostTask( | 309 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 166 FROM_HERE, | 310 FROM_HERE, |
| 167 base::Bind(callback, net::Error::ERR_INVALID_ARGUMENT, nullptr)); | 311 base::Bind(callback, net::Error::ERR_INVALID_ARGUMENT, nullptr)); |
| 168 return; | 312 return; |
| 169 } | 313 } |
| 170 | 314 |
| 171 if (HasMaxConcurrentQueriesInProgress()) { | 315 if (HasMaxConcurrentQueriesInProgress()) { |
| 172 base::ThreadTaskRunnerHandle::Get()->PostTask( | 316 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 173 FROM_HERE, | 317 FROM_HERE, |
| 174 base::Bind(callback, net::Error::ERR_TEMPORARILY_THROTTLED, nullptr)); | 318 base::Bind(callback, net::Error::ERR_TEMPORARILY_THROTTLED, nullptr)); |
| 175 return; | 319 return; |
| 176 } | 320 } |
| 177 | 321 |
| 178 std::unique_ptr<net::ct::MerkleAuditProof> proof( | 322 audit_proof_queries_.emplace_back(new AuditProofQuery( |
| 179 new net::ct::MerkleAuditProof); | 323 dns_client_.get(), domain_for_log, tree_size, net_log_)); |
| 180 proof->leaf_index = leaf_index; | |
| 181 // TODO(robpercival): Once a "tree_size" field is added to MerkleAuditProof, | |
| 182 // pass |tree_size| to QueryAuditProofNodes using that. | |
| 183 | 324 |
| 184 // Query for the first batch of audit proof nodes (i.e. starting from 0). | 325 AuditProofQuery::CompletionCallback internal_callback = |
| 185 QueryAuditProofNodes(std::move(proof), domain_for_log, tree_size, 0, | 326 base::Bind(&LogDnsClient::QueryAuditProofComplete, |
| 186 callback); | 327 weak_ptr_factory_.GetWeakPtr(), callback); |
| 328 | |
| 329 audit_proof_queries_.back()->Start(leaf_hash, internal_callback); | |
| 187 } | 330 } |
| 188 | 331 |
| 189 void LogDnsClient::QueryLeafIndexComplete(net::DnsTransaction* transaction, | 332 void LogDnsClient::QueryAuditProofComplete(const AuditProofCallback& callback, |
| 190 int net_error, | 333 int result, |
| 191 const net::DnsResponse* response) { | 334 AuditProofQuery* query) { |
| 192 auto query_iterator = | 335 DCHECK(query); |
| 193 std::find_if(leaf_index_queries_.begin(), leaf_index_queries_.end(), | |
| 194 [transaction](const Query<LeafIndexCallback>& query) { | |
| 195 return query.transaction.get() == transaction; | |
| 196 }); | |
| 197 if (query_iterator == leaf_index_queries_.end()) { | |
| 198 NOTREACHED(); | |
| 199 return; | |
| 200 } | |
| 201 const Query<LeafIndexCallback> query = std::move(*query_iterator); | |
| 202 leaf_index_queries_.erase(query_iterator); | |
| 203 | 336 |
| 204 // If we've received no response but no net::error either (shouldn't happen), | 337 std::unique_ptr<net::ct::MerkleAuditProof> proof; |
| 205 // report the response as invalid. | 338 if (result == net::OK) { |
| 206 if (response == nullptr && net_error == net::OK) { | 339 proof = query->TakeProof(); |
| 207 net_error = net::ERR_INVALID_RESPONSE; | |
| 208 } | 340 } |
| 209 | 341 |
| 210 if (net_error != net::OK) { | 342 // Finished with the query - destroy it. Do this before invoking |callback| |
| 211 base::ThreadTaskRunnerHandle::Get()->PostTask( | 343 // in case it wants to perform another query and |audit_proof_queries_| is |
| 212 FROM_HERE, base::Bind(query.callback, net_error, 0)); | 344 // already at its limit (as specified by |max_concurrent_queries_|. |
|
Ryan Sleevi
2016/10/03 23:51:08
Because you're asynchronously invoking this callba
Rob Percival
2016/10/04 16:01:57
Done.
| |
| 213 return; | 345 auto query_iterator = |
| 214 } | 346 std::find_if(audit_proof_queries_.begin(), audit_proof_queries_.end(), |
| 215 | 347 [query](const std::unique_ptr<AuditProofQuery>& p) { |
| 216 uint64_t leaf_index; | 348 return p.get() == query; |
| 217 if (!ParseLeafIndex(*response, &leaf_index)) { | 349 }); |
| 218 base::ThreadTaskRunnerHandle::Get()->PostTask( | 350 DCHECK(query_iterator != audit_proof_queries_.end()); |
| 219 FROM_HERE, | 351 audit_proof_queries_.erase(query_iterator); |
| 220 base::Bind(query.callback, net::ERR_DNS_MALFORMED_RESPONSE, 0)); | |
| 221 return; | |
| 222 } | |
| 223 | 352 |
| 224 base::ThreadTaskRunnerHandle::Get()->PostTask( | 353 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 225 FROM_HERE, base::Bind(query.callback, net::OK, leaf_index)); | 354 FROM_HERE, base::Bind(callback, result, base::Passed(&proof))); |
| 226 } | |
| 227 | |
| 228 void LogDnsClient::QueryAuditProofNodes( | |
| 229 std::unique_ptr<net::ct::MerkleAuditProof> proof, | |
| 230 base::StringPiece domain_for_log, | |
| 231 uint64_t tree_size, | |
| 232 uint64_t node_index, | |
| 233 const AuditProofCallback& callback) { | |
| 234 // Preconditions that should be guaranteed internally by this class. | |
| 235 DCHECK(proof); | |
| 236 DCHECK(!domain_for_log.empty()); | |
| 237 DCHECK_LT(proof->leaf_index, tree_size); | |
| 238 DCHECK_LT(node_index, | |
| 239 net::ct::CalculateAuditPathLength(proof->leaf_index, tree_size)); | |
| 240 | |
| 241 net::DnsTransactionFactory* factory = dns_client_->GetTransactionFactory(); | |
| 242 if (factory == nullptr) { | |
| 243 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
| 244 FROM_HERE, | |
| 245 base::Bind(callback, net::Error::ERR_NAME_RESOLUTION_FAILED, nullptr)); | |
| 246 return; | |
| 247 } | |
| 248 | |
| 249 std::string qname = base::StringPrintf( | |
| 250 "%" PRIu64 ".%" PRIu64 ".%" PRIu64 ".tree.%s.", node_index, | |
| 251 proof->leaf_index, tree_size, domain_for_log.data()); | |
| 252 | |
| 253 net::DnsTransactionFactory::CallbackType transaction_callback = | |
| 254 base::Bind(&LogDnsClient::QueryAuditProofNodesComplete, | |
| 255 weak_ptr_factory_.GetWeakPtr(), base::Passed(std::move(proof)), | |
| 256 domain_for_log, tree_size); | |
| 257 | |
| 258 std::unique_ptr<net::DnsTransaction> dns_transaction = | |
| 259 factory->CreateTransaction(qname, net::dns_protocol::kTypeTXT, | |
| 260 transaction_callback, net_log_); | |
| 261 dns_transaction->Start(); | |
| 262 audit_proof_queries_.push_back({std::move(dns_transaction), callback}); | |
| 263 } | |
| 264 | |
| 265 void LogDnsClient::QueryAuditProofNodesComplete( | |
| 266 std::unique_ptr<net::ct::MerkleAuditProof> proof, | |
| 267 base::StringPiece domain_for_log, | |
| 268 uint64_t tree_size, | |
| 269 net::DnsTransaction* transaction, | |
| 270 int net_error, | |
| 271 const net::DnsResponse* response) { | |
| 272 // Preconditions that should be guaranteed internally by this class. | |
| 273 DCHECK(proof); | |
| 274 DCHECK(!domain_for_log.empty()); | |
| 275 | |
| 276 auto query_iterator = | |
| 277 std::find_if(audit_proof_queries_.begin(), audit_proof_queries_.end(), | |
| 278 [transaction](const Query<AuditProofCallback>& query) { | |
| 279 return query.transaction.get() == transaction; | |
| 280 }); | |
| 281 | |
| 282 if (query_iterator == audit_proof_queries_.end()) { | |
| 283 NOTREACHED(); | |
| 284 return; | |
| 285 } | |
| 286 const Query<AuditProofCallback> query = std::move(*query_iterator); | |
| 287 audit_proof_queries_.erase(query_iterator); | |
| 288 | |
| 289 // If we've received no response but no net::error either (shouldn't happen), | |
| 290 // report the response as invalid. | |
| 291 if (response == nullptr && net_error == net::OK) { | |
| 292 net_error = net::ERR_INVALID_RESPONSE; | |
| 293 } | |
| 294 | |
| 295 if (net_error != net::OK) { | |
| 296 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
| 297 FROM_HERE, base::Bind(query.callback, net_error, nullptr)); | |
| 298 return; | |
| 299 } | |
| 300 | |
| 301 const uint64_t audit_path_length = | |
| 302 net::ct::CalculateAuditPathLength(proof->leaf_index, tree_size); | |
| 303 proof->nodes.reserve(audit_path_length); | |
| 304 | |
| 305 if (!ParseAuditPath(*response, proof.get())) { | |
| 306 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
| 307 FROM_HERE, | |
| 308 base::Bind(query.callback, net::ERR_DNS_MALFORMED_RESPONSE, nullptr)); | |
| 309 return; | |
| 310 } | |
| 311 | |
| 312 const uint64_t audit_path_nodes_received = proof->nodes.size(); | |
| 313 if (audit_path_nodes_received < audit_path_length) { | |
| 314 QueryAuditProofNodes(std::move(proof), domain_for_log, tree_size, | |
| 315 audit_path_nodes_received, query.callback); | |
| 316 return; | |
| 317 } | |
| 318 | |
| 319 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
| 320 FROM_HERE, | |
| 321 base::Bind(query.callback, net::OK, base::Passed(std::move(proof)))); | |
| 322 } | 355 } |
| 323 | 356 |
| 324 bool LogDnsClient::HasMaxConcurrentQueriesInProgress() const { | 357 bool LogDnsClient::HasMaxConcurrentQueriesInProgress() const { |
| 325 const size_t queries_in_progress = | |
| 326 leaf_index_queries_.size() + audit_proof_queries_.size(); | |
| 327 | |
| 328 return max_concurrent_queries_ != 0 && | 358 return max_concurrent_queries_ != 0 && |
| 329 queries_in_progress >= max_concurrent_queries_; | 359 audit_proof_queries_.size() >= max_concurrent_queries_; |
| 330 } | 360 } |
| 331 | 361 |
| 332 void LogDnsClient::UpdateDnsConfig() { | 362 void LogDnsClient::UpdateDnsConfig() { |
| 333 net::DnsConfig config; | 363 net::DnsConfig config; |
| 334 net::NetworkChangeNotifier::GetDnsConfig(&config); | 364 net::NetworkChangeNotifier::GetDnsConfig(&config); |
| 335 if (config.IsValid()) | 365 if (config.IsValid()) |
| 336 dns_client_->SetConfig(config); | 366 dns_client_->SetConfig(config); |
| 337 } | 367 } |
| 338 | 368 |
| 339 } // namespace certificate_transparency | 369 } // namespace certificate_transparency |
| OLD | NEW |