diff options
Diffstat (limited to 'dns.hh')
-rw-r--r-- | dns.hh | 243 |
1 files changed, 243 insertions, 0 deletions
@@ -0,0 +1,243 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#pragma once +#include "qtype.hh" +#include "dnsname.hh" +#include <ctime> +#include <sys/types.h> + +#undef BADSIG // signal.h SIG_ERR + +struct DNSRecord; + +class RCode +{ +public: + enum rcodes_ { NoError=0, FormErr=1, ServFail=2, NXDomain=3, NotImp=4, Refused=5, YXDomain=6, YXRRSet=7, NXRRSet=8, NotAuth=9, NotZone=10}; + static std::string to_s(uint8_t rcode); + static std::string to_short_s(uint8_t rcode); + const static std::array<std::string, 24> rcodes_s; +}; + +class ERCode +{ +public: + enum rcodes_ { BADVERS=16, BADSIG=16, BADKEY=17, BADTIME=18, BADMODE=19, BADNAME=20, BADALG=21, BADTRUNC=22, BADCOOKIE=23 }; + static std::string to_s(uint8_t rcode); +}; + +class Opcode +{ +public: + enum { Query=0, IQuery=1, Status=2, Notify=4, Update=5 }; + static std::string to_s(uint8_t opcode); +}; + +//! This class represents a resource record +class DNSResourceRecord +{ +public: + DNSResourceRecord() : last_modified(0), ttl(0), signttl(0), domain_id(-1), qclass(1), scopeMask(0), auth(1), disabled(0) {}; + static DNSResourceRecord fromWire(const DNSRecord& d); + + enum Place : uint8_t {QUESTION=0, ANSWER=1, AUTHORITY=2, ADDITIONAL=3}; //!< Type describing the positioning within, say, a DNSPacket + + void setContent(const string& content); + string getZoneRepresentation(bool noDot=false) const; + + // data + DNSName qname; //!< the name of this record, for example: www.powerdns.com + DNSName ordername; + DNSName wildcardname; + string content; //!< what this record points to. Example: 10.1.2.3 + + // Aligned on 8-byte boundaries on systems where time_t is 8 bytes and int + // is 4 bytes, aka modern linux on x86_64 + time_t last_modified; //!< For autocalculating SOA serial numbers - the backend needs to fill this in + + uint32_t ttl; //!< Time To Live of this record + uint32_t signttl; //!< If non-zero, use this TTL as original TTL in the RRSIG + + int domain_id; //!< If a backend implements this, the domain_id of the zone this record is in + QType qtype; //!< qtype of this record, ie A, CNAME, MX etc + uint16_t qclass; //!< class of this record + + uint8_t scopeMask; + bool auth; + bool disabled; + + bool operator==(const DNSResourceRecord& rhs); + + bool operator<(const DNSResourceRecord &b) const + { + if(qname < b.qname) + return true; + if(qname == b.qname) + return(content < b.content); + return false; + } +}; + +#define GCCPACKATTRIBUTE __attribute__((packed)) + +struct dnsrecordheader +{ + uint16_t d_type; + uint16_t d_class; + uint32_t d_ttl; + uint16_t d_clen; +} GCCPACKATTRIBUTE; + +struct EDNS0Record +{ + uint8_t extRCode, version; + uint16_t extFlags; +} GCCPACKATTRIBUTE; + +static_assert(sizeof(EDNS0Record) == 4, "EDNS0Record size must be 4"); + +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) +#include <machine/endian.h> +#elif __linux__ || __GNU__ +# include <endian.h> + +#else // with thanks to <arpa/nameser.h> + +# define LITTLE_ENDIAN 1234 /* least-significant byte first (vax, pc) */ +# define BIG_ENDIAN 4321 /* most-significant byte first (IBM, net) */ +# define PDP_ENDIAN 3412 /* LSB first in word, MSW first in long (pdp) */ + +#if defined(vax) || defined(ns32000) || defined(sun386) || defined(i386) || \ + defined(__i386) || defined(__ia64) || defined(__amd64) || \ + defined(MIPSEL) || defined(_MIPSEL) || defined(BIT_ZERO_ON_RIGHT) || \ + defined(__alpha__) || defined(__alpha) || \ + (defined(__Lynx__) && defined(__x86__)) +# define BYTE_ORDER LITTLE_ENDIAN +#endif + +#if defined(sel) || defined(pyr) || defined(mc68000) || defined(sparc) || \ + defined(__sparc) || \ + defined(is68k) || defined(tahoe) || defined(ibm032) || defined(ibm370) || \ + defined(MIPSEB) || defined(_MIPSEB) || defined(_IBMR2) || defined(DGUX) ||\ + defined(apollo) || defined(__convex__) || defined(_CRAY) || \ + defined(__hppa) || defined(__hp9000) || \ + defined(__hp9000s300) || defined(__hp9000s700) || \ + defined(__hp3000s900) || defined(MPE) || \ + defined(BIT_ZERO_ON_LEFT) || defined(m68k) || \ + (defined(__Lynx__) && \ + (defined(__68k__) || defined(__sparc__) || defined(__powerpc__))) +# define BYTE_ORDER BIG_ENDIAN +#endif + +#endif + +struct dnsheader { + unsigned id :16; /* query identification number */ +#if BYTE_ORDER == BIG_ENDIAN + /* fields in third byte */ + unsigned qr: 1; /* response flag */ + unsigned opcode: 4; /* purpose of message */ + unsigned aa: 1; /* authoritative answer */ + unsigned tc: 1; /* truncated message */ + unsigned rd: 1; /* recursion desired */ + /* fields in fourth byte */ + unsigned ra: 1; /* recursion available */ + unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */ + unsigned ad: 1; /* authentic data from named */ + unsigned cd: 1; /* checking disabled by resolver */ + unsigned rcode :4; /* response code */ +#elif BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN + /* fields in third byte */ + unsigned rd :1; /* recursion desired */ + unsigned tc :1; /* truncated message */ + unsigned aa :1; /* authoritative answer */ + unsigned opcode :4; /* purpose of message */ + unsigned qr :1; /* response flag */ + /* fields in fourth byte */ + unsigned rcode :4; /* response code */ + unsigned cd: 1; /* checking disabled by resolver */ + unsigned ad: 1; /* authentic data from named */ + unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */ + unsigned ra :1; /* recursion available */ +#endif + /* remaining bytes */ + unsigned qdcount :16; /* number of question entries */ + unsigned ancount :16; /* number of answer entries */ + unsigned nscount :16; /* number of authority entries */ + unsigned arcount :16; /* number of resource entries */ +}; + +static_assert(sizeof(dnsheader) == 12, "dnsheader size must be 12"); + +class dnsheader_aligned +{ +public: + dnsheader_aligned(const void* mem) + { + if (reinterpret_cast<uintptr_t>(mem) % sizeof(uint32_t) == 0) { + d_p = reinterpret_cast<const dnsheader*>(mem); + } + else { + memcpy(&d_h, mem, sizeof(dnsheader)); + d_p = &d_h; + } + } + + const dnsheader* get() const + { + return d_p; + } + +private: + dnsheader d_h; + const dnsheader *d_p; +}; + +inline uint16_t * getFlagsFromDNSHeader(struct dnsheader * dh) +{ + return (uint16_t*) (((char *) dh) + sizeof(uint16_t)); +} + +#define DNS_TYPE_SIZE (2) +#define DNS_CLASS_SIZE (2) +#define DNS_TTL_SIZE (4) +#define DNS_RDLENGTH_SIZE (2) +#define EDNS_EXTENDED_RCODE_SIZE (1) +#define EDNS_VERSION_SIZE (1) +#define EDNS_OPTION_CODE_SIZE (2) +#define EDNS_OPTION_LENGTH_SIZE (2) + +#if BYTE_ORDER == BIG_ENDIAN +#define FLAGS_RD_OFFSET (8) +#define FLAGS_CD_OFFSET (12) +#elif BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN +#define FLAGS_RD_OFFSET (0) +#define FLAGS_CD_OFFSET (12) +#endif + +uint32_t hashQuestion(const uint8_t* packet, uint16_t len, uint32_t init, bool& ok); + +struct TSIGTriplet +{ + DNSName name, algo; + string secret; +}; |