]> git.siccegge.de Git - tools.git/blob - dnssec-check
Also check DNSKEY records
[tools.git] / dnssec-check
1 #!/usr/bin/python
2
3 from __future__ import print_function
4 import ldns
5 from unbound import ub_ctx, idn2dname, RR_TYPE_SOA, RR_TYPE_DNSKEY, RR_TYPE_RRSIG, ub_strerror
6 from optparse import OptionParser
7 import sys
8 from datetime import datetime, timedelta
9
10 def parse_rrsig_expire(expirestring):
11 expires = datetime(int(expirestring[:4]),
12 int(expirestring[4:6]),
13 int(expirestring[6:8]),
14 int(expirestring[8:10]),
15 int(expirestring[10:12]),
16 int(expirestring[12:14]))
17
18 delta = expires - datetime.utcnow()
19 return delta
20
21 def check_dnssec_expire(resolver, name, warn, crit):
22 for rrtype in [RR_TYPE_SOA, RR_TYPE_DNSKEY]:
23 s, result = resolver.resolve(name, rrtype=rrtype)
24 if 0 != s:
25 ub_strerror(s)
26 return 3
27
28 if not result.secure:
29 print("CRIT (does not verify) %s" % (name, ))
30 return 2
31
32 s, packet = ldns.ldns_wire2pkt(result.packet)
33 rrsigs = packet.rr_list_by_type(RR_TYPE_RRSIG, ldns.LDNS_SECTION_ANSWER).rrs()
34
35 for rrsig in rrsigs:
36 delta = parse_rrsig_expire(str(rrsig.rrsig_expiration()))
37
38 if delta < crit:
39 print("CRIT (expires in %s) %s" % (delta, name))
40 return 2
41 elif delta < warn:
42 print("WARN (expires in %s) %s" % (delta, name))
43 return 1
44 return 0
45
46
47 def main():
48 parser = OptionParser()
49 parser.add_option("-n", "--name",
50 action="append", type="string", dest="names",
51 help="DNS Names to check")
52 parser.add_option("-a", "--ancor",
53 action="store", type="string", dest="ancor",
54 default="/etc/unbound/root.key",
55 help="DNSSEC root ancor")
56 parser.add_option("-w", "--warning-days",
57 action="store", type=int, dest="warn", default=5,
58 help="minimum remaining validity in days before a warning is issued")
59 parser.add_option("-c", "--critical-days",
60 action="store", type=int, dest="crit", default=2,
61 help="minimum remaining validity in days before a warning is issued")
62 parser.add_option("-v", action="store_true", dest="verbose", default=False)
63 parser.add_option("-q", action="store_false", dest="verbose")
64
65 opts, _args = parser.parse_args()
66 if not opts.names:
67 parser.error("needs at least one DNS name")
68
69 resolver = ub_ctx()
70 resolver.add_ta_file(opts.ancor)
71 encoding = sys.getfilesystemencoding()
72
73 final = 0
74 for name in opts.names:
75 name = idn2dname(name.decode(encoding))
76 result = check_dnssec_expire(resolver, name,
77 timedelta(opts.warn), timedelta(opts.crit))
78 if result == 0 and opts.verbose:
79 print("OK %s" % name)
80 if result == 2:
81 final = 2
82 elif result == 1 and final != 2:
83 final = 1
84 elif result == 3 and final not in [1, 2]:
85 final = 3
86
87 sys.exit(final)
88
89 if __name__ == "__main__":
90 main()