From ec1f73e7b1ff8b396b39978e7945b49271870d27 Mon Sep 17 00:00:00 2001 From: "th.l" <thl-cmk@outlook.com> Date: Sat, 4 Dec 2021 13:40:55 +0100 Subject: [PATCH] update project --- active_check_traceroute.mkp | Bin 0 -> 7345 bytes checks/check_traceroute | 69 +++++ lib/nagios/plugins/check_traceroute | 297 ++++++++++++++++++++++ packages/active_check_traceroute | 37 +++ web/plugins/metrics/traceroute.py | 32 +++ web/plugins/wato/active_checks_routing.py | 179 +++++++++++++ 6 files changed, 614 insertions(+) create mode 100644 active_check_traceroute.mkp create mode 100644 checks/check_traceroute create mode 100755 lib/nagios/plugins/check_traceroute create mode 100644 packages/active_check_traceroute create mode 100644 web/plugins/metrics/traceroute.py create mode 100644 web/plugins/wato/active_checks_routing.py diff --git a/active_check_traceroute.mkp b/active_check_traceroute.mkp new file mode 100644 index 0000000000000000000000000000000000000000..1fa711dfb8738d7caf5ba8e42dfd15a0da11910e GIT binary patch literal 7345 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 literal 0 HcmV?d00001 diff --git a/checks/check_traceroute b/checks/check_traceroute new file mode 100644 index 0000000..a0eec4b --- /dev/null +++ b/checks/check_traceroute @@ -0,0 +1,69 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# Copyright (C) 2019 tribe29 GmbH - License: GNU General Public License v2 +# This file is part of Checkmk (https://checkmk.com). It is subject to the terms and +# conditions defined in the file COPYING, which is part of this source code package. + + +def check_traceroute_arguments(params): + args = [] + + if not params['dns']: + args.append('-n') + method = params['method'] + if method == 'icmp': + args.append('-I') + elif method == 'tcp': + args.append('-T') + # else: None -> default method + + for router, state in params['routers']: + args += ['-%s' % state, router] + + family = params.get('address_family') + if family is None: + family = 'ipv6' if is_ipv6_primary(host_name()) else 'ipv4' + + if family == 'ipv6': + args.append('-6') + else: + args.append('-4') + + # additional options + if 'port' in params: + args.append(f'-p {params["port"]}') + + if 'queries' in params: + args.append(f'-q {params["queries"]}') + + if 'max_ttl' in params: + args.append(f'-m {params["max_ttl"]}') + + # needs root + if 'source_interface' in params: + args.append(f'-i {params["source_interface"]}') + # needs root + if 'source_address' in params: + args.append(f'-s {params["source_address"]}') + + if 'destination_address' in params: + args.append(params['destination_address']) + else: + args.append('$HOSTADDRESS$') + + return args + + +def _check_description(params): + if 'description' in params: + return f'Routing {params["description"]}' + + return 'Routing' + + +active_check_info['traceroute'] = { + 'command_line': 'check_traceroute $ARG1$', + 'argument_function': check_traceroute_arguments, + 'service_description': _check_description, + 'has_perfdata': True, +} diff --git a/lib/nagios/plugins/check_traceroute b/lib/nagios/plugins/check_traceroute new file mode 100755 index 0000000..dfa2290 --- /dev/null +++ b/lib/nagios/plugins/check_traceroute @@ -0,0 +1,297 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# Copyright (C) 2019 tribe29 GmbH - License: GNU General Public License v2 +# This file is part of Checkmk (https://checkmk.com). It is subject to the terms and +# conditions defined in the file COPYING, which is part of this source code package. + +# This check does a traceroute to the specified target host +# (usually $HOSTADDRESS$ itself) and checks which route(s) are +# being taken. That way you can check if your preferred or +# some alternative route in in place. +# traceroute is expected to be in the search path and installed +# with SUID root bit. + +# Example output from traceroute -n +# traceroute to www.google.de (173.194.44.55), 30 hops max, 60 byte packets +# 1 10.10.11.4 0.419 ms 0.444 ms 0.518 ms +# 2 33.117.16.28 14.359 ms 14.371 ms 14.434 ms +# 3 112.18.7.119 14.750 ms 14.765 ms 19.530 ms +# 4 184.50.190.61 17.844 ms 17.865 ms 17.862 ms +# 5 67.249.94.88 24.285 ms 78.527 ms 26.834 ms +# 6 209.85.240.99 27.910 ms 27.420 ms 27.442 ms +# 7 173.194.44.55 26.583 ms 20.410 ms 23.142 ms + +# Output without -n option: +# traceroute to www.google.de (173.194.44.56), 30 hops max, 60 byte packets +# 1 fritz.box (10.10.11.4) 0.570 ms 0.606 ms 0.677 ms +# 2 foo-bar.x-online.net (33.117.16.28) 14.566 ms 14.580 ms 14.658 ms +# 3 xu-2-3-0.rt-inxs-1.x-online.net (112.13.6.109) 18.214 ms 18.228 ms 18.221 ms +# 4 * * * +# 5 66.249.94.88 (66.249.94.88) 24.481 ms 24.498 ms 24.271 ms +# 6 209.85.240.99 (209.85.240.99) 27.628 ms 21.605 ms 21.943 ms +# 7 muc03s08-in-f24.1e100.net (173.194.44.56) 21.277 ms 22.236 ms 22.192 ms + +# Example output for IPv6 +# traceroute to ipv6.google.com (2404:6800:4004:80e::200e), 30 hops max, 80 byte packets +# 1 2001:2e8:665:0:2:2:0:1 (2001:2e8:665:0:2:2:0:1) 0.082 ms 0.046 ms 0.044 ms +# 2 2001:2e8:22:204::2 (2001:2e8:22:204::2) 0.893 ms 0.881 ms 0.961 ms +# 3 * 2001:4860:0:1::1abd (2001:4860:0:1::1abd) 225.189 ms * +# 4 2001:4860:0:1003::1 (2001:4860:0:1003::1) 3.052 ms 2.820 ms 2001:4860:0:1002::1 (2001:4860:0:1002::1) 1.501 ms +# 5 nrt13s48-in-x0e.1e100.net (2404:6800:4004:80e::200e) 1.910 ms 1.828 ms 1.753 ms + +# It is also possible that for one hop several different answers appear: +# 11 xe-0-0-1-0.co2-96c-1b.ntwk.msn.net (204.152.141.11) 174.185 ms xe-10-0-2-0.co1-96c-1a.ntwk.msn.net (207.46.40.94) 174.279 ms xe-0-0-1-0.co2-96c-1b.ntwk.msn.net (204.152.141.11) 174.444 ms + +# if DNS fails then it looks like this: +# 5 66.249.94.88 (66.249.94.88) 24.481 ms 24.498 ms 24.271 ms +# 6 209.85.240.99 (209.85.240.99) 27.628 ms 21.605 ms 21.943 ms + +import ast +import getopt +import ipaddress +import os +import subprocess +import sys + + +class MissingValueError(Exception): + pass + + +class ProtocolVersionError(Exception): + pass + + +class ExecutionError(Exception): + pass + + +def parse_exception(exc): + exc = str(exc) + if exc[0] == "{": + exc = "%d - %s" % list(ast.literal_eval(exc).values())[0] + return str(exc) + + +def output_check_result(s, perfdata): + if perfdata: + perfdata_output_entries = ["%s=%s" % (p[0], ";".join(map(str, p[1:]))) for p in perfdata] + s += " | %s" % " ".join(perfdata_output_entries) + sys.stdout.write("%s\n" % s) + + +def option_to_state(c): + return {"w": 1, "c": 2}[c.lower()] + + +def _execute_traceroute(target, nodns, method, address_family, queries, max_ttl, port, source_addr, source_int): + cmd = ["traceroute"] + if nodns: + cmd.append("-n") + if method: + cmd.append(method) + if address_family: + cmd.append(address_family) + if port and method != "-I": + cmd.append(f"-p {port}") + if queries: + cmd.append(f"-q {queries}") + if max_ttl: + cmd.append(f"-m {max_ttl}") + if source_int: + cmd.append(f"-i {source_int}") + + if source_addr: + cmd.append(f"-s {source_addr}") + + cmd.append(target) + + if (source_int is not None) or (source_addr is not None): + cmd = ' '.join(cmd) + shell = True + else: + shell = False + + p = subprocess.Popen(args=cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding="utf8", shell=shell) + sto, ste = p.communicate() + if p.returncode: + raise ExecutionError("UNKNOWN - " + ste.replace("\n", " ")) + return sto + + +def check_traceroute(lines, routes): + # find all visited routers + routers = set([]) + hops = len(lines[1:]) + for line in lines[1:]: + parts = line.strip().split() + for part in parts: + try: + part = part.lstrip("(").rstrip(",").rstrip(")") + ipaddress.ip_interface(part) + routers.add(part) + except ValueError: + pass + + state = 0 + bad_routers = [] + missing_routers = [] + for option, route in routes: + s = option_to_state(option) + if option.islower() and route in routers: + state = max(state, s) + bad_routers.append("%s(%s)" % (route, "!" * s)) + elif option.isupper() and route not in routers: + state = max(state, s) + missing_routers.append("%s(%s)" % (route, "!" * s)) + + info_text = "%d hops, missing routers: %s, bad routers: %s" % ( + hops, + missing_routers and ", ".join(missing_routers) or "none", + bad_routers and ", ".join(bad_routers) or "none", + ) + perfdata = [("hops", hops)] + return state, info_text, perfdata + + +def validate_ip_version(address_arg, ip_version_arg): + # ipv6 address can have an appended interface index/name: 'fe80::%{interface}' + try: + ip_address_version = ipaddress.ip_interface(address_arg.split("%")[0]).ip.version + except ValueError: + # May be a host or DNS name, don't execute the validation in this case. + # check_traceroute will perform the name resolution for us. + return + + if not ip_address_version == ip_version_arg: + raise ProtocolVersionError( + 'IP protocol version "%s" not the same as the IP address version "%s".' + % (ip_version_arg, ip_address_version) + ) + + +def usage(): + sys.stdout.write( + """check_traceroute -{c|w|C|W} ROUTE [-{o|c|w|O|C|W} ROUTE...] TARGET + +Check by which routes TARGET is being reached. Each possible route is being +prefixed with a state option: + + -w Make outcome WARN if that route is present + -W Make outcome WARN if that route is missing + -c Make outcome CRIT if that route is present + -C Make outcome CRIT if that route is missing + +Other options: + + -h, --help show this help and exit + --debug show Python exceptions verbosely + -n disable reverse DNS lookups + -I Use ICMP ECHO for probes + -T Use TCP SYN for probes + -4 Use IPv4 + -6 Use IPv6 + -p port Set the destination port to use + -m max_ttl Set the max number of hops (max TTL to be reached). Default is 30 + -s src_addr Use source address + -i device Specify a network interface to operate with + -q nqueries Set the number of probes per each hop. Default is 3 + +""" + ) + + +def main(args=None): + if args is None: + args = sys.argv[1:] + + os.unsetenv("LANG") + + opt_verbose = 0 + opt_debug = False + opt_nodns = False + opt_method = None + opt_address_family = None + opt_port = None + opt_source_int = None + opt_source_addr = None + opt_queries = None + opt_max_ttl = None + + short_options = "hw:W:c:C:i:s:p:q:m:nTI46" + long_options = [ + "verbose", + "help", + "debug", + ] + + route_params = [] + + try: + opts, args = getopt.getopt(args, short_options, long_options) + + if len(args) < 1: + usage() + raise MissingValueError("Please specify the target destination.") + + target_address = args[0] + + # first parse modifers + for o, a in opts: + if o in ["-v", "--verbose"]: + opt_verbose += 1 + elif o in ["-d", "--debug"]: + opt_debug = True + elif o in ["-w", "-W", "-c", "-C"]: + route_params.append((o[1], a)) + elif o == "-n": + opt_nodns = True + elif o in ["-T", "-I"]: + opt_method = o + elif o in ["-4", "-6"]: + if opt_address_family: + raise ProtocolVersionError("Cannot use both IPv4 and IPv6") + validate_ip_version(target_address, int(o.lstrip("-"))) + opt_address_family = o + elif o in ["-s"]: + opt_source_addr = a + elif o in ["-i"]: + opt_source_int = a + elif o in ["-p"]: + opt_port = a + elif o in ["-q"]: + opt_queries = a + elif o in ["-m"]: + opt_max_ttl = a + + # now handle action options + for o, a in opts: + if o in ["-h", "--help"]: + usage() + sys.exit(0) + + sto = _execute_traceroute(target_address, opt_nodns, opt_method, opt_address_family, opt_queries, + opt_max_ttl, opt_port, opt_source_addr, opt_source_int) + status, output, perfdata = check_traceroute(sto.split("\n"), route_params) + info_text = output.strip() + "\n%s" % sto + return status, info_text, perfdata + + except ExecutionError as e: + return 3, str(e), None + + except MissingValueError as e: + return 3, str(e), None + + except ProtocolVersionError as e: + return 3, str(e), None + + except Exception as e: + if opt_debug: + raise + return 2, "Unhandled exception: %s" % parse_exception(e), None + + +if __name__ == "__main__": + exitcode, info, perf = main() + output_check_result(info, perf) + sys.exit(exitcode) diff --git a/packages/active_check_traceroute b/packages/active_check_traceroute new file mode 100644 index 0000000..9d4a911 --- /dev/null +++ b/packages/active_check_traceroute @@ -0,0 +1,37 @@ +{'author': 'Th.L. (thl-cmk[at]outlook[dot]com)', + 'description': 'extended traceroute check plugin\n' + '\n' + 'adds the following options:\n' + '- service description suffix\n' + '- alternate destination address\n' + '- destination port for UDP/TCP path trace\n' + '- max hops\n' + '- queries per hop\n' + '- source address \n' + '- source interface (needs root permissions).\n' + '\n' + 'Source address and source interface uses the "shell=True" ' + 'option in in\n' + 'the "subprocess.Popen" command. This is highly insecure, so ' + 'be careful.\n' + '\n' + 'Note: the original option TCP path trace also needs root ' + 'permissions.\n' + '\n' + 'To give "traceroute" root permissions you need to set the ' + 'SUID bit for\n' + 'your traceroute program, like "sudo chmod u+s ' + '/usr/bin/traceroute.db" \n' + 'on Ubuntu 20.04.3 LTS.\n', + 'download_url': 'https://thl-cmk.hopto.org', + 'files': {'checks': ['check_traceroute'], + 'lib': ['nagios/plugins/check_traceroute'], + 'web': ['plugins/wato/active_checks_routing.py', + 'plugins/metrics/traceroute.py']}, + 'name': 'active_check_traceroute', + 'num_files': 4, + 'title': 'Active Check Traceroute', + 'version': '20212104.v.0.0.1a', + 'version.min_required': '2.0.0', + 'version.packaged': '2021.09.20', + 'version.usable_until': None} \ No newline at end of file diff --git a/web/plugins/metrics/traceroute.py b/web/plugins/metrics/traceroute.py new file mode 100644 index 0000000..9ee094f --- /dev/null +++ b/web/plugins/metrics/traceroute.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# License: GNU General Public License v2 +# +# Author: thl-cmk[at]outlook[dot]com +# URL : https://thl-cmk.hopto.org +# Date : 2021-12-04 +# +# +# + +from cmk.gui.i18n import _ + +from cmk.gui.plugins.metrics import ( + metric_info, + graph_info, + perfometer_info + +) + +metric_info['hops'] = { + 'title': _('Number of hops'), + 'unit': 'count', + 'color': '41/a', +} + +perfometer_info.append({ + 'type': 'linear', + 'segments': ['hops'], + 'total': 30, +}) diff --git a/web/plugins/wato/active_checks_routing.py b/web/plugins/wato/active_checks_routing.py new file mode 100644 index 0000000..474e425 --- /dev/null +++ b/web/plugins/wato/active_checks_routing.py @@ -0,0 +1,179 @@ +#!/usr/bin/env python3 +# -*- encoding: utf-8; py-indent-offset: 4 -*- + +# +# (c) 2013 Heinlein Support GmbH +# Robert Sander <r.sander@heinlein-support.de> +# + +# This 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 in version 2. This file is distributed +# in the hope that it will be useful, but WITHOUT ANY WARRANTY; with- +# out even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. See the GNU General Public License for more de- +# ails. You should have received a copy of the GNU General Public +# License along with GNU Make; see the file COPYING. If not, write +# to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +# Boston, MA 02110-1301 USA. + +from cmk.gui.i18n import _ +from cmk.gui.valuespec import ( + Dictionary, + ListOf, + Tuple, + Transform, + Checkbox, + DropdownChoice, + TextInput, + Integer, + TextAscii, +) + +from cmk.gui.plugins.wato import ( + rulespec_registry, + HostRulespec, +) + +from cmk.gui.plugins.wato.active_checks import ( + RulespecGroupActiveChecks +) + + +def _ip_address_family_element(): + return ( + 'address_family', + DropdownChoice( + title=_('IP address family'), + choices=[ + (None, _('Primary address family')), + ('ipv4', _('Enforce IPv4')), + ('ipv6', _('Enforce IPv6')), + ], + default_value=None, + ), + ) + + +def _transform_add_address_family(v): + v.setdefault('address_family', None) + return v + + +def _valuespec_active_checks_traceroute(): + return Transform( + Dictionary( + title=_('Check current routing'), + help=_( + 'This active check uses <tt>traceroute</tt> in order to determine the current ' + 'routing from the monitoring host to the target host. You can specify any number ' + 'of missing or expected routes in order to detect e.g. an (unintended) failover ' + 'to a secondary route.' + ), + elements=[ + ('description', + TextAscii( + title=_('Service Description suffix'), + help=_('Must be unique for every host. The service description starts always with \"Routing\".'), + size=30, + )), + ('dns', + Checkbox( + title=_('Name resolution'), + label=_('Use DNS to convert IP addresses into hostnames'), + help=_( + 'If you use this option, then <tt>traceroute</tt> is <b>not</b> being ' + 'called with the option <tt>-n</tt>. That means that all IP addresses ' + 'are tried to be converted into names. This usually adds additional ' + 'execution time. Also DNS resolution might fail for some addresses.' + ), + ),), + _ip_address_family_element(), + ('routers', + ListOf( + Tuple( + elements=[ + TextInput( + title=_('Router (FQDN, IP-Address)'), + allow_empty=False, + ), + DropdownChoice( + title=_('How'), + choices=[ + ('W', _('WARN - if this router is not being used')), + ('C', _('CRIT - if this router is not being used')), + ('w', _('WARN - if this router is being used')), + ('c', _('CRIT - if this router is being used')), + ], + ), + ] + ), + title=_('Router that must or must not be used'), + add_label=_('Add Condition'), + ),), + ('method', + DropdownChoice( + title=_('Method of probing'), + choices=[ + (None, _('UDP (default behaviour of traceroute)')), + ('icmp', _('ICMP Echo Request')), + ('tcp', _('TCP SYN, needs root permissions')), + ], + default_value='icmp', + ),), + ('port', + Integer( + title=_('Port'), + help=_('Set the destination port to use. It is either initial udp port value for \"default\" ' + 'method (incremented by each probe, default is 33434), or initial seq for \"icmp\" ' + '(incremented as well, default from 1), or some constant destination port for other ' + 'methods (with default of 80 for \"tcp\", 53 for \"udp\", etc.)'), + maxvalue=65535, + ),), + ('destination_address', + TextAscii( + title=_('Alternate Destination'), + help=_('Path trace to alternate destination instead of \"HOSTADDRESS\".'), + ),), + ('queries', + Integer( + title=_('Number of queries'), + help=_('Set the number of probes per each hop. Default is 3.'), + default_value=3, + minvalue=1, + maxvalue=10, + ),), + ('max_ttl', + Integer( + title=_('Max hops'), + help=_('Set the max number of hops (max TTL to be reached). Default is 30'), + default_value=30, + minvalue=1, + maxvalue=255, + ),), + ('source_interface', + TextAscii( + title=_('Source interface'), + help=_('Specify a network interface to operate with. Needs root permissions.'), + ),), + ('source_address', + TextAscii( + title=_('Source address'), + help=_('Use source source address for outgoing packets'), + ),), + ], + optional_keys=['description', 'max_ttl', 'queries', 'destination_address', 'source_address', + 'source_interface', 'port'], + ), + forth=_transform_add_address_family, + ) + + +rulespec_registry.register( + HostRulespec( + group=RulespecGroupActiveChecks, + match_type='all', + name='active_checks:traceroute', + valuespec=_valuespec_active_checks_traceroute, + ) +) -- GitLab