Compare commits

..

25 commits

Author SHA1 Message Date
ea68a363ca Fix Python 3.11 STARTTLS handling 2023-08-04 19:35:27 +02:00
c8f93d56dc Release 0.3.2
- Update version and copyright information
- Update changelog and icingaexchange.yml
2021-03-07 14:14:06 +01:00
16e8cb41fe Improve README
- Update dependency versions to those of Debian Buster
- link to bug tracker
- fix minor formatting issues
2021-03-07 14:14:06 +01:00
5438f7f089 Remove CA certificate statistics
The CA certificate statistics do not work with recent Python versions
and broke the plugin initialization.

Fixes #2
2021-03-07 14:14:06 +01:00
76fbb73233 Release 0.3.1 move project home
-----BEGIN PGP SIGNATURE-----
 
 iQFIBAABCgAyFiEEKHuXKkUYdvdO9493DXkdyNc3wdkFAl0P7+YUHGphbkBkaXR0
 YmVybmVyLmluZm8ACgkQDXkdyNc3wdlXPggAgnZzoLWWJvsA3Fl0CqjGCivl0Hdb
 WKJ8huOCPiSKU54AeqScilWDZ+G9ksi9PnqVcQ5U1Th4pAAC89f5ccHgulf64quR
 3wDcCHublhDYQqy8gijOH4Z/McB13nMWQpLN8sJQ97p76abCqhZhbo7Pd6b5Duuc
 mfKK67aBe28qMp0rQdobUvKtkLAbnLMc+L0Tejw/qC9F8SQ+z01W6B7Jn7FKXSPc
 cnrpktaIC2AjhU2xzdbAW29oyn8I0yC8xwFDCZ+qGgeaIMVnFxslo+XCdEurcBHk
 p1bAc86O9Qo4yA0tVWqLqSym4SCDeYPQ2D0YTLEb6zG/NtootNagy5Hgcw==
 =k2P6
 -----END PGP SIGNATURE-----

Merge tag '0.3.1'

Release 0.3.1 move project home
2019-06-23 23:32:26 +02:00
787115b4bb Merge branch 'release/0.3.1' into develop 2019-06-23 23:32:06 +02:00
9999c4e868 Update Icinga exchange metadata 2019-06-23 23:31:53 +02:00
57f1b5fb55 Update changes.md 2019-06-23 23:26:19 +02:00
5f54f2ca45 Raise version number 2019-06-23 23:22:24 +02:00
cf0ec04526 Fix project URL 2019-06-23 23:16:21 +02:00
8be4413b45 Fix command name in README
Fixes #1
2019-06-23 23:11:41 +02:00
e4651d7dac Update project URL 2019-06-23 23:10:30 +02:00
1724ce9985 Release 0.3.0
-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQEcBAABCgAGBQJXZZ/pAAoJEA15HcjXN8HZb78IALVycFS0xR6zzUNmn23FHMoq
 SdhNeCgchKmm3Gpnp5Vgrbpqmkj2YXR90U8S3kQU2NO/K5UzeE3dWnVD3GTvzkCi
 T0K5TOuooIhD9c6qYYPd8h4gzYDvA27iK1l0nv0U6teVIIxmXeRAIKa8goipJJlN
 NcdwrppCRJlXguqB8AcISAq048d2Q/Ut/E0mB/T1qAuZc1bHLsYFpamiAA9fS9yR
 SYPOEqChFZheG1Zbv3bMYy4RM00JwhxU/l7h+lN60FCTBuNFOXJsMr7s4iE5PkPA
 9HnOC+hyl/bc0/9jsY5q3JzuBpMBKcZpjGWe55la3nzcwbMAFZhnNluGnB3QvvU=
 =ME53
 -----END PGP SIGNATURE-----

Merge tag '0.3.0' into develop

Release 0.3.0

* tag '0.3.0':
2016-06-18 21:24:30 +02:00
c76fa75126 Merge branch 'release/0.3.0'
* release/0.3.0:
  Add changelog entry and metadata for 0.3.0
  Add --hostname option
