Skip to content

Commit

Permalink
Merge pull request #14482 from omoerbeek/backport-14471-to-rec-5.0.x
Browse files Browse the repository at this point in the history
rec: Backport of 14471 to rec-5.0.x: dump right SOA into dumpFile and report non-relative SOA for includeSOA=true
  • Loading branch information
omoerbeek authored Jul 18, 2024
2 parents 543b58d + eed38f4 commit e6eaef7
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 33 deletions.
11 changes: 8 additions & 3 deletions pdns/recursordist/filterpo.cc
Original file line number Diff line number Diff line change
Expand Up @@ -797,9 +797,14 @@ void DNSFilterEngine::Zone::dumpAddrPolicy(FILE* fp, const Netmask& nm, const DN

void DNSFilterEngine::Zone::dump(FILE* fp) const
{
/* fake the SOA record */
auto soa = DNSRecordContent::make(QType::SOA, QClass::IN, "fake.RPZ. hostmaster.fake.RPZ. " + std::to_string(d_serial) + " " + std::to_string(d_refresh) + " 600 3600000 604800");
fprintf(fp, "%s IN SOA %s\n", d_domain.toString().c_str(), soa->getZoneRepresentation().c_str());
if (DNSRecord soa = d_zoneData->d_soa; !soa.d_name.empty()) {
fprintf(fp, "%s IN SOA %s\n", soa.d_name.toString().c_str(), soa.getContent()->getZoneRepresentation().c_str());
}
else {
/* fake the SOA record */
auto soarr = DNSRecordContent::make(QType::SOA, QClass::IN, "fake.RPZ. hostmaster.fake.RPZ. " + std::to_string(d_serial) + " " + std::to_string(d_refresh) + " 600 3600000 604800");
fprintf(fp, "%s IN SOA %s\n", d_domain.toString().c_str(), soarr->getZoneRepresentation().c_str());
}

for (const auto& pair : d_qpolName) {
dumpNamedPolicy(fp, pair.first + d_domain, pair.second);
Expand Down
5 changes: 4 additions & 1 deletion pdns/recursordist/rpzloader.cc
Original file line number Diff line number Diff line change
Expand Up @@ -223,10 +223,13 @@ static shared_ptr<const SOARecordContent> loadRPZFromServer(Logr::log_t plogger,
continue;
}

// We want the full name in the SOA record
if (dr.d_type == QType::SOA) {
zone->setSOA(dr);
}
dr.d_name.makeUsRelative(zoneName);
if (dr.d_type == QType::SOA) {
sr = getRR<SOARecordContent>(dr);
zone->setSOA(dr);
continue;
}

Expand Down
58 changes: 29 additions & 29 deletions regression-tests.recursor-dnssec/test_RPZ.py
Original file line number Diff line number Diff line change
Expand Up @@ -253,20 +253,20 @@ class RPZRecursorTest(RecursorTest):
log-rpz-changes=yes
""" % (_confdir, _wsPort, _wsPassword, _apiKey)

def assertAdditionalHasSOA(self, msg):
def assertAdditionalHasSOA(self, msg, name):
if not isinstance(msg, dns.message.Message):
raise TypeError("msg is not a dns.message.Message but a %s" % type(msg))

found = False
for rrset in msg.additional:
if rrset.rdtype == dns.rdatatype.SOA:
if rrset.rdtype == dns.rdatatype.SOA and str(rrset.name) == name:
found = True
break

if not found:
raise AssertionError("No SOA record found in the authority section:\n%s" % msg.to_text())
raise AssertionError("No %s SOA record found in the additional section:\n%s" % (name, msg.to_text()))

def checkBlocked(self, name, shouldBeBlocked=True, adQuery=False, singleCheck=False, soa=False):
def checkBlocked(self, name, shouldBeBlocked=True, adQuery=False, singleCheck=False, soa=None):
query = dns.message.make_query(name, 'A', want_dnssec=True)
query.flags |= dns.flags.CD
if adQuery:
Expand All @@ -283,14 +283,14 @@ def checkBlocked(self, name, shouldBeBlocked=True, adQuery=False, singleCheck=Fa

self.assertRRsetInAnswer(res, expected)
if soa:
self.assertAdditionalHasSOA(res)
self.assertAdditionalHasSOA(res, soa)
if singleCheck:
break

def checkNotBlocked(self, name, adQuery=False, singleCheck=False):
self.checkBlocked(name, False, adQuery, singleCheck)

def checkCustom(self, qname, qtype, expected, soa=False):
def checkCustom(self, qname, qtype, expected, soa=None):
query = dns.message.make_query(qname, qtype, want_dnssec=True)
query.flags |= dns.flags.CD
for method in ("sendUDPQuery", "sendTCPQuery"):
Expand All @@ -299,9 +299,9 @@ def checkCustom(self, qname, qtype, expected, soa=False):
self.assertRcodeEqual(res, dns.rcode.NOERROR)
self.assertRRsetInAnswer(res, expected)
if soa:
self.assertAdditionalHasSOA(res)
self.assertAdditionalHasSOA(res, soa)

def checkNoData(self, qname, qtype, soa=False):
def checkNoData(self, qname, qtype, soa=None):
query = dns.message.make_query(qname, qtype, want_dnssec=True)
query.flags |= dns.flags.CD
for method in ("sendUDPQuery", "sendTCPQuery"):
Expand All @@ -310,7 +310,7 @@ def checkNoData(self, qname, qtype, soa=False):
self.assertRcodeEqual(res, dns.rcode.NOERROR)
self.assertEqual(len(res.answer), 0)
if soa:
self.assertAdditionalHasSOA(res)
self.assertAdditionalHasSOA(res, soa)

def checkNXD(self, qname, qtype='A'):
query = dns.message.make_query(qname, qtype, want_dnssec=True)
Expand All @@ -322,7 +322,7 @@ def checkNXD(self, qname, qtype='A'):
self.assertEqual(len(res.answer), 0)
self.assertEqual(len(res.authority), 1)

def checkTruncated(self, qname, qtype='A', soa=False):
def checkTruncated(self, qname, qtype='A', soa=None):
query = dns.message.make_query(qname, qtype, want_dnssec=True)
query.flags |= dns.flags.CD
res = self.sendUDPQuery(query)
Expand All @@ -331,7 +331,7 @@ def checkTruncated(self, qname, qtype='A', soa=False):
self.assertEqual(len(res.answer), 0)
self.assertEqual(len(res.authority), 0)
if soa:
self.assertAdditionalHasSOA(res)
self.assertAdditionalHasSOA(res, soa)

res = self.sendTCPQuery(query)
self.assertRcodeEqual(res, dns.rcode.NXDOMAIN)
Expand Down Expand Up @@ -433,38 +433,38 @@ def testRPZ(self):
# first zone, only a should be blocked
self.waitUntilCorrectSerialIsLoaded(1)
self.checkRPZStats(1, 1, 1, self._xfrDone)
self.checkBlocked('a.example.', soa=True)
self.checkBlocked('a.example.', soa='zone.rpz.')
self.checkNotBlocked('b.example.')
self.checkNotBlocked('c.example.')

# second zone, a and b should be blocked
self.waitUntilCorrectSerialIsLoaded(2)
self.checkRPZStats(2, 2, 1, self._xfrDone)
self.checkBlocked('a.example.', soa=True)
self.checkBlocked('b.example.', soa=True)
self.checkBlocked('a.example.', soa='zone.rpz.')
self.checkBlocked('b.example.', soa='zone.rpz.')
self.checkNotBlocked('c.example.')

# third zone, only b should be blocked
self.waitUntilCorrectSerialIsLoaded(3)
self.checkRPZStats(3, 1, 1, self._xfrDone)
self.checkNotBlocked('a.example.')
self.checkBlocked('b.example.', soa=True)
self.checkBlocked('b.example.', soa='zone.rpz.')
self.checkNotBlocked('c.example.')

# fourth zone, only c should be blocked
self.waitUntilCorrectSerialIsLoaded(4)
self.checkRPZStats(4, 1, 1, self._xfrDone)
self.checkNotBlocked('a.example.')
self.checkNotBlocked('b.example.')
self.checkBlocked('c.example.', soa=True)
self.checkBlocked('c.example.', soa='zone.rpz.')

# fifth zone, we should get a full AXFR this time, and only d should be blocked
self.waitUntilCorrectSerialIsLoaded(5)
self.checkRPZStats(5, 3, 2, self._xfrDone)
self.checkNotBlocked('a.example.')
self.checkNotBlocked('b.example.')
self.checkNotBlocked('c.example.')
self.checkBlocked('d.example.', soa=True)
self.checkBlocked('d.example.', soa='zone.rpz.')

# sixth zone, only e should be blocked, f is a local data record
self.waitUntilCorrectSerialIsLoaded(6)
Expand All @@ -473,10 +473,10 @@ def testRPZ(self):
self.checkNotBlocked('b.example.')
self.checkNotBlocked('c.example.')
self.checkNotBlocked('d.example.')
self.checkCustom('e.example.', 'A', dns.rrset.from_text('e.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.1', '192.0.2.2'), soa=True)
self.checkCustom('e.example.', 'A', dns.rrset.from_text('e.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.1', '192.0.2.2'), soa='zone.rpz.')
self.checkCustom('e.example.', 'MX', dns.rrset.from_text('e.example.', 0, dns.rdataclass.IN, 'MX', '10 mx.example.'))
self.checkNoData('e.example.', 'AAAA', soa=True)
self.checkCustom('f.example.', 'A', dns.rrset.from_text('f.example.', 0, dns.rdataclass.IN, 'CNAME', 'e.example.'), soa=True)
self.checkNoData('e.example.', 'AAAA', soa='zone.rpz.')
self.checkCustom('f.example.', 'A', dns.rrset.from_text('f.example.', 0, dns.rdataclass.IN, 'CNAME', 'e.example.'), soa='zone.rpz.')

# seventh zone, e should only have one A
self.waitUntilCorrectSerialIsLoaded(7)
Expand All @@ -485,14 +485,14 @@ def testRPZ(self):
self.checkNotBlocked('b.example.')
self.checkNotBlocked('c.example.')
self.checkNotBlocked('d.example.')
self.checkCustom('e.example.', 'A', dns.rrset.from_text('e.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.2'), soa=True)
self.checkCustom('e.example.', 'MX', dns.rrset.from_text('e.example.', 0, dns.rdataclass.IN, 'MX', '10 mx.example.'), soa=True)
self.checkNoData('e.example.', 'AAAA', soa=True)
self.checkCustom('f.example.', 'A', dns.rrset.from_text('f.example.', 0, dns.rdataclass.IN, 'CNAME', 'e.example.'), soa=True)
self.checkCustom('e.example.', 'A', dns.rrset.from_text('e.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.2'), soa='zone.rpz.')
self.checkCustom('e.example.', 'MX', dns.rrset.from_text('e.example.', 0, dns.rdataclass.IN, 'MX', '10 mx.example.'), soa='zone.rpz.')
self.checkNoData('e.example.', 'AAAA', soa='zone.rpz.')
self.checkCustom('f.example.', 'A', dns.rrset.from_text('f.example.', 0, dns.rdataclass.IN, 'CNAME', 'e.example.'), soa='zone.rpz.')
# check that the policy is disabled for AD=1 queries
self.checkNotBlocked('e.example.', True)
# check non-custom policies
self.checkTruncated('tc.example.', soa=True)
self.checkTruncated('tc.example.', soa='zone.rpz.')
self.checkDropped('drop.example.')

# eighth zone, all entries should be gone
Expand All @@ -518,7 +518,7 @@ def testRPZ(self):
self.checkNotBlocked('c.example.')
self.checkNotBlocked('d.example.')
self.checkNotBlocked('e.example.')
self.checkBlocked('f.example.', soa=True)
self.checkBlocked('f.example.', soa='zone.rpz.')
self.checkNXD('tc.example.')
self.checkNXD('drop.example.')

Expand All @@ -533,7 +533,7 @@ def testRPZ(self):
self.checkNotBlocked('d.example.')
self.checkNotBlocked('e.example.')
self.checkNXD('f.example.')
self.checkBlocked('g.example.', soa=True)
self.checkBlocked('g.example.', soa='zone.rpz.')
self.checkNXD('tc.example.')
self.checkNXD('drop.example.')

Expand Down Expand Up @@ -580,15 +580,15 @@ def generateRecursorConfig(cls, confdir):
def testRPZ(self):
self.checkCustom('a.example.', 'A', dns.rrset.from_text('a.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.42', '192.0.2.43'))
self.checkCustom('a.example.', 'TXT', dns.rrset.from_text('a.example.', 0, dns.rdataclass.IN, 'TXT', '"some text"'))
self.checkBlocked('z.example.', soa=True)
self.checkBlocked('z.example.', soa='zone.rpz.')
self.checkNotBlocked('b.example.')
self.checkNotBlocked('c.example.')
self.checkNotBlocked('d.example.')
self.checkNotBlocked('e.example.')
# check that the policy is disabled for AD=1 queries
self.checkNotBlocked('z.example.', True)
# check non-custom policies
self.checkTruncated('tc.example.', soa=True)
self.checkTruncated('tc.example.', soa='zone.rpz.')
self.checkDropped('drop.example.')

class RPZFileDefaultPolRecursorTest(RPZRecursorTest):
Expand Down

0 comments on commit e6eaef7

Please sign in to comment.