return false;
}
-static void computeRRSIG(const DNSSECPrivateKey& dpk, const DNSName& signer, const DNSName& signQName, uint16_t signQType, uint32_t signTTL, uint32_t sigValidity, RRSIGRecordContent& rrc, vector<shared_ptr<DNSRecordContent> >& toSign)
+static void computeRRSIG(const DNSSECPrivateKey& dpk, const DNSName& signer, const DNSName& signQName, uint16_t signQType, uint32_t signTTL, uint32_t sigValidity, RRSIGRecordContent& rrc, vector<shared_ptr<DNSRecordContent> >& toSign, boost::optional<uint8_t> algo=boost::none)
{
time_t now = time(nullptr);
DNSKEYRecordContent drc = dpk.getDNSKEY();
rrc.d_signer = signer;
rrc.d_tag = 0;
rrc.d_tag = drc.getTag();
- rrc.d_algorithm = drc.d_algorithm;
+ rrc.d_algorithm = algo ? *algo : drc.d_algorithm;
std::string msg = getMessageForRRSET(signQName, rrc, toSign);
typedef std::unordered_map<DNSName, std::pair<DNSSECPrivateKey, DSRecordContent> > testkeysset_t;
-static void addRRSIG(const testkeysset_t& keys, std::vector<DNSRecord>& records, const DNSName& signer, uint32_t sigValidity)
+static void addRRSIG(const testkeysset_t& keys, std::vector<DNSRecord>& records, const DNSName& signer, uint32_t sigValidity, bool broken=false, boost::optional<uint8_t> algo=boost::none)
{
if (records.empty()) {
return;
}
RRSIGRecordContent rrc;
- computeRRSIG(it->second.first, signer, records[recordsCount-1].d_name, records[recordsCount-1].d_type, records[recordsCount-1].d_ttl, sigValidity, rrc, recordcontents);
+ computeRRSIG(it->second.first, signer, records[recordsCount-1].d_name, records[recordsCount-1].d_type, records[recordsCount-1].d_ttl, sigValidity, rrc, recordcontents, algo);
+ if (broken) {
+ rrc.d_signature[0] ^= 42;
+ }
DNSRecord rec;
rec.d_place = records[recordsCount-1].d_place;
BOOST_CHECK_EQUAL(queriesCount, 1);
}
+BOOST_AUTO_TEST_CASE(test_dnssec_bogus_bad_sig) {
+ std::unique_ptr<SyncRes> sr;
+ initSR(sr, true);
+
+ g_dnssecmode = DNSSECMode::ValidateAll;
+
+ primeHints();
+ const DNSName target(".");
+ testkeysset_t keys;
+
+ auto luaconfsCopy = g_luaconfs.getCopy();
+ luaconfsCopy.dsAnchors.clear();
+ generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
+
+ g_luaconfs.setState(luaconfsCopy);
+
+ size_t queriesCount = 0;
+
+ sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
+ queriesCount++;
+
+ if (domain == target && type == QType::NS) {
+
+ setLWResult(res, 0, true, false, true);
+ char addr[] = "a.root-servers.net.";
+ for (char idx = 'a'; idx <= 'm'; idx++) {
+ addr[0] = idx;
+ addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
+ }
+
+ addRRSIG(keys, res->d_records, domain, 300, true);
+
+ addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
+ addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
+
+ return 1;
+ } else if (domain == target && type == QType::DNSKEY) {
+
+ setLWResult(res, 0, true, false, true);
+
+ addDNSKEY(keys, domain, 300, res->d_records);
+ addRRSIG(keys, res->d_records, domain, 300);
+
+ return 1;
+ }
+
+ return 0;
+ });
+
+ vector<DNSRecord> ret;
+ int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
+ BOOST_CHECK_EQUAL(res, RCode::NoError);
+ BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
+ /* 13 NS + 1 RRSIG */
+ BOOST_REQUIRE_EQUAL(ret.size(), 14);
+ BOOST_CHECK_EQUAL(queriesCount, 2);
+
+ /* again, to test the cache */
+ ret.clear();
+ res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
+ BOOST_CHECK_EQUAL(res, RCode::NoError);
+ BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
+ BOOST_REQUIRE_EQUAL(ret.size(), 14);
+ BOOST_CHECK_EQUAL(queriesCount, 2);
+}
+
+BOOST_AUTO_TEST_CASE(test_dnssec_bogus_bad_algo) {
+ std::unique_ptr<SyncRes> sr;
+ initSR(sr, true);
+
+ g_dnssecmode = DNSSECMode::ValidateAll;
+
+ primeHints();
+ const DNSName target(".");
+ testkeysset_t keys;
+
+ auto luaconfsCopy = g_luaconfs.getCopy();
+ luaconfsCopy.dsAnchors.clear();
+ generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
+
+ g_luaconfs.setState(luaconfsCopy);
+
+ size_t queriesCount = 0;
+
+ sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
+ queriesCount++;
+
+ if (domain == target && type == QType::NS) {
+
+ setLWResult(res, 0, true, false, true);
+ char addr[] = "a.root-servers.net.";
+ for (char idx = 'a'; idx <= 'm'; idx++) {
+ addr[0] = idx;
+ addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
+ }
+
+ /* FORCE WRONG ALGO */
+ addRRSIG(keys, res->d_records, domain, 300, false, DNSSECKeeper::RSASHA256);
+
+ addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
+ addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
+
+ return 1;
+ } else if (domain == target && type == QType::DNSKEY) {
+
+ setLWResult(res, 0, true, false, true);
+
+ addDNSKEY(keys, domain, 300, res->d_records);
+ addRRSIG(keys, res->d_records, domain, 300);
+
+ return 1;
+ }
+
+ return 0;
+ });
+
+ vector<DNSRecord> ret;
+ int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
+ BOOST_CHECK_EQUAL(res, RCode::NoError);
+ BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
+ /* 13 NS + 1 RRSIG */
+ BOOST_REQUIRE_EQUAL(ret.size(), 14);
+ BOOST_CHECK_EQUAL(queriesCount, 2);
+
+ /* again, to test the cache */
+ ret.clear();
+ res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
+ BOOST_CHECK_EQUAL(res, RCode::NoError);
+ BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
+ BOOST_REQUIRE_EQUAL(ret.size(), 14);
+ BOOST_CHECK_EQUAL(queriesCount, 2);
+}
+
BOOST_AUTO_TEST_CASE(test_dnssec_secure_various_algos) {
std::unique_ptr<SyncRes> sr;
initSR(sr, true);
BOOST_CHECK_EQUAL(queriesCount, 8);
}
+BOOST_AUTO_TEST_CASE(test_dnssec_insecure_to_secure_cname) {
+ std::unique_ptr<SyncRes> sr;
+ initSR(sr, true);
+
+ g_dnssecmode = DNSSECMode::ValidateAll;
+
+ primeHints();
+ const DNSName target("power-dns.com.");
+ const DNSName targetCName("powerdns.com.");
+ const ComboAddress targetCNameAddr("192.0.2.42");
+ testkeysset_t keys;
+
+ auto luaconfsCopy = g_luaconfs.getCopy();
+ luaconfsCopy.dsAnchors.clear();
+ generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
+ generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
+ generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
+ g_luaconfs.setState(luaconfsCopy);
+
+ size_t queriesCount = 0;
+
+ sr->setAsyncCallback([target,targetCName,targetCNameAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
+ queriesCount++;
+
+ if (type == QType::DS) {
+ if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
+ setLWResult(res, 0, false, false, true);
+ addDS(domain, 300, res->d_records, keys);
+ addRRSIG(keys, res->d_records, domain, 300);
+ return 1;
+ }
+ else if (domain == DNSName("power-dns.com.")) {
+ setLWResult(res, 0, false, false, true);
+ addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
+ addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
+ addRRSIG(keys, res->d_records, DNSName("com."), 300);
+ return 1;
+ }
+ }
+ else if (type == QType::DNSKEY) {
+ if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
+ setLWResult(res, 0, true, false, true);
+ addDNSKEY(keys, domain, 300, res->d_records);
+ addRRSIG(keys, res->d_records, domain, 300);
+ return 1;
+ }
+ else {
+ setLWResult(res, 0, false, false, true);
+ addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
+ return 1;
+ }
+ }
+ else {
+ if (isRootServer(ip)) {
+ setLWResult(res, 0, false, false, true);
+ addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
+ addDS(DNSName("com."), 300, res->d_records, keys);
+ addRRSIG(keys, res->d_records, DNSName("."), 300);
+ addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
+ return 1;
+ }
+ else if (ip == ComboAddress("192.0.2.1:53")) {
+ setLWResult(res, 0, false, false, true);
+ addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
+ if (domain == targetCName) {
+ addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
+ }
+ else if (domain == target) {
+ addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
+ }
+ addRRSIG(keys, res->d_records, DNSName("com."), 300);
+ addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
+ return 1;
+ }
+ else if (ip == ComboAddress("192.0.2.2:53")) {
+ setLWResult(res, 0, true, false, true);
+ if (domain == target) {
+ addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
+ }
+ else if (domain == targetCName) {
+ addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
+ addRRSIG(keys, res->d_records, domain, 300);
+ }
+ return 1;
+ }
+ }
+
+ return 0;
+ });
+
+ vector<DNSRecord> ret;
+ int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
+ BOOST_CHECK_EQUAL(res, RCode::NoError);
+ BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
+ BOOST_REQUIRE_EQUAL(ret.size(), 3);
+ BOOST_CHECK_EQUAL(queriesCount, 8);
+
+ /* again, to test the cache */
+ ret.clear();
+ res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
+ BOOST_CHECK_EQUAL(res, RCode::NoError);
+ BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
+ BOOST_REQUIRE_EQUAL(ret.size(), 3);
+ BOOST_CHECK_EQUAL(queriesCount, 8);
+}
+
+BOOST_AUTO_TEST_CASE(test_dnssec_bogus_to_secure_cname) {
+ std::unique_ptr<SyncRes> sr;
+ initSR(sr, true);
+
+ g_dnssecmode = DNSSECMode::ValidateAll;
+
+ primeHints();
+ const DNSName target("power-dns.com.");
+ const DNSName targetCName("powerdns.com.");
+ const ComboAddress targetCNameAddr("192.0.2.42");
+ testkeysset_t keys;
+
+ auto luaconfsCopy = g_luaconfs.getCopy();
+ luaconfsCopy.dsAnchors.clear();
+ generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
+ generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
+ generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
+ generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
+ g_luaconfs.setState(luaconfsCopy);
+
+ size_t queriesCount = 0;
+
+ sr->setAsyncCallback([target,targetCName,targetCNameAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
+ queriesCount++;
+
+ if (type == QType::DS) {
+ setLWResult(res, 0, false, false, true);
+ addDS(domain, 300, res->d_records, keys);
+ addRRSIG(keys, res->d_records, domain, 300);
+ return 1;
+ }
+ else if (type == QType::DNSKEY) {
+ setLWResult(res, 0, true, false, true);
+ addDNSKEY(keys, domain, 300, res->d_records);
+ addRRSIG(keys, res->d_records, domain, 300);
+ return 1;
+ }
+ else {
+ if (isRootServer(ip)) {
+ setLWResult(res, 0, false, false, true);
+ addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
+ addDS(DNSName("com."), 300, res->d_records, keys);
+ addRRSIG(keys, res->d_records, DNSName("."), 300);
+ addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
+ return 1;
+ }
+ else if (ip == ComboAddress("192.0.2.1:53")) {
+ setLWResult(res, 0, false, false, true);
+ addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
+ addDS(domain, 300, res->d_records, keys);
+ addRRSIG(keys, res->d_records, DNSName("com."), 300);
+ addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
+ return 1;
+ }
+ else if (ip == ComboAddress("192.0.2.2:53")) {
+ setLWResult(res, 0, true, false, true);
+ if (domain == target) {
+ addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
+ /* No RRSIG, leading to bogus */
+ }
+ else if (domain == targetCName) {
+ addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
+ addRRSIG(keys, res->d_records, domain, 300);
+ }
+ return 1;
+ }
+ }
+
+ return 0;
+ });
+
+ vector<DNSRecord> ret;
+ int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
+ BOOST_CHECK_EQUAL(res, RCode::NoError);
+ BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
+ BOOST_REQUIRE_EQUAL(ret.size(), 3);
+ BOOST_CHECK_EQUAL(queriesCount, 8);
+
+ /* again, to test the cache */
+ ret.clear();
+ res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
+ BOOST_CHECK_EQUAL(res, RCode::NoError);
+ BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
+ BOOST_REQUIRE_EQUAL(ret.size(), 3);
+ BOOST_CHECK_EQUAL(queriesCount, 8);
+}
+
+BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_bogus_cname) {
+ std::unique_ptr<SyncRes> sr;
+ initSR(sr, true);
+
+ g_dnssecmode = DNSSECMode::ValidateAll;
+
+ primeHints();
+ const DNSName target("power-dns.com.");
+ const DNSName targetCName("powerdns.com.");
+ const ComboAddress targetCNameAddr("192.0.2.42");
+ testkeysset_t keys;
+
+ auto luaconfsCopy = g_luaconfs.getCopy();
+ luaconfsCopy.dsAnchors.clear();
+ generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
+ generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
+ generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
+ generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
+ g_luaconfs.setState(luaconfsCopy);
+
+ size_t queriesCount = 0;
+
+ sr->setAsyncCallback([target,targetCName,targetCNameAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
+ queriesCount++;
+
+ if (type == QType::DS) {
+ setLWResult(res, 0, false, false, true);
+ addDS(domain, 300, res->d_records, keys);
+ addRRSIG(keys, res->d_records, domain, 300);
+ return 1;
+ }
+ else if (type == QType::DNSKEY) {
+ setLWResult(res, 0, true, false, true);
+ addDNSKEY(keys, domain, 300, res->d_records);
+ addRRSIG(keys, res->d_records, domain, 300);
+ return 1;
+ }
+ else {
+ if (isRootServer(ip)) {
+ setLWResult(res, 0, false, false, true);
+ addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
+ addDS(DNSName("com."), 300, res->d_records, keys);
+ addRRSIG(keys, res->d_records, DNSName("."), 300);
+ addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
+ return 1;
+ }
+ else if (ip == ComboAddress("192.0.2.1:53")) {
+ setLWResult(res, 0, false, false, true);
+ addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
+ addDS(domain, 300, res->d_records, keys);
+ addRRSIG(keys, res->d_records, DNSName("com."), 300);
+ addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
+ return 1;
+ }
+ else if (ip == ComboAddress("192.0.2.2:53")) {
+ setLWResult(res, 0, true, false, true);
+ if (domain == target) {
+ addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
+ addRRSIG(keys, res->d_records, domain, 300);
+ }
+ else if (domain == targetCName) {
+ addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
+ /* No RRSIG, leading to bogus */
+ }
+ return 1;
+ }
+ }
+
+ return 0;
+ });
+
+ vector<DNSRecord> ret;
+ int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
+ BOOST_CHECK_EQUAL(res, RCode::NoError);
+ BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
+ BOOST_REQUIRE_EQUAL(ret.size(), 3);
+ BOOST_CHECK_EQUAL(queriesCount, 8);
+
+ /* again, to test the cache */
+ ret.clear();
+ res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
+ BOOST_CHECK_EQUAL(res, RCode::NoError);
+ BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
+ BOOST_REQUIRE_EQUAL(ret.size(), 3);
+ BOOST_CHECK_EQUAL(queriesCount, 8);
+}
+
+BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_secure_cname) {
+ std::unique_ptr<SyncRes> sr;
+ initSR(sr, true);
+
+ g_dnssecmode = DNSSECMode::ValidateAll;
+
+ primeHints();
+ const DNSName target("power-dns.com.");
+ const DNSName targetCName("powerdns.com.");
+ const ComboAddress targetCNameAddr("192.0.2.42");
+ testkeysset_t keys;
+
+ auto luaconfsCopy = g_luaconfs.getCopy();
+ luaconfsCopy.dsAnchors.clear();
+ generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
+ generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
+ generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
+ generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
+ g_luaconfs.setState(luaconfsCopy);
+
+ size_t queriesCount = 0;
+
+ sr->setAsyncCallback([target,targetCName,targetCNameAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
+ queriesCount++;
+
+ if (type == QType::DS) {
+ setLWResult(res, 0, false, false, true);
+ addDS(domain, 300, res->d_records, keys);
+ addRRSIG(keys, res->d_records, domain, 300);
+ return 1;
+ }
+ else if (type == QType::DNSKEY) {
+ setLWResult(res, 0, true, false, true);
+ addDNSKEY(keys, domain, 300, res->d_records);
+ addRRSIG(keys, res->d_records, domain, 300);
+ return 1;
+ }
+ else {
+ if (isRootServer(ip)) {
+ setLWResult(res, 0, false, false, true);
+ addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
+ addDS(DNSName("com."), 300, res->d_records, keys);
+ addRRSIG(keys, res->d_records, DNSName("."), 300);
+ addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
+ return 1;
+ }
+ else if (ip == ComboAddress("192.0.2.1:53")) {
+ setLWResult(res, 0, false, false, true);
+ addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
+ addDS(domain, 300, res->d_records, keys);
+ addRRSIG(keys, res->d_records, DNSName("com."), 300);
+ addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
+ return 1;
+ }
+ else if (ip == ComboAddress("192.0.2.2:53")) {
+ setLWResult(res, 0, true, false, true);
+ if (domain == target) {
+ addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
+ addRRSIG(keys, res->d_records, domain, 300);
+ }
+ else if (domain == targetCName) {
+ addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
+ addRRSIG(keys, res->d_records, domain, 300);
+ }
+ return 1;
+ }
+ }
+
+ return 0;
+ });
+
+ vector<DNSRecord> ret;
+ int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
+ BOOST_CHECK_EQUAL(res, RCode::NoError);
+ BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
+ BOOST_REQUIRE_EQUAL(ret.size(), 4);
+ BOOST_CHECK_EQUAL(queriesCount, 9);
+
+ /* again, to test the cache */
+ ret.clear();
+ res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
+ BOOST_CHECK_EQUAL(res, RCode::NoError);
+ BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
+ BOOST_REQUIRE_EQUAL(ret.size(), 4);
+ BOOST_CHECK_EQUAL(queriesCount, 9);
+}
+
+BOOST_AUTO_TEST_CASE(test_dnssec_bogus_to_insecure_cname) {
+ std::unique_ptr<SyncRes> sr;
+ initSR(sr, true);
+
+ g_dnssecmode = DNSSECMode::ValidateAll;
+
+ primeHints();
+ const DNSName target("powerdns.com.");
+ const DNSName targetCName("power-dns.com.");
+ const ComboAddress targetCNameAddr("192.0.2.42");
+ testkeysset_t keys;
+
+ auto luaconfsCopy = g_luaconfs.getCopy();
+ luaconfsCopy.dsAnchors.clear();
+ generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
+ generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
+ generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
+ generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
+ g_luaconfs.setState(luaconfsCopy);
+
+ size_t queriesCount = 0;
+
+ sr->setAsyncCallback([target,targetCName,targetCNameAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
+ queriesCount++;
+
+ if (type == QType::DS) {
+ if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
+ setLWResult(res, 0, false, false, true);
+ addDS(domain, 300, res->d_records, keys);
+ addRRSIG(keys, res->d_records, domain, 300);
+ return 1;
+ }
+ else if (domain == DNSName("power-dns.com.")) {
+ setLWResult(res, 0, false, false, true);
+ addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
+ addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
+ addRRSIG(keys, res->d_records, DNSName("com."), 300);
+ return 1;
+ }
+ }
+ else if (type == QType::DNSKEY) {
+ if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
+ setLWResult(res, 0, true, false, true);
+ addDNSKEY(keys, domain, 300, res->d_records);
+ addRRSIG(keys, res->d_records, domain, 300);
+ return 1;
+ }
+ else {
+ setLWResult(res, 0, false, false, true);
+ addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
+ return 1;
+ }
+ }
+ else {
+ if (isRootServer(ip)) {
+ setLWResult(res, 0, false, false, true);
+ addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
+ addDS(DNSName("com."), 300, res->d_records, keys);
+ addRRSIG(keys, res->d_records, DNSName("."), 300);
+ addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
+ return 1;
+ }
+ else if (ip == ComboAddress("192.0.2.1:53")) {
+ setLWResult(res, 0, false, false, true);
+ addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
+ if (domain == DNSName("powerdns.com.")) {
+ addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
+ }
+ else if (domain == targetCName) {
+ addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
+ }
+ addRRSIG(keys, res->d_records, DNSName("com."), 300);
+ addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
+ return 1;
+ }
+ else if (ip == ComboAddress("192.0.2.2:53")) {
+ setLWResult(res, 0, true, false, true);
+ if (domain == DNSName("powerdns.com.")) {
+ addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
+ /* No RRSIG -> Bogus */
+ }
+ else if (domain == targetCName) {
+ addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
+ }
+ return 1;
+ }
+ }
+
+ return 0;
+ });
+
+ vector<DNSRecord> ret;
+ int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
+ BOOST_CHECK_EQUAL(res, RCode::NoError);
+ BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
+ /* no RRSIG to show */
+ BOOST_CHECK_EQUAL(ret.size(), 2);
+ BOOST_CHECK_EQUAL(queriesCount, 7);
+
+ /* again, to test the cache */
+ ret.clear();
+ res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
+ BOOST_CHECK_EQUAL(res, RCode::NoError);
+ BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
+ BOOST_CHECK_EQUAL(ret.size(), 2);
+ BOOST_CHECK_EQUAL(queriesCount, 7);
+}
+
BOOST_AUTO_TEST_CASE(test_dnssec_insecure_ta) {
std::unique_ptr<SyncRes> sr;
initSR(sr, true);