]>
git.siccegge.de Git - dane-monitoring-plugins.git/blob - check_dane_xmpp
5 from __future__
import print_function
11 from socket
import socket
, AF_INET6
, AF_INET
, create_connection
12 from ssl
import SSLError
, CertificateError
, SSLContext
13 from ssl
import PROTOCOL_TLSv1_2
, CERT_REQUIRED
15 from unbound
import ub_ctx
17 from check_dane
.resolve
import Resolver
, ResolverException
, srv_lookup
18 from check_dane
.tlsa
import verify_tlsa_record
19 from check_dane
.cert
import verify_certificate
, add_certificate_options
21 XMPP_OPEN
= ("<stream:stream xmlns='jabber:{0}' xmlns:stream='"
22 "http://etherx.jabber.org/streams' xmlns:tls='http://www.ietf.org/rfc/"
23 "rfc2595.txt' to='{1}' xml:lang='en' version='1.0'>")
24 XMPP_CLOSE
= "</stream:stream>"
25 XMPP_STARTTLS
= "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>"
28 def init_connection(sslcontext
, args
, family
, endpoint
, metadata
):
30 logging
.debug("Connecting to %s", endpoint
)
32 connection
= socket(family
=family
)
33 connection
.connect(endpoint
)
35 connection
.sendall(XMPP_OPEN
.format(metadata
['type'], args
.Host
).encode())
36 answer
= connection
.recv(4096)
39 if not '</stream:features>' in answer
:
40 answer
= connection
.recv(4096)
43 connection
.sendall(XMPP_STARTTLS
.encode())
44 answer
= connection
.recv(4096)
47 connection
= sslcontext
.wrap_socket(connection
, server_hostname
=host
)
48 connection
.do_handshake()
50 connection
.sendall(XMPP_OPEN
.format(metadata
['type'], args
.Host
).encode())
51 answer
= connection
.recv(4096)
54 if not '</stream:features>' in answer
:
55 answer
= connection
.recv(4096)
61 def close_connection(connection
):
62 connection
.send(XMPP_CLOSE
.encode())
63 answer
= connection
.recv(512)
68 sslcontext
= SSLContext(PROTOCOL_TLSv1_2
)
69 sslcontext
.verify_mode
= CERT_REQUIRED
70 sslcontext
.load_verify_locations(args
.castore
)
73 resolver
.add_ta_file(args
.ancor
)
75 return sslcontext
, resolver
79 logging
.basicConfig(format
='%(levelname)5s %(message)s')
80 parser
= argparse
.ArgumentParser()
81 parser
.add_argument("Host")
83 parser
.add_argument("--verbose", action
="store_true")
84 parser
.add_argument("--quiet", action
="store_true")
85 # parser.add_argument("-p", "--port",
86 # action="store", type=int, default=0,
88 group
= parser
.add_mutually_exclusive_group()
89 group
.add_argument("--s2s", action
="store_true",
90 help="Only check server-to-server connections")
91 group
.add_argument("--c2s", action
="store_true",
92 help="Only check client-to-server connections")
93 # parser.add_argument("--ssl",
94 # action="store_true",
95 # help="Use direct TLS connection instead of starttls (default: disabled)")
96 parser
.add_argument("--check-dane",
98 help="Verify presented certificate via DANE (default: enabled)")
99 parser
.add_argument("--check-ca",
100 action
="store_false",
101 help="Verify presented certificate via the CA system (default: enabled)")
102 parser
.add_argument("--check-expire",
103 action
="store_false",
104 help="Verify presented certificate for expiration (default: enabled)")
106 parser
.add_argument("-a", "--ancor",
107 action
="store", type=str, default
="/etc/unbound/root.key",
108 help="DNSSEC root ancor")
109 parser
.add_argument("--castore", action
="store", type=str,
110 default
="/etc/ssl/certs/ca-certificates.crt",
111 help="ca certificate bundle")
113 group
= parser
.add_mutually_exclusive_group()
114 group
.add_argument("-6", "--6", action
="store_true", dest
="use6", help="check via IPv6 only")
115 group
.add_argument("-4", "--4", action
="store_true", dest
="use4", help="check via IPv4 only")
116 group
.add_argument("--64", action
="store_false", dest
="use64", help="check via IPv4 and IPv6 (default)")
118 add_certificate_options(parser
)
120 args
= parser
.parse_args()
123 logging
.getLogger().setLevel(logging
.DEBUG
)
125 logging
.getLogger().setLevel(logging
.WARNING
)
127 logging
.getLogger().setLevel(logging
.INFO
)
129 host
= args
.Host
.encode('idna').decode()
131 sslcontext
, resolver
= init(args
)
134 afamilies
= [AF_INET6
]
136 afamilies
= [AF_INET6
]
138 afamilies
= [AF_INET
, AF_INET6
]
140 xresolver
= Resolver(args
.ancor
)
143 for endpoint
, meta
in srv_lookup("_xmpp-client._tcp.%s" % host
, xresolver
):
144 meta
['type'] = 'client'
145 endpoints
.append((endpoint
, meta
))
147 for endpoint
, meta
in srv_lookup("_xmpp-server._tcp.%s" % host
, xresolver
):
148 meta
['type'] = 'server'
149 endpoints
.append((endpoint
, meta
))
152 for afamily
in afamilies
:
153 for endpoint
, metadata
in endpoints
:
154 host
, port
= endpoint
156 connection
= init_connection(sslcontext
, args
, afamily
, endpoint
, metadata
)
158 logging
.exception("Connection refused")
161 nretval
= verify_certificate(connection
.getpeercert(), args
)
162 retval
= max(retval
, nretval
)
163 nretval
= verify_tlsa_record(resolver
, "_%d._tcp.%s" % (port
, host
),
164 connection
.getpeercert(binary_form
=True))
165 retval
= max(retval
, nretval
)
167 close_connection(connection
)
172 if __name__
== '__main__':