From: HÃ¥kan Lindqvist Date: Wed, 6 Jul 2022 14:44:37 +0000 (+0200) Subject: Add option to NegativeAndSOAAction to place SOA in the authority section X-Git-Tag: auth-4.8.0-alpha0~21^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=61643ae013433a7b282ebbecd7ce313d6bf7b148;p=thirdparty%2Fpdns.git Add option to NegativeAndSOAAction to place SOA in the authority section Ie, allow generating a full NODATA/NXDOMAIN cacheable negative response, rather than an RPZ-style reponse with only an informational SOA record in the additional section --- diff --git a/pdns/dnsdist-ecs.cc b/pdns/dnsdist-ecs.cc index e4e3bd6e8b..d87e189e6b 100644 --- a/pdns/dnsdist-ecs.cc +++ b/pdns/dnsdist-ecs.cc @@ -858,9 +858,9 @@ bool addEDNS(PacketBuffer& packet, size_t maximumSize, bool dnssecOK, uint16_t p /* This function keeps the existing header and DNSSECOK bit (if any) but wipes anything else, - generating a NXD or NODATA answer with a SOA record in the additional section. + generating a NXD or NODATA answer with a SOA record in the additional section (or optionally the authority section for a full cacheable NXDOMAIN/NODATA). */ -bool setNegativeAndAdditionalSOA(DNSQuestion& dq, bool nxd, const DNSName& zone, uint32_t ttl, const DNSName& mname, const DNSName& rname, uint32_t serial, uint32_t refresh, uint32_t retry, uint32_t expire, uint32_t minimum) +bool setNegativeAndAdditionalSOA(DNSQuestion& dq, bool nxd, const DNSName& zone, uint32_t ttl, const DNSName& mname, const DNSName& rname, uint32_t serial, uint32_t refresh, uint32_t retry, uint32_t expire, uint32_t minimum, bool soaInAuthoritySection) { auto& packet = dq.getMutableData(); auto dh = dq.getHeader(); @@ -933,7 +933,15 @@ bool setNegativeAndAdditionalSOA(DNSQuestion& dq, bool nxd, const DNSName& zone, packet.insert(packet.end(), soa.begin(), soa.end()); dh = dq.getHeader(); - dh->arcount = htons(1); + + /* We are populating a response with only the query in place, order of sections is QD,AN,NS,AR + NS (authority) is before AR (additional) so we can just decide which section the SOA record is in here + and have EDNS added to AR afterwards */ + if (soaInAuthoritySection) { + dh->nscount = htons(1); + } else { + dh->arcount = htons(1); + } if (hadEDNS) { /* now we need to add a new OPT record */ diff --git a/pdns/dnsdist-ecs.hh b/pdns/dnsdist-ecs.hh index 89e6237963..124ba6261b 100644 --- a/pdns/dnsdist-ecs.hh +++ b/pdns/dnsdist-ecs.hh @@ -38,7 +38,7 @@ int getEDNSOptionsStart(const PacketBuffer& packet, const size_t offset, uint16_ bool isEDNSOptionInOpt(const PacketBuffer& packet, const size_t optStart, const size_t optLen, const uint16_t optionCodeToFind, size_t* optContentStart = nullptr, uint16_t* optContentLen = nullptr); bool addEDNS(PacketBuffer& packet, size_t maximumSize, bool dnssecOK, uint16_t payloadSize, uint8_t ednsrcode); bool addEDNSToQueryTurnedResponse(DNSQuestion& dq); -bool setNegativeAndAdditionalSOA(DNSQuestion& dq, bool nxd, const DNSName& zone, uint32_t ttl, const DNSName& mname, const DNSName& rname, uint32_t serial, uint32_t refresh, uint32_t retry, uint32_t expire, uint32_t minimum); +bool setNegativeAndAdditionalSOA(DNSQuestion& dq, bool nxd, const DNSName& zone, uint32_t ttl, const DNSName& mname, const DNSName& rname, uint32_t serial, uint32_t refresh, uint32_t retry, uint32_t expire, uint32_t minimum, bool soaInAuthoritySection); bool handleEDNSClientSubnet(DNSQuestion& dq, bool& ednsAdded, bool& ecsAdded); bool handleEDNSClientSubnet(PacketBuffer& packet, size_t maximumSize, size_t qnameWireLength, bool& ednsAdded, bool& ecsAdded, bool overrideExisting, const string& newECSOption); diff --git a/pdns/dnsdist-lua-actions.cc b/pdns/dnsdist-lua-actions.cc index 167baf36e3..45deb30646 100644 --- a/pdns/dnsdist-lua-actions.cc +++ b/pdns/dnsdist-lua-actions.cc @@ -1912,13 +1912,13 @@ private: class NegativeAndSOAAction: public DNSAction { public: - NegativeAndSOAAction(bool nxd, const DNSName& zone, uint32_t ttl, const DNSName& mname, const DNSName& rname, uint32_t serial, uint32_t refresh, uint32_t retry, uint32_t expire, uint32_t minimum): d_zone(zone), d_mname(mname), d_rname(rname), d_ttl(ttl), d_serial(serial), d_refresh(refresh), d_retry(retry), d_expire(expire), d_minimum(minimum), d_nxd(nxd) + NegativeAndSOAAction(bool nxd, const DNSName& zone, uint32_t ttl, const DNSName& mname, const DNSName& rname, uint32_t serial, uint32_t refresh, uint32_t retry, uint32_t expire, uint32_t minimum, bool soaInAuthoritySection): d_zone(zone), d_mname(mname), d_rname(rname), d_ttl(ttl), d_serial(serial), d_refresh(refresh), d_retry(retry), d_expire(expire), d_minimum(minimum), d_nxd(nxd), d_soaInAuthoritySection(soaInAuthoritySection) { } DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override { - if (!setNegativeAndAdditionalSOA(*dq, d_nxd, d_zone, d_ttl, d_mname, d_rname, d_serial, d_refresh, d_retry, d_expire, d_minimum)) { + if (!setNegativeAndAdditionalSOA(*dq, d_nxd, d_zone, d_ttl, d_mname, d_rname, d_serial, d_refresh, d_retry, d_expire, d_minimum, d_soaInAuthoritySection)) { return Action::None; } @@ -1945,6 +1945,7 @@ private: uint32_t d_expire; uint32_t d_minimum; bool d_nxd; + bool d_soaInAuthoritySection; }; class SetProxyProtocolValuesAction : public DNSAction @@ -2460,7 +2461,14 @@ void setupLuaActions(LuaContext& luaCtx) #endif /* defined(HAVE_LMDB) || defined(HAVE_CDB) */ luaCtx.writeFunction("NegativeAndSOAAction", [](bool nxd, const std::string& zone, uint32_t ttl, const std::string& mname, const std::string& rname, uint32_t serial, uint32_t refresh, uint32_t retry, uint32_t expire, uint32_t minimum, boost::optional vars) { - auto ret = std::shared_ptr(new NegativeAndSOAAction(nxd, DNSName(zone), ttl, DNSName(mname), DNSName(rname), serial, refresh, retry, expire, minimum)); + bool soaInAuthoritySection = false; + if (vars) { + if (vars->count("soaInAuthoritySection")) { + soaInAuthoritySection = boost::get((*vars)["soaInAuthoritySection"]); + } + } + + auto ret = std::shared_ptr(new NegativeAndSOAAction(nxd, DNSName(zone), ttl, DNSName(mname), DNSName(rname), serial, refresh, retry, expire, minimum, soaInAuthoritySection)); auto action = std::dynamic_pointer_cast(ret); parseResponseConfig(vars, action->d_responseConfig); return ret; diff --git a/pdns/dnsdist-lua-bindings-dnsquestion.cc b/pdns/dnsdist-lua-bindings-dnsquestion.cc index a6b80078cd..d7af5e92c3 100644 --- a/pdns/dnsdist-lua-bindings-dnsquestion.cc +++ b/pdns/dnsdist-lua-bindings-dnsquestion.cc @@ -310,7 +310,8 @@ void setupLuaBindingsDNSQuestion(LuaContext& luaCtx) checkParameterBound("setNegativeAndAdditionalSOA", retry, std::numeric_limits::max()); checkParameterBound("setNegativeAndAdditionalSOA", expire, std::numeric_limits::max()); checkParameterBound("setNegativeAndAdditionalSOA", minimum, std::numeric_limits::max()); - return setNegativeAndAdditionalSOA(dq, nxd, DNSName(zone), ttl, DNSName(mname), DNSName(rname), serial, refresh, retry, expire, minimum); + + return setNegativeAndAdditionalSOA(dq, nxd, DNSName(zone), ttl, DNSName(mname), DNSName(rname), serial, refresh, retry, expire, minimum, false); }); #endif /* DISABLE_NON_FFI_DQ_BINDINGS */ } diff --git a/pdns/dnsdistdist/docs/rules-actions.rst b/pdns/dnsdistdist/docs/rules-actions.rst index 83076963f4..9048266bfb 100644 --- a/pdns/dnsdistdist/docs/rules-actions.rst +++ b/pdns/dnsdistdist/docs/rules-actions.rst @@ -1169,6 +1169,9 @@ The following actions exist. .. versionadded:: 1.6.0 + .. versionchanged:: 1.8.0 + Added the ``soaInAuthoritySection`` option. + Turn a question into a response, either a NXDOMAIN or a NODATA one based on ''nxd'', setting the QR bit to 1 and adding a SOA record in the additional section. Note that this function was called :func:`SetNegativeAndSOAAction` before 1.6.0. @@ -1189,6 +1192,7 @@ The following actions exist. * ``aa``: bool - Set the AA bit to this value (true means the bit is set, false means it's cleared). Default is to clear it. * ``ad``: bool - Set the AD bit to this value (true means the bit is set, false means it's cleared). Default is to clear it. * ``ra``: bool - Set the RA bit to this value (true means the bit is set, false means it's cleared). Default is to copy the value of the RD bit from the incoming query. + * ``soaInAuthoritySection``: bool - Place the SOA record in the authority section for a complete NXDOMAIN/NODATA response that works as a cacheable negative response, rather than the RPZ-style response with a purely informational SOA in the additional section. Default is false (SOA in additional section). .. function:: NoneAction() diff --git a/pdns/test-dnsdist_cc.cc b/pdns/test-dnsdist_cc.cc index 8bf0e99b26..8ee936f341 100644 --- a/pdns/test-dnsdist_cc.cc +++ b/pdns/test-dnsdist_cc.cc @@ -1917,7 +1917,7 @@ BOOST_AUTO_TEST_CASE(test_setNegativeAndAdditionalSOA) { DNSName qname(reinterpret_cast(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed); DNSQuestion dq(&qname, qtype, QClass::IN, &remote, &remote, packet, dnsdist::Protocol::DoUDP, &queryTime); - BOOST_CHECK(setNegativeAndAdditionalSOA(dq, true, DNSName("zone."), 42, DNSName("mname."), DNSName("rname."), 1, 2, 3, 4 , 5)); + BOOST_CHECK(setNegativeAndAdditionalSOA(dq, true, DNSName("zone."), 42, DNSName("mname."), DNSName("rname."), 1, 2, 3, 4 , 5, false)); BOOST_CHECK(packet.size() > query.size()); MOADNSParser mdp(true, reinterpret_cast(packet.data()), packet.size()); @@ -1941,7 +1941,7 @@ BOOST_AUTO_TEST_CASE(test_setNegativeAndAdditionalSOA) { DNSName qname(reinterpret_cast(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed); DNSQuestion dq(&qname, qtype, QClass::IN, &remote, &remote, packet, dnsdist::Protocol::DoUDP, &queryTime); - BOOST_CHECK(setNegativeAndAdditionalSOA(dq, true, DNSName("zone."), 42, DNSName("mname."), DNSName("rname."), 1, 2, 3, 4 , 5)); + BOOST_CHECK(setNegativeAndAdditionalSOA(dq, true, DNSName("zone."), 42, DNSName("mname."), DNSName("rname."), 1, 2, 3, 4 , 5, false)); BOOST_CHECK(packet.size() > queryWithEDNS.size()); MOADNSParser mdp(true, reinterpret_cast(packet.data()), packet.size()); @@ -1969,7 +1969,7 @@ BOOST_AUTO_TEST_CASE(test_setNegativeAndAdditionalSOA) { DNSName qname(reinterpret_cast(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed); DNSQuestion dq(&qname, qtype, QClass::IN, &remote, &remote, packet, dnsdist::Protocol::DoUDP, &queryTime); - BOOST_CHECK(setNegativeAndAdditionalSOA(dq, false, DNSName("zone."), 42, DNSName("mname."), DNSName("rname."), 1, 2, 3, 4 , 5)); + BOOST_CHECK(setNegativeAndAdditionalSOA(dq, false, DNSName("zone."), 42, DNSName("mname."), DNSName("rname."), 1, 2, 3, 4 , 5, false)); BOOST_CHECK(packet.size() > query.size()); MOADNSParser mdp(true, reinterpret_cast(packet.data()), packet.size()); @@ -1993,7 +1993,7 @@ BOOST_AUTO_TEST_CASE(test_setNegativeAndAdditionalSOA) { DNSName qname(reinterpret_cast(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed); DNSQuestion dq(&qname, qtype, QClass::IN, &remote, &remote, packet, dnsdist::Protocol::DoUDP, &queryTime); - BOOST_CHECK(setNegativeAndAdditionalSOA(dq, false, DNSName("zone."), 42, DNSName("mname."), DNSName("rname."), 1, 2, 3, 4 , 5)); + BOOST_CHECK(setNegativeAndAdditionalSOA(dq, false, DNSName("zone."), 42, DNSName("mname."), DNSName("rname."), 1, 2, 3, 4 , 5, false)); BOOST_CHECK(packet.size() > queryWithEDNS.size()); MOADNSParser mdp(true, reinterpret_cast(packet.data()), packet.size()); @@ -2010,6 +2010,112 @@ BOOST_AUTO_TEST_CASE(test_setNegativeAndAdditionalSOA) { BOOST_CHECK_EQUAL(mdp.d_answers.at(1).first.d_type, static_cast(QType::OPT)); BOOST_CHECK_EQUAL(mdp.d_answers.at(1).first.d_name, g_rootdnsname); } + + /* SOA in the authority section*/ + + /* test NXD */ + { + /* no incoming EDNS */ + auto packet = query; + + unsigned int consumed = 0; + uint16_t qtype; + DNSName qname(reinterpret_cast(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed); + DNSQuestion dq(&qname, qtype, QClass::IN, &remote, &remote, packet, dnsdist::Protocol::DoUDP, &queryTime); + + BOOST_CHECK(setNegativeAndAdditionalSOA(dq, true, DNSName("zone."), 42, DNSName("mname."), DNSName("rname."), 1, 2, 3, 4 , 5, true)); + BOOST_CHECK(packet.size() > query.size()); + MOADNSParser mdp(true, reinterpret_cast(packet.data()), packet.size()); + + BOOST_CHECK_EQUAL(mdp.d_qname.toString(), "www.powerdns.com."); + BOOST_CHECK_EQUAL(mdp.d_header.rcode, RCode::NXDomain); + BOOST_CHECK_EQUAL(mdp.d_header.qdcount, 1U); + BOOST_CHECK_EQUAL(mdp.d_header.ancount, 0U); + BOOST_CHECK_EQUAL(mdp.d_header.nscount, 1U); + BOOST_CHECK_EQUAL(mdp.d_header.arcount, 0U); + BOOST_REQUIRE_EQUAL(mdp.d_answers.size(), 1U); + BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_type, static_cast(QType::SOA)); + BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_class, QClass::IN); + BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_name, DNSName("zone.")); + } + { + /* now with incoming EDNS */ + auto packet = queryWithEDNS; + + unsigned int consumed = 0; + uint16_t qtype; + DNSName qname(reinterpret_cast(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed); + DNSQuestion dq(&qname, qtype, QClass::IN, &remote, &remote, packet, dnsdist::Protocol::DoUDP, &queryTime); + + BOOST_CHECK(setNegativeAndAdditionalSOA(dq, true, DNSName("zone."), 42, DNSName("mname."), DNSName("rname."), 1, 2, 3, 4 , 5, true)); + BOOST_CHECK(packet.size() > queryWithEDNS.size()); + MOADNSParser mdp(true, reinterpret_cast(packet.data()), packet.size()); + + BOOST_CHECK_EQUAL(mdp.d_qname.toString(), "www.powerdns.com."); + BOOST_CHECK_EQUAL(mdp.d_header.rcode, RCode::NXDomain); + BOOST_CHECK_EQUAL(mdp.d_header.qdcount, 1U); + BOOST_CHECK_EQUAL(mdp.d_header.ancount, 0U); + BOOST_CHECK_EQUAL(mdp.d_header.nscount, 1U); + BOOST_CHECK_EQUAL(mdp.d_header.arcount, 1U); + BOOST_REQUIRE_EQUAL(mdp.d_answers.size(), 2U); + BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_type, static_cast(QType::SOA)); + BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_class, QClass::IN); + BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_name, DNSName("zone.")); + BOOST_CHECK_EQUAL(mdp.d_answers.at(1).first.d_type, static_cast(QType::OPT)); + BOOST_CHECK_EQUAL(mdp.d_answers.at(1).first.d_name, g_rootdnsname); + } + + /* test No Data */ + { + /* no incoming EDNS */ + auto packet = query; + + unsigned int consumed = 0; + uint16_t qtype; + DNSName qname(reinterpret_cast(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed); + DNSQuestion dq(&qname, qtype, QClass::IN, &remote, &remote, packet, dnsdist::Protocol::DoUDP, &queryTime); + + BOOST_CHECK(setNegativeAndAdditionalSOA(dq, false, DNSName("zone."), 42, DNSName("mname."), DNSName("rname."), 1, 2, 3, 4 , 5, true)); + BOOST_CHECK(packet.size() > query.size()); + MOADNSParser mdp(true, reinterpret_cast(packet.data()), packet.size()); + + BOOST_CHECK_EQUAL(mdp.d_qname.toString(), "www.powerdns.com."); + BOOST_CHECK_EQUAL(mdp.d_header.rcode, RCode::NoError); + BOOST_CHECK_EQUAL(mdp.d_header.qdcount, 1U); + BOOST_CHECK_EQUAL(mdp.d_header.ancount, 0U); + BOOST_CHECK_EQUAL(mdp.d_header.nscount, 1U); + BOOST_CHECK_EQUAL(mdp.d_header.arcount, 0U); + BOOST_REQUIRE_EQUAL(mdp.d_answers.size(), 1U); + BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_type, static_cast(QType::SOA)); + BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_class, QClass::IN); + BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_name, DNSName("zone.")); + } + { + /* now with incoming EDNS */ + auto packet = queryWithEDNS; + + unsigned int consumed = 0; + uint16_t qtype; + DNSName qname(reinterpret_cast(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed); + DNSQuestion dq(&qname, qtype, QClass::IN, &remote, &remote, packet, dnsdist::Protocol::DoUDP, &queryTime); + + BOOST_CHECK(setNegativeAndAdditionalSOA(dq, false, DNSName("zone."), 42, DNSName("mname."), DNSName("rname."), 1, 2, 3, 4 , 5, true)); + BOOST_CHECK(packet.size() > queryWithEDNS.size()); + MOADNSParser mdp(true, reinterpret_cast(packet.data()), packet.size()); + + BOOST_CHECK_EQUAL(mdp.d_qname.toString(), "www.powerdns.com."); + BOOST_CHECK_EQUAL(mdp.d_header.rcode, RCode::NoError); + BOOST_CHECK_EQUAL(mdp.d_header.qdcount, 1U); + BOOST_CHECK_EQUAL(mdp.d_header.ancount, 0U); + BOOST_CHECK_EQUAL(mdp.d_header.nscount, 1U); + BOOST_CHECK_EQUAL(mdp.d_header.arcount, 1U); + BOOST_REQUIRE_EQUAL(mdp.d_answers.size(), 2U); + BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_type, static_cast(QType::SOA)); + BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_class, QClass::IN); + BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_name, DNSName("zone.")); + BOOST_CHECK_EQUAL(mdp.d_answers.at(1).first.d_type, static_cast(QType::OPT)); + BOOST_CHECK_EQUAL(mdp.d_answers.at(1).first.d_name, g_rootdnsname); + } } BOOST_AUTO_TEST_CASE(getEDNSOptionsWithoutEDNS) { diff --git a/regression-tests.dnsdist/test_RulesActions.py b/regression-tests.dnsdist/test_RulesActions.py index f709fe49d9..d91d0425d8 100644 --- a/regression-tests.dnsdist/test_RulesActions.py +++ b/regression-tests.dnsdist/test_RulesActions.py @@ -1449,6 +1449,98 @@ class TestAdvancedNegativeAndSOA(DNSDistTest): (_, receivedResponse) = sender(query, response=None, useQueue=False) self.checkMessageEDNSWithoutOptions(expectedResponse, receivedResponse) + +class TestAdvancedNegativeAndSOAAuthSection(DNSDistTest): + + _selfGeneratedPayloadSize = 1232 + _config_template = """ + addAction("nxd.negativeandsoa.advanced.tests.powerdns.com.", NegativeAndSOAAction(true, "auth.", 42, "mname", "rname", 5, 4, 3, 2, 1, { soaInAuthoritySection=true })) + addAction("nodata.negativeandsoa.advanced.tests.powerdns.com.", NegativeAndSOAAction(false, "another-auth.", 42, "mname", "rname", 1, 2, 3, 4, 5, { soaInAuthoritySection=true })) + setPayloadSizeOnSelfGeneratedAnswers(%d) + newServer{address="127.0.0.1:%s"} + """ + _config_params = ['_selfGeneratedPayloadSize', '_testServerPort'] + + + def testAdvancedNegativeAndSOANXD(self): + """ + Advanced: NegativeAndSOAAction NXD + """ + name = 'nxd.negativeandsoa.advanced.tests.powerdns.com.' + # no EDNS + query = dns.message.make_query(name, 'A', 'IN', use_edns=False) + query.flags &= ~dns.flags.RD + expectedResponse = dns.message.make_response(query) + expectedResponse.set_rcode(dns.rcode.NXDOMAIN) + soa = dns.rrset.from_text("auth.", + 42, + dns.rdataclass.IN, + dns.rdatatype.SOA, + 'mname. rname. 5 4 3 2 1') + expectedResponse.authority.append(soa) + + for method in ("sendUDPQuery", "sendTCPQuery"): + sender = getattr(self, method) + (_, receivedResponse) = sender(query, response=None, useQueue=False) + self.checkMessageNoEDNS(expectedResponse, receivedResponse) + + # withEDNS + query = dns.message.make_query(name, 'A', 'IN', use_edns=True) + query.flags &= ~dns.flags.RD + expectedResponse = dns.message.make_response(query, our_payload=self._selfGeneratedPayloadSize) + expectedResponse.set_rcode(dns.rcode.NXDOMAIN) + soa = dns.rrset.from_text("auth.", + 42, + dns.rdataclass.IN, + dns.rdatatype.SOA, + 'mname. rname. 5 4 3 2 1') + expectedResponse.authority.append(soa) + + for method in ("sendUDPQuery", "sendTCPQuery"): + sender = getattr(self, method) + (_, receivedResponse) = sender(query, response=None, useQueue=False) + self.checkMessageEDNSWithoutOptions(expectedResponse, receivedResponse) + + def testAdvancedNegativeAndSOANoData(self): + """ + Advanced: NegativeAndSOAAction NoData + """ + name = 'nodata.negativeandsoa.advanced.tests.powerdns.com.' + # no EDNS + query = dns.message.make_query(name, 'A', 'IN', use_edns=False) + query.flags &= ~dns.flags.RD + expectedResponse = dns.message.make_response(query) + expectedResponse.set_rcode(dns.rcode.NOERROR) + soa = dns.rrset.from_text("another-auth.", + 42, + dns.rdataclass.IN, + dns.rdatatype.SOA, + 'mname. rname. 1 2 3 4 5') + expectedResponse.authority.append(soa) + + for method in ("sendUDPQuery", "sendTCPQuery"): + sender = getattr(self, method) + (_, receivedResponse) = sender(query, response=None, useQueue=False) + self.checkMessageNoEDNS(expectedResponse, receivedResponse) + + # with EDNS + query = dns.message.make_query(name, 'A', 'IN', use_edns=True) + query.flags &= ~dns.flags.RD + expectedResponse = dns.message.make_response(query, our_payload=self._selfGeneratedPayloadSize) + expectedResponse.set_rcode(dns.rcode.NOERROR) + soa = dns.rrset.from_text("another-auth.", + 42, + dns.rdataclass.IN, + dns.rdatatype.SOA, + 'mname. rname. 1 2 3 4 5') + expectedResponse.authority.append(soa) + + for method in ("sendUDPQuery", "sendTCPQuery"): + sender = getattr(self, method) + (_, receivedResponse) = sender(query, response=None, useQueue=False) + self.checkMessageEDNSWithoutOptions(expectedResponse, receivedResponse) + + class TestAdvancedLuaRule(DNSDistTest): _config_template = """