Commit 88d2b6df authored by Libor Peltan's avatar Libor Peltan Committed by Daniel Salzman

tests-extra: add NSEC tree update test

parent 319511c6
#!/usr/bin/env python3
'''Test for NSEC and NSEC3 fix after zone update'''
from dnstest.utils import *
from dnstest.test import Test
import random
t = Test()
master = t.server("knot")
slave = t.server("knot")
zones = t.zone_rnd(5, dnssec=False, records=50) +"records."), master, slave)
master.disable_notify = True
slave.disable_notify = True
for zone in zones:
master.dnssec(zone).enable = True
master.dnssec(zone).nsec3 = random.choice([True, False])
master.dnssec(zone).nsec3_iters = 2
master.dnssec(zone).nsec3_salt_len = 8
# initial convenience check
t.xfr_diff(master, slave, zones)
# update master
for zone in zones:
# sync slave with current master's state
# resign master and check that the resign made nothing
t.xfr_diff(master, slave, zones, no_rrsig_rdata=True)
......@@ -694,6 +694,13 @@ class Server(object):
self.zones[].zfile.upd_file(storage=storage, version=version)
def random_ddns(self, zone):
zone = zone_arg_check(zone)
up = self.update(zone)
def add_module(self, zone, module):
zone = zone_arg_check(zone)
......@@ -330,7 +330,7 @@ class Test(object):
return item_owner_split[0].lower() + " " + item_data
def _axfr_records(self, resp, zone):
def _axfr_records(self, resp, zone, no_rrsig_rdata):
unique = set()
records = list()
......@@ -342,7 +342,18 @@ class Test(object):
for rr in rrs:
item_lower = self._canonize_record(rrset.rdtype, rr.strip())
if item_lower in unique and rrset.rdtype != dns.rdatatype.SOA:
if no_rrsig_rdata and rrset.rdtype == dns.rdatatype.SOA:
# Reset SOA serial.
soa_split = item_lower.split()
soa_split[6] = "0"
item_lower = " ".join(soa_split)
if no_rrsig_rdata and rrset.rdtype == dns.rdatatype.RRSIG:
# Trim RRSIG signature part.
rrsig_split = item_lower.split(None, 5)
item_lower = " ".join(rrsig_split[:5])
elif item_lower in unique and rrset.rdtype != dns.rdatatype.SOA:
detail_log("!Duplicate record server='%s':" %
detail_log(" %s" % item_lower)
......@@ -367,9 +378,9 @@ class Test(object):
for record in diff2:
detail_log(" %s" % record)
def _axfr_diff(self, server1, server2, zone):
unique1, rrsets1 = self._axfr_records(server1.dig(, "AXFR", log_no_sep=True), zone)
unique2, rrsets2 = self._axfr_records(server2.dig(, "AXFR", log_no_sep=True), zone)
def _axfr_diff(self, server1, server2, zone, no_rrsig_rdata):
unique1, rrsets1 = self._axfr_records(server1.dig(, "AXFR", log_no_sep=True), zone, no_rrsig_rdata)
unique2, rrsets2 = self._axfr_records(server2.dig(, "AXFR", log_no_sep=True), zone, no_rrsig_rdata)
self._axfr_diff_resp(unique1, rrsets1, unique2, rrsets2, server1, server2)
......@@ -527,20 +538,22 @@ class Test(object):
for change1, change2 in zip(changes1, changes2):
def xfr_diff(self, server1, server2, zones, serials=None, udp=False):
def xfr_diff(self, server1, server2, zones, serials=None, udp=False, no_rrsig_rdata=False):
for zone in zones:
check_log("CHECK %sXFR DIFF %s %s<->%s" % ("I" if serials else "A",,,
if serials:
if no_rrsig_rdata:
set_err("RRSIG rdata and SOA serial skipping not implemented for IXFR diff")
self._ixfr_diff(server1, server2, zone, serials[], udp)
self._axfr_diff(server1, server2, zone)
self._axfr_diff(server1, server2, zone, no_rrsig_rdata)
def axfr_diff_resp(self, resp1, resp2, server1, server2, zone):
unique1, rrsets1 = self._axfr_records(resp1, zone)
unique2, rrsets2 = self._axfr_records(resp2, zone)
def axfr_diff_resp(self, resp1, resp2, server1, server2, zone, no_rrsig_rdata=False):
unique1, rrsets1 = self._axfr_records(resp1, zone, no_rrsig_rdata)
unique2, rrsets2 = self._axfr_records(resp2, zone, no_rrsig_rdata)
self._axfr_diff_resp(unique1, rrsets1, unique2, rrsets2, server1, server2)
......@@ -7,6 +7,7 @@ import shutil
import zone_generate
import glob
import distutils.dir_util
from subprocess import DEVNULL, PIPE, Popen
from dnstest.utils import *
......@@ -245,6 +246,22 @@ class ZoneFile(object):
file.write("%s IN AAAA dead:beef:dead:beef:dead:beef:%04x:%04x\n" %
(owner, rnd1, rnd2))
def gen_rnd_ddns(self, ddns):
'''Walk zonefile, randomly mark some records to be removed by ddns and some added'''
with open(self.path, 'r') as file:
for fline in file:
line = fline.split(None, 3)
if line[0] not in [";;"] and line[2] not in ["SOA", "RRSIG", "DNSKEY", "DS", "CDS", "CDNSKEY", "NSEC", "NSEC3", "NSEC3PARAM"]:
if random.randint(1, 20) in [4, 5]:
ddns.delete(line[0], line[2])
if random.randint(1, 20) in [2, 3] and line[2] not in ["DNAME"]:
ddns.add("xyz."+line[0], line[1], line[2], line[3])
except (dns.rdatatype.UnknownRdatatype,,
# problems - simply skip. This is completely stochastic anyway.
def remove(self):
'''Remove zone file.'''
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment