]> git.siccegge.de Git - dane-monitoring-plugins.git/blob - check_dane_https
3d758c240df6617e3c88bc92a40626880eff1c81
[dane-monitoring-plugins.git] / check_dane_https
1 #!/usr/bin/python3
2
3 from __future__ import print_function
4
5 import sys
6 import argparse
7 import logging
8
9 from socket import socket, AF_INET6, AF_INET
10 from ssl import SSLContext, PROTOCOL_TLSv1_2, CERT_REQUIRED
11 from unbound import ub_ctx
12
13 from check_dane.tlsa import verify_tlsa_record
14 from check_dane.cert import verify_certificate, add_certificate_options
15
16 def init_connection(sslcontext, family, host, port):
17 connection = sslcontext.wrap_socket(socket(family),
18 server_hostname=host)
19 connection.connect((host, port))
20 connection.send(b"HEAD / HTTP/1.1\r\nHost: %s\r\n\r\n" % host.encode())
21 answer = connection.recv(512)
22 logging.debug(answer)
23
24 return connection
25
26
27 def close_connection(connection):
28 connection.close()
29
30
31 def init(args):
32 sslcontext = SSLContext(PROTOCOL_TLSv1_2)
33 sslcontext.verify_mode = CERT_REQUIRED
34 sslcontext.load_verify_locations(args.castore)
35
36 resolver = ub_ctx()
37 resolver.add_ta_file(args.ancor)
38
39 return sslcontext, resolver
40
41
42 def main():
43 logging.basicConfig(format='%(levelname)5s %(message)s')
44 parser = argparse.ArgumentParser()
45 parser.add_argument("Host")
46
47 parser.add_argument("--verbose", action="store_true")
48 parser.add_argument("--quiet", action="store_true")
49 parser.add_argument("-p", "--port",
50 action="store", type=int, default=443,
51 help="HTTPS port")
52 parser.add_argument("--check-dane",
53 action="store_false",
54 help="Verify presented certificate via DANE (default: enabled)")
55 parser.add_argument("--check-ca",
56 action="store_false",
57 help="Verify presented certificate via the CA system (default: enabled)")
58 parser.add_argument("--check-expire",
59 action="store_false",
60 help="Verify presented certificate for expiration (default: enabled)")
61
62 parser.add_argument("-a", "--ancor",
63 action="store", type=str, default="/etc/unbound/root.key",
64 help="DNSSEC root ancor")
65 parser.add_argument("--castore", action="store", type=str,
66 default="/etc/ssl/certs/ca-certificates.crt",
67 help="ca certificate bundle")
68
69 group = parser.add_mutually_exclusive_group()
70 group.add_argument("-6", "--6", action="store_true", dest="use6", help="check via IPv6 only")
71 group.add_argument("-4", "--4", action="store_true", dest="use4", help="check via IPv4 only")
72 group.add_argument("--64", action="store_false", dest="use64", help="check via IPv4 and IPv6 (default)")
73
74 add_certificate_options(parser)
75
76 args = parser.parse_args()
77
78 if args.verbose:
79 logging.getLogger().setLevel(logging.DEBUG)
80 elif args.quiet:
81 logging.getLogger().setLevel(logging.WARNING)
82 else:
83 logging.getLogger().setLevel(logging.INFO)
84
85 host = args.Host.encode('idna').decode()
86 sslcontext, resolver = init(args)
87
88 if args.use6:
89 afamilies = [AF_INET6]
90 elif args.use4:
91 afamilies = [AF_INET6]
92 else:
93 afamilies = [AF_INET, AF_INET6]
94
95 retval = 0
96 for afamily in afamilies:
97 try:
98 connection = init_connection(sslcontext, afamily, host, args.port)
99 except ConnectionRefusedError:
100 logging.error("Connection refused")
101 return 2
102
103 nretval = verify_certificate(connection.getpeercert(), args)
104 retval = max(retval, nretval)
105 nretval = verify_tlsa_record(resolver, "_%d._tcp.%s" % (args.port, host),
106 connection.getpeercert(binary_form=True))
107 retval = max(retval, nretval)
108
109 close_connection(connection)
110
111 return retval
112
113
114 if __name__ == '__main__':
115 sys.exit(main())