2016-06-18 21:24:23 +02:00
c0280cc713 Add changelog entry and metadata for 0.3.0 2016-06-18 21:17:54 +02:00
55ff04ba21 Add --hostname option
This commit adds a --hostname option that is mutually exclusive to
-H/--host-address. The idea is to make check_xmppng compatible with
check_v46. Thanks to Andreas Krause for the inspiration.
2016-06-18 21:13:17 +02:00
c7cce10d8e Release 0.2.1
-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQEcBAABCgAGBQJWo95QAAoJEA15HcjXN8HZ9j8IANvHb8cKtailuaxrGsU+yZr1
 jST51KE3Tw92L5nWt66kk8lOF9FJVJ2vzyqF+Rm8RaBuDYp2osTV/bwJzIbHruFl
 fMZpNhNBuVFlbCfxQA4aIdvpUQDN62RIANFHU+IOdjtCp85VAlzcjH6qyO7E92ug
 1cBYuS5612pmilcAywimWI0gNkx+Bd0SQC+a1YaL2lR8N/42ufIAuzgtzcoZSOjf
 0v46D2+l3xiHE0efRfWlXJhchrcpfhw9n9msJjwVEOVO/PiLCzJEZNJxt6uar3Rh
 Lzt7hny+pv7rubN78rvhAgARhwjsCaQFR4aJWs87z33KuHTFizFtFRwgW+kKbLk=
 =ty7q
 -----END PGP SIGNATURE-----

Merge tag '0.2.1' into develop

Release 0.2.1

* tag '0.2.1':
  Update changes.md and icingaexchange.yml
2016-01-23 21:10:57 +01:00
827b00dff8 Merge branch 'release/0.2.1'
* release/0.2.1:
  Update changes.md and icingaexchange.yml
  Fix performance data output
2016-01-23 21:10:53 +01:00
6a4254c8a5 Update changes.md and icingaexchange.yml 2016-01-23 21:10:08 +01:00
2c50b91b1a Fix performance data output
This commit fixes the unit of measure of daysvalid to be conformant to
the performance data specification at
http://docs.icinga.org/latest/de/perfdata.html#pluginperfdata by
omiting the invalid unit 'd' at the end of the value.
2016-01-23 20:48:32 +01:00
e8b04bd40d Release 0.2
-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQEcBAABCgAGBQJWgvqrAAoJEA15HcjXN8HZ+hQIAJ1cZ0OXpfGTKcrfkv3OwVoO
 ZdfrgjBVqLp3PaMRUADNG/5VHl2VpBvwkOlWKZIcUJQZtB0iRPa6HEh+dPhLCP5+
 pC8R5kXI1TdmBH3SRs7kF20MpQKCIobWuPjMzkSW1D+0iqKXrGK/Xgaq8CJCTKDT
 K0TjC4Y/bDOgLDMp0su1hAAx3lxM4gz7977NhI71UjZMnKk3IkNWIAVK1kMObrWB
 tCPC7LGaRs1DjR3HS5XZVcIaWPwKvxse4vqXPOECQYqtGWBu8PSIdXIheTfAmKXk
 trrEkQ7E3TwuhUEYIVxV+6j/sgjlbPi3qsCXvH/E55zYZ6MrKEE/kYtnqTxqVTo=
 =FPiU
 -----END PGP SIGNATURE-----

Merge tag '0.2' into develop

Release 0.2

* tag '0.2':
  Add new release to icingaexchange.yml
  Finalize version number
2015-12-29 22:27:07 +01:00
3469355a4b Merge branch 'release/0.2'
* release/0.2:
  Add new release to icingaexchange.yml
  Finalize version number
  Improve human readable output
2015-12-29 22:27:02 +01:00
f8e1a0eb38 Add new release to icingaexchange.yml 2015-12-29 22:25:30 +01:00
37351a87a0 Finalize version number 2015-12-29 22:25:03 +01:00
11a16bb362 Improve human readable output
This change introduces more readable and useful output by adding the
certificate expiration to the human readable string. The response time
is now formatted too.
2015-12-29 22:17:59 +01:00
13 changed files with 324 additions and 228 deletions

View file

