#!/usr/bin/python from __future__ import print_function import ldns from unbound import ub_ctx, idn2dname, RR_TYPE_SOA, RR_TYPE_RRSIG, ub_strerror from optparse import OptionParser import sys from datetime import datetime, timedelta def parse_rrsig_expire(expirestring): expires = datetime(int(expirestring[:4]), int(expirestring[4:6]), int(expirestring[6:8]), int(expirestring[8:10]), int(expirestring[10:12]), int(expirestring[12:14])) delta = expires - datetime.utcnow() return delta def check_dnssec_expire(resolver, name, warn, crit): s, result = resolver.resolve(name, rrtype=RR_TYPE_SOA) if 0 != s: ub_strerror(s) return s, packet = ldns.ldns_wire2pkt(result.packet) rrsigs = packet.rr_list_by_type(RR_TYPE_RRSIG, ldns.LDNS_SECTION_ANSWER).rrs() for rrsig in rrsigs: delta = parse_rrsig_expire(str(rrsig.rrsig_expiration())) if delta < crit: print("CRIT (%s) %s" % (delta, name)) elif delta < warn: print("WARN (%s) %s" % (delta, name)) def main(): parser = OptionParser() parser.add_option("-n", "--name", action="append", type="string", dest="names", help="DNS Names to check") parser.add_option("-a", "--ancor", action="store", type="string", dest="ancor", default="/etc/unbound/root.key", help="DNSSEC root ancor") parser.add_option("-w", "--warning-days", action="store", type=int, dest="warn", default=5, help="minimum remaining validity in days before a warning is issued") parser.add_option("-c", "--critical-days", action="store", type=int, dest="crit", default=2, help="minimum remaining validity in days before a warning is issued") opts, _args = parser.parse_args() resolver = ub_ctx() resolver.add_ta_file(opts.ancor) encoding = sys.getfilesystemencoding() for name in opts.names: check_dnssec_expire(resolver, idn2dname(name.decode(encoding)), timedelta(opts.warn), timedelta(opts.crit)) if __name__ == "__main__": main()