ladybird/Libraries/LibDNS/Message.h
Pavel Shliak cd14b215d1 LibDNS: Clean up #include directives
This change aims to improve the speed of incremental builds.
2024-11-21 14:08:33 +01:00

702 lines
27 KiB
C++

/*
* Copyright (c) 2024, Ali Mohammad Pur <mpfard@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Base64.h>
#include <AK/IPv4Address.h>
#include <AK/IPv6Address.h>
#include <AK/RedBlackTree.h>
#include <AK/Time.h>
namespace DNS {
namespace Messages {
struct DomainName;
struct ParseContext {
CountingStream& stream;
NonnullOwnPtr<RedBlackTree<u16, DomainName>> pointers;
};
enum class OpCode : u8;
struct Options {
// 1 1 1 1 1 1
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | ID |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// |QR| Opcode |AA|TC|RD|RA| Z |AD|CD| RCODE |
constexpr inline static u16 QRMask = 0b1000000000000000;
constexpr inline static u16 OpCodeMask = 0b0111100000000000;
constexpr inline static u16 AuthoritativeAnswerMask = 0b0000010000000000;
constexpr inline static u16 TruncatedMask = 0b0000001000000000;
constexpr inline static u16 RecursionDesiredMask = 0b0000000100000000;
constexpr inline static u16 RecursionAvailableMask = 0b0000000010000000;
constexpr inline static u16 AuthenticatedDataMask = 0b0000000000100000;
constexpr inline static u16 CheckingDisabledMask = 0b0000000000010000;
constexpr inline static u16 ResponseCodeMask = 0b0000000000001111;
enum class ResponseCode : u16 {
NoError = 0,
FormatError = 1,
ServerFailure = 2,
NameError = 3,
NotImplemented = 4,
Refused = 5,
};
void set_is_question(bool value) { raw = (raw & ~QRMask) | (value ? QRMask : 0); }
void set_is_authoritative_answer(bool value) { raw = (raw & ~AuthoritativeAnswerMask) | (value ? AuthoritativeAnswerMask : 0); }
void set_is_truncated(bool value) { raw = (raw & ~TruncatedMask) | (value ? TruncatedMask : 0); }
void set_recursion_desired(bool value) { raw = (raw & ~RecursionDesiredMask) | (value ? RecursionDesiredMask : 0); }
void set_recursion_available(bool value) { raw = (raw & ~RecursionAvailableMask) | (value ? RecursionAvailableMask : 0); }
void set_response_code(ResponseCode code) { raw = (raw & ~ResponseCodeMask) | static_cast<u16>(code); }
void set_checking_disabled(bool value) { raw = (raw & ~CheckingDisabledMask) | (value ? CheckingDisabledMask : 0); }
void set_authenticated_data(bool value) { raw = (raw & ~AuthenticatedDataMask) | (value ? AuthenticatedDataMask : 0); }
void set_op_code(OpCode code) { raw = (raw & ~OpCodeMask) | (static_cast<u16>(code) << 11); }
bool is_question() const { return (raw & QRMask) == 0; }
bool is_authoritative_answer() const { return (raw & AuthoritativeAnswerMask) != 0; }
bool is_truncated() const { return (raw & TruncatedMask) != 0; }
bool recursion_desired() const { return (raw & RecursionDesiredMask) != 0; }
bool recursion_available() const { return (raw & RecursionAvailableMask) != 0; }
bool checking_disabled() const { return (raw & CheckingDisabledMask) != 0; }
bool authenticated_data() const { return (raw & AuthenticatedDataMask) != 0; }
ResponseCode response_code() const { return static_cast<ResponseCode>(raw & ResponseCodeMask); }
OpCode op_code() const { return static_cast<OpCode>((raw & OpCodeMask) >> 11); }
String to_string() const;
NetworkOrdered<u16> raw { 0 };
};
StringView to_string(Options::ResponseCode);
struct Header {
NetworkOrdered<u16> id;
Options options;
NetworkOrdered<u16> question_count;
NetworkOrdered<u16> answer_count;
NetworkOrdered<u16> authority_count;
NetworkOrdered<u16> additional_count;
};
struct DomainName {
Vector<ByteString> labels;
static DomainName from_string(StringView);
static ErrorOr<DomainName> from_raw(ParseContext&);
ErrorOr<void> to_raw(ByteBuffer&) const;
String to_string() const;
};
// Listing from IANA https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-4.
enum class ResourceType : u16 {
Reserved = 0, // [RFC6895]
A = 1, // a host address [RFC1035]
NS = 2, // an authoritative name server [RFC1035]
MD = 3, // a mail destination (OBSOLETE - use MX) [RFC1035]
MF = 4, // a mail forwarder (OBSOLETE - use MX) [RFC1035]
CNAME = 5, // the canonical name for an alias [RFC1035]
SOA = 6, // marks the start of a zone of authority [RFC1035]
MB = 7, // a mailbox domain name (EXPERIMENTAL) [RFC1035]
MG = 8, // a mail group member (EXPERIMENTAL) [RFC1035]
MR = 9, // a mail rename domain name (EXPERIMENTAL) [RFC1035]
NULL_ = 10, // a null RR (EXPERIMENTAL) [RFC1035]
WKS = 11, // a well known service description [RFC1035]
PTR = 12, // a domain name pointer [RFC1035]
HINFO = 13, // host information [RFC1035]
MINFO = 14, // mailbox or mail list information [RFC1035]
MX = 15, // mail exchange [RFC1035]
TXT = 16, // text strings [RFC1035]
RP = 17, // for Responsible Person [RFC1183]
AFSDB = 18, // for AFS Data Base location [RFC1183][RFC5864]
X25 = 19, // for X.25 PSDN address [RFC1183]
ISDN = 20, // for ISDN address [RFC1183]
RT = 21, // for Route Through [RFC1183]
NSAP = 22, // for NSAP address, NSAP style A record (DEPRECATED) [RFC1706][Moving TPC.INT and NSAP.INT infrastructure domains to historic]
NSAP_PTR = 23, // for domain name pointer, NSAP style (DEPRECATED) [RFC1706][Moving TPC.INT and NSAP.INT infrastructure domains to historic]
SIG = 24, // for security signature [RFC2536][RFC2931][RFC3110][RFC4034]
KEY = 25, // for security key [RFC2536][RFC2539][RFC3110][RFC4034]
PX = 26, // X.400 mail mapping information [RFC2163]
GPOS = 27, // Geographical Position [RFC1712]
AAAA = 28, // IP6 Address [RFC3596]
LOC = 29, // Location Information [RFC1876]
NXT = 30, // Next Domain (OBSOLETE) [RFC2535][RFC3755]
EID = 31, // Endpoint Identifier [Michael_Patton][http://ana-3.lcs.mit.edu/~jnc/nimrod/dns.txt]
NIMLOC = 32, // Nimrod Locator [1][Michael_Patton][http://ana-3.lcs.mit.edu/~jnc/nimrod/dns.txt]
SRV = 33, // Server Selection [1][RFC2782]
ATMA = 34, // ATM Address "[ ATM Forum Technical Committee, "ATM Name System, V2.0", Doc ID: AF-DANS-0152.000, July 2000. Available from and held in escrow by IANA.]"
NAPTR = 35, // Naming Authority Pointer [RFC3403]
KX = 36, // Key Exchanger [RFC2230]
CERT = 37, // CERT [RFC4398]
A6 = 38, // A6 (OBSOLETE - use AAAA) [RFC2874][RFC3226][RFC6563]
DNAME = 39, // DNAME [RFC6672]
SINK = 40, // SINK [Donald_E_Eastlake][draft-eastlake-kitchen-sink]
OPT = 41, // OPT [RFC3225][RFC6891]
APL = 42, // APL [RFC3123]
DS = 43, // Delegation Signer [RFC4034]
SSHFP = 44, // SSH Key Fingerprint [RFC4255]
IPSECKEY = 45, // IPSECKEY [RFC4025]
RRSIG = 46, // RRSIG [RFC4034]
NSEC = 47, // NSEC [RFC4034][RFC9077]
DNSKEY = 48, // DNSKEY [RFC4034]
DHCID = 49, // DHCID [RFC4701]
NSEC3 = 50, // NSEC3 [RFC5155][RFC9077]
NSEC3PARAM = 51, // NSEC3PARAM [RFC5155]
TLSA = 52, // TLSA [RFC6698]
SMIMEA = 53, // S/MIME cert association [RFC8162]
HIP = 55, // Host Identity Protocol [RFC8005]
NINFO = 56, // NINFO [Jim_Reid]
RKEY = 57, // RKEY [Jim_Reid]
TALINK = 58, // Trust Anchor LINK [Wouter_Wijngaards]
CDS = 59, // Child DS [RFC7344]
CDNSKEY = 60, // DNSKEY(s) the Child wants reflected in DS [RFC7344]
OPENPGPKEY = 61, // OpenPGP Key [RFC7929]
CSYNC = 62, // Child-To-Parent Synchronization [RFC7477]
ZONEMD = 63, // Message Digest Over Zone Data [RFC8976]
SVCB = 64, // General-purpose service binding [RFC9460]
HTTPS = 65, // SVCB-compatible type for use with HTTP [RFC9460]
SPF = 99, // [RFC7208]
UINFO = 100, // [IANA-Reserved]
UID = 101, // [IANA-Reserved]
GID = 102, // [IANA-Reserved]
UNSPEC = 103, // [IANA-Reserved]
NID = 104, // [RFC6742]
L32 = 105, // [RFC6742]
L64 = 106, // [RFC6742]
LP = 107, // [RFC6742]
EUI48 = 108, // an EUI-48 address [RFC7043]
EUI64 = 109, // an EUI-64 address [RFC7043]
NXNAME = 128, // NXDOMAIN indicator for Compact Denial of Existence [draft-ietf-dnsop-compact-denial-of-existence-04]
TKEY = 249, // Transaction Key [RFC2930]
TSIG = 250, // Transaction Signature [RFC8945]
IXFR = 251, // incremental transfer [RFC1995]
AXFR = 252, // transfer of an entire zone [RFC1035][RFC5936]
MAILB = 253, // mailbox-related RRs (MB, MG or MR) [RFC1035]
MAILA = 254, // mail agent RRs (OBSOLETE - see MX) [RFC1035]
ANY = 255, // A request for some or all records the server has available [RFC1035][RFC6895][RFC8482]
URI = 256, // URI [RFC7553]
CAA = 257, // Certification Authority Restriction [RFC8659]
AVC = 258, // Application Visibility and Control [Wolfgang_Riedel]
DOA = 259, // Digital Object Architecture [draft-durand-doa-over-dns]
AMTRELAY = 260, // Automatic Multicast Tunneling Relay [RFC8777]
RESINFO = 261, // Resolver Information as Key/Value Pairs [RFC9606]
WALLET = 262, // Public wallet address [Paul_Hoffman]
CLA = 263, // BP Convergence Layer Adapter [draft-johnson-dns-ipn-cla-07]
IPN = 264, // BP Node Number [draft-johnson-dns-ipn-cla-07]
TA = 32768, // DNSSEC Trust Authorities "[Sam_Weiler][Deploying DNSSEC Without a Signed Root. Technical Report 1999-19, Information Networking Institute, Carnegie Mellon University, April 2004.]"
DLV = 32769, // DNSSEC Lookaside Validation (OBSOLETE) [RFC8749][RFC4431]
};
StringView to_string(ResourceType);
Optional<ResourceType> resource_type_from_string(StringView);
// Listing from IANA https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-2.
enum class Class : u16 {
IN = 1, // the Internet [RFC1035]
CH = 3, // the CHAOS class [Moon1981]
HS = 4, // Hesiod [Dyer1987]
};
StringView to_string(Class);
// Listing from IANA https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-3.
enum class OpCode : u8 {
Query = 0, // a standard query (QUERY)
IQuery = 1, // an inverse query (IQUERY)
Status = 2, // a server status request (STATUS)
Notify = 4, // NOTIFY
Update = 5, // dynamic update (RFC 2136)
DSO = 6, // DNS Stateful Operations (DSO) [RFC8490]
Reserved = 7, // [RFC6895]
ReservedMask = 15 // [RFC6895]
};
StringView to_string(OpCode);
namespace TLSA {
// Listings from IANA https://www.iana.org/assignments/dane-parameters/dane-parameters.xhtml.
enum class CertUsage : u8 {
CAConstraint = 0,
ServiceCertificateConstraint = 1,
TrustAnchorAssertion = 2,
DomainIssuedCertificate = 3,
Private = 255
};
enum class Selector : u8 {
FullCertificate = 0,
SubjectPublicKeyInfo = 1,
Private = 255
};
enum class MatchingType : u8 {
Full = 0,
SHA256 = 1,
SHA512 = 2,
Private = 255
};
}
namespace DNSSEC {
// Listing from IANA https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml.
enum class Algorithm : u8 {
RSAMD5 = 1, // RSA/MD5 [RFC4034][RFC3110]
DSA = 3, // DSA/SHA-1 [RFC3755][RFC2536]
RSASHA1 = 5, // RSA/SHA-1 [RFC3110]
RSASHA1NSEC3SHA1 = 7, // [RFC5155]
RSASHA256 = 8, // RSA/SHA-256 [RFC5702]
RSASHA512 = 10, // RSA/SHA-512 [RFC5702]
ECDSAP256SHA256 = 13, // ECDSA Curve P-256 with SHA-256 [RFC6605]
ECDSAP384SHA384 = 14, // ECDSA Curve P-384 with SHA-384 [RFC6605]
ED25519 = 15, // Ed25519 [RFC8080]
Unknown = 255 // Reserved for Private Use
};
static inline StringView to_string(Algorithm algorithm)
{
switch (algorithm) {
case Algorithm::RSAMD5:
return "RSAMD5"sv;
case Algorithm::DSA:
return "DSA"sv;
case Algorithm::RSASHA1:
return "RSASHA1"sv;
case Algorithm::RSASHA1NSEC3SHA1:
return "RSASHA1NSEC3SHA1"sv;
case Algorithm::RSASHA256:
return "RSASHA256"sv;
case Algorithm::RSASHA512:
return "RSASHA512"sv;
case Algorithm::ECDSAP256SHA256:
return "ECDSAP256SHA256"sv;
case Algorithm::ECDSAP384SHA384:
return "ECDSAP384SHA384"sv;
case Algorithm::ED25519:
return "ED25519"sv;
case Algorithm::Unknown:
return "Unknown"sv;
}
VERIFY_NOT_REACHED();
}
// Listing from IANA https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml.
enum class DigestType : u8 {
SHA1 = 1, // SHA-1 [RFC3658]
SHA256 = 2, // SHA-256 [RFC4509]
GOST3411 = 3, // GOST R 34.11-94 [RFC5933]
SHA384 = 4, // SHA-384 [RFC6605]
SHA512 = 5, // SHA-512 [RFC6605]
SHA224 = 6, // SHA-224 [RFC6605]
Unknown = 255 // Reserved for Private Use
};
static inline StringView to_string(DigestType digest_type)
{
switch (digest_type) {
case DigestType::SHA1:
return "SHA1"sv;
case DigestType::SHA256:
return "SHA256"sv;
case DigestType::GOST3411:
return "GOST3411"sv;
case DigestType::SHA384:
return "SHA384"sv;
case DigestType::SHA512:
return "SHA512"sv;
case DigestType::SHA224:
return "SHA224"sv;
case DigestType::Unknown:
return "Unknown"sv;
}
VERIFY_NOT_REACHED();
}
// Listing from IANA https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml.
enum class NSEC3HashAlgorithm : u8 {
SHA1 = 1, // [RFC5155]
SHA256 = 2, // [RFC6605]
GOST3411 = 3, // [RFC5933]
SHA384 = 4, // [RFC6605]
SHA512 = 5, // [RFC6605]
SHA224 = 6, // [RFC6605]
Unknown = 255 // Reserved for Private Use
};
static inline StringView to_string(NSEC3HashAlgorithm hash_algorithm)
{
switch (hash_algorithm) {
case NSEC3HashAlgorithm::SHA1:
return "SHA1"sv;
case NSEC3HashAlgorithm::SHA256:
return "SHA256"sv;
case NSEC3HashAlgorithm::GOST3411:
return "GOST3411"sv;
case NSEC3HashAlgorithm::SHA384:
return "SHA384"sv;
case NSEC3HashAlgorithm::SHA512:
return "SHA512"sv;
case NSEC3HashAlgorithm::SHA224:
return "SHA224"sv;
case NSEC3HashAlgorithm::Unknown:
return "Unknown"sv;
}
VERIFY_NOT_REACHED();
}
}
struct Question {
DomainName name;
ResourceType type;
Class class_;
static ErrorOr<Question> from_raw(ParseContext&);
ErrorOr<void> to_raw(ByteBuffer&) const;
};
namespace Records {
struct A {
IPv4Address address;
static constexpr ResourceType type = ResourceType::A;
static ErrorOr<A> from_raw(ParseContext&);
ErrorOr<void> to_raw(ByteBuffer&) const { return Error::from_string_literal("Not implemented"); }
ErrorOr<String> to_string() const { return address.to_string(); }
};
struct AAAA {
IPv6Address address;
static constexpr ResourceType type = ResourceType::AAAA;
static ErrorOr<AAAA> from_raw(ParseContext&);
ErrorOr<void> to_raw(ByteBuffer&) const { return Error::from_string_literal("Not implemented"); }
ErrorOr<String> to_string() const { return address.to_string(); }
};
struct TXT {
ByteString content;
static constexpr ResourceType type = ResourceType::TXT;
static ErrorOr<TXT> from_raw(ParseContext&);
ErrorOr<void> to_raw(ByteBuffer&) const { return Error::from_string_literal("Not implemented"); }
ErrorOr<String> to_string() const { return String::formatted("Text: '{}'", StringView { content }); }
};
struct CNAME {
DomainName names;
static constexpr ResourceType type = ResourceType::CNAME;
static ErrorOr<CNAME> from_raw(ParseContext&);
ErrorOr<void> to_raw(ByteBuffer&) const { return Error::from_string_literal("Not implemented"); }
ErrorOr<String> to_string() const { return names.to_string(); }
};
struct NS {
DomainName name;
static constexpr ResourceType type = ResourceType::NS;
static ErrorOr<NS> from_raw(ParseContext&);
ErrorOr<void> to_raw(ByteBuffer&) const { return Error::from_string_literal("Not implemented"); }
ErrorOr<String> to_string() const { return name.to_string(); }
};
struct SOA {
DomainName mname;
DomainName rname;
u32 serial;
u32 refresh;
u32 retry;
u32 expire;
u32 minimum;
static constexpr ResourceType type = ResourceType::SOA;
static ErrorOr<SOA> from_raw(ParseContext&);
ErrorOr<void> to_raw(ByteBuffer&) const { return Error::from_string_literal("Not implemented"); }
ErrorOr<String> to_string() const
{
return String::formatted("SOA MName: '{}', RName: '{}', Serial: {}, Refresh: {}, Retry: {}, Expire: {}, Minimum: {}", mname.to_string(), rname.to_string(), serial, refresh, retry, expire, minimum);
}
};
struct MX {
u16 preference;
DomainName exchange;
static constexpr ResourceType type = ResourceType::MX;
static ErrorOr<MX> from_raw(ParseContext&);
ErrorOr<void> to_raw(ByteBuffer&) const { return Error::from_string_literal("Not implemented"); }
ErrorOr<String> to_string() const { return String::formatted("MX Preference: {}, Exchange: '{}'", preference, exchange.to_string()); }
};
struct PTR {
DomainName name;
static constexpr ResourceType type = ResourceType::PTR;
static ErrorOr<PTR> from_raw(ParseContext&);
ErrorOr<void> to_raw(ByteBuffer&) const { return Error::from_string_literal("Not implemented"); }
ErrorOr<String> to_string() const { return name.to_string(); }
};
struct SRV {
u16 priority;
u16 weight;
u16 port;
DomainName target;
static constexpr ResourceType type = ResourceType::SRV;
static ErrorOr<SRV> from_raw(ParseContext&);
ErrorOr<void> to_raw(ByteBuffer&) const { return Error::from_string_literal("Not implemented"); }
ErrorOr<String> to_string() const { return String::formatted("SRV Priority: {}, Weight: {}, Port: {}, Target: '{}'", priority, weight, port, target.to_string()); }
};
struct DNSKEY {
u16 flags;
u8 protocol;
DNSSEC::Algorithm algorithm;
ByteBuffer public_key;
constexpr static inline u16 FlagSecureEntryPoint = 0b1000000000000000;
constexpr static inline u16 FlagZoneKey = 0b0100000000000000;
constexpr static inline u16 FlagRevoked = 0b0010000000000000;
constexpr bool is_secure_entry_point() const { return flags & FlagSecureEntryPoint; }
constexpr bool is_zone_key() const { return flags & FlagZoneKey; }
constexpr bool is_revoked() const { return flags & FlagRevoked; }
constexpr bool is_key_signing_key() const { return is_secure_entry_point() && is_zone_key() && !is_revoked(); }
static constexpr ResourceType type = ResourceType::DNSKEY;
static ErrorOr<DNSKEY> from_raw(ParseContext&);
ErrorOr<void> to_raw(ByteBuffer&) const { return Error::from_string_literal("Not implemented"); }
ErrorOr<String> to_string() const
{
return String::formatted("DNSKEY Flags: {}{}{}{}({}), Protocol: {}, Algorithm: {}, Public Key: {}",
is_secure_entry_point() ? "sep "sv : ""sv,
is_zone_key() ? "zone "sv : ""sv,
is_revoked() ? "revoked "sv : ""sv,
is_key_signing_key() ? "ksk "sv : ""sv,
flags,
protocol,
DNSSEC::to_string(algorithm),
TRY(encode_base64(public_key)));
}
};
struct CDNSKEY : public DNSKEY {
template<typename... Ts>
CDNSKEY(Ts&&... args)
: DNSKEY(forward<Ts>(args)...)
{
}
static constexpr ResourceType type = ResourceType::CDNSKEY;
static ErrorOr<CDNSKEY> from_raw(ParseContext& raw) { return DNSKEY::from_raw(raw); }
};
struct DS {
u16 key_tag;
DNSSEC::Algorithm algorithm;
DNSSEC::DigestType digest_type;
ByteBuffer digest;
static constexpr ResourceType type = ResourceType::DS;
static ErrorOr<DS> from_raw(ParseContext&);
ErrorOr<void> to_raw(ByteBuffer&) const { return Error::from_string_literal("Not implemented"); }
ErrorOr<String> to_string() const { return "DS"_string; }
};
struct CDS : public DS {
template<typename... Ts>
CDS(Ts&&... args)
: DS(forward<Ts>(args)...)
{
}
static constexpr ResourceType type = ResourceType::CDS;
static ErrorOr<CDS> from_raw(ParseContext& raw) { return DS::from_raw(raw); }
};
struct SIG {
ResourceType type_covered;
DNSSEC::Algorithm algorithm;
u8 label_count;
u32 original_ttl;
UnixDateTime expiration;
UnixDateTime inception;
u16 key_tag;
DomainName signers_name;
ByteBuffer signature;
static constexpr ResourceType type = ResourceType::SIG;
static ErrorOr<SIG> from_raw(ParseContext&);
ErrorOr<void> to_raw(ByteBuffer&) const { return Error::from_string_literal("Not implemented"); }
ErrorOr<String> to_string() const;
};
struct RRSIG : public SIG {
template<typename... Ts>
RRSIG(Ts&&... args)
: SIG(forward<Ts>(args)...)
{
}
static constexpr ResourceType type = ResourceType::RRSIG;
static ErrorOr<RRSIG> from_raw(ParseContext& raw) { return SIG::from_raw(raw); }
};
struct NSEC {
DomainName next_domain_name;
Vector<ResourceType> types;
static constexpr ResourceType type = ResourceType::NSEC;
static ErrorOr<NSEC> from_raw(ParseContext&);
ErrorOr<void> to_raw(ByteBuffer&) const { return Error::from_string_literal("Not implemented"); }
ErrorOr<String> to_string() const { return "NSEC"_string; }
};
struct NSEC3 {
DNSSEC::NSEC3HashAlgorithm hash_algorithm;
u8 flags;
u16 iterations;
ByteBuffer salt;
DomainName next_hashed_owner_name;
Vector<ResourceType> types;
static constexpr ResourceType type = ResourceType::NSEC3;
static ErrorOr<NSEC3> from_raw(ParseContext&);
ErrorOr<void> to_raw(ByteBuffer&) const { return Error::from_string_literal("Not implemented"); }
ErrorOr<String> to_string() const { return "NSEC3"_string; }
};
struct NSEC3PARAM {
DNSSEC::NSEC3HashAlgorithm hash_algorithm;
u8 flags;
u16 iterations;
ByteBuffer salt;
constexpr static inline u8 FlagOptOut = 0b10000000;
constexpr bool is_opt_out() const { return flags & FlagOptOut; }
static constexpr ResourceType type = ResourceType::NSEC3PARAM;
static ErrorOr<NSEC3PARAM> from_raw(ParseContext&);
ErrorOr<void> to_raw(ByteBuffer&) const { return Error::from_string_literal("Not implemented"); }
ErrorOr<String> to_string() const { return "NSEC3PARAM"_string; }
};
struct TLSA {
Messages::TLSA::CertUsage cert_usage;
Messages::TLSA::Selector selector;
Messages::TLSA::MatchingType matching_type;
ByteBuffer certificate_association_data;
static ErrorOr<TLSA> from_raw(ParseContext&);
ErrorOr<void> to_raw(ByteBuffer&) const { return Error::from_string_literal("Not implemented"); }
ErrorOr<String> to_string() const { return "TLSA"_string; }
};
struct HINFO {
ByteString cpu;
ByteString os;
static constexpr ResourceType type = ResourceType::HINFO;
static ErrorOr<HINFO> from_raw(ParseContext&);
ErrorOr<void> to_raw(ByteBuffer&) const { return Error::from_string_literal("Not implemented"); }
ErrorOr<String> to_string() const { return String::formatted("HINFO CPU: '{}', OS: '{}'", StringView { cpu }, StringView { os }); }
};
struct OPT {
struct Option {
u16 code;
ByteBuffer data;
};
// 1 1 1 1 1 1
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | UDP Payload Size |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | Extended RCode | VER | ZZ |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// |DO| Z |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | OPT-LEN / OPT-DATA...
NetworkOrdered<u16> udp_payload_size { 0 };
NetworkOrdered<u32> extended_rcode_and_flags { 0 };
Vector<Option> options;
static constexpr u32 MaskExtendedRCode = 0b11111111000000000000000000000000;
static constexpr u32 MaskVersion = 0b00000000111100000000000000000000;
static constexpr u32 MaskDO = 0b00000000000000001000000000000000;
static constexpr ResourceType type = ResourceType::OPT;
constexpr u8 extended_rcode() const { return (extended_rcode_and_flags & MaskExtendedRCode) >> 24; }
constexpr u8 version() const { return (extended_rcode_and_flags & MaskVersion) >> 20; }
constexpr bool dnssec_ok() const { return extended_rcode_and_flags & MaskDO; }
void set_extended_rcode(u8 value) { extended_rcode_and_flags = (extended_rcode_and_flags & ~MaskExtendedRCode) | (value << 24); }
void set_version(u8 value) { extended_rcode_and_flags = (extended_rcode_and_flags & ~MaskVersion) | (value << 20); }
void set_dnssec_ok(bool value) { extended_rcode_and_flags = (extended_rcode_and_flags & ~MaskDO) | (value ? MaskDO : 0); }
static ErrorOr<OPT> from_raw(ParseContext&);
ErrorOr<void> to_raw(ByteBuffer&) const;
ErrorOr<String> to_string() const
{
StringBuilder builder;
builder.appendff("OPT UDP Payload Size: {}, Extended RCode: {}, Version: {}, DNSSEC OK: {}", udp_payload_size, extended_rcode(), version(), dnssec_ok());
for (auto& option : options)
builder.appendff(", opt[{} = '{:hex-dump}']", option.code, option.data.bytes());
return builder.to_string();
}
};
}
using Record = Variant<
Records::A,
Records::AAAA,
Records::TXT,
Records::CNAME,
Records::NS,
Records::SOA,
Records::MX,
Records::PTR,
Records::SRV,
Records::DNSKEY,
Records::CDNSKEY,
Records::DS,
Records::CDS,
Records::RRSIG,
Records::NSEC,
Records::NSEC3,
Records::NSEC3PARAM,
Records::TLSA,
Records::HINFO,
Records::OPT,
// TODO: Add more records.
ByteBuffer>; // Fallback for unknown records.
struct ResourceRecord {
DomainName name;
ResourceType type;
Class class_;
u32 ttl;
Record record;
Optional<ByteBuffer> raw;
static ErrorOr<ResourceRecord> from_raw(ParseContext&);
ErrorOr<void> to_raw(ByteBuffer&) const;
ErrorOr<String> to_string() const;
};
struct ZoneAuthority {
DomainName name;
ByteString admin_mailbox;
u32 serial;
u32 refresh;
u32 retry;
u32 expire;
u32 minimum_ttl;
};
struct Message {
Header header;
Vector<Question> questions;
Vector<ResourceRecord> answers;
Vector<ResourceRecord> authorities;
Vector<ResourceRecord> additional_records;
static ErrorOr<Message> from_raw(ParseContext&);
static ErrorOr<Message> from_raw(Stream&);
ErrorOr<size_t> to_raw(ByteBuffer&) const;
ErrorOr<String> format_for_log() const;
};
}
}