| 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/callback_helpers.h" | 8 #include "base/callback_helpers.h" |
| 9 #include "base/format_macros.h" | 9 #include "base/format_macros.h" |
| 10 #include "base/location.h" | 10 #include "base/location.h" |
| 11 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/memory/ptr_util.h" | 12 #include "base/memory/ptr_util.h" |
| 13 #include "base/metrics/histogram_macros.h" |
| 13 #include "base/strings/string_number_conversions.h" | 14 #include "base/strings/string_number_conversions.h" |
| 14 #include "base/strings/string_util.h" | 15 #include "base/strings/string_util.h" |
| 15 #include "base/strings/stringprintf.h" | 16 #include "base/strings/stringprintf.h" |
| 16 #include "base/threading/thread_task_runner_handle.h" | 17 #include "base/threading/thread_task_runner_handle.h" |
| 17 #include "base/time/time.h" | 18 #include "base/time/time.h" |
| 18 #include "components/base32/base32.h" | 19 #include "components/base32/base32.h" |
| 19 #include "crypto/sha2.h" | 20 #include "crypto/sha2.h" |
| 20 #include "net/cert/merkle_audit_proof.h" | 21 #include "net/cert/merkle_audit_proof.h" |
| 21 #include "net/dns/dns_client.h" | 22 #include "net/dns/dns_client.h" |
| 22 #include "net/dns/dns_config_service.h" | 23 #include "net/dns/dns_config_service.h" |
| 23 #include "net/dns/dns_protocol.h" | 24 #include "net/dns/dns_protocol.h" |
| 24 #include "net/dns/dns_response.h" | 25 #include "net/dns/dns_response.h" |
| 25 #include "net/dns/dns_transaction.h" | 26 #include "net/dns/dns_transaction.h" |
| 26 #include "net/dns/record_parsed.h" | 27 #include "net/dns/record_parsed.h" |
| 27 #include "net/dns/record_rdata.h" | 28 #include "net/dns/record_rdata.h" |
| 28 | 29 |
| 29 namespace certificate_transparency { | 30 namespace certificate_transparency { |
| 30 | 31 |
| 31 namespace { | 32 namespace { |
| 32 | 33 |
| 34 // Used by UMA_HISTOGRAM_ENUMERATION to record query success/failures. |
| 35 // These values are written to logs. New enum values can be added, but existing |
| 36 // enums must never be renumbered or deleted and reused. |
| 37 enum QueryStatus { |
| 38 QUERY_STATUS_SUCCESS = 0, |
| 39 QUERY_STATUS_FAILED_UNKNOWN = 1, |
| 40 QUERY_STATUS_FAILED_NAME_RESOLUTION = 2, |
| 41 QUERY_STATUS_FAILED_LEAF_INDEX_MALFORMED = 3, |
| 42 QUERY_STATUS_FAILED_INCLUSION_PROOF_MALFORMED = 4, |
| 43 QUERY_STATUS_MAX // Upper bound |
| 44 }; |
| 45 |
| 46 void LogQueryStatus(QueryStatus result) { |
| 47 UMA_HISTOGRAM_ENUMERATION("Net.CertificateTransparency.DnsQueryStatus", |
| 48 result, QUERY_STATUS_MAX); |
| 49 } |
| 50 |
| 51 void LogQueryDuration(const base::TimeDelta& duration) { |
| 52 UMA_HISTOGRAM_MEDIUM_TIMES("Net.CertificateTransparency.DnsQueryDuration", |
| 53 duration); |
| 54 } |
| 55 |
| 33 // Parses the DNS response and extracts a single string from the TXT RDATA. | 56 // Parses the DNS response and extracts a single string from the TXT RDATA. |
| 34 // If the response is malformed, not a TXT record, or contains any number of | 57 // If the response is malformed, not a TXT record, or contains any number of |
| 35 // strings other than 1, this returns false and extracts nothing. | 58 // strings other than 1, this returns false and extracts nothing. |
| 36 // Otherwise, it returns true and the extracted string is assigned to |*txt|. | 59 // Otherwise, it returns true and the extracted string is assigned to |*txt|. |
| 37 bool ParseTxtResponse(const net::DnsResponse& response, std::string* txt) { | 60 bool ParseTxtResponse(const net::DnsResponse& response, std::string* txt) { |
| 38 DCHECK(txt); | 61 DCHECK(txt); |
| 39 | 62 |
| 40 net::DnsRecordParser parser = response.Parser(); | 63 net::DnsRecordParser parser = response.Parser(); |
| 41 // We don't care about the creation time, since we're going to throw | 64 // We don't care about the creation time, since we're going to throw |
| 42 // |parsed_record| away as soon as we've extracted the payload, so provide | 65 // |parsed_record| away as soon as we've extracted the payload, so provide |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 184 net::CompletionCallback callback_; | 207 net::CompletionCallback callback_; |
| 185 // The DnsClient to use for sending DNS requests to the CT log. | 208 // The DnsClient to use for sending DNS requests to the CT log. |
| 186 net::DnsClient* dns_client_; | 209 net::DnsClient* dns_client_; |
| 187 // The most recent DNS request. Null if no DNS requests have been made. | 210 // The most recent DNS request. Null if no DNS requests have been made. |
| 188 std::unique_ptr<net::DnsTransaction> current_dns_transaction_; | 211 std::unique_ptr<net::DnsTransaction> current_dns_transaction_; |
| 189 // The most recent DNS response. Only valid so long as the corresponding DNS | 212 // The most recent DNS response. Only valid so long as the corresponding DNS |
| 190 // request is stored in |current_dns_transaction_|. | 213 // request is stored in |current_dns_transaction_|. |
| 191 const net::DnsResponse* last_dns_response_; | 214 const net::DnsResponse* last_dns_response_; |
| 192 // The NetLog that DNS transactions will log to. | 215 // The NetLog that DNS transactions will log to. |
| 193 net::NetLogWithSource net_log_; | 216 net::NetLogWithSource net_log_; |
| 217 // The time that Start() was last called. Used to measure query duration. |
| 218 base::TimeTicks start_time_; |
| 194 // Produces WeakPtrs to |this| for binding callbacks. | 219 // Produces WeakPtrs to |this| for binding callbacks. |
| 195 base::WeakPtrFactory<AuditProofQuery> weak_ptr_factory_; | 220 base::WeakPtrFactory<AuditProofQuery> weak_ptr_factory_; |
| 196 }; | 221 }; |
| 197 | 222 |
| 198 LogDnsClient::AuditProofQuery::AuditProofQuery( | 223 LogDnsClient::AuditProofQuery::AuditProofQuery( |
| 199 net::DnsClient* dns_client, | 224 net::DnsClient* dns_client, |
| 200 const std::string& domain_for_log, | 225 const std::string& domain_for_log, |
| 201 const net::NetLogWithSource& net_log) | 226 const net::NetLogWithSource& net_log) |
| 202 : next_state_(State::NONE), | 227 : next_state_(State::NONE), |
| 203 domain_for_log_(domain_for_log), | 228 domain_for_log_(domain_for_log), |
| 204 dns_client_(dns_client), | 229 dns_client_(dns_client), |
| 205 net_log_(net_log), | 230 net_log_(net_log), |
| 206 weak_ptr_factory_(this) { | 231 weak_ptr_factory_(this) { |
| 207 DCHECK(dns_client_); | 232 DCHECK(dns_client_); |
| 208 DCHECK(!domain_for_log_.empty()); | 233 DCHECK(!domain_for_log_.empty()); |
| 209 } | 234 } |
| 210 | 235 |
| 211 // |leaf_hash| is not a const-ref to allow callers to std::move that string into | 236 // |leaf_hash| is not a const-ref to allow callers to std::move that string into |
| 212 // the method, avoiding the need to make a copy. | 237 // the method, avoiding the need to make a copy. |
| 213 net::Error LogDnsClient::AuditProofQuery::Start( | 238 net::Error LogDnsClient::AuditProofQuery::Start( |
| 214 std::string leaf_hash, | 239 std::string leaf_hash, |
| 215 uint64_t tree_size, | 240 uint64_t tree_size, |
| 216 const net::CompletionCallback& callback, | 241 const net::CompletionCallback& callback, |
| 217 net::ct::MerkleAuditProof* proof) { | 242 net::ct::MerkleAuditProof* proof) { |
| 218 // It should not already be in progress. | 243 // It should not already be in progress. |
| 219 DCHECK_EQ(State::NONE, next_state_); | 244 DCHECK_EQ(State::NONE, next_state_); |
| 245 start_time_ = base::TimeTicks::Now(); |
| 220 proof_ = proof; | 246 proof_ = proof; |
| 221 proof_->tree_size = tree_size; | 247 proof_->tree_size = tree_size; |
| 222 leaf_hash_ = std::move(leaf_hash); | 248 leaf_hash_ = std::move(leaf_hash); |
| 223 callback_ = callback; | 249 callback_ = callback; |
| 224 // The first step in the query is to request the leaf index corresponding to | 250 // The first step in the query is to request the leaf index corresponding to |
| 225 // |leaf_hash| from the CT log. | 251 // |leaf_hash| from the CT log. |
| 226 next_state_ = State::REQUEST_LEAF_INDEX; | 252 next_state_ = State::REQUEST_LEAF_INDEX; |
| 227 // Begin the state machine. | 253 // Begin the state machine. |
| 228 return DoLoop(net::OK); | 254 return DoLoop(net::OK); |
| 229 } | 255 } |
| 230 | 256 |
| 231 net::Error LogDnsClient::AuditProofQuery::DoLoop(net::Error result) { | 257 net::Error LogDnsClient::AuditProofQuery::DoLoop(net::Error result) { |
| 232 CHECK_NE(State::NONE, next_state_); | 258 CHECK_NE(State::NONE, next_state_); |
| 259 State state; |
| 233 do { | 260 do { |
| 234 State state = next_state_; | 261 state = next_state_; |
| 235 next_state_ = State::NONE; | 262 next_state_ = State::NONE; |
| 236 switch (state) { | 263 switch (state) { |
| 237 case State::REQUEST_LEAF_INDEX: | 264 case State::REQUEST_LEAF_INDEX: |
| 238 result = RequestLeafIndex(); | 265 result = RequestLeafIndex(); |
| 239 break; | 266 break; |
| 240 case State::REQUEST_LEAF_INDEX_COMPLETE: | 267 case State::REQUEST_LEAF_INDEX_COMPLETE: |
| 241 result = RequestLeafIndexComplete(result); | 268 result = RequestLeafIndexComplete(result); |
| 242 break; | 269 break; |
| 243 case State::REQUEST_AUDIT_PROOF_NODES: | 270 case State::REQUEST_AUDIT_PROOF_NODES: |
| 244 result = RequestAuditProofNodes(); | 271 result = RequestAuditProofNodes(); |
| 245 break; | 272 break; |
| 246 case State::REQUEST_AUDIT_PROOF_NODES_COMPLETE: | 273 case State::REQUEST_AUDIT_PROOF_NODES_COMPLETE: |
| 247 result = RequestAuditProofNodesComplete(result); | 274 result = RequestAuditProofNodesComplete(result); |
| 248 break; | 275 break; |
| 249 case State::NONE: | 276 case State::NONE: |
| 250 NOTREACHED(); | 277 NOTREACHED(); |
| 251 break; | 278 break; |
| 252 } | 279 } |
| 253 } while (result != net::ERR_IO_PENDING && next_state_ != State::NONE); | 280 } while (result != net::ERR_IO_PENDING && next_state_ != State::NONE); |
| 254 | 281 |
| 282 if (result != net::ERR_IO_PENDING) { |
| 283 // If the query is complete, log some metrics. |
| 284 LogQueryDuration(base::TimeTicks::Now() - start_time_); |
| 285 |
| 286 switch (result) { |
| 287 case net::OK: |
| 288 LogQueryStatus(QUERY_STATUS_SUCCESS); |
| 289 break; |
| 290 case net::ERR_NAME_RESOLUTION_FAILED: |
| 291 LogQueryStatus(QUERY_STATUS_FAILED_NAME_RESOLUTION); |
| 292 break; |
| 293 case net::ERR_DNS_MALFORMED_RESPONSE: |
| 294 switch (state) { |
| 295 case State::REQUEST_LEAF_INDEX_COMPLETE: |
| 296 LogQueryStatus(QUERY_STATUS_FAILED_LEAF_INDEX_MALFORMED); |
| 297 break; |
| 298 case State::REQUEST_AUDIT_PROOF_NODES_COMPLETE: |
| 299 LogQueryStatus(QUERY_STATUS_FAILED_INCLUSION_PROOF_MALFORMED); |
| 300 break; |
| 301 default: |
| 302 NOTREACHED(); |
| 303 break; |
| 304 } |
| 305 break; |
| 306 default: |
| 307 // Some other error occurred. |
| 308 LogQueryStatus(QUERY_STATUS_FAILED_UNKNOWN); |
| 309 break; |
| 310 } |
| 311 } |
| 312 |
| 255 return result; | 313 return result; |
| 256 } | 314 } |
| 257 | 315 |
| 258 void LogDnsClient::AuditProofQuery::OnDnsTransactionComplete( | 316 void LogDnsClient::AuditProofQuery::OnDnsTransactionComplete( |
| 259 net::DnsTransaction* transaction, | 317 net::DnsTransaction* transaction, |
| 260 int net_error, | 318 int net_error, |
| 261 const net::DnsResponse* response) { | 319 const net::DnsResponse* response) { |
| 262 DCHECK_EQ(current_dns_transaction_.get(), transaction); | 320 DCHECK_EQ(current_dns_transaction_.get(), transaction); |
| 263 last_dns_response_ = response; | 321 last_dns_response_ = response; |
| 264 net::Error result = DoLoop(static_cast<net::Error>(net_error)); | 322 net::Error result = DoLoop(static_cast<net::Error>(net_error)); |
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 470 } | 528 } |
| 471 | 529 |
| 472 void LogDnsClient::UpdateDnsConfig() { | 530 void LogDnsClient::UpdateDnsConfig() { |
| 473 net::DnsConfig config; | 531 net::DnsConfig config; |
| 474 net::NetworkChangeNotifier::GetDnsConfig(&config); | 532 net::NetworkChangeNotifier::GetDnsConfig(&config); |
| 475 if (config.IsValid()) | 533 if (config.IsValid()) |
| 476 dns_client_->SetConfig(config); | 534 dns_client_->SetConfig(config); |
| 477 } | 535 } |
| 478 | 536 |
| 479 } // namespace certificate_transparency | 537 } // namespace certificate_transparency |
| OLD | NEW |