3 from __future__
import print_function
11 from unbound
import RR_TYPE_SOA
, RR_TYPE_DNSKEY
, RR_TYPE_NS
12 from unbound
import RR_TYPE_A
, RR_TYPE_AAAA
13 from ldns
import LDNS_SECTION_ANSWER
14 from ldns
import ldns_wire2pkt
17 from check_dane
.resolve
import Resolver
, ResolverException
18 from check_dane
.resolve
import format_address
, dnssec_verify_rrsig_validity
21 def check_main_records(resolver
, zone
, args
):
22 """Confirms that the necessary records on a zone all verify"""
25 for rrtype
in [RR_TYPE_DNSKEY
, RR_TYPE_NS
, RR_TYPE_SOA
]:
26 result
= resolver
.resolve(zone
, rrtype
=rrtype
, secure
=True)
27 nretval
= dnssec_verify_rrsig_validity(result
.packet
, args
.warndays
, args
.critdays
)
28 retval
= max(nretval
, retval
)
33 def check_nsec_cycle(resolver
, zone
, args
):
34 """Confirms that NSEC records are completely available"""
38 def check_synced(resolver
, zone
, args
):
39 """Makes sure the zone is at the same serial on all secondaries"""
41 result
= resolver
.resolve(zone
, RR_TYPE_NS
, secure
=True)
43 if result
.data
is None:
44 logging
.error("No nameservers found for zone %s", zone
)
47 nameservers
= result
.data
.as_domain_list()
49 for nameserver
in nameservers
:
51 for rrtype
in [RR_TYPE_AAAA
, RR_TYPE_A
]:
52 result
= resolver
.resolve(nameserver
, rrtype
=rrtype
, secure
=True)
53 if result
.data
is not None:
54 ips
= ips
+ [format_address(data
, rrtype
) for data
in result
.data
.data
]
57 logging
.warning("Could not find any address for nameserver %s", nameserver
)
59 nameserver_ips
= nameserver_ips
+ ips
61 if nameserver_ips
== []:
62 logging
.error("No authoritive nameserver for %s could be resolved", zone
)
66 for ip
in nameserver_ips
:
67 newresolver
= Resolver(args
.ancor
, ip
)
69 # We can't request secure here as the authoritative
70 # nameservers for the zone won't let us retrieve the
71 # signature chain below their own zone. We'll later
72 # recheck the SOA record using the main recursor
74 # Alternatively one could get the DS / DNSKEY for the zone with
75 # resolver and add it to newresolver as a hint.
76 result
= newresolver
.resolve(zone
, rrtype
=RR_TYPE_SOA
)
78 s
, result
= ldns_wire2pkt(result
.packet
)
80 logging
.error("Parsing packet failed with errorcode %d", s
)
83 rrs
= result
.rr_list_by_type(RR_TYPE_SOA
, LDNS_SECTION_ANSWER
).rrs()
86 serial
= str(soa
).split()[6]
87 results
[serial
] = results
.get(serial
, []) + [ip
]
92 logging
.error("different SOAs: %s", results
)
95 except ResolverException
as e
:
96 logging
.error(e
.message
)
100 logging
.basicConfig(format
='%(levelname)5s %(message)s')
101 parser
= argparse
.ArgumentParser()
102 parser
.add_argument("Zone")
104 parser
.add_argument("--verbose", action
="store_true")
105 parser
.add_argument("--quiet", action
="store_true")
107 parser
.add_argument("-a", "--ancor",
108 action
="store", type=str, default
="/etc/unbound/root.key",
109 help="DNSSEC root ancor")
111 parser
.add_argument("--nsec", action
="store_false",
112 help="Verifies the complete NSEC/NSEC3 cycle (default: false)")
113 parser
.add_argument("--warndays", type=int, default
=-1,
114 help="Days before rrsig expiration to warn")
115 parser
.add_argument("--critdays", type=int, default
=-1,
116 help="Days before rrsig expiration to raise error")
119 args
= parser
.parse_args()
122 logging
.getLogger().setLevel(logging
.DEBUG
)
124 logging
.getLogger().setLevel(logging
.WARNING
)
126 logging
.getLogger().setLevel(logging
.INFO
)
128 resolver
= Resolver(args
.ancor
)
129 zone
= args
.Zone
.encode('idna').decode()
131 retval1
= check_synced(resolver
, zone
, args
)
132 retval2
= check_main_records(resolver
, zone
, args
)
134 retval3
= check_nsec_cycle(resolver
, zone
, args
)
135 return max(retval1
, retval2
, retval3
)
137 return max(retval1
, retval2
)
139 if __name__
== '__main__':