/* MIT License * * Copyright (c) The c-ares project and its contributors * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * SPDX-License-Identifier: MIT */ #ifndef DNS_PROTO_H #define DNS_PROTO_H // Utilities for processing DNS packet contents #include "ares_setup.h" #include "ares.h" // Include ares internal file for DNS protocol constants #include "ares_nameser.h" #include #include #include extern "C" void arestest_strtolower(char *dest, const char *src, size_t dest_size); namespace ares { typedef unsigned char byte; std::string HexDump(std::vector data); std::string HexDump(const byte *data, int len); std::string HexDump(const char *data, int len); std::string StatusToString(int status); std::string RcodeToString(int rcode); std::string RRTypeToString(int rrtype); std::string ClassToString(int qclass); std::string AddressToString(const void *addr, int len); const ares_dns_rr_t *fetch_rr_opt(const ares_dns_record_t *rec); // Convert DNS protocol data to strings. // Note that these functions are not defensive; they assume // a validly formatted input, and so should not be used on // externally-determined inputs. std::string PacketToString(const std::vector &packet); std::string QuestionToString(const std::vector &packet, const byte **data, int *len); std::string RRToString(const std::vector &packet, const byte **data, int *len); // Manipulate DNS protocol data. void PushInt32(std::vector *data, int value); void PushInt16(std::vector *data, int value); std::vector EncodeString(const std::string &name); struct DNSQuestion { DNSQuestion(const std::string &name, int rrtype, int qclass) : name_(name), rrtype_(rrtype), qclass_(qclass) { } DNSQuestion(const std::string &name, int rrtype) : name_(name), rrtype_(rrtype), qclass_(C_IN) { } virtual ~DNSQuestion() { } virtual std::vector data(const char *request_name, const ares_dns_record_t *dnsrec) const; virtual std::vector data(const ares_dns_record_t *dnsrec) const { return data(nullptr, dnsrec); } virtual std::vector data() const { return data(nullptr, nullptr); } std::string name_; int rrtype_; int qclass_; }; struct DNSRR : public DNSQuestion { DNSRR(const std::string &name, int rrtype, int qclass, int ttl) : DNSQuestion(name, rrtype, qclass), ttl_(ttl) { } DNSRR(const std::string &name, int rrtype, int ttl) : DNSQuestion(name, rrtype), ttl_(ttl) { } virtual ~DNSRR() { } virtual std::vector data(const ares_dns_record_t *dnsrec) const = 0; int ttl_; }; struct DNSAddressRR : public DNSRR { DNSAddressRR(const std::string &name, int rrtype, int ttl, const byte *addr, int addrlen) : DNSRR(name, rrtype, ttl), addr_(addr, addr + addrlen) { } DNSAddressRR(const std::string &name, int rrtype, int ttl, const std::vector &addr) : DNSRR(name, rrtype, ttl), addr_(addr) { } virtual std::vector data(const ares_dns_record_t *dnsrec) const; std::vector addr_; }; struct DNSARR : public DNSAddressRR { DNSARR(const std::string &name, int ttl, const byte *addr, int addrlen) : DNSAddressRR(name, T_A, ttl, addr, addrlen) { } DNSARR(const std::string &name, int ttl, const std::vector &addr) : DNSAddressRR(name, T_A, ttl, addr) { } }; struct DNSAaaaRR : public DNSAddressRR { DNSAaaaRR(const std::string &name, int ttl, const byte *addr, int addrlen) : DNSAddressRR(name, T_AAAA, ttl, addr, addrlen) { } DNSAaaaRR(const std::string &name, int ttl, const std::vector &addr) : DNSAddressRR(name, T_AAAA, ttl, addr) { } }; struct DNSSingleNameRR : public DNSRR { DNSSingleNameRR(const std::string &name, int rrtype, int ttl, const std::string &other) : DNSRR(name, rrtype, ttl), other_(other) { } virtual std::vector data(const ares_dns_record_t *dnsrec) const; std::string other_; }; struct DNSCnameRR : public DNSSingleNameRR { DNSCnameRR(const std::string &name, int ttl, const std::string &other) : DNSSingleNameRR(name, T_CNAME, ttl, other) { } }; struct DNSNsRR : public DNSSingleNameRR { DNSNsRR(const std::string &name, int ttl, const std::string &other) : DNSSingleNameRR(name, T_NS, ttl, other) { } }; struct DNSPtrRR : public DNSSingleNameRR { DNSPtrRR(const std::string &name, int ttl, const std::string &other) : DNSSingleNameRR(name, T_PTR, ttl, other) { } }; struct DNSTxtRR : public DNSRR { DNSTxtRR(const std::string &name, int ttl, const std::vector &txt) : DNSRR(name, T_TXT, ttl), txt_(txt) { } virtual std::vector data(const ares_dns_record_t *dnsrec) const; std::vector txt_; }; struct DNSMxRR : public DNSRR { DNSMxRR(const std::string &name, int ttl, int pref, const std::string &other) : DNSRR(name, T_MX, ttl), pref_(pref), other_(other) { } virtual std::vector data(const ares_dns_record_t *dnsrec) const; int pref_; std::string other_; }; struct DNSSrvRR : public DNSRR { DNSSrvRR(const std::string &name, int ttl, int prio, int weight, int port, const std::string &target) : DNSRR(name, T_SRV, ttl), prio_(prio), weight_(weight), port_(port), target_(target) { } virtual std::vector data(const ares_dns_record_t *dnsrec) const; int prio_; int weight_; int port_; std::string target_; }; struct DNSUriRR : public DNSRR { DNSUriRR(const std::string &name, int ttl, int prio, int weight, const std::string &target) : DNSRR(name, T_URI, ttl), prio_(prio), weight_(weight), target_(target) { } virtual std::vector data(const ares_dns_record_t *dnsrec) const; int prio_; int weight_; std::string target_; }; struct DNSSoaRR : public DNSRR { DNSSoaRR(const std::string &name, int ttl, const std::string &nsname, const std::string &rname, int serial, int refresh, int retry, int expire, int minimum) : DNSRR(name, T_SOA, ttl), nsname_(nsname), rname_(rname), serial_(serial), refresh_(refresh), retry_(retry), expire_(expire), minimum_(minimum) { } virtual std::vector data(const ares_dns_record_t *dnsrec) const; std::string nsname_; std::string rname_; int serial_; int refresh_; int retry_; int expire_; int minimum_; }; struct DNSNaptrRR : public DNSRR { DNSNaptrRR(const std::string &name, int ttl, int order, int pref, const std::string &flags, const std::string &service, const std::string ®exp, const std::string &replacement) : DNSRR(name, T_NAPTR, ttl), order_(order), pref_(pref), flags_(flags), service_(service), regexp_(regexp), replacement_(replacement) { } virtual std::vector data(const ares_dns_record_t *dnsrec) const; int order_; int pref_; std::string flags_; std::string service_; std::string regexp_; std::string replacement_; }; struct DNSOption { int code_; std::vector data_; }; struct DNSOptRR : public DNSRR { DNSOptRR(unsigned char extrcode, unsigned char version, unsigned short flags, int udpsize, std::vector client_cookie, std::vector server_cookie, bool expect_server_cookie) : DNSRR("", T_OPT, static_cast(udpsize), ((int)extrcode) << 24 | ((int)version) << 16 | ((int)flags) /* ttl */) { client_cookie_ = client_cookie; server_cookie_ = server_cookie; expect_server_cookie_ = expect_server_cookie; } virtual std::vector data(const ares_dns_record_t *dnsrec) const; std::vector opts_; std::vector client_cookie_; std::vector server_cookie_; bool expect_server_cookie_; }; struct DNSPacket { DNSPacket() : qid_(0), response_(false), opcode_(O_QUERY), aa_(false), tc_(false), rd_(false), ra_(false), z_(false), ad_(false), cd_(false), rcode_(NOERROR) { } // Convenience functions that take ownership of given pointers. DNSPacket &add_question(DNSQuestion *q) { questions_.push_back(std::unique_ptr(q)); return *this; } DNSPacket &add_answer(DNSRR *q) { answers_.push_back(std::unique_ptr(q)); return *this; } DNSPacket &add_auth(DNSRR *q) { auths_.push_back(std::unique_ptr(q)); return *this; } DNSPacket &add_additional(DNSRR *q) { adds_.push_back(std::unique_ptr(q)); return *this; } // Chainable setters. DNSPacket &set_qid(int qid) { qid_ = qid; return *this; } DNSPacket &set_response(bool v = true) { response_ = v; return *this; } DNSPacket &set_aa(bool v = true) { aa_ = v; return *this; } DNSPacket &set_tc(bool v = true) { tc_ = v; return *this; } DNSPacket &set_rd(bool v = true) { rd_ = v; return *this; } DNSPacket &set_ra(bool v = true) { ra_ = v; return *this; } DNSPacket &set_z(bool v = true) { z_ = v; return *this; } DNSPacket &set_ad(bool v = true) { ad_ = v; return *this; } DNSPacket &set_cd(bool v = true) { cd_ = v; return *this; } DNSPacket &set_rcode(int rcode) { rcode_ = rcode; return *this; } // Return the encoded packet. std::vector data(const char *request_name, const ares_dns_record_t *dnsrec) const; std::vector data() const { return data(nullptr, nullptr); } int qid_; bool response_; int opcode_; bool aa_; bool tc_; bool rd_; bool ra_; bool z_; bool ad_; bool cd_; int rcode_; std::vector> questions_; std::vector> answers_; std::vector> auths_; std::vector> adds_; }; } // namespace ares #endif