Record type changes
^^^^^^^^^^^^^^^^^^^
-The in-database format of ``CSYNC`` and ``IPSECKEY`` records has changed from 'generic' format to its specialized format.
+The in-database format of ``CSYNC``, ``IPSECKEY``, ``NID``, ``L32``, ``L64``, and ``LP`` records has changed from 'generic' format to its specialized format.
API users might notice that replacing records of these types leaves the old TYPExx records around, even if PowerDNS is not serving them.
To fix this, enable :ref:`setting-upgrade-unknown-types` and replace the records; this will then delete those TYPExx records.
d_pos+=len;
}
+void PacketReader::xfrNodeOrLocatorID(NodeOrLocatorID& ret)
+{
+ if (d_pos + sizeof(ret) > d_content.size()) {
+ throw std::out_of_range("Attempt to read 64 bit value outside of packet");
+ }
+ memcpy(&ret, &d_content.at(d_pos), sizeof(ret));
+ d_pos += sizeof(ret);
+}
+
void PacketReader::xfr48BitInt(uint64_t& ret)
{
ret=0;
uint16_t get16BitInt();
uint8_t get8BitInt();
+ void xfrNodeOrLocatorID(NodeOrLocatorID& val);
void xfr48BitInt(uint64_t& val);
void xfr32BitInt(uint32_t& val)
)
RKEYRecordContent::RKEYRecordContent() {}
+boilerplate_conv(NID,
+ conv.xfr16BitInt(d_preference);
+ conv.xfrNodeOrLocatorID(d_node_id);)
+
+boilerplate_conv(L32,
+ conv.xfr16BitInt(d_preference);
+ conv.xfrIP(d_locator);)
+
+boilerplate_conv(L64,
+ conv.xfr16BitInt(d_preference);
+ conv.xfrNodeOrLocatorID(d_locator);)
+
+boilerplate_conv(LP,
+ conv.xfr16BitInt(d_preference);
+ conv.xfrName(d_fqdn, false);)
+
/* EUI48 start */
void EUI48RecordContent::report()
{
APLRecordContent::report();
IPSECKEYRecordContent::report();
CSYNCRecordContent::report();
+ NIDRecordContent::report();
+ L32RecordContent::report();
+ L64RecordContent::report();
+ LPRecordContent::report();
}
void reportAllTypes()
private:
};
+
+class NIDRecordContent : public DNSRecordContent
+{
+public:
+ includeboilerplate(NID);
+
+private:
+ uint16_t d_preference;
+ NodeOrLocatorID d_node_id;
+};
+
+class L32RecordContent : public DNSRecordContent
+{
+public:
+ includeboilerplate(L32);
+
+private:
+ uint16_t d_preference;
+ uint32_t d_locator;
+};
+
+class L64RecordContent : public DNSRecordContent
+{
+public:
+ includeboilerplate(L64);
+
+private:
+ uint16_t d_preference;
+ NodeOrLocatorID d_locator;
+};
+
+class LPRecordContent : public DNSRecordContent
+{
+public:
+ includeboilerplate(LP);
+
+private:
+ uint16_t d_preference;
+ DNSName d_fqdn;
+};
+
class EUI48RecordContent : public DNSRecordContent
{
public:
d_content.insert(d_content.end(), bytes, bytes + sizeof(bytes));
}
+template <typename Container> void GenericDNSPacketWriter<Container>::xfrNodeOrLocatorID(NodeOrLocatorID val)
+{
+ d_content.insert(d_content.end(), val, val + sizeof(val));
+}
template <typename Container> void GenericDNSPacketWriter<Container>::xfr32BitInt(uint32_t val)
{
void truncate();
void xfr48BitInt(uint64_t val);
+ void xfrNodeOrLocatorID(NodeOrLocatorID val);
void xfr32BitInt(uint32_t val);
void xfr16BitInt(uint16_t val);
void xfrType(uint16_t val)
size_t parseRFC1035CharString(const std::string &in, std::string &val); // from ragel
std::string makeLuaString(const std::string& in);
+
+// Used in NID and L64 records
+typedef uint8_t NodeOrLocatorID[8];
{"SVCB", 64},
{"HTTPS", 65},
{"SPF", 99},
+ {"NID", 104},
+ {"L32", 105},
+ {"L64", 106},
+ {"LP", 107},
{"EUI48", 108},
{"EUI64", 109},
{"TKEY", 249},
SVCB = 64,
HTTPS = 65,
SPF = 99,
+ NID = 104,
+ L32 = 105,
+ L64 = 106,
+ LP = 107,
EUI48 = 108,
EUI64 = 109,
TKEY = 249,
throw RecordTextException("Overflow reading 48 bit integer from record content"); // fixme improve
}
+void RecordTextReader::xfrNodeOrLocatorID(NodeOrLocatorID& val) {
+ skipSpaces();
+ size_t len;
+ for(len=0;
+ d_pos+len < d_string.length() && (isxdigit(d_string.at(d_pos+len)) || d_string.at(d_pos+len) == ':');
+ len++) ; // find length of ID
+
+ // Parse as v6, and then strip the final 64 zero bytes
+ struct in6_addr tmpbuf;
+ string to_parse = d_string.substr(d_pos, len) + ":0:0:0:0";
+
+ if (inet_pton(AF_INET6, to_parse.c_str(), &tmpbuf) != 1) {
+ throw RecordTextException("while parsing colon-delimited 64-bit field: '" + d_string.substr(d_pos, len) + "' is invalid");
+ }
+
+ std::memcpy(&val, tmpbuf.s6_addr, sizeof(val));
+ d_pos += len;
+}
+
void RecordTextReader::xfr64BitInt(uint64_t &val)
{
skipSpaces();
d_nodot=noDot;
}
+void RecordTextWriter::xfrNodeOrLocatorID(const NodeOrLocatorID& val)
+{
+ if(!d_string.empty()) {
+ d_string.append(1,' ');
+ }
+
+ size_t ctr = 0;
+ char tmp[5];
+ for (auto const &c : val) {
+ snprintf(tmp, sizeof(tmp), "%02X", c);
+ d_string+=tmp;
+ ctr++;
+ if (ctr % 2 == 0 && ctr != 8) {
+ d_string+=':';
+ }
+ }
+}
+
void RecordTextWriter::xfr48BitInt(const uint64_t& val)
{
if(!d_string.empty())
#include "namespaces.hh"
#include "dnsname.hh"
#include "iputils.hh"
+#include "misc.hh"
#include "svc-records.hh"
class RecordTextException : public runtime_error
{
public:
RecordTextReader(string str, DNSName zone=DNSName(""));
+ void xfrNodeOrLocatorID(NodeOrLocatorID& val);
void xfr64BitInt(uint64_t& val);
void xfr48BitInt(uint64_t& val);
void xfr32BitInt(uint32_t& val);
{
public:
RecordTextWriter(string& str, bool noDot=false);
+ void xfrNodeOrLocatorID(const NodeOrLocatorID& val);
void xfr48BitInt(const uint64_t& val);
void xfr32BitInt(const uint32_t& val);
void xfr16BitInt(const uint16_t& val);
(CASE_L(QType::SVCB, "16 foo.powerdns.org. alpn=h2,h3 mandatory=alpn ipv4hint=192.0.2.1", "16 foo.powerdns.org. mandatory=alpn alpn=h2,h3 ipv4hint=192.0.2.1", "\0\x10\3foo\x08powerdns\x03org\x00\x00\x00\x00\x02\x00\x01\x00\x01\x00\x06\x02h2\x02h3\x00\x04\x00\x04\xc0\x00\x02\x01"))
(CASE_S(QType::SPF, "\"v=spf1 a:mail.rec.test ~all\"", "\x1bv=spf1 a:mail.rec.test ~all"))
+
+ (CASE_S(QType::NID, "15 0123:4567:89AB:CDEF", "\x00\x0F\x01\x23\x45\x67\x89\xab\xcd\xef"))
+ (CASE_S(QType::NID, "15 2001:0DB8:1234:ABCD", "\x00\x0F\x20\x01\x0d\xb8\x12\x34\xab\xcd"))
+ (CASE_S(QType::L32, "513 192.0.2.1", "\x02\x01\xc0\x00\x02\x01"))
+ (CASE_S(QType::L64, "255 2001:0DB8:1234:ABCD", "\x00\xFF\x20\x01\x0d\xb8\x12\x34\xab\xcd"))
+ (CASE_S(QType::LP, "512 foo.powerdns.org.", "\x02\x00\3foo\x08powerdns\x03org\x00"))
+
(CASE_S(QType::EUI48, "00-11-22-33-44-55", "\x00\x11\x22\x33\x44\x55"))
(CASE_S(QType::EUI64, "00-11-22-33-44-55-66-77", "\x00\x11\x22\x33\x44\x55\x66\x77"))
(CASE_S(QType::TKEY, "gss-tsig. 12345 12345 3 21 4 dGVzdA== 4 dGVzdA==", "\x08gss-tsig\x00\x00\x00\x30\x39\x00\x00\x30\x39\x00\x03\x00\x15\x00\x04test\x00\x04test"))
32,1,13,184,0,0,0,0,0,0,0,0,0,0,0,2}));
}
+BOOST_AUTO_TEST_CASE(test_NodeOrLocatorID) {
+ DNSName name("powerdns.com.");
+ vector<uint8_t> packet;
+
+ NodeOrLocatorID in = {0, 0, 0, 0, 0, 0, 0, 1};
+
+ DNSPacketWriter writer(packet, name, QType::NID, QClass::IN, 0);
+ writer.getHeader()->qr = 1;
+
+ writer.startRecord(name, QType::NID);
+ writer.commit();
+ auto start = writer.getContent().size();
+
+ writer.xfrNodeOrLocatorID(in);
+ writer.commit();
+ auto cit = writer.getContent().begin();
+ for (size_t i = 0; i<start; i++)
+ cit++;
+
+ vector<uint8_t> c(cit, writer.getContent().end());
+ BOOST_CHECK(c == vector<uint8_t>({
+ 0, 0, 0, 0,
+ 0, 0, 0, 1}));
+}
+
BOOST_AUTO_TEST_SUITE_END()
BOOST_CHECK_EQUAL(source, target);
}
+BOOST_AUTO_TEST_CASE(test_xfrNodeOrLocatorID) {
+ string source("0000:0000:0000:0001");
+ RecordTextReader rtr(source);
+ NodeOrLocatorID v;
+ rtr.xfrNodeOrLocatorID(v);
+ BOOST_CHECK_EQUAL(v[0], 0);
+ BOOST_CHECK_EQUAL(v[1], 0);
+ BOOST_CHECK_EQUAL(v[2], 0);
+ BOOST_CHECK_EQUAL(v[3], 0);
+ BOOST_CHECK_EQUAL(v[4], 0);
+ BOOST_CHECK_EQUAL(v[5], 0);
+ BOOST_CHECK_EQUAL(v[6], 0);
+ BOOST_CHECK_EQUAL(v[7], 1);
+
+ string target;
+ RecordTextWriter rtw(target);
+ rtw.xfrNodeOrLocatorID(v);
+ BOOST_CHECK_EQUAL(source, target);
+}
+
BOOST_AUTO_TEST_SUITE_END()