--- /dev/null
+#define BOOST_TEST_DYN_LINK
+#include <boost/test/unit_test.hpp>
+
+#include "test-syncres_cc.hh"
+
+BOOST_AUTO_TEST_SUITE(syncres_cc10)
+BOOST_AUTO_TEST_CASE(test_outgoing_v4_only)
+{
+ std::unique_ptr<SyncRes> sr;
+ initSR(sr);
+ SyncRes::s_doIPv6 = false;
+ primeHints();
+ bool v6Hit = false;
+ bool v4Hit = false;
+ int queries = 0;
+
+ const DNSName target("powerdns.com.");
+ sr->setAsyncCallback([target, &v4Hit, &v6Hit, &queries](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, LWResult* res, bool* chained) {
+ queries++;
+ if (isRootServer(ip)) {
+ setLWResult(res, 0, false, false, true);
+
+ if (domain == DNSName("powerdns.com.")) {
+ addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
+ addRecordToLW(res, "ns1.powerdns.com.", QType::AAAA, "2001:DB8:1::53", DNSResourceRecord::ADDITIONAL, 3600);
+ addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
+ }
+ return 1;
+ }
+ else if (ip == ComboAddress("192.0.2.1:53")) {
+ setLWResult(res, 0, true, false, false);
+ v4Hit = true;
+ if (domain == DNSName("powerdns.com.")) {
+ addRecordToLW(res, domain, QType::A, "192.0.2.2");
+ }
+ return 1;
+ }
+ else if (ip == ComboAddress("[2001:DB8:1::53]:53")) {
+ setLWResult(res, 0, true, false, false);
+ v6Hit = true;
+ if (domain == DNSName("powerdns.com.")) {
+ addRecordToLW(res, domain, QType::A, "192.0.2.2");
+ }
+ return 1;
+ }
+ return 0;
+ });
+
+ vector<DNSRecord> ret;
+ int rcode;
+ rcode = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
+ BOOST_REQUIRE_EQUAL(queries, 2);
+ BOOST_REQUIRE_EQUAL(v4Hit, true);
+ BOOST_REQUIRE_EQUAL(v6Hit, false);
+ BOOST_CHECK_EQUAL(rcode, RCode::NoError);
+ BOOST_CHECK_EQUAL(ret.size(), 1);
+}
+
+BOOST_AUTO_TEST_CASE(test_outgoing_v4_only_no_A_in_delegation)
+{
+ // The name is not resolvable, as there's no A glue for an in-bailiwick NS
+ std::unique_ptr<SyncRes> sr;
+ initSR(sr);
+ SyncRes::s_doIPv6 = false;
+ primeHints();
+ int queries = 0;
+
+ const DNSName target("powerdns.com.");
+ sr->setAsyncCallback([target, &queries](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, LWResult* res, bool* chained) {
+ queries++;
+ if (isRootServer(ip)) {
+ setLWResult(res, 0, false, false, true);
+
+ if (domain == DNSName("powerdns.com.")) {
+ addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
+ addRecordToLW(res, "ns1.powerdns.com.", QType::AAAA, "2001:DB8:1::53", DNSResourceRecord::ADDITIONAL, 3600);
+ }
+ return 1;
+ }
+ else if (ip == ComboAddress("[2001:DB8:1::53]:53")) {
+ setLWResult(res, 0, true, false, false);
+ if (domain == DNSName("powerdns.com.")) {
+ addRecordToLW(res, domain, QType::A, "192.0.2.2");
+ }
+ return 1;
+ }
+ return 0;
+ });
+
+ vector<DNSRecord> ret;
+ int rcode;
+ rcode = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
+ BOOST_REQUIRE_EQUAL(queries, 14); // We keep trying all parent nameservers, this is wrong!
+ BOOST_CHECK_EQUAL(rcode, RCode::ServFail);
+ BOOST_CHECK_EQUAL(ret.size(), 0);
+}
+
+BOOST_AUTO_TEST_CASE(test_outgoing_v6_only_no_AAAA_in_delegation)
+{
+ std::unique_ptr<SyncRes> sr;
+ initSR(sr);
+ SyncRes::s_doIPv4 = false;
+ SyncRes::s_doIPv6 = true;
+ primeHints();
+ int queries = 0;
+
+ const DNSName target("powerdns.com.");
+ sr->setAsyncCallback([target, &queries](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, LWResult* res, bool* chained) {
+ cout<<ip.toString()<<endl;
+ cout<<domain<<"|"<<type<<endl;
+ queries++;
+ if (isRootServer(ip)) {
+ setLWResult(res, 0, false, false, true);
+ if (domain == DNSName("powerdns.com.")) {
+ addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
+ addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
+ }
+ return 1;
+ }
+ else if (ip == ComboAddress("192.0.2.1:53")) {
+ setLWResult(res, 0, true, false, false);
+ if (domain == DNSName("powerdns.com.")) {
+ addRecordToLW(res, domain, QType::A, "192.0.2.2");
+ }
+ return 1;
+ }
+ return 0;
+ });
+
+ vector<DNSRecord> ret;
+ int rcode;
+ rcode = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
+ BOOST_REQUIRE_EQUAL(queries, 14); // The recursor tries all parent nameservers... this needs to be fixed
+ BOOST_CHECK_EQUAL(rcode, RCode::ServFail);
+ BOOST_CHECK_EQUAL(ret.size(), 0);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
uint8_t SyncRes::s_ecsipv4cachelimit;
uint8_t SyncRes::s_ecsipv6cachelimit;
+bool SyncRes::s_doIPv4;
bool SyncRes::s_doIPv6;
bool SyncRes::s_nopacketcache;
bool SyncRes::s_rootNXTrust;
vState newState = Indeterminate;
res_t resv4;
// If IPv4 ever becomes second class, we should revisit this
- if (doResolve(qname, QType::A, resv4, depth+1, beenthere, newState) == 0) { // this consults cache, OR goes out
+ if (s_doIPv4 && doResolve(qname, QType::A, resv4, depth+1, beenthere, newState) == 0) { // this consults cache, OR goes out
for (auto const &i : resv4) {
if (i.d_type == QType::A) {
if (auto rec = getRR<ARecordContent>(i)) {
}
}
}
- if (s_doIPv6) {
+ if (s_doIPv6) { // s_doIPv6 **IMPLIES** pdns::isQueryLocalAddressFamilyEnabled(AF_INET6) returned true
if (ret.empty()) {
// We did not find IPv4 addresses, try to get IPv6 ones
newState = Indeterminate;
for(auto k=ns.cbegin();k!=ns.cend(); ++k) {
if(k->d_ttl > (unsigned int)d_now.tv_sec ) {
vector<DNSRecord> aset;
+ QType nsqt{QType::ADDR};
+ if (s_doIPv4 && !s_doIPv6) {
+ nsqt = QType::A;
+ } else if (!s_doIPv4 && s_doIPv6) {
+ nsqt = QType::AAAA;
+ }
const DNSRecord& dr=*k;
auto nrr = getRR<NSRecordContent>(dr);
- if(nrr && (!nrr->getNS().isPartOf(subdomain) || s_RC->get(d_now.tv_sec, nrr->getNS(), s_doIPv6 ? QType(QType::ADDR) : QType(QType::A),
+ if(nrr && (!nrr->getNS().isPartOf(subdomain) || s_RC->get(d_now.tv_sec, nrr->getNS(), nsqt,
false, doLog() ? &aset : 0, d_cacheRemote, d_routingTag) > 5)) {
bestns.push_back(dr);
LOG(prefix<<qname<<": NS (with ip, or non-glue) in cache for '"<<subdomain<<"' -> '"<<nrr->getNS()<<"'"<<endl);