@ -1,4 +1,4 @@
# check_xmppng - check plugin for XMPP # `check_xmppng` - check plugin for XMPP
This program implements a nagios check plugin for XMPP servers implementing the This program implements a nagios check plugin for XMPP servers implementing the
XMPP protocol as specified in [RFC 6120](http://tools.ietf.org/html/rfc6120). XMPP protocol as specified in [RFC 6120](http://tools.ietf.org/html/rfc6120).
@ -10,8 +10,9 @@ The program implements the following features:
* support STARTTLS as specified in RFC 6120 section 5. * support STARTTLS as specified in RFC 6120 section 5.
* check the validity of the server certificate presented by the XMPP server * check the validity of the server certificate presented by the XMPP server
The plugin has been implemented because of insufficiencies in check_ssl_cert The plugin has been implemented because of insufficiencies in `check_ssl_cert`
and the existing [check_xmpp](https://exchange.icinga.org/exchange/check_xmpp). and the existing
[`check_xmpp`](https://exchange.icinga.org/exchange/check_xmpp).
Maximum acceptable timeouts as well as minimum acceptable number of days the Maximum acceptable timeouts as well as minimum acceptable number of days the
server certificate needs to be valid can be specified as command line server certificate needs to be valid can be specified as command line
@ -30,14 +31,14 @@ the Python standard library:
The software has been developed and tested with the following versions: The software has been developed and tested with the following versions:
* Python 3.4.2 * Python 3.7.3
* defusedxml 0.4.1 * defusedxml 0.5.0
* nagiosplugin 1.2.2 * nagiosplugin 1.2.4
## License ## License
check_xmppng is free software: you can redistribute it and/or modify it under `check_xmppng` is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later Foundation, either version 3 of the License, or (at your option) any later
version. version.
@ -54,10 +55,10 @@ http://www.gnu.org/licenses/.
## Usage ## Usage
``` ```
usage: check_xmpp [-h] -H HOST_ADDRESS [-p PORT] [--s2s | --c2s] [-4 | -6] usage: check_xmppng [-h] -H HOST_ADDRESS [-p PORT] [--s2s | --c2s] [-4 | -6]
[--servername SERVERNAME] [--starttls] [-w SECONDS] [--servername SERVERNAME] [--starttls] [-w SECONDS]
[-c SECONDS] [--no-check-certificates] [-r CAROOTS] [-c SECONDS] [--no-check-certificates] [-r CAROOTS]
[--warn-days WARNDAYS] [--crit-days CRITDAYS] [-v] [--warn-days WARNDAYS] [--crit-days CRITDAYS] [-v]
Check XMPP services Check XMPP services
@ -95,5 +96,6 @@ optional arguments:
## Contact ## Contact
If you want to provide feedback or bug reports please send me a mail to If you want to provide feedback or bug reports please use the [bug
jan (at) dittberner [dot] info. tracker](https://git.dittberner.info/jan/check_xmppng/issues) or send me an
email to jan (at) dittberner [dot] info.

View file

@ -1,5 +1,31 @@
# change log # change log
## version 0.3.3 2023-08-04
* fix starttls behaviour with Python 3.11
## version 0.3.2 2021-03-07
* remove broken CA certificate statistics
## version 0.3.1 2019-06-23
* move to new project location
## version 0.3.0 2016-06-18
* add alternative --hostname parameter to make check_xmpp compatible with
check_v46 (thanks to Andreas Krause for the idea)
## version 0.2.1 2016-01-23
* fix perfdata output for daysvalid metric
## version 0.2 2015-12-29
* improve human readable output by returning both response time as well as
certificate expiry
## version 0.1.2 2015-02-11 ## version 0.1.2 2015-02-11
* first icinga exchange release * first icinga exchange release

View file

@ -2,7 +2,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Nagios compatible check for XMPP servers. # Nagios compatible check for XMPP servers.
# Copyright (C) 2015 Jan Dittberner # Copyright (C) 2015-2021 Jan Dittberner
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
@ -31,8 +31,7 @@ from defusedxml.sax import make_parser
import nagiosplugin import nagiosplugin
__author__ = "Jan Dittberner" __author__ = "Jan Dittberner"
__version__ = "0.1.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'
@ -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,11 +213,13 @@ 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,
servername, checkcerts, caroots servername, checkcerts, caroots
): ):
self.address = host_address self.address = host_address
self.port = port self.port = port
@ -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,53 +245,28 @@ 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
): ):
""" """
Handle a single XMPP message. Handle a single XMPP message.
@ -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,28 +322,19 @@ 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()
stats = context.cert_store_stats()
if stats['x509_ca'] == 0:
_LOG.info(
"tried to load CA certificates from default locations, but"
" could not find any CA certificates.")
raise XmppException('no CA certificates found')
else:
_LOG.debug('certificate store statistics: %s', stats)
return context return context
def initiate_tls(self): def initiate_tls(self):
@ -354,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(
@ -376,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()")
@ -392,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()")
@ -408,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:
@ -418,6 +411,7 @@ class Xmpp(nagiosplugin.Resource):
except socket.gaierror as e: except socket.gaierror as e:
self.state = nagiosplugin.Critical self.state = nagiosplugin.Critical
self.cause = str(e) self.cause = str(e)
_LOG.debug("got an gaierror %s", e)
return nagiosplugin.Metric("time", "unknown") return nagiosplugin.Metric("time", "unknown")
except XmppException as e: except XmppException as e:
self.state = nagiosplugin.Critical self.state = nagiosplugin.Critical
@ -429,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):
@ -455,31 +449,50 @@ class DaysValidContext(nagiosplugin.Context):
Context for checking the certificate expiry date. Context for checking the certificate expiry date.
""" """
fmt_hint = "less than {value} days"
def __init__( def __init__(
self, name, warndays=0, critdays=0, self, name, warndays=0, critdays=0,
fmt_metric='certificate expires in {value} days' fmt_metric='certificate valid for {value} days'
): ):
super(DaysValidContext, self).__init__(name, fmt_metric=fmt_metric) super(DaysValidContext, self).__init__(name, fmt_metric=fmt_metric)
self.warning = nagiosplugin.Range('@%d:' % warndays) self.warning = nagiosplugin.Range('@%d:' % warndays)
self.critical = nagiosplugin.Range('@%d:' % critdays) self.critical = nagiosplugin.Range('@%d:' % critdays)
self.warndays = warndays
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:
hint = self.describe(metric)
if self.critical.match(metric.value): if self.critical.match(metric.value):
return nagiosplugin.Result(nagiosplugin.Critical, hint, metric) return nagiosplugin.Result(
nagiosplugin.Critical,
hint=self.fmt_hint.format(value=self.critdays),
metric=metric)
if self.warning.match(metric.value): if self.warning.match(metric.value):
return nagiosplugin.Result(nagiosplugin.Warn, hint, metric) return nagiosplugin.Result(
return nagiosplugin.Result(nagiosplugin.Ok, hint, metric) nagiosplugin.Warn,
hint=self.fmt_hint.format(value=self.warndays),
metric=metric)
return nagiosplugin.Result(
nagiosplugin.Ok, "", metric)
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, 'd') return nagiosplugin.Performance('daysvalid', metric.value, '')
return None return None
class XmppSummary(nagiosplugin.Summary):
"""
Summary instance that outputs all metrics if the check results are ok.
"""
def ok(self, results):
return ", ".join([str(res) for res in results])
@nagiosplugin.guarded @nagiosplugin.guarded
def main(): def main():
""" """
@ -488,8 +501,11 @@ def main():
""" """
import argparse import argparse
parser = argparse.ArgumentParser(description="Check XMPP services") parser = argparse.ArgumentParser(description="Check XMPP services")
parser.add_argument( host_address = parser.add_mutually_exclusive_group(required=True)
"-H", "--host-address", help="host address", required=True) host_address.add_argument("-H", "--host-address", help="host address")
host_address.add_argument(
"--hostname", help="host name, alternative for host-address",
dest="host_address")
parser.add_argument( parser.add_argument(
"-p", "--port", help="port", type=int) "-p", "--port", help="port", type=int)
is_server = parser.add_mutually_exclusive_group() is_server = parser.add_mutually_exclusive_group()
@ -551,8 +567,10 @@ def main():
] ]
check = nagiosplugin.Check( check = nagiosplugin.Check(
Xmpp(**kwargs), Xmpp(**kwargs),
XmppContext('time', warning, critical), XmppContext(
DaysValidContext('daysleft', warndays, critdays) 'time', warning, critical, fmt_metric="request took {value}{uom}"),
DaysValidContext('daysleft', warndays, critdays),
XmppSummary(),
) )
check.main(verbose=verbose, timeout=0) check.main(verbose=verbose, timeout=0)

