1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
|
#!/usr/bin/env python3
"""
More precise check of simple KSK rollover.
The key_rollovers test is too over-complicated already, unable to add test cases.
"""
from dnstest.utils import *
from dnstest.keys import Keymgr
from dnstest.test import Test
# check zone if keys are present and used for signing
def check_zone(server, zone, slave, dnskeys, dnskey_rrsigs, cdnskeys, soa_rrsigs, msg):
qdnskeys = server.dig("example.com", "DNSKEY", bufsize=4096)
found_dnskeys = qdnskeys.count("DNSKEY")
qdnskeyrrsig = server.dig("example.com", "DNSKEY", dnssec=True, bufsize=4096)
found_rrsigs = qdnskeyrrsig.count("RRSIG")
qcdnskey = server.dig("example.com", "CDNSKEY", bufsize=4096)
found_cdnskeys = qcdnskey.count("CDNSKEY")
qsoa = server.dig("example.com", "SOA", dnssec=True, bufsize=4096)
found_soa_rrsigs = qsoa.count("RRSIG")
check_log("DNSKEYs: %d (expected %d)" % (found_dnskeys, dnskeys));
check_log("RRSIGs: %d (expected %d)" % (found_soa_rrsigs, soa_rrsigs));
check_log("DNSKEY-RRSIGs: %d (expected %d)" % (found_rrsigs, dnskey_rrsigs));
check_log("CDNSKEYs: %d (expected %d)" % (found_cdnskeys, cdnskeys));
if found_dnskeys != dnskeys:
set_err("BAD DNSKEY COUNT: " + msg)
detail_log("!DNSKEYs not published and activated as expected: " + msg)
if found_soa_rrsigs != soa_rrsigs:
set_err("BAD RRSIG COUNT: " + msg)
detail_log("!RRSIGs not published and activated as expected: " + msg)
if found_rrsigs != dnskey_rrsigs:
set_err("BAD DNSKEY RRSIG COUNT: " + msg)
detail_log("!RRSIGs not published and activated as expected: " + msg)
if found_cdnskeys != cdnskeys:
set_err("BAD CDNSKEY COUNT: " + msg)
detail_log("!CDNSKEYs not published and activated as expected: " + msg)
detail_log(SEP)
serial = server.zone_wait(zone)
slave.zone_wait(zone, serial, equal=True, greater=False)
t.xfr_diff(server, slave, zone)
server.zone_backup(zone, flush=True)
server.zone_verify(zone)
global_last_roll = 0
def check_min_time(min_time, msg):
global global_last_roll
prev_roll = global_last_roll
global_last_roll = time.time()
if global_last_roll - prev_roll < min_time:
set_err("Too early roll: " + msg)
detail_log("!Roll-over went too fast (%d < %d): %s" % (global_last_roll - prev_roll, min_time, msg))
def wait_for_count(t, server, rrtype, count, min_time, timeout, msg):
rtime = 0
while True:
q = server.dig("example.com", rrtype, dnssec=True, bufsize=4096)
found = q.count(rrtype)
if found == count:
break
rtime = rtime + 1
t.sleep(1)
if rtime > timeout:
break
check_min_time(min_time, msg)
def get_cds(server):
cds_rr = server.dig("example.com.", "CDS").resp.answer
if len(cds_rr) == 0:
return ""
return str(cds_rr[0].to_rdataset())
def wait_for_cds_change(t, server, min_time, timeout, msg):
rtime = 0
CDS1 = get_cds(server)
while True:
CDS2 = get_cds(server)
if CDS1 != CDS2:
break
rtime = rtime + 1
t.sleep(1)
if rtime > timeout:
break
check_min_time(min_time, msg)
def watch_ksk_rollover(t, server, zone, before_keys, after_keys, total_keys, desc, set_stss, set_ksk_lifetime, submission_cb):
msg = desc + ": initial keys"
check_zone(server, zone, server, before_keys, 1, 0, 1, msg)
for z in zone:
server.ctl("zone-key-rollover %s ksk" % z.name)
msg = desc + ": published new"
wait_for_count(t, server, "DNSKEY", total_keys, 0, 10, msg)
check_zone(server, zone, server, total_keys, 2, 0, 1, msg)
msg = desc + ": new KSK ready"
wait_for_cds_change(t, server, 15, 26, msg) # propagation-delay + dnskey_ttl
check_zone(server, zone, server, total_keys, 2, 1, 1, msg)
submission_cb()
msg = desc + ": both still active"
wait_for_cds_change(t, server, 0, 10, msg)
check_zone(server, zone, server, total_keys, 2, 0, 1, msg)
msg = desc + ": old key removed"
wait_for_count(t, server, "DNSKEY", after_keys, 10, 20, msg) # ds_ttl
check_zone(server, zone, server, after_keys, 1, 0, 1, msg)
t = Test()
parent = t.server("knot")
parent_zone = t.zone("com.", storage=".")
t.link(parent_zone, parent)
parent.dnssec(parent_zone).enable = True
child = t.server("knot")
child_zone = t.zone("example.com.")
t.link(child_zone, child, ixfr=True)
def cds_submission():
cds = child.dig("example.com.", "CDS")
up = parent.update(parent_zone)
up.delete("example.com.", "DS")
for rd in cds.resp.answer[0].to_rdataset():
up.add("example.com.", 11, "DS", rd.to_text())
up.send("NOERROR")
child.dnssec(child_zone).enable = True
child.dnssec(child_zone).dnskey_ttl = 6
child.dnssec(child_zone).propagation_delay = 11
child.dnssec(child_zone).ksk_sbm_check = [ parent ]
child.dnssec(child_zone).ksk_sbm_check_interval = 3
child.dnssec(child_zone).cds_publish = "rollover"
t.start()
child.zone_wait(child_zone)
cds_submission()
t.sleep(5)
watch_ksk_rollover(t, child, child_zone, 2, 2, 3, "KSK rollover", None, 27, cds_submission)
t.end()
|