|
|
@ -33,7 +33,6 @@ import nagiosplugin
|
|
|
|
__author__ = "Jan Dittberner"
|
|
|
|
__author__ = "Jan Dittberner"
|
|
|
|
__version__ = "0.3.2"
|
|
|
|
__version__ = "0.3.2"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
NS_IETF_XMPP_SASL = 'urn:ietf:params:xml:ns:xmpp-sasl'
|
|
|
|
NS_IETF_XMPP_SASL = 'urn:ietf:params:xml:ns:xmpp-sasl'
|
|
|
|
NS_IETF_XMPP_TLS = 'urn:ietf:params:xml:ns:xmpp-tls'
|
|
|
|
NS_IETF_XMPP_TLS = 'urn:ietf:params:xml:ns:xmpp-tls'
|
|
|
|
NS_IETF_XMPP_STREAMS = 'urn:ietf:params:xml:ns:xmpp-streams'
|
|
|
|
NS_IETF_XMPP_STREAMS = 'urn:ietf:params:xml:ns:xmpp-streams'
|
|
|
@ -55,10 +54,14 @@ class XmppException(Exception):
|
|
|
|
Custom exception class.
|
|
|
|
Custom exception class.
|
|
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, message):
|
|
|
|
def __init__(self, message):
|
|
|
|
self.message = message
|
|
|
|
self.message = message
|
|
|
|
super(XmppException, self).__init__()
|
|
|
|
super(XmppException, self).__init__()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
|
|
|
return self.message
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class XmppStreamError(object):
|
|
|
|
class XmppStreamError(object):
|
|
|
|
"""
|
|
|
|
"""
|
|
|
@ -69,7 +72,7 @@ class XmppStreamError(object):
|
|
|
|
text = None
|
|
|
|
text = None
|
|
|
|
other_elements = {}
|
|
|
|
other_elements = {}
|
|
|
|
|
|
|
|
|
|
|
|
def str(self):
|
|
|
|
def __str__(self):
|
|
|
|
if self.text:
|
|
|
|
if self.text:
|
|
|
|
return "{condition}: {text}".format(
|
|
|
|
return "{condition}: {text}".format(
|
|
|
|
condition=self.condition, text=self.text)
|
|
|
|
condition=self.condition, text=self.text)
|
|
|
@ -84,12 +87,13 @@ class XmppResponseHandler(ContentHandler):
|
|
|
|
seen_elements = set()
|
|
|
|
seen_elements = set()
|
|
|
|
mechanisms = []
|
|
|
|
mechanisms = []
|
|
|
|
starttls = False
|
|
|
|
starttls = False
|
|
|
|
tlsrequired = False
|
|
|
|
tls_required = False
|
|
|
|
capabilities = {}
|
|
|
|
capabilities = {}
|
|
|
|
state = XMPP_STATE_NEW
|
|
|
|
state = XMPP_STATE_NEW
|
|
|
|
streaminfo = None
|
|
|
|
stream_info = None
|
|
|
|
|
|
|
|
error_instance = None
|
|
|
|
|
|
|
|
|
|
|
|
inelem = []
|
|
|
|
in_elem = []
|
|
|
|
level = 0
|
|
|
|
level = 0
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, expect_starttls):
|
|
|
|
def __init__(self, expect_starttls):
|
|
|
@ -97,35 +101,35 @@ class XmppResponseHandler(ContentHandler):
|
|
|
|
super(XmppResponseHandler, self).__init__()
|
|
|
|
super(XmppResponseHandler, self).__init__()
|
|
|
|
|
|
|
|
|
|
|
|
def startElementNS(self, name, qname, attrs):
|
|
|
|
def startElementNS(self, name, qname, attrs):
|
|
|
|
self.inelem.append(name)
|
|
|
|
self.in_elem.append(name)
|
|
|
|
self.seen_elements.add(name)
|
|
|
|
self.seen_elements.add(name)
|
|
|
|
if name == (NS_ETHERX_STREAMS, 'stream'):
|
|
|
|
if name == (NS_ETHERX_STREAMS, 'stream'):
|
|
|
|
self.state = XMPP_STATE_STREAM_START
|
|
|
|
self.state = XMPP_STATE_STREAM_START
|
|
|
|
self.streaminfo = dict([
|
|
|
|
self.stream_info = dict([
|
|
|
|
(qname, attrs.getValueByQName(qname)) for
|
|
|
|
(qname, attrs.getValueByQName(qname)) for
|
|
|
|
qname in attrs.getQNames()])
|
|
|
|
qname in attrs.getQNames()])
|
|
|
|
elif name == (NS_IETF_XMPP_TLS, 'starttls'):
|
|
|
|
elif name == (NS_IETF_XMPP_TLS, 'starttls'):
|
|
|
|
self.starttls = True
|
|
|
|
self.starttls = True
|
|
|
|
elif (
|
|
|
|
elif (
|
|
|
|
self.inelem[-2] == (NS_IETF_XMPP_TLS, 'starttls') and
|
|
|
|
self.in_elem[-2] == (NS_IETF_XMPP_TLS, 'starttls') and
|
|
|
|
name == (NS_IETF_XMPP_TLS, 'required')
|
|
|
|
name == (NS_IETF_XMPP_TLS, 'required')
|
|
|
|
):
|
|
|
|
):
|
|
|
|
self.tlsrequired = True
|
|
|
|
self.tls_required = True
|
|
|
|
_LOG.info("info other side requires TLS")
|
|
|
|
_LOG.info("info other side requires TLS")
|
|
|
|
elif name == (NS_JABBER_CAPS, 'c'):
|
|
|
|
elif name == (NS_JABBER_CAPS, 'c'):
|
|
|
|
for qname in attrs.getQNames():
|
|
|
|
for qname in attrs.getQNames():
|
|
|
|
self.capabilities[qname] = attrs.getValueByQName(qname)
|
|
|
|
self.capabilities[qname] = attrs.getValueByQName(qname)
|
|
|
|
elif name == (NS_ETHERX_STREAMS, 'error'):
|
|
|
|
elif name == (NS_ETHERX_STREAMS, 'error'):
|
|
|
|
self.state = XMPP_STATE_ERROR
|
|
|
|
self.state = XMPP_STATE_ERROR
|
|
|
|
self.errorinstance = XmppStreamError()
|
|
|
|
self.error_instance = XmppStreamError()
|
|
|
|
elif (
|
|
|
|
elif (
|
|
|
|
self.state == XMPP_STATE_ERROR and
|
|
|
|
self.state == XMPP_STATE_ERROR and
|
|
|
|
name != (NS_IETF_XMPP_STREAMS, 'text')
|
|
|
|
name != (NS_IETF_XMPP_STREAMS, 'text')
|
|
|
|
):
|
|
|
|
):
|
|
|
|
if name[0] == NS_IETF_XMPP_STREAMS:
|
|
|
|
if name[0] == NS_IETF_XMPP_STREAMS:
|
|
|
|
self.errorinstance.condition = name[1]
|
|
|
|
self.error_instance.condition = name[1]
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
self.errorinstance.other_elements[name] = {'attrs': dict([
|
|
|
|
self.error_instance.other_elements[name] = {'attrs': dict([
|
|
|
|
(qname, attrs.getValueByQName(qname)) for
|
|
|
|
(qname, attrs.getValueByQName(qname)) for
|
|
|
|
qname in attrs.getQNames()
|
|
|
|
qname in attrs.getQNames()
|
|
|
|
])}
|
|
|
|
])}
|
|
|
@ -138,25 +142,25 @@ class XmppResponseHandler(ContentHandler):
|
|
|
|
self.state = XMPP_STATE_FINISHED
|
|
|
|
self.state = XMPP_STATE_FINISHED
|
|
|
|
elif name == (NS_ETHERX_STREAMS, 'error'):
|
|
|
|
elif name == (NS_ETHERX_STREAMS, 'error'):
|
|
|
|
raise XmppException("XMPP stream error: {error}".format(
|
|
|
|
raise XmppException("XMPP stream error: {error}".format(
|
|
|
|
error=self.errorinstance))
|
|
|
|
error=self.error_instance))
|
|
|
|
elif name == (NS_IETF_XMPP_TLS, 'proceed'):
|
|
|
|
elif name == (NS_IETF_XMPP_TLS, 'proceed'):
|
|
|
|
self.state = XMPP_STATE_PROCEED_STARTTLS
|
|
|
|
self.state = XMPP_STATE_PROCEED_STARTTLS
|
|
|
|
elif name == (NS_IETF_XMPP_TLS, 'failure'):
|
|
|
|
elif name == (NS_IETF_XMPP_TLS, 'failure'):
|
|
|
|
raise XmppException("starttls initiation failed")
|
|
|
|
raise XmppException("starttls initiation failed")
|
|
|
|
_LOG.debug('end %s', name)
|
|
|
|
_LOG.debug('end %s', name)
|
|
|
|
del self.inelem[-1]
|
|
|
|
del self.in_elem[-1]
|
|
|
|
|
|
|
|
|
|
|
|
def characters(self, content):
|
|
|
|
def characters(self, content):
|
|
|
|
elem = self.inelem[-1]
|
|
|
|
elem = self.in_elem[-1]
|
|
|
|
if elem == (NS_IETF_XMPP_SASL, 'mechanism'):
|
|
|
|
if elem == (NS_IETF_XMPP_SASL, 'mechanism'):
|
|
|
|
self.mechanisms.append(content)
|
|
|
|
self.mechanisms.append(content)
|
|
|
|
elif self.state == XMPP_STATE_ERROR:
|
|
|
|
elif self.state == XMPP_STATE_ERROR:
|
|
|
|
if elem == (NS_IETF_XMPP_STREAMS, 'text'):
|
|
|
|
if elem == (NS_IETF_XMPP_STREAMS, 'text'):
|
|
|
|
self.errorinstance.text = content
|
|
|
|
self.error_instance.text = content
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
self.errorinstance.other_elements[elem]['text'] = content
|
|
|
|
self.error_instance.other_elements[elem]['text'] = content
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
_LOG.warning('ignored content in %s: %s', self.inelem, content)
|
|
|
|
_LOG.warning('ignored content in %s: %s', self.in_elem, content)
|
|
|
|
|
|
|
|
|
|
|
|
def is_valid_start(self):
|
|
|
|
def is_valid_start(self):
|
|
|
|
if not self.state == XMPP_STATE_RECEIVED_FEATURES:
|
|
|
|
if not self.state == XMPP_STATE_RECEIVED_FEATURES:
|
|
|
@ -164,14 +168,43 @@ class XmppResponseHandler(ContentHandler):
|
|
|
|
if self.expect_starttls is True and self.starttls is False:
|
|
|
|
if self.expect_starttls is True and self.starttls is False:
|
|
|
|
raise XmppException('expected STARTTLS capable service')
|
|
|
|
raise XmppException('expected STARTTLS capable service')
|
|
|
|
if (
|
|
|
|
if (
|
|
|
|
'version' not in self.streaminfo or
|
|
|
|
'version' not in self.stream_info or
|
|
|
|
self.streaminfo['version'] != '1.0'
|
|
|
|
self.stream_info['version'] != '1.0'
|
|
|
|
):
|
|
|
|
):
|
|
|
|
_LOG.warning(
|
|
|
|
_LOG.warning(
|
|
|
|
'unknown stream version %s', self.streaminfo['version'])
|
|
|
|
'unknown stream version %s', self.stream_info['version'])
|
|
|
|
return True
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def open_socket(addrinfo):
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
Open a client socket based on information in the addrinfo list of
|
|
|
|
|
|
|
|
tuples.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
new_socket = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for res in addrinfo:
|
|
|
|
|
|
|
|
af, socktype, proto, canonname, sa = res
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
|
|
new_socket = socket.socket(af, socktype, proto)
|
|
|
|
|
|
|
|
except socket.error:
|
|
|
|
|
|
|
|
new_socket = None
|
|
|
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
|
|
new_socket.connect(sa)
|
|
|
|
|
|
|
|
except socket.error:
|
|
|
|
|
|
|
|
new_socket.close()
|
|
|
|
|
|
|
|
new_socket = None
|
|
|
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if new_socket is None:
|
|
|
|
|
|
|
|
raise XmppException("could not open socket")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return new_socket
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Xmpp(nagiosplugin.Resource):
|
|
|
|
class Xmpp(nagiosplugin.Resource):
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
Xmpp resource.
|
|
|
|
Xmpp resource.
|
|
|
@ -180,7 +213,9 @@ class Xmpp(nagiosplugin.Resource):
|
|
|
|
state = nagiosplugin.Unknown
|
|
|
|
state = nagiosplugin.Unknown
|
|
|
|
cause = None
|
|
|
|
cause = None
|
|
|
|
socket = None
|
|
|
|
socket = None
|
|
|
|
daysleft = None
|
|
|
|
days_left = None
|
|
|
|
|
|
|
|
parser = None
|
|
|
|
|
|
|
|
content_handler = None
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(
|
|
|
|
def __init__(
|
|
|
|
self, host_address, port, ipv6, is_server, starttls,
|
|
|
|
self, host_address, port, ipv6, is_server, starttls,
|
|
|
@ -192,8 +227,8 @@ class Xmpp(nagiosplugin.Resource):
|
|
|
|
self.is_server = is_server
|
|
|
|
self.is_server = is_server
|
|
|
|
self.starttls = starttls
|
|
|
|
self.starttls = starttls
|
|
|
|
self.servername = servername
|
|
|
|
self.servername = servername
|
|
|
|
self.checkcerts = checkcerts
|
|
|
|
self.check_certs = checkcerts
|
|
|
|
self.caroots = caroots
|
|
|
|
self.ca_roots = caroots
|
|
|
|
self.make_parser()
|
|
|
|
self.make_parser()
|
|
|
|
self.set_content_handler()
|
|
|
|
self.set_content_handler()
|
|
|
|
|
|
|
|
|
|
|
@ -210,50 +245,25 @@ class Xmpp(nagiosplugin.Resource):
|
|
|
|
Set the XMPP SAX content handler.
|
|
|
|
Set the XMPP SAX content handler.
|
|
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
self.contenthandler = XmppResponseHandler(
|
|
|
|
self.content_handler = XmppResponseHandler(
|
|
|
|
expect_starttls=self.starttls)
|
|
|
|
expect_starttls=self.starttls)
|
|
|
|
self.parser.setContentHandler(self.contenthandler)
|
|
|
|
self.parser.setContentHandler(self.content_handler)
|
|
|
|
|
|
|
|
|
|
|
|
def get_addrinfo(self):
|
|
|
|
def get_addr_info(self):
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
Perform the DNS lookup and return a list of potential socket address
|
|
|
|
Perform the DNS lookup and return a list of potential socket address
|
|
|
|
tuples as returned by :py:method:`socket.getaddrinfo`.
|
|
|
|
tuples as returned by :py:method:`socket.getaddrinfo`.
|
|
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
if self.ipv6 is None:
|
|
|
|
if self.ipv6 is None:
|
|
|
|
addrfamily = 0
|
|
|
|
addr_family = 0
|
|
|
|
elif self.ipv6 is True:
|
|
|
|
elif self.ipv6 is True:
|
|
|
|
addrfamily = socket.AF_INET6
|
|
|
|
addr_family = socket.AF_INET6
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
addrfamily = socket.AF_INET
|
|
|
|
addr_family = socket.AF_INET
|
|
|
|
return socket.getaddrinfo(
|
|
|
|
return socket.getaddrinfo(
|
|
|
|
self.address, self.port, addrfamily, socket.SOCK_STREAM,
|
|
|
|
self.address, self.port, addr_family, socket.SOCK_STREAM,
|
|
|
|
socket.IPPROTO_TCP)
|
|
|
|
socket.IPPROTO_TCP)
|
|
|
|
self.result = nagiosplugin.Critical
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def open_socket(self, addrinfo):
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
Open a client socket based on information in the addrinfo list of
|
|
|
|
|
|
|
|
tuples.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
for res in addrinfo:
|
|
|
|
|
|
|
|
af, socktype, proto, canonname, sa = res
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
|
|
s = socket.socket(af, socktype, proto)
|
|
|
|
|
|
|
|
except socket.error:
|
|
|
|
|
|
|
|
s = None
|
|
|
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
|
|
s.connect(sa)
|
|
|
|
|
|
|
|
except socket.error:
|
|
|
|
|
|
|
|
s.close()
|
|
|
|
|
|
|
|
s = None
|
|
|
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
break
|
|
|
|
|
|
|
|
if s is None:
|
|
|
|
|
|
|
|
raise XmppException("could not open socket")
|
|
|
|
|
|
|
|
return s
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def handle_xmpp_stanza(
|
|
|
|
def handle_xmpp_stanza(
|
|
|
|
self, message_str, timeout=0.1, expected_state=None
|
|
|
|
self, message_str, timeout=0.1, expected_state=None
|
|
|
@ -283,37 +293,28 @@ class Xmpp(nagiosplugin.Resource):
|
|
|
|
chunks.append(data)
|
|
|
|
chunks.append(data)
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
break
|
|
|
|
break
|
|
|
|
xmltext = b''.join(chunks).decode('utf-8')
|
|
|
|
xml_text = b''.join(chunks).decode('utf-8')
|
|
|
|
_LOG.debug("read %s", xmltext)
|
|
|
|
_LOG.debug("read %s", xml_text)
|
|
|
|
self.parser.feed(xmltext)
|
|
|
|
self.parser.feed(xml_text)
|
|
|
|
if (
|
|
|
|
if (
|
|
|
|
expected_state is not None and
|
|
|
|
expected_state is not None and
|
|
|
|
self.contenthandler.state != expected_state
|
|
|
|
self.content_handler.state != expected_state
|
|
|
|
):
|
|
|
|
):
|
|
|
|
raise XmppException(
|
|
|
|
raise XmppException(
|
|
|
|
"unexpected state %s" % self.contenthandler.state)
|
|
|
|
"unexpected state %s" % self.content_handler.state)
|
|
|
|
|
|
|
|
|
|
|
|
def start_stream(self):
|
|
|
|
def start_stream(self):
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
Start a XMPP conversation with the server.
|
|
|
|
Start a XMPP conversation with the server.
|
|
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
if self.is_server:
|
|
|
|
namespace = "jabber:server" if self.is_server else "jabber:client"
|
|
|
|
self.handle_xmpp_stanza((
|
|
|
|
|
|
|
|
"<?xml version='1.0' ?><stream:stream to='{servername}' "
|
|
|
|
self.handle_xmpp_stanza(
|
|
|
|
"xmlns='jabber:server' "
|
|
|
|
f"<stream:stream xmlns:stream='{NS_ETHERX_STREAMS}' xmlns='{namespace}' to='{self.servername}'"
|
|
|
|
"xmlns:stream='http://etherx.jabber.org/streams' "
|
|
|
|
f" version='1.0'>",
|
|
|
|
"version='1.0'>"
|
|
|
|
expected_state=XMPP_STATE_RECEIVED_FEATURES
|
|
|
|
).format(servername=self.servername),
|
|
|
|
)
|
|
|
|
expected_state=XMPP_STATE_RECEIVED_FEATURES)
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
self.handle_xmpp_stanza((
|
|
|
|
|
|
|
|
"<?xml version='1.0' ?><stream:stream to='{servername}' "
|
|
|
|
|
|
|
|
"xmlns='jabber:client' "
|
|
|
|
|
|
|
|
"xmlns:stream='http://etherx.jabber.org/streams' "
|
|
|
|
|
|
|
|
"version='1.0'>"
|
|
|
|
|
|
|
|
).format(servername=self.servername),
|
|
|
|
|
|
|
|
expected_state=XMPP_STATE_RECEIVED_FEATURES)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def setup_ssl_context(self):
|
|
|
|
def setup_ssl_context(self):
|
|
|
|
"""
|
|
|
|
"""
|
|
|
@ -321,17 +322,16 @@ class Xmpp(nagiosplugin.Resource):
|
|
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
context = ssl.create_default_context()
|
|
|
|
context = ssl.create_default_context()
|
|
|
|
context.options = ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3
|
|
|
|
if not self.check_certs:
|
|
|
|
if not self.checkcerts:
|
|
|
|
|
|
|
|
context.check_hostname = False
|
|
|
|
context.check_hostname = False
|
|
|
|
context.verify_mode = ssl.CERT_NONE
|
|
|
|
context.verify_mode = ssl.CERT_NONE
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
context.verify_mode = ssl.CERT_REQUIRED
|
|
|
|
context.verify_mode = ssl.CERT_REQUIRED
|
|
|
|
if self.caroots:
|
|
|
|
if self.ca_roots:
|
|
|
|
if os.path.isfile(self.caroots):
|
|
|
|
if os.path.isfile(self.ca_roots):
|
|
|
|
kwargs = {'cafile': self.caroots}
|
|
|
|
kwargs = {'cafile': self.ca_roots}
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
kwargs = {'capath': self.caroots}
|
|
|
|
kwargs = {'capath': self.ca_roots}
|
|
|
|
context.load_verify_locations(**kwargs)
|
|
|
|
context.load_verify_locations(**kwargs)
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
context.load_default_certs()
|
|
|
|
context.load_default_certs()
|
|
|
@ -346,21 +346,22 @@ class Xmpp(nagiosplugin.Resource):
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
_LOG.debug("start initiate_tls()")
|
|
|
|
_LOG.debug("start initiate_tls()")
|
|
|
|
self.handle_xmpp_stanza(
|
|
|
|
self.handle_xmpp_stanza(
|
|
|
|
"<starttls xmlns='{xmlns}'/>".format(xmlns=NS_IETF_XMPP_TLS),
|
|
|
|
f"<starttls xmlns='{NS_IETF_XMPP_TLS}'/>",
|
|
|
|
|
|
|
|
timeout=0.5,
|
|
|
|
expected_state=XMPP_STATE_PROCEED_STARTTLS)
|
|
|
|
expected_state=XMPP_STATE_PROCEED_STARTTLS)
|
|
|
|
sslcontext = self.setup_ssl_context()
|
|
|
|
sslcontext = self.setup_ssl_context()
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
self.socket = sslcontext.wrap_socket(
|
|
|
|
self.socket = sslcontext.wrap_socket(
|
|
|
|
self.socket, server_hostname=self.servername)
|
|
|
|
self.socket, server_hostname=self.servername)
|
|
|
|
_LOG.info("TLS socket setup successful")
|
|
|
|
_LOG.info("TLS socket setup successful")
|
|
|
|
except ssl.SSLError as ssle:
|
|
|
|
except ssl.CertificateError as certificate_error:
|
|
|
|
raise XmppException("SSL error %s" % ssle.strerror)
|
|
|
|
raise XmppException("Certificate error %s" % certificate_error)
|
|
|
|
except ssl.CertificateError as certerr:
|
|
|
|
except ssl.SSLError as ssl_error:
|
|
|
|
raise XmppException("Certificate error %s" % certerr)
|
|
|
|
raise XmppException("SSL error %s" % ssl_error.strerror)
|
|
|
|
self.starttls = False
|
|
|
|
self.starttls = False
|
|
|
|
# reset infos retrieved previously as written in RFC 3920 sec. 5.
|
|
|
|
# reset infos retrieved previously as written in RFC 3920 sec. 5.
|
|
|
|
self.parser.reset()
|
|
|
|
self.parser.reset()
|
|
|
|
if self.checkcerts:
|
|
|
|
if self.check_certs:
|
|
|
|
certinfo = self.socket.getpeercert()
|
|
|
|
certinfo = self.socket.getpeercert()
|
|
|
|
_LOG.debug("got the following certificate info: %s", certinfo)
|
|
|
|
_LOG.debug("got the following certificate info: %s", certinfo)
|
|
|
|
_LOG.info(
|
|
|
|
_LOG.info(
|
|
|
@ -368,12 +369,12 @@ class Xmpp(nagiosplugin.Resource):
|
|
|
|
certinfo['notBefore'], certinfo['notAfter'])
|
|
|
|
certinfo['notBefore'], certinfo['notAfter'])
|
|
|
|
enddate = ssl.cert_time_to_seconds(certinfo['notAfter'])
|
|
|
|
enddate = ssl.cert_time_to_seconds(certinfo['notAfter'])
|
|
|
|
remaining = datetime.fromtimestamp(enddate) - datetime.now()
|
|
|
|
remaining = datetime.fromtimestamp(enddate) - datetime.now()
|
|
|
|
self.daysleft = remaining.days
|
|
|
|
self.days_left = remaining.days
|
|
|
|
# start new parsing
|
|
|
|
# start new parsing
|
|
|
|
self.make_parser()
|
|
|
|
self.make_parser()
|
|
|
|
self.set_content_handler()
|
|
|
|
self.set_content_handler()
|
|
|
|
self.start_stream()
|
|
|
|
self.start_stream()
|
|
|
|
if not self.contenthandler.is_valid_start():
|
|
|
|
if not self.content_handler.is_valid_start():
|
|
|
|
raise XmppException("no valid response to XMPP client request")
|
|
|
|
raise XmppException("no valid response to XMPP client request")
|
|
|
|
_LOG.debug("end initiate_tls()")
|
|
|
|
_LOG.debug("end initiate_tls()")
|
|
|
|
|
|
|
|
|
|
|
@ -384,9 +385,9 @@ class Xmpp(nagiosplugin.Resource):
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
_LOG.debug("start handle_xmpp()")
|
|
|
|
_LOG.debug("start handle_xmpp()")
|
|
|
|
self.start_stream()
|
|
|
|
self.start_stream()
|
|
|
|
if not self.contenthandler.is_valid_start():
|
|
|
|
if not self.content_handler.is_valid_start():
|
|
|
|
raise XmppException("no valid response to XMPP client request")
|
|
|
|
raise XmppException("no valid response to XMPP client request")
|
|
|
|
if self.starttls is True or self.contenthandler.tlsrequired:
|
|
|
|
if self.starttls is True or self.content_handler.tls_required:
|
|
|
|
self.initiate_tls()
|
|
|
|
self.initiate_tls()
|
|
|
|
self.handle_xmpp_stanza("</stream:stream>")
|
|
|
|
self.handle_xmpp_stanza("</stream:stream>")
|
|
|
|
_LOG.debug("end handle_xmpp()")
|
|
|
|
_LOG.debug("end handle_xmpp()")
|
|
|
@ -400,8 +401,8 @@ class Xmpp(nagiosplugin.Resource):
|
|
|
|
start = datetime.now()
|
|
|
|
start = datetime.now()
|
|
|
|
_LOG.debug("start probe() at %s", start)
|
|
|
|
_LOG.debug("start probe() at %s", start)
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
addrinfo = self.get_addrinfo()
|
|
|
|
addrinfo = self.get_addr_info()
|
|
|
|
self.socket = self.open_socket(addrinfo)
|
|
|
|
self.socket = open_socket(addrinfo)
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
self.handle_xmpp()
|
|
|
|
self.handle_xmpp()
|
|
|
|
finally:
|
|
|
|
finally:
|
|
|
@ -422,7 +423,7 @@ class Xmpp(nagiosplugin.Resource):
|
|
|
|
_LOG.debug("end probe() at %s", end)
|
|
|
|
_LOG.debug("end probe() at %s", end)
|
|
|
|
yield nagiosplugin.Metric(
|
|
|
|
yield nagiosplugin.Metric(
|
|
|
|
'time', (end - start).total_seconds(), 's', min=0)
|
|
|
|
'time', (end - start).total_seconds(), 's', min=0)
|
|
|
|
yield nagiosplugin.Metric('daysleft', self.daysleft, 'd')
|
|
|
|
yield nagiosplugin.Metric('daysleft', self.days_left, 'd')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class XmppContext(nagiosplugin.ScalarContext):
|
|
|
|
class XmppContext(nagiosplugin.ScalarContext):
|
|
|
@ -461,7 +462,7 @@ class DaysValidContext(nagiosplugin.Context):
|
|
|
|
self.critdays = critdays
|
|
|
|
self.critdays = critdays
|
|
|
|
|
|
|
|
|
|
|
|
def evaluate(self, metric, resource):
|
|
|
|
def evaluate(self, metric, resource):
|
|
|
|
if resource.checkcerts and metric.value is not None:
|
|
|
|
if resource.check_certs and metric.value is not None:
|
|
|
|
if self.critical.match(metric.value):
|
|
|
|
if self.critical.match(metric.value):
|
|
|
|
return nagiosplugin.Result(
|
|
|
|
return nagiosplugin.Result(
|
|
|
|
nagiosplugin.Critical,
|
|
|
|
nagiosplugin.Critical,
|
|
|
@ -477,7 +478,7 @@ class DaysValidContext(nagiosplugin.Context):
|
|
|
|
return nagiosplugin.Result(nagiosplugin.Ok)
|
|
|
|
return nagiosplugin.Result(nagiosplugin.Ok)
|
|
|
|
|
|
|
|
|
|
|
|
def performance(self, metric, resource):
|
|
|
|
def performance(self, metric, resource):
|
|
|
|
if resource.checkcerts and metric.value is not None:
|
|
|
|
if resource.check_certs and metric.value is not None:
|
|
|
|
return nagiosplugin.Performance('daysvalid', metric.value, '')
|
|
|
|
return nagiosplugin.Performance('daysvalid', metric.value, '')
|
|
|
|
return None
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|