0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-06-28 14:58:20 +02:00
construct/include/ircd/rfc1035.h
2018-02-05 21:24:34 -08:00

207 lines
5.3 KiB
C++

// Matrix Construct
//
// Copyright (C) Matrix Construct Developers, Authors & Contributors
// Copyright (C) 2016-2018 Jason Volk <jason@zemos.net>
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice is present in all copies. The
// full license for this software is available in the LICENSE file.
#pragma once
#define HAVE_IRCD_RFC1035_H
/// RFC 1035 (Nov. 1987)
///
namespace ircd::rfc1035
{
IRCD_EXCEPTION(ircd::error, error)
struct header;
struct question;
struct answer;
struct record;
enum class op :uint8_t;
extern const std::array<string_view, 25> rcode;
extern const std::unordered_map<string_view, uint16_t> qtype;
const_buffer make_name(const mutable_buffer &out, const string_view &fqdn);
size_t parse_name(const mutable_buffer &out, const const_buffer &in);
mutable_buffer make_query(const mutable_buffer &, const header &, const vector_view<const question> &);
mutable_buffer make_query(const mutable_buffer &, const uint16_t &id, const vector_view<const question> &);
mutable_buffer make_query(const mutable_buffer &, const uint16_t &id, const question &);
}
/// Helper class to construct or parse a question. An object is constructed
/// with a fully qualified domain string and the query type (qtype). At the
/// appropriate time we will call print() which prints a properly binary-
/// formatted question for the question section in a DNS query; generally the
/// user does not need to do this.
///
/// Note that each part of the fqdn cannot be longer than 63 characters. The
/// supplied buffer must be large enough to hold the output, which is about
/// the length of the fqdn + 6 bytes. The qtype can be specified as a string
/// i.e "A" or "PTR" and it will be translated into the protocol number for
/// you in the constructor.
///
struct ircd::rfc1035::question
{
uint16_t qtype;
uint16_t qclass {0x01};
size_t namelen {0};
char name[256];
/// Composes the question into buffer, returns used portion
mutable_buffer print(const mutable_buffer &) const;
const_buffer parse(const const_buffer &);
/// Supply fully qualified domain name and numerical query type
question(const string_view &fqdn, const uint16_t &qtype);
/// Supply fully qualified domain name and name of query type i.e "A"
question(const string_view &fqdn, const string_view &qtype)
:question{fqdn, rfc1035::qtype.at(qtype)}
{}
question() = default;
};
/// Helper class to parse an answer.
///
struct ircd::rfc1035::answer
{
uint16_t qtype;
uint16_t qclass;
uint32_t ttl;
uint16_t rdlength;
const_buffer rdata;
string_view name;
char namebuf[256];
const_buffer parse(const const_buffer &);
answer() = default;
};
/// Direct representation of the DNS header. This is laid out for
/// little-endian platforms only. The uint16_t's are still big-endian and
/// must be bswap()'ed.
///
struct ircd::rfc1035::header
{
uint16_t id; ///< query identification number
uint8_t rd:1; ///< 0 = recursion not desired; 1 = desired
uint8_t tc:1; ///< 0 = not-truncated; 1 = 512 bytes of reply only
uint8_t aa:1; ///< 0 = non-authoritative; 1 = authoritative
uint8_t opcode:4; ///< purpose of message
uint8_t qr:1; ///< 0 = query; 1 = respnse
uint8_t rcode:4; ///< response code
uint8_t cd:1; ///< checking disabled by resolver
uint8_t ad:1; ///< authentic data from named
uint8_t unused:1; ///< unused bits (MBZ as of 4.9.3a3)
uint8_t ra:1; ///< 1 = recursion available
uint16_t qdcount; ///< number of question entries
uint16_t ancount; ///< number of answer entries
uint16_t nscount; ///< number of authority entries
uint16_t arcount; ///< number of resource entries
std::string debug() const;
}
__attribute__((packed));
static_assert
(
sizeof(ircd::rfc1035::header) == 12,
"The RFC1035 header is not the right size in this environment"
);
/// DNS operation code
///
enum class ircd::rfc1035::op
:uint8_t
{
QUERY = 0, ///< Query [RFC 1035]
IQUERY = 1, ///< Inverse Query [RFC 1035, RFC 3425]
STATUS = 2, ///< Server status request [RFC 1035]
NOTIFY = 4, ///< Notify [RFC 1996]
UPDATE = 5, ///< Update [RFC 2136]
};
/// Resource record abstract base
///
struct ircd::rfc1035::record
{
struct A;
struct AAAA;
struct CNAME;
struct SRV;
uint16_t type {0};
time_t ttl {0};
const_buffer rdata;
template<class T> const T &as() const;
record(const answer &);
record() = default;
virtual ~record() noexcept;
};
template<class T>
const T &
ircd::rfc1035::record::as()
const
{
return dynamic_cast<T &>(*this);
}
//
// Types of records
//
/// IPv4 address record
struct ircd::rfc1035::record::A
:record
{
uint32_t ip4 {0};
A(const answer &);
A() = default;
};
/// IPv6 address record
struct ircd::rfc1035::record::AAAA
:record
{
uint128_t ip6 {0};
AAAA(const answer &);
AAAA() = default;
};
/// Canonical name aliasing record
struct ircd::rfc1035::record::CNAME
:record
{
string_view name;
char namebuf[256];
CNAME(const answer &);
CNAME() = default;
};
/// Service record
struct ircd::rfc1035::record::SRV
:record
{
uint16_t priority {0};
uint16_t weight {0};
uint16_t port {0};
string_view tgt;
char tgtbuf[256];
SRV(const answer &);
SRV() = default;
};