1232 is the largest number of payload bytes that can fit in the smallest IPv6 packet.
IPv6 has a minimum MTU of 1280 bytes (:rfc:`RFC 8200, section 5 <8200#section-5>`), minus 40 bytes for the IPv6 header, minus 8 bytes for the UDP header gives 1232, the maximum payload size for the DNS response.
+.. _setting-upgrade-unknown-types:
+
+``upgrade-unknown-types``
+-------------------------
+
+- Boolean
+- Default: no
+
+.. versionadded:: 4.4.0
+
+Transparently upgrade records stored as `TYPE#xxx` and RFC 3597 (hex format)
+contents, if the type is natively supported.
+When this is disabled, records stored in this format cannot be served.
+
+Recommendation: keep disabled for better performance.
+Enable for testing PowerDNS upgrades, without changing stored records.
+
+This option is supported by the bind and Generic SQL backends.
+
.. _setting-version-string:
``version-string``
nsec3zone=getNSEC3PARAM(bbd->d_name, &ns3pr);
auto records = std::make_shared<recordstorage_t>();
- ZoneParserTNG zpt(bbd->d_filename, bbd->d_name, s_binddirectory);
+ ZoneParserTNG zpt(bbd->d_filename, bbd->d_name, s_binddirectory, d_upgradeContent);
zpt.setMaxGenerateSteps(::arg().asNum("max-generate-steps"));
DNSResourceRecord rr;
string hashed;
d_hybrid=mustDo("hybrid");
d_transaction_id=0;
s_ignore_broken_records=mustDo("ignore-broken-records");
+ d_upgradeContent=::arg().mustDo("upgrade-unknown-types");
if (!loadZones && d_hybrid)
return;
int d_transaction_id;
static bool s_ignore_broken_records;
bool d_hybrid;
+ bool d_upgradeContent;
BB2DomainInfo createDomainEntry(const DNSName& domain, const string &filename); //!< does not insert in s_state
d_db = nullptr;
d_logprefix="["+mode+"Backend"+suffix+"] ";
- try
- {
+ try {
d_dnssecQueries = mustDo("dnssec");
}
- catch (const ArgException&)
- {
+ catch (const ArgException&) {
d_dnssecQueries = false;
}
+ try {
+ d_upgradeContent = ::arg().mustDo("upgrade-unknown-types");
+ }
+ catch (const ArgException&) {
+ d_upgradeContent = false;
+ }
+
d_NoIdQuery=getArg("basic-query");
d_IdQuery=getArg("id-query");
d_ANYNoIdQuery=getArg("any-query");
r.qtype=row[3];
- if (r.qtype==QType::MX || r.qtype==QType::SRV) {
+ if (d_upgradeContent && DNSRecordContent::isUnknownType(row[3])) {
+ r.content = DNSRecordContent::upgradeContent(r.qname, r.qtype, row[0]);
+ }
+ else if (r.qtype==QType::MX || r.qtype==QType::SRV) {
r.content.reserve(row[2].size() + row[0].size() + 1);
r.content=row[2]+" "+row[0];
}
std::unique_ptr<SSql> d_db{nullptr};
bool d_dnssecQueries;
bool d_inTransaction{false};
+ bool d_upgradeContent{false};
};
::arg().set("tcp-fast-open", "Enable TCP Fast Open support on the listening sockets, using the supplied numerical value as the queue size")="0";
::arg().set("max-generate-steps", "Maximum number of $GENERATE steps when loading a zone from a file")="0";
+ ::arg().setSwitch("upgrade-unknown-types","Transparently upgrade known TYPExxx records. Recommended to keep off, except for PowerDNS upgrades until data sources are cleaned up")="no";
::arg().set("rng", "Specify the random number generator to use. Valid values are auto,sodium,openssl,getrandom,arc4random,urandom.")="auto";
::arg().setDefaults();
#include "namespaces.hh"
-class UnknownRecordContent : public DNSRecordContent
+UnknownRecordContent::UnknownRecordContent(const string& zone)
{
-public:
- UnknownRecordContent(const DNSRecord& dr, PacketReader& pr)
- : d_dr(dr)
- {
- pr.copyRecord(d_record, dr.d_clen);
+ // parse the input
+ vector<string> parts;
+ stringtok(parts, zone);
+ // we need exactly 3 parts, except if the length field is set to 0 then we only need 2
+ if (parts.size() != 3 && !(parts.size() == 2 && equals(parts.at(1), "0"))) {
+ throw MOADNSException("Unknown record was stored incorrectly, need 3 fields, got " + std::to_string(parts.size()) + ": " + zone);
}
- UnknownRecordContent(const string& zone)
- {
- // parse the input
- vector<string> parts;
- stringtok(parts, zone);
- // we need exactly 3 parts, except if the length field is set to 0 then we only need 2
- if (parts.size() != 3 && !(parts.size() == 2 && equals(parts.at(1), "0"))) {
- throw MOADNSException("Unknown record was stored incorrectly, need 3 fields, got " + std::to_string(parts.size()) + ": " + zone);
- }
-
- if (parts.at(0) != "\\#") {
- throw MOADNSException("Unknown record was stored incorrectly, first part should be '\\#', got '" + parts.at(0) + "'");
- }
+ if (parts.at(0) != "\\#") {
+ throw MOADNSException("Unknown record was stored incorrectly, first part should be '\\#', got '" + parts.at(0) + "'");
+ }
- const string& relevant = (parts.size() > 2) ? parts.at(2) : "";
- unsigned int total = pdns_stou(parts.at(1));
- if (relevant.size() % 2 || (relevant.size() / 2) != total) {
- throw MOADNSException((boost::format("invalid unknown record length: size not equal to length field (%d != 2 * %d)") % relevant.size() % total).str());
- }
+ const string& relevant = (parts.size() > 2) ? parts.at(2) : "";
+ unsigned int total = pdns_stou(parts.at(1));
+ if (relevant.size() % 2 || (relevant.size() / 2) != total) {
+ throw MOADNSException((boost::format("invalid unknown record length: size not equal to length field (%d != 2 * %d)") % relevant.size() % total).str());
+ }
- string out;
- out.reserve(total + 1);
+ string out;
+ out.reserve(total + 1);
- for (unsigned int n = 0; n < total; ++n) {
- int c;
- if (sscanf(&relevant.at(2*n), "%02x", &c) != 1) {
- throw MOADNSException("unable to read data at position " + std::to_string(2 * n) + " from unknown record of size " + std::to_string(relevant.size()));
- }
- out.append(1, (char)c);
+ for (unsigned int n = 0; n < total; ++n) {
+ int c;
+ if (sscanf(&relevant.at(2*n), "%02x", &c) != 1) {
+ throw MOADNSException("unable to read data at position " + std::to_string(2 * n) + " from unknown record of size " + std::to_string(relevant.size()));
}
-
- d_record.insert(d_record.end(), out.begin(), out.end());
+ out.append(1, (char)c);
}
- string getZoneRepresentation(bool noDot) const override
- {
- ostringstream str;
- str<<"\\# "<<(unsigned int)d_record.size()<<" ";
- char hex[4];
- for(size_t n=0; n<d_record.size(); ++n) {
- snprintf(hex, sizeof(hex), "%02x", d_record.at(n));
- str << hex;
- }
- return str.str();
- }
+ d_record.insert(d_record.end(), out.begin(), out.end());
+}
- void toPacket(DNSPacketWriter& pw) override
- {
- pw.xfrBlob(string(d_record.begin(),d_record.end()));
+string UnknownRecordContent::getZoneRepresentation(bool noDot) const
+{
+ ostringstream str;
+ str<<"\\# "<<(unsigned int)d_record.size()<<" ";
+ char hex[4];
+ for (size_t n=0; n<d_record.size(); ++n) {
+ snprintf(hex, sizeof(hex), "%02x", d_record.at(n));
+ str << hex;
}
+ return str.str();
+}
- uint16_t getType() const override
- {
- return d_dr.d_type;
- }
-private:
- DNSRecord d_dr;
- vector<uint8_t> d_record;
-};
+void UnknownRecordContent::toPacket(DNSPacketWriter& pw)
+{
+ pw.xfrBlob(string(d_record.begin(),d_record.end()));
+}
shared_ptr<DNSRecordContent> DNSRecordContent::deserialize(const DNSName& qname, uint16_t qtype, const string& serialized)
{
return i->second(dr, pr);
}
+string DNSRecordContent::upgradeContent(const DNSName& qname, const QType qtype, const string& content) {
+ // seamless upgrade for previously unsupported but now implemented types.
+ UnknownRecordContent unknown_content(content);
+ shared_ptr<DNSRecordContent> rc = DNSRecordContent::deserialize(qname, qtype.getCode(), unknown_content.serialize(qname));
+ return rc->getZoneRepresentation();
+}
DNSRecordContent::typemap_t& DNSRecordContent::getTypemap()
{
And we might be able to reverse 2 -> 3 as well
*/
-#include "namespaces.hh"
#include "namespaces.hh"
class MOADNSException : public runtime_error
static std::shared_ptr<DNSRecordContent> mastermake(const DNSRecord &dr, PacketReader& pr);
static std::shared_ptr<DNSRecordContent> mastermake(const DNSRecord &dr, PacketReader& pr, uint16_t opcode);
static std::shared_ptr<DNSRecordContent> mastermake(uint16_t qtype, uint16_t qclass, const string& zone);
+ static string upgradeContent(const DNSName& qname, const QType qtype, const string& content);
virtual std::string getZoneRepresentation(bool noDot=false) const = 0;
virtual ~DNSRecordContent() {}
getZmakermap().erase(key);
}
+ static bool isUnknownType(const string& name)
+ {
+ return boost::starts_with(name, "TYPE") || boost::starts_with(name, "type");
+ }
+
static uint16_t TypeToNumber(const string& name)
{
n2typemap_t::const_iterator iter = getN2Typemap().find(toUpper(name));
if(iter != getN2Typemap().end())
return iter->second.second;
- if(boost::starts_with(name, "TYPE") || boost::starts_with(name, "type"))
+ if (isUnknownType(name))
return (uint16_t) pdns_stou(name.substr(4));
throw runtime_error("Unknown DNS type '"+name+"'");
DNSRecord dr;
};
+class UnknownRecordContent : public DNSRecordContent
+{
+public:
+ UnknownRecordContent(const DNSRecord& dr, PacketReader& pr)
+ : d_dr(dr)
+ {
+ pr.copyRecord(d_record, dr.d_clen);
+ }
+
+ UnknownRecordContent(const string& zone);
+
+ string getZoneRepresentation(bool noDot) const override;
+ void toPacket(DNSPacketWriter& pw) override;
+ uint16_t getType() const override
+ {
+ return d_dr.d_type;
+ }
+
+private:
+ DNSRecord d_dr;
+ vector<uint8_t> d_record;
+};
//! This class can be used to parse incoming packets, and is copyable
class MOADNSParser : public boost::noncopyable
::arg().set("max-signature-cache-entries", "Maximum number of signatures cache entries")="";
::arg().set("rng", "Specify random number generator to use. Valid values are auto,sodium,openssl,getrandom,arc4random,urandom.")="auto";
::arg().set("max-generate-steps", "Maximum number of $GENERATE steps when loading a zone from a file")="0";
+ ::arg().setSwitch("upgrade-unknown-types","Transparently upgrade known TYPExxx records. Recommended to keep off, except for PowerDNS upgrades until data sources are cleaned up")="no";
::arg().laxFile(configname.c_str());
if(!::arg()["load-modules"].empty()) {
static string g_INstr("IN");
-ZoneParserTNG::ZoneParserTNG(const string& fname, const DNSName& zname, const string& reldir) : d_reldir(reldir),
- d_zonename(zname), d_defaultttl(3600),
- d_templatecounter(0), d_templatestop(0),
- d_templatestep(0), d_havedollarttl(false){
+ZoneParserTNG::ZoneParserTNG(const string& fname, const DNSName& zname, const string& reldir, bool upgradeContent):
+ d_reldir(reldir), d_zonename(zname), d_defaultttl(3600),
+ d_templatecounter(0), d_templatestop(0), d_templatestep(0),
+ d_havedollarttl(false), d_fromfile(true), d_upgradeContent(upgradeContent)
+{
stackFile(fname);
}
-ZoneParserTNG::ZoneParserTNG(const vector<string> zonedata, const DNSName& zname):
+ZoneParserTNG::ZoneParserTNG(const vector<string> zonedata, const DNSName& zname, bool upgradeContent):
d_zonename(zname), d_zonedata(zonedata), d_defaultttl(3600),
d_templatecounter(0), d_templatestop(0), d_templatestep(0),
- d_havedollarttl(false), d_fromfile(false)
+ d_havedollarttl(false), d_fromfile(false), d_upgradeContent(upgradeContent)
{
d_zonedataline = d_zonedata.begin();
}
string nextpart;
rr.ttl=d_defaultttl;
- bool haveTTL=0, haveQTYPE=0;
+ bool haveTTL{false}, haveQTYPE{false};
+ string qtypeString;
pair<string::size_type, string::size_type> range;
while(!d_parts.empty()) {
break;
try {
- rr.qtype=DNSRecordContent::TypeToNumber(nextpart);
+ rr.qtype = DNSRecordContent::TypeToNumber(nextpart);
// cout<<"Got qtype ("<<rr.qtype.getCode()<<")\n";
- haveQTYPE=1;
+ qtypeString = nextpart;
+ haveQTYPE = true;
continue;
}
catch(...) {
}
trim_if(rr.content, is_any_of(" \r\n\t\x1a"));
+ if (d_upgradeContent && DNSRecordContent::isUnknownType(qtypeString)) {
+ rr.content = DNSRecordContent::upgradeContent(rr.qname, rr.qtype, rr.content);
+ }
+
vector<string> recparts;
switch(rr.qtype.getCode()) {
case QType::MX:
class ZoneParserTNG
{
public:
- ZoneParserTNG(const string& fname, const DNSName& zname=g_rootdnsname, const string& reldir="");
- ZoneParserTNG(const vector<string> zonedata, const DNSName& zname);
+ ZoneParserTNG(const string& fname, const DNSName& zname=g_rootdnsname, const string& reldir="", bool upgradeContent=false);
+ ZoneParserTNG(const vector<string> zonedata, const DNSName& zname, bool upgradeContent=false);
~ZoneParserTNG();
bool get(DNSResourceRecord& rr, std::string* comment=0);
bool d_havedollarttl;
bool d_fromfile;
bool d_generateEnabled{true};
+ bool d_upgradeContent;
};