blob: 48c1a2f814e74ffe2633feea8030d4b03f25ef7d [file] [log] [blame]
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef NET_DNS_HOST_RESOLVER_DNS_TASK_H_
#define NET_DNS_HOST_RESOLVER_DNS_TASK_H_
#include <initializer_list>
#include <memory>
#include <optional>
#include <set>
#include <vector>
#include "base/containers/circular_deque.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/safe_ref.h"
#include "base/memory/weak_ptr.h"
#include "base/numerics/safe_conversions.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "base/values.h"
#include "net/base/ip_endpoint.h"
#include "net/base/net_export.h"
#include "net/base/request_priority.h"
#include "net/dns/host_cache.h"
#include "net/dns/host_resolver.h"
#include "net/dns/httpssvc_metrics.h"
#include "net/dns/public/secure_dns_mode.h"
#include "net/dns/resolve_context.h"
#include "net/log/net_log_with_source.h"
#include "third_party/abseil-cpp/absl/types/variant.h"
namespace net {
class DnsClient;
class DnsTransaction;
class DnsResponse;
// Resolves the hostname using DnsTransaction, which is a full implementation of
// a DNS stub resolver. One DnsTransaction is created for each resolution
// needed, which for AF_UNSPEC resolutions includes both A and AAAA. The
// transactions are scheduled separately and started separately.
class NET_EXPORT_PRIVATE HostResolverDnsTask
: public base::SupportsWeakPtr<HostResolverDnsTask> {
public:
using Results = std::set<std::unique_ptr<HostResolverInternalResult>>;
// Represents a single transaction results.
struct SingleTransactionResults {
SingleTransactionResults(DnsQueryType query_type, Results results);
~SingleTransactionResults();
SingleTransactionResults(SingleTransactionResults&&);
SingleTransactionResults& operator=(SingleTransactionResults&&);
SingleTransactionResults(const SingleTransactionResults&) = delete;
SingleTransactionResults& operator=(const SingleTransactionResults&) =
delete;
DnsQueryType query_type;
Results results;
};
class Delegate {
public:
virtual void OnDnsTaskComplete(base::TimeTicks start_time,
bool allow_fallback,
HostCache::Entry results,
bool secure) = 0;
// Called when one transaction completes successfully, or one more
// transactions get cancelled, but only if more transactions are
// needed. If no more transactions are needed, expect `OnDnsTaskComplete()`
// to be called instead. `single_transaction_results` is passed only when
// one transaction completes successfully.
virtual void OnIntermediateTransactionsComplete(
std::optional<SingleTransactionResults> single_transaction_results) = 0;
virtual RequestPriority priority() const = 0;
virtual void AddTransactionTimeQueued(base::TimeDelta time_queued) = 0;
protected:
Delegate() = default;
virtual ~Delegate() = default;
};
HostResolverDnsTask(DnsClient* client,
HostResolver::Host host,
NetworkAnonymizationKey anonymization_key,
DnsQueryTypeSet query_types,
ResolveContext* resolve_context,
bool secure,
SecureDnsMode secure_dns_mode,
Delegate* delegate,
const NetLogWithSource& job_net_log,
const base::TickClock* tick_clock,
bool fallback_available,
const HostResolver::HttpsSvcbOptions& https_svcb_options);
~HostResolverDnsTask();
HostResolverDnsTask(const HostResolverDnsTask&) = delete;
HostResolverDnsTask& operator=(const HostResolverDnsTask&) = delete;
int num_additional_transactions_needed() const {
return base::checked_cast<int>(transactions_needed_.size());
}
int num_transactions_in_progress() const {
return base::checked_cast<int>(transactions_in_progress_.size());
}
bool secure() const { return secure_; }
void StartNextTransaction();
private:
enum class TransactionErrorBehavior {
// Errors lead to task fallback (immediately unless another pending/started
// transaction has the `kFatalOrEmpty` behavior).
kFallback,
// Transaction errors are treated as if a NOERROR response were received,
// allowing task success if other transactions complete successfully.
kSynthesizeEmpty,
// Transaction errors are potentially fatal (determined by
// `OnTransactionComplete` and often its helper
// `IsFatalTransactionFailure()`) for the entire Job and may disallow
// fallback. Otherwise, same as `kSynthesizeEmpty`.
// TODO(crbug.com/40203587): Implement the fatality behavior.
kFatalOrEmpty,
};
struct TransactionInfo {
explicit TransactionInfo(DnsQueryType type,
TransactionErrorBehavior error_behavior =
TransactionErrorBehavior::kFallback);
~TransactionInfo();
TransactionInfo(TransactionInfo&&);
TransactionInfo& operator=(TransactionInfo&&);
bool operator<(const TransactionInfo& other) const;
DnsQueryType type;
TransactionErrorBehavior error_behavior;
std::unique_ptr<DnsTransaction> transaction;
};
base::Value::Dict NetLogDnsTaskCreationParams();
base::Value::Dict NetLogDnsTaskTimeoutParams();
DnsQueryTypeSet MaybeDisableAdditionalQueries(DnsQueryTypeSet types);
void PushTransactionsNeeded(DnsQueryTypeSet query_types);
void CreateAndStartTransaction(TransactionInfo transaction_info);
void OnTimeout();
// Called on completion of a `DnsTransaction`, but not necessarily completion
// of all work for the individual transaction in this task (see
// `OnTransactionsFinished()`).
void OnDnsTransactionComplete(
std::set<TransactionInfo>::iterator transaction_info_it,
uint16_t request_port,
int net_error,
const DnsResponse* response);
bool IsFatalTransactionFailure(int transaction_error,
const TransactionInfo& transaction_info,
const DnsResponse* response);
void SortTransactionAndHandleResults(TransactionInfo transaction_info,
Results transaction_results);
void OnTransactionSorted(
std::set<TransactionInfo>::iterator transaction_info_it,
Results transaction_results,
bool success,
std::vector<IPEndPoint> sorted);
void HandleTransactionResults(TransactionInfo transaction_info,
Results transaction_results);
void OnTransactionsFinished(
std::optional<SingleTransactionResults> single_transaction_results);
void OnSortComplete(base::TimeTicks sort_start_time,
HostCache::Entry results,
bool secure,
bool success,
std::vector<IPEndPoint> sorted);
bool AnyPotentiallyFatalTransactionsRemain();
void CancelNonFatalTransactions();
void OnFailure(
int net_error,
bool allow_fallback,
std::optional<base::TimeDelta> ttl = std::nullopt,
std::optional<DnsQueryType> failed_transaction_type = std::nullopt);
void OnSuccess(HostCache::Entry results);
// Returns whether any transactions left to finish are of a transaction type
// in `types`. Used for logging and starting the timeout timer (see
// MaybeStartTimeoutTimer()).
bool AnyOfTypeTransactionsRemain(
std::initializer_list<DnsQueryType> types) const;
void MaybeStartTimeoutTimer();
bool ShouldTriggerHttpToHttpsUpgrade(const Results& results);
const raw_ptr<DnsClient> client_;
HostResolver::Host host_;
NetworkAnonymizationKey anonymization_key_;
base::SafeRef<ResolveContext> resolve_context_;
// Whether lookups in this DnsTask should occur using DoH or plaintext.
const bool secure_;
const SecureDnsMode secure_dns_mode_;
// The listener to the results of this DnsTask.
const raw_ptr<Delegate> delegate_;
const NetLogWithSource net_log_;
bool any_transaction_started_ = false;
base::circular_deque<TransactionInfo> transactions_needed_;
// Active transactions have iterators pointing to their entry in this set, so
// individual entries should not be modified or removed until completion or
// cancellation of the transaction.
std::set<TransactionInfo> transactions_in_progress_;
// For histograms.
base::TimeTicks a_record_end_time_;
base::TimeTicks aaaa_record_end_time_;
std::optional<HostCache::Entry> saved_results_;
bool saved_results_is_failure_ = false;
const raw_ptr<const base::TickClock> tick_clock_;
base::TimeTicks task_start_time_;
std::optional<HttpssvcMetrics> httpssvc_metrics_;
// Timer for task timeout. Generally started after completion of address
// transactions to allow aborting experimental or supplemental transactions.
base::OneShotTimer timeout_timer_;
// If true, there are still significant fallback options available if this
// task completes unsuccessfully. Used as a signal that underlying
// transactions should timeout more quickly.
bool fallback_available_;
const HostResolver::HttpsSvcbOptions https_svcb_options_;
};
} // namespace net
#endif // NET_DNS_HOST_RESOLVER_DNS_TASK_H_