12
debian/changelog vendored
View file

@ -1,12 +0,0 @@
nagios-check-xmppng (0.1.2-1~bpo8+1) jessie-backports; urgency=medium
* Rebuild for jessie-backports.
* set jessie-backports as debian branch in debian/gbp.conf
-- Jan Dittberner <jandd@debian.org> Sun, 20 Sep 2015 18:38:33 +0200
nagios-check-xmppng (0.1.2-1) unstable; urgency=medium
* Initial release. (Closes: #777732)
-- Jan Dittberner <jandd@debian.org> Thu, 12 Feb 2015 00:49:30 +0100

1
debian/compat vendored
View file

@ -1 +0,0 @@
9

30
debian/control vendored
View file

@ -1,30 +0,0 @@
Source: nagios-check-xmppng
Section: net
Priority: extra
Maintainer: Jan Dittberner <jandd@debian.org>
Homepage: https://exchange.icinga.org/jandd/check_xmppng
Build-Depends: debhelper (>= 9)
Standards-Version: 3.9.6
Vcs-Browser: https://git.dittberner.info/?p=check_xmpp.git
Vcs-Git: https://git.dittberner.info/check_xmpp.git -b debian
Package: nagios-check-xmppng
Architecture: all
Depends: python3 (>= 3.4),
python3-defusedxml (>= 0.4.1),
python3-nagiosplugin (>= 1.2.2),
${misc:Depends}
Suggests: icinga | icinga2 | nagios3
Description: monitoring plugin to check XMPP servers
a nagios compatible check plugin for XMPP servers implementing the XMPP
protocol as specified in RFC 6120.
.
The plugin provides the following features:
.
- check client to server (C2S) as well as server to server (S2S) ports
- check XMPP servers on IPv6 and IPv4 addresses
- support STARTTLS as specified in RFC 6120 section 5.
- check the validity of the server certificate presented by the XMPP server
.
The plugin has been implemented because of insufficiencies in the existing
check_ssl_cert and check_xmpp plugins.

24
debian/copyright vendored
View file

@ -1,24 +0,0 @@
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: check_xmppng
Upstream-Contact: Jan Dittberner <jan@dittberner.info>
Source: https://git.dittberner.info/?p=check_xmpp.git
Files: *
Copyright: 2015 Jan Dittberner
License: GPL-3
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
.
On Debian systems, the full text of the GNU General Public
License version 3 can be found in the file
`/usr/share/common-licenses/GPL-3'.

1
debian/docs vendored
View file

@ -1 +0,0 @@
README.md

8
debian/gbp.conf vendored
View file

@ -1,8 +0,0 @@
[DEFAULT]
debian-branch = jessie-backports
upstream-branch = master
upstream-tag = %(version)s
no-create-orig = True
[import-orig]
pristine-tar = False

1
debian/install vendored
View file

@ -1 +0,0 @@
check_xmppng /usr/lib/nagios/plugins/

10
debian/rules vendored
View file

@ -1,10 +0,0 @@
#!/usr/bin/make -f
# -*- makefile -*-
#export DH_VERBOSE=1
override_dh_installchangelogs:
dh_installchangelogs changes.md
%:
dh $@

View file

@ -1 +0,0 @@
3.0 (quilt)

View file

@ -1,12 +1,150 @@
name: check_xmppng name: check_xmppng
description: "file:///README.md" description: "file:///README.md"
url: "https://git.dittberner.info/?p=check_xmpp.git" url: "https://git.dittberner.info/jan/check_xmppng"
tags: XMPP, X.509 tags: XMPP, X.509
vendor: vendor:
target: Messaging target: Messaging
type: Plugin type: Plugin
license: gplv3 license: gplv3
releases: releases:
- name: 0.3.3
description: "fix CA certificate check"
files:
-
name: check_xmppng
url: "file:///check_xmppng"
description: "Check command"
checksum: fdf942cb5c778aaa395a0ed1eba6dcda
-
name: COPYING
url: "file:///COPYING"
description: "GPL 3.0 license text"
checksum: d32239bcb673463ab874e80d47fae504
-
name: README.md
url: "file:///README.md"
description: "documentation"
checksum: 701ad7a882406a1f552a118d471a0b45
-
name: changes.md
url: "file:///changes.md"
description: "change log"
checksum: 0e23c919b413a4214c323b1953909c14
- name: 0.3.2
description: "fix CA certificate check"
files:
-
name: check_xmppng
url: "file:///check_xmppng"
description: "Check command"
checksum: e0ded038e79a2538d3b0c99cdc599810
-
name: COPYING
url: "file:///COPYING"
description: "GPL 3.0 license text"
checksum: d32239bcb673463ab874e80d47fae504
-
name: README.md
url: "file:///README.md"
description: "documentation"
checksum: 701ad7a882406a1f552a118d471a0b45
-
name: changes.md
url: "file:///changes.md"
description: "change log"
checksum: 60adfa1bf31c5a5fefb57ca55d186c7b
- name: 0.3.1
description: "new project home"
files:
-
name: check_xmppng
url: "file:///check_xmppng"
description: "Check command"
checksum: 3ba088ad712e7eff3897b0be70dc5437
-
name: COPYING
url: "file:///COPYING"
description: "GPL 3.0 license text"
checksum: d32239bcb673463ab874e80d47fae504
-
name: README.md
url: "file:///README.md"
description: "documentation"
checksum: 1e6f6632b12e4ef5fc4f02c3ea65da8a
-
name: changes.md
url: "file:///changes.md"
description: "change log"
checksum: df32115e17a931a083c2c9065c998147
- name: 0.3.0
description: "add --hostname option"
files:
-
name: check_xmppng
url: "file:///check_xmppng"
description: "Check command"
checksum: 9774a26db6c54af4a51902b90ffe13bc
-
name: COPYING
url: "file:///COPYING"
description: "GPL 3.0 license text"
checksum: d32239bcb673463ab874e80d47fae504
-
name: README.md
url: "file:///README.md"
description: "documentation"
checksum: 1e6f6632b12e4ef5fc4f02c3ea65da8a
-
name: changes.md
url: "file:///changes.md"
description: "change log"
checksum: f2c1f311817cbb51eac4c62b9c097579
- name: 0.2.1
description: "fixed perfdata output"
files:
-
name: check_xmppng
url: "file:///check_xmppng"
description: "Check command"
checksum: 992ee1b3209bba6ddb29b46c939b2978
-
name: COPYING
url: "file:///COPYING"
description: "GPL 3.0 license text"
checksum: d32239bcb673463ab874e80d47fae504
-
name: README.md
url: "file:///README.md"
description: "documentation"
checksum: 1e6f6632b12e4ef5fc4f02c3ea65da8a
-
name: changes.md
url: "file:///changes.md"
description: "change log"
checksum: a7a17e05c732e24f7b0529fb868a172f
- name: 0.2
description: "better human readable output"
files:
-
name: check_xmppng
url: "file:///check_xmppng"
description: "Check command"
checksum: 7369095c7daad89e04e0fbdd81ef0e00
-
name: COPYING
url: "file:///COPYING"
description: "GPL 3.0 license text"
checksum: d32239bcb673463ab874e80d47fae504
-
name: README.md
url: "file:///README.md"
description: "documentation"
checksum: 1e6f6632b12e4ef5fc4f02c3ea65da8a
-
name: changes.md
url: "file:///changes.md"
description: "change log"
checksum: f09a79d4762efc8c5a97e6d9f301b398
- -
name: 0.1.2 name: 0.1.2
description: "first icingaexchange release" description: "first icingaexchange release"