// Copyright 2022 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_OPT_RECORD_RDATA_H_ #define NET_DNS_OPT_RECORD_RDATA_H_ #include #include #include #include #include #include #include "net/base/net_export.h" #include "net/dns/public/dns_protocol.h" #include "net/dns/record_rdata.h" namespace net { // OPT record format (https://tools.ietf.org/html/rfc6891): class NET_EXPORT_PRIVATE OptRecordRdata : public RecordRdata { public: static std::unique_ptr Create(std::string_view data); class NET_EXPORT_PRIVATE Opt { public: static constexpr size_t kHeaderSize = 4; // sizeof(code) + sizeof(size) Opt() = delete; explicit Opt(std::string data); Opt(const Opt& other) = delete; Opt& operator=(const Opt& other) = delete; Opt(Opt&& other) = delete; Opt& operator=(Opt&& other) = delete; virtual ~Opt() = default; bool operator==(const Opt& other) const; bool operator!=(const Opt& other) const; virtual uint16_t GetCode() const = 0; std::string_view data() const { return data_; } private: bool IsEqual(const Opt& other) const; std::string data_; }; class NET_EXPORT_PRIVATE EdeOpt : public Opt { public: static const uint16_t kOptCode = dns_protocol::kEdnsExtendedDnsError; // The following errors are defined by in the IANA registry. // https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#extended-dns-error-codes enum EdeInfoCode { kOtherError, kUnsupportedDnskeyAlgorithm, kUnsupportedDsDigestType, kStaleAnswer, kForgedAnswer, kDnssecIndeterminate, kDnssecBogus, kSignatureExpired, kSignatureNotYetValid, kDnskeyMissing, kRrsigsMissing, kNoZoneKeyBitSet, kNsecMissing, kCachedError, kNotReady, kBlocked, kCensored, kFiltered, kProhibited, kStaleNxdomainAnswer, kNotAuthoritative, kNotSupported, kNoReachableAuthority, kNetworkError, kInvalidData, kSignatureExpiredBeforeValid, kTooEarly, kUnsupportedNsec3IterationsValue, // Note: kUnrecognizedErrorCode is not defined by RFC 8914. // Used when error code does not match existing RFC error code. kUnrecognizedErrorCode }; EdeOpt(uint16_t info_code, std::string extra_text); EdeOpt(const EdeOpt& other) = delete; EdeOpt& operator=(const EdeOpt& other) = delete; EdeOpt(EdeOpt&& other) = delete; EdeOpt& operator=(EdeOpt&& other) = delete; ~EdeOpt() override; // Attempts to parse an EDE option from `data`. Returns nullptr on failure. static std::unique_ptr Create(std::string data); uint16_t GetCode() const override; uint16_t info_code() const { return info_code_; } std::string_view extra_text() const { return extra_text_; } EdeInfoCode GetEnumFromInfoCode() const; // Convert a uint16_t to an EdeInfoCode enum. static EdeInfoCode GetEnumFromInfoCode(uint16_t info_code); private: EdeOpt(); uint16_t info_code_; std::string extra_text_; }; class NET_EXPORT_PRIVATE PaddingOpt : public Opt { public: static const uint16_t kOptCode = dns_protocol::kEdnsPadding; PaddingOpt() = delete; // Construct a PaddingOpt with the specified padding string. explicit PaddingOpt(std::string padding); // Constructs PaddingOpt with '\0' character padding of specified length. // Note: This padding_len only specifies the length of the data section. // Users must take into account the header length `Opt::kHeaderSize` explicit PaddingOpt(uint16_t padding_len); PaddingOpt(const PaddingOpt& other) = delete; PaddingOpt& operator=(const PaddingOpt& other) = delete; PaddingOpt(PaddingOpt&& other) = delete; PaddingOpt& operator=(PaddingOpt&& other) = delete; ~PaddingOpt() override; uint16_t GetCode() const override; }; class NET_EXPORT_PRIVATE UnknownOpt : public Opt { public: UnknownOpt() = delete; UnknownOpt(const UnknownOpt& other) = delete; UnknownOpt& operator=(const UnknownOpt& other) = delete; UnknownOpt(UnknownOpt&& other) = delete; UnknownOpt& operator=(UnknownOpt&& other) = delete; ~UnknownOpt() override; // Create UnknownOpt with option code and data. // Cannot instantiate UnknownOpt directly in order to prevent Opt with // dedicated class class (ex. EdeOpt) from being stored in UnknownOpt. // object. // This method must purely be used for testing. // Only the parser can instantiate an UnknownOpt object (via friend // classes). static std::unique_ptr CreateForTesting(uint16_t code, std::string data); uint16_t GetCode() const override; private: UnknownOpt(uint16_t code, std::string data); uint16_t code_; friend std::unique_ptr OptRecordRdata::Create( std::string_view data); }; static constexpr uint16_t kOptsWithDedicatedClasses[] = { dns_protocol::kEdnsPadding, dns_protocol::kEdnsExtendedDnsError}; static const uint16_t kType = dns_protocol::kTypeOPT; OptRecordRdata(); OptRecordRdata(const OptRecordRdata&) = delete; OptRecordRdata& operator=(const OptRecordRdata&) = delete; OptRecordRdata(OptRecordRdata&& other) = delete; OptRecordRdata& operator=(OptRecordRdata&& other) = delete; ~OptRecordRdata() override; bool operator==(const OptRecordRdata& other) const; bool operator!=(const OptRecordRdata& other) const; // Checks whether two OptRecordRdata objects are equal. This comparison takes // into account the order of insertion. Two OptRecordRdata objects with // identical Opt records inserted in a different order will not be equal. bool IsEqual(const RecordRdata* other) const override; uint16_t Type() const override; const std::vector& buf() const { return buf_; } const std::multimap>& opts() const { return opts_; } // Add specified Opt to rdata. Updates raw buffer as well. void AddOpt(const std::unique_ptr opt); // Checks if an Opt with the specified opt_code is contained. bool ContainsOptCode(uint16_t opt_code) const; size_t OptCount() const { return opts_.size(); } // Returns all options sorted by option code, using insertion order to break // ties. std::vector GetOpts() const; // Returns all EDE options in insertion order. std::vector GetEdeOpts() const; // Returns all Padding options in insertion order. std::vector GetPaddingOpts() const; private: // Opt objects are stored in a multimap; key is the opt code. std::multimap> opts_; std::vector buf_; }; } // namespace net #endif // NET_DNS_OPT_RECORD_RDATA_H_