From 0cda12f91660a2465fdf4748020dfebf5ac24177 Mon Sep 17 00:00:00 2001 From: "th.l" <thl-cmk@outlook.com> Date: Sun, 28 Apr 2024 17:48:15 +0200 Subject: [PATCH] update project --- README.md | 2 +- mkp/check_radius-0.1.0-20240428.mkp | Bin 0 -> 11238 bytes source/checks/check_radius | 39 ++- source/gui/metrics/check_radius.py | 12 +- .../gui/wato/check_parameters/check_radius.py | 246 +++++++++++++++- source/lib/nagios/plugins/check_radius | 278 ++++++++++++++---- source/lib/nagios/plugins/dictionary | 2 +- .../lib/nagios/plugins/dictionary.freeradius | 0 source/packages/check_radius | 11 +- 9 files changed, 490 insertions(+), 100 deletions(-) create mode 100644 mkp/check_radius-0.1.0-20240428.mkp mode change 100644 => 100755 source/lib/nagios/plugins/dictionary mode change 100644 => 100755 source/lib/nagios/plugins/dictionary.freeradius diff --git a/README.md b/README.md index 6f8835b..e5f9ebc 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[PACKAGE]: ../../raw/master/mkp/check_radius-0.0.1-20240421.mkp "check_radius-0.0.1-20240421.mkp" +[PACKAGE]: ../../raw/master/mkp/check_radius-0.1.0-20240428.mkp "check_radius-0.1.0-20240428.mkp" # Check RADIUS This is a (very) basic active RADIUS check. Tests if a RADIUS server is responsive (accept/reject/timeout). There is (limited) support to add AV-pairs to the RADIUS request. diff --git a/mkp/check_radius-0.1.0-20240428.mkp b/mkp/check_radius-0.1.0-20240428.mkp new file mode 100644 index 0000000000000000000000000000000000000000..c895811b07fc9b346597ffd6feffbc1f8170408e GIT binary patch literal 11238 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 literal 0 HcmV?d00001 diff --git a/source/checks/check_radius b/source/checks/check_radius index eaa316c..3521903 100644 --- a/source/checks/check_radius +++ b/source/checks/check_radius @@ -14,32 +14,53 @@ def check_radius_arguments(params): args = [] - if server := params.get('server'): + if (server := params.get('server')) is not None: args.extend(['-H', server]) else: args.append('-H $HOSTADDRESS$') - if auth_port := params.get("auth_port"): - args.extend(['--authport', auth_port]) + if (auth_port := params.get("auth_port")) is not None: + args.extend(['--auth-port', auth_port]) - if secret := params.get("secret"): + if (secret := params.get("secret")) is not None: args.extend(["--secret", passwordstore_get_cmdline("%s", secret)]) - if user_name := params.get("user_name"): + if (user_name := params.get("user_name")) is not None: args.extend([f'--username', user_name]) - if user_password := params.get("user_password"): + if (user_password := params.get("user_password")) is not None: args.extend(["--password", passwordstore_get_cmdline("%s", user_password)]) - if timeout := params.get('timeout'): - args.extend(['-timeout', timeout]) + if (timeout := params.get('timeout')) is not None: + args.extend(['--timeout', timeout]) + + if (request_attributes := params.get('request_params').get('request_attributes')) is not None: + for av_name, av_value in request_attributes: + args.extend(['--request-attribute', f'{av_name}:{av_value}']) + + if (expected_response := params.get('response_params').get('expected_response')) is not None: + args.extend(['--expected-response', expected_response]) + + if (state_not_expected_response := params.get('response_params').get('state_not_expected_response')) is not None: + args.extend(['--state-not-expected-response', state_not_expected_response]) + + if (num_resp_attributes := params.get('response_params').get('num_resp_attributes')) is not None: + args.extend(['--num-resp-attributes', num_resp_attributes]) + + if (state_wrong_number_of_response_attributes := params.get('response_params').get( + 'state_wrong_number_of_response_attributes')) is not None: + args.extend(['--state-wrong-num-resp-attributes', state_wrong_number_of_response_attributes]) + + if (level_upper_response_time := params.get('response_params').get('level_upper_response_time')) is not None: + warn, crit = level_upper_response_time + args.extend(['--max-response-time', f'{warn}, {crit}']) return args def _check_description(params): if 'description' in params: - return f'RADIUS server {params["description"]}' + return f'RADIUS {params["description"]}' return 'RADIUS server' diff --git a/source/gui/metrics/check_radius.py b/source/gui/metrics/check_radius.py index 5c8cff2..67790d9 100644 --- a/source/gui/metrics/check_radius.py +++ b/source/gui/metrics/check_radius.py @@ -18,8 +18,8 @@ from cmk.gui.plugins.metrics.utils import ( perfometer_info ) -metric_info['radius_request_time'] = { - 'title': _('Request time'), +metric_info['radius_response_time'] = { + 'title': _('Response time'), 'unit': 's', 'color': '#9a52bf', } @@ -27,17 +27,17 @@ metric_info['radius_request_time'] = { graph_info['check_radius_time'] = { 'title': _('RADIUS request time'), 'metrics': [ - ('radius_request_time', 'area'), + ('radius_response_time', 'area'), ], 'scalars': [ - ('radius_request_time:crit', _('Crit')), - ('radius_request_time:warn', _('Warn')), + ('radius_response_time:crit', _('Crit')), + ('radius_response_time:warn', _('Warn')), ], } perfometer_info.append({ 'type': 'logarithmic', - 'metric': 'radius_request_time', + 'metric': 'radius_response_time', 'half_value': 1.0, 'exponent': 10.0, }) diff --git a/source/gui/wato/check_parameters/check_radius.py b/source/gui/wato/check_parameters/check_radius.py index d38398d..71dd1d8 100644 --- a/source/gui/wato/check_parameters/check_radius.py +++ b/source/gui/wato/check_parameters/check_radius.py @@ -12,15 +12,153 @@ # 2024-01-01: modified for cmk 2.2.x from cmk.gui.i18n import _ +from cmk.gui.plugins.wato.active_checks.common import RulespecGroupActiveChecks +from cmk.gui.plugins.wato.utils import HostRulespec, IndividualOrStoredPassword, rulespec_registry from cmk.gui.valuespec import ( + Alternative, Dictionary, + DropdownChoice, + FixedValue, + Foldable, + IPv4Address, Integer, - TextAscii, + ListOf, + MonitoringState, + TextInput, Transform, + Tuple, ) -from cmk.gui.plugins.wato.active_checks.common import RulespecGroupActiveChecks -from cmk.gui.plugins.wato.utils import HostRulespec, rulespec_registry, IndividualOrStoredPassword +_called_station_id = Tuple( + title='Called-Station-Id', + orientation='horizontal', + elements=[ + FixedValue('Called-Station-Id'), # , totext='' # add empty totext to remove "duplicate" attribute name + TextInput( + size=20, + placeholder='AA-BB-CC-DD-EE-FF', + allow_empty=False, + ), + ], +) +_calling_station_id = Tuple( + title='Calling-Station-Id', + orientation='horizontal', + elements=[ + FixedValue('Calling-Station-Id'), + TextInput( + size=20, + placeholder='AA-BB-CC-DD-EE-FF', + allow_empty=False, + ), + ], +) +_framed_mtu = Tuple( + title='Framed-MTU', + orientation='horizontal', + elements=[ + FixedValue('Framed-MTU'), + Integer( + size=5, + default_value=1500 + ), + ], +) +_nas_identifier = Tuple( + title='NAS-Identifier', + orientation='horizontal', + elements=[ + FixedValue('NAS-Identifier'), + TextInput( + size=20, + placeholder='NAS001', + allow_empty=False, + ), + ], +) +_nas_ip_address = Tuple( + title='NAS-IP-Address', + orientation='horizontal', + elements=[ + FixedValue('NAS-IP-Address'), + IPv4Address(), + ], +) +_nas_port_id = Tuple( + title='NAS-Port-Id', + orientation='horizontal', + elements=[ + FixedValue('NAS-Port-Id'), + TextInput( + size=20, + placeholder='GigabitEthernet0/8', + allow_empty=False, + ), + ], +) +_nas_port_type = Tuple( + title='NAS-Port-Type', + orientation='horizontal', + elements=[ + FixedValue('NAS-Port-Type'), + DropdownChoice( + choices=[ + ('0', 'Async'), + ('1', 'Sync'), + ('2', 'ISDN'), + ('3', 'ISDN-V120'), + ('4', 'ISDN-V110'), + ('5', 'Virtual'), + ('6', 'PIAFS'), + ('7', 'HDLC-Clear-Channel'), + ('8', 'X.25'), + ('9', 'X.75'), + ('10', 'G.3-Fax'), + ('11', 'SDSL'), + ('12', 'ADSL-CAP'), + ('13', 'ADSL-DMT'), + ('14', 'IDSL'), + ('15', 'Ethernet'), + ('16', 'xDSL'), + ('17', 'Cable'), + ('18', 'Wireless-Other'), + ('19', 'Wireless-802.11'), + ] + ), + ], +) +_nas_port = Tuple( + title='NAS-Port', + orientation='horizontal', + elements=[ + FixedValue('NAS-Port'), + Integer( + size=7, + ), + ], +) +_service_type = Tuple( + title='Service-Type', + orientation='horizontal', + elements=[ + FixedValue('Service-Type'), + DropdownChoice( + choices=[ + ('1', 'Login-User'), + ('2', 'Framed-User'), + ('3', 'Callback-Login-User'), + ('4', 'Callback-Framed-User'), + ('5', 'Outbound-User'), + ('6', 'Administrative-User'), + ('7', 'NAS-Prompt-User'), + ('8', 'Authenticate-Only'), + ('9', 'Callback-NAS-Prompt'), + ('10', 'Call-Check'), + ('11', 'Callback-Administrative'), + ] + ), + ], +) def _valuespec_active_checks_radius(): @@ -30,49 +168,51 @@ def _valuespec_active_checks_radius(): help=_(''), elements=[ ('description', - TextAscii( + TextInput( title=_('Service description'), help=_( - 'Must be unique for every host. The service description starts always with \"RADIUS server\".'), + 'Must be unique for every host. The service description starts always with \"RADIUS server\".' + ), size=50, placeholder='Item name for the service', allow_empty=False, )), ('server', - TextAscii( + TextInput( title=_('Server IP-address or name'), help=_( 'Hostname or IP-address to monitor. Default is the host name/IP-Address of the monitored host.' ), size=50, allow_empty=False, + placeholder='i.e 192.168.10.10 or srvrad01.company.intern' )), ('auth_port', Integer( - title=_('RADIUS authentication port'), + title=_('Authentication port'), help=_('The RADIUS port to use for authentication. Default is 1812.'), - # size=5, + size=5, default_value=1812, minvalue=1, maxvalue=65535, )), ('secret', IndividualOrStoredPassword( - title=_('Server secret'), - help=_('The RADIUS secret.'), - # size=50, + title=_('Shared secret'), + help=_('The shared secret.'), allow_empty=False, )), ('timeout', Integer( - title=_('Server timeout'), - help=_('The user password.'), + title=_('Request timeout'), + help=_('The timeout for the RADIUS request.'), default_value=2, minvalue=1, maxvalue=30, + unit='s', )), ('user_name', - TextAscii( + TextInput( title=_('User name'), help=_('The user name to use in the request.'), size=50, @@ -83,11 +223,85 @@ def _valuespec_active_checks_radius(): IndividualOrStoredPassword( title=_('User password'), help=_('The user password.'), - # size=50, allow_empty=False )), + ('request_params', + Foldable( + Dictionary( + title="Hide/Show Request Parameters", + elements=[ + ('request_attributes', + ListOf( + Alternative( + orientation='horizontal', + elements=[ + _called_station_id, + _calling_station_id, + _framed_mtu, + _nas_identifier, + _nas_ip_address, + _nas_port, + _nas_port_id, + _nas_port_type, + _service_type, + ], + ), + title=_('Request Attributes'), + add_label=_('add attribute'), + )), + ], + ), + title='Request paranmeters', + )), + ('response_params', + Foldable( + Dictionary( + title="Hide/Show Response Parameters", + elements=[ + ('expected_response', + DropdownChoice( + choices=( + (2, 'Accepted'), + (3, 'Rejected'), + ), + title=_('Expected response'), + help=_('Expected response from the RADIUS server.'), + )), + ('state_not_expected_response', + MonitoringState( + title=_('Monitoring state not expected response'), + default_value=2, + )), + ('level_upper_response_time', + Tuple( + elements=[ + Integer(title=_('Warning at'), unit='ms', minvalue=0, maxvalue=10000), + Integer(title=_('Critical at'), unit='ms', minvalue=0, maxvalue=10000), + ], + title=_('Max. response time'), + )), + ('num_resp_attributes', + Integer( + title=_('# of expected attribues in response'), + help=_('The expected number of RADIUS attibutes in the response.'), + minvalue=0, + maxvalue=65535, + )), + ('state_wrong_number_of_response_attributes', + MonitoringState( + title=_('Monitoring state on wrong # of response attributes'), + default_value=1, + )), + ], + ), + title='Response paranmeters', + )) ], - required_keys=['secret'] + required_keys=[ + 'secret', + 'request_params', + 'response_params', + ] ), ) diff --git a/source/lib/nagios/plugins/check_radius b/source/lib/nagios/plugins/check_radius index 4680980..2147c1f 100755 --- a/source/lib/nagios/plugins/check_radius +++ b/source/lib/nagios/plugins/check_radius @@ -13,48 +13,146 @@ # # https://github.com/pyradius/pyrad # -import socket -from typing import Sequence -import sys -from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter, Namespace, ArgumentTypeError -from time import time_ns +from argparse import ( + ArgumentDefaultsHelpFormatter, + ArgumentParser, + ArgumentTypeError, + Namespace, +) from os import environ +from socket import error as socket_error +from sys import ( + argv as sys_argv, + exit as sys_exit, + stdout as sys_stdout, +) +from time import time_ns +from typing import Sequence, Tuple import cmk.utils.password_store no_radiuslib = False try: - from pyrad.client import Client as rad_client - from pyrad.dictionary import Dictionary as rad_dictionary - import pyrad.packet + from pyrad.client import Client as radClient + from pyrad.dictionary import Dictionary as radDictionary + from pyrad.packet import AccessAccept, AccessReject, AccessRequest + from pyrad.client import Timeout as pyTimeout except ModuleNotFoundError: no_radiuslib = True -def parse_arguments(argv: Sequence[str]) -> Namespace: +class Args(Namespace): + host: str + auth_port: int + secret: str + timeout: int + username: str + password: str + num_resp_attributes: int + state_wrong_num_resp_attributes: int + request_attribute: Tuple[str, str] + max_response_time: Tuple[int, int] + expected_response: int + state_not_expected_response: int + + +VERSION = '0.1.0-20240428' + +cmk_state = { + 0: '', + 1: '(!)', + 2: '(!!)', + 3: '(?)', +} +response_str = { + 2: 'accept', + 3: 'reject', +} + + +def parse_arguments(argv: Sequence[str]) -> Args: + def _av_pair(s): + try: + name, value = s.split(':') + return name, value + except ValueError: + raise ArgumentTypeError("AV-Pairs must be in the form of name:vale") + + def _levels(s) -> Tuple[int, int]: + try: + warn, crit = s.split(',') + warn = int(warn) + crit = int(crit) + return warn, crit + except ValueError: + raise ArgumentTypeError("Levels must be in the form 'warn,crit' value") + parser = ArgumentParser( + description='This is a (very) basic active RADIUS check for Check_mk. Tests if a RADIUS server is responsive ' + '(accept/reject/timeout). There is (limited) support to add AV-pairs to the RADIUS request.', formatter_class=ArgumentDefaultsHelpFormatter, - epilog='' + epilog=f'(c) thl-cmk[at]outlook[dot], Version: {VERSION}, For more information see: https://thl-cmk.hopto.org' ) + # + # required request parameters + # parser.add_argument( '-H', '--host', required=True, - help='Host/IP-Address of RADIUS server to query (required)') + help='Host/IP-Address of RADIUS server to query (required)', + ) parser.add_argument( '--secret', required=True, - help='secret RADIUS key') + help='secret RADIUS key', + ) parser.add_argument( - '--username', default='dummyuser', - help='user name to test with') + '--username', default='dummyuser', required=True, + help='user name to test with', + ) parser.add_argument( - '--password', default='dummyuser', - help='user password to test with') + '--password', default='dummypassword', required=True, + help='user password to test with', + ) + # + # optional request parameters + # parser.add_argument( - '--authport', type=int, default=1812, - help='RADIUS authentication port to use.') + '--auth_port', type=int, default=1812, + help='RADIUS authentication port to use.', + ) parser.add_argument( '--timeout', type=int, default=1, - help='RADIUS server timeout.') + help='RADIUS server timeout', + ) + parser.add_argument( + '--request-attribute', nargs='*', type=_av_pair, action='append', default=[], + help='add request attribute in the form of "attribute-name:attribute-value" ' + 'ie: "Called-Station-Id:AA-BB-CC-DD-EE-FF". Repeat to add more attributes. ' + 'For valid attributes the dictionary file.', + ) + # + # response parameters + # + parser.add_argument( + '--expected-response', type=int, choices=[2, 3], + help=' 2 -> Accepted, 3 -> Rejected', + ) + parser.add_argument( + '--state-not-expected-response', type=int, choices=[0, 1, 2, 3], default=1, + help='Monitoring state: 0 -> OK, 1 -> WARN, 2 -> CRIT, 3 -> UNKNOWN', + ) + parser.add_argument( + '--num-resp-attributes', type=int, + help='Expected number of response attributes', + ) + parser.add_argument( + '--state-wrong-num-resp-attributes', type=int, choices=[0, 1, 2, 3], default=1, + help='Monitoring state: 0 -> OK, 1 -> WARN, 2 -> CRIT, 3 -> UNKNOWN', + ) + parser.add_argument( + '--max-response-time', type=_levels, + help='Upper levels for response time in ms in the format WARN,CRIT time. ie: 10,50' + ) args = parser.parse_args(argv) args.host = args.host.strip(' ') @@ -63,80 +161,130 @@ def parse_arguments(argv: Sequence[str]) -> Namespace: def main(args=None): if args is None: - args = sys.argv[1:] # without the path/plugin itself + args = sys_argv[1:] # without the path/plugin itself args = parse_arguments(args) if no_radiuslib: - sys.stdout.write( - 'To use this check plugin you need to install the python pyrad lib in your CMK python environment.\n' + sys_stdout.write( + 'To use this check plugin you need to install the python pyrad lib in your CMK python environment.(!!!)\n' ) - sys.exit(3) + sys_exit(3) omd_root = environ["OMD_ROOT"] - info_text = '' - long_output = '' - perf_data = '' + info_text = [] + long_output = [] + perf_data = [] status = 0 - rad_server = rad_client( + rad_server = radClient( server=args.host, - authport=args.authport, + authport=args.auth_port, secret=args.secret.encode('utf-8'), - dict=rad_dictionary(f'{omd_root}/local/lib/nagios/plugins/dictionary'), + # freeradius dictionaries are under /usr/share/freeradius/ + dict=radDictionary(f'{omd_root}/local/lib/nagios/plugins/dictionary'), timeout=args.timeout, ) rad_req = rad_server.CreateAuthPacket( - code=pyrad.packet.AccessRequest, + code=AccessRequest, User_Name=args.username, NAS_Identifier=args.host, ) rad_req["User-Password"] = rad_req.PwCrypt(args.password) + + # add optional request attributes + for av_pair in args.request_attribute: + name, value = av_pair[0] + try: + rad_req[name] = value + except TypeError: + sys_stdout.write( + f'WARNING: attribute value must be the real value not the name of the ' + f'value: {value}{cmk_state[1]}{cmk_state[1]}' + ) + status = max(status, 1) + continue + before_request_time = time_ns() try: response = rad_server.SendPacket(rad_req) - except pyrad.client.Timeout as e: - status = 2 - info_text = 'Radius request timeout' - long_output += f'\nRadius request timeout.\n{e}' - except socket.error as e: - status = 2 - info_text = 'Network error' - long_output += f'\nNetwork error\n{e}' + except pyTimeout as e: + status = max(status, 2) + message = f'Radius request timeout{cmk_state[2]}' + info_text.append(message) + long_output.append(f'{message}\n{e}') + except socket_error as e: + status = max(status, 2) + message = f'Network error{cmk_state[2]}' + info_text.append(message) + long_output.append(f'{message}\n{e}') else: - request_time = (time_ns() - before_request_time) / 1000 / 1000 / 1000 # -> ns to seconds - match response.code: - case pyrad.packet.AccessAccept: - info_text += 'Response: access accept' - long_output += '\nResponse: access accept' - long_output += f'\nResponse code: {response.code}' - if response.has_key: - long_output += f'\nNumber of attributes in response: {len(response.keys())}' - long_output += f'\n\nResponse attributes:' - for key in response.keys(): - long_output += f'\n{key}: {response.get(key)}' + # first: calculate response time + response_time = (time_ns() - before_request_time) / 1000 / 1000 / 1000 # -> ns to seconds + + # + # second: check response code + message = f'Response: access {response_str.get(response.code, f"unknown ({response.code})")}' + if args.expected_response and response.code != args.expected_response: + message += f' (expected: {response_str[args.expected_response]}{cmk_state[args.state_not_expected_response]})' + status = max(status, args.state_not_expected_response) + info_text.append(message) + long_output.append(message) + + # third: check response time + message = f'Response time {response_time * 1000:.0f}ms' + if args.max_response_time: + warn, crit = args.max_response_time + warn = warn + crit = crit + if response_time >= warn / 1000: + message += f' (WARN/CRIT at {warn}/{crit}' + if response_time >= crit / 1000: + message += cmk_state[2] + status = max(status, 2) else: - long_output += f'\nNo attributes in response: {len(response.keys())}' - case pyrad.packet.AccessReject: - info_text += 'Response: access reject' - long_output += '\nResponse: access reject' - long_output += f'\nResponse code: {response.code}' - case _: - info_text += f'Response: code unknown' - long_output += f'\nResponse: code unknown' - long_output += f'\nResponse code: {response.code}' - status = 3 - - perf_data += f'radius_request_time={request_time}' - - info_text = info_text.strip(',').strip(' ') - sys.stdout.write(f'{info_text}\n{long_output} | {perf_data}\n') + message += cmk_state[1] + status = max(status, 1) + perf_data.append(f'radius_response_time={response_time};{warn};{crit};;') + else: + perf_data.append(f'radius_response_time={response_time}') + info_text.append(message) + long_output.append(message) + + if response.code == AccessAccept: + # + # forth: check return attributes + if response.has_key: + message = f'Number of attributes in response: {len(response.keys())}' + else: + message = long_output.append('No return attributes in response') + if args.num_resp_attributes and len(response.keys()) != args.num_resp_attributes: + message += f' (expected {args.num_resp_attributes}{cmk_state[args.state_wrong_num_resp_attributes]})' + status = max(status, args.state_wrong_num_resp_attributes) + info_text.append(message) + + long_output.append(message) + + if response.has_key: + long_output.append('\nResponse attributes:') + for key in response.keys(): + long_output.append(f'{key}: {response.get(key)}') + + # + # format output data + info_text = ', '.join(info_text) + long_output = '\n'.join(long_output) + perf_data = '|'.join(perf_data) + if perf_data: + sys_stdout.write(f'{info_text}\n{long_output}|{perf_data}\n') + else: + sys_stdout.write(f'{info_text}\n{long_output}') return status if __name__ == '__main__': cmk.utils.password_store.replace_passwords() exitcode = main() - sys.exit(exitcode) + sys_exit(exitcode) diff --git a/source/lib/nagios/plugins/dictionary b/source/lib/nagios/plugins/dictionary old mode 100644 new mode 100755 index 30fb528..125de2f --- a/source/lib/nagios/plugins/dictionary +++ b/source/lib/nagios/plugins/dictionary @@ -230,7 +230,7 @@ ATTRIBUTE Autz-Type 1011 integer # User Types VALUE Service-Type Login-User 1 -VALUE Service-Type Framed-User 2 +VALUE Service-Type pdate 2 VALUE Service-Type Callback-Login-User 3 VALUE Service-Type Callback-Framed-User 4 VALUE Service-Type Outbound-User 5 diff --git a/source/lib/nagios/plugins/dictionary.freeradius b/source/lib/nagios/plugins/dictionary.freeradius old mode 100644 new mode 100755 diff --git a/source/packages/check_radius b/source/packages/check_radius index b14b394..bff1f3c 100644 --- a/source/packages/check_radius +++ b/source/packages/check_radius @@ -1,5 +1,12 @@ {'author': 'Th.L. (thl-cmk[at]outlook[dot]com)', - 'description': 'active RADIUS check\n', + 'description': 'This is a (very) basic active RADIUS check:\n' + '\n' + ' - tests if a RADIUS server is responsive ' + '(accept/reject/timeout).\n' + ' - (limited) support to add AV-pairs to the RADIUS request\n' + ' - checks response code, response time and number of response ' + 'attributes\n' + '\n', 'download_url': 'https://thl-cmk.hopto.org', 'files': {'checks': ['check_radius'], 'gui': ['metrics/check_radius.py', @@ -9,7 +16,7 @@ 'nagios/plugins/dictionary.freeradius']}, 'name': 'check_radius', 'title': 'Check RADIUS', - 'version': '0.0.1-20240421', + 'version': '0.1.0-20240428', 'version.min_required': '2.2.0b1', 'version.packaged': '2.2.0p24', 'version.usable_until': None} -- GitLab