diff --git a/README.md b/README.md index 9209cf4aca73434dbe4fed878d996a1102c59651..2f8f7419d92fd70a3a6a38ab4d6e7c3769699f05 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[PACKAGE]: ../../raw/master/packagee-0.1.2-20230706.mkp "package-0.1.2-20230706.mkp" +[PACKAGE]: ../../raw/master/mkp/inv_ipv4_routes-0.0.1-20231227.mkp "inv_ipv4_routes-0.0.1-20231227.mkp" # Title A short description about the plugin diff --git a/agent_based/inv_ipv4_routes.py b/agent_based/inv_ipv4_routes.py new file mode 100644 index 0000000000000000000000000000000000000000..81c85eeac65dcaadf920f7e64300e18e47f2e027 --- /dev/null +++ b/agent_based/inv_ipv4_routes.py @@ -0,0 +1,185 @@ +#!/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 : 2023-12-27 +# File : inv_ipv4_route.py +# +# inventory of IPv4 routing information + + +import ipaddress +from dataclasses import dataclass +from typing import List + +from cmk.base.plugins.agent_based.agent_based_api.v1 import ( + OIDEnd, +) +from cmk.base.plugins.agent_based.agent_based_api.v1 import ( + register, + SNMPTree, + TableRow, + exists, + render, +) +from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import ( + StringTable, + InventoryResult, +) + +_route_type = { + '1': 'other', + '2': 'reject', + '3': 'local', + '4': 'remote', +} +_route_status = { + '1': 'active', + '2': 'not in service', + '3': 'not ready', + '4': 'create and go', + '5': 'create and wait', + '6': 'destroy', +} + +_route_protocol = { + '1': 'other', + '2': 'local', + '3': 'net mgmt', + '4': 'ICMP', + '5': 'egp', + '6': 'ggp', + '7': 'hello', + '8': 'RIP', + '9': 'ISIS', + '10': 'esIs', + '11': 'Cisco IGRP', + '12': 'bbnSpfIgp', + '13': 'OSPF', + '14': 'BGP', + '15': 'idpr', + '16': 'Cisco EIGRP', + '17': 'dvmrp', +} + + +@dataclass(frozen=True) +class Ipv4Route: + age: int | None + cidr: int + destination: str + if_index: int + if_name: str + netmask: str + next_hop: str + protocol: str + status: str + type: str + + +def parse_inv_ipv4_routes(string_table: List[StringTable]) -> List[Ipv4Route]: + routes, if_info = string_table + + interface_by_index = {if_index: if_name for if_index, if_name in if_info} + + ipv4_routes = [] + for destination, netmask, next_hop, if_index, route_type, protocol, age, status in routes: + ipv4 = ipaddress.IPv4Network(address=f'{destination}/{netmask}', strict=False) + ipv4_routes.append( + Ipv4Route( + age=int(age) if age.isdigit() else None, + cidr=int(ipv4.prefixlen), + destination=str(destination), + if_index=int(if_index), + if_name=str(interface_by_index.get(if_index, f'unknown ({if_index})')), + netmask=str(netmask), + next_hop=str(next_hop), + protocol=_route_protocol.get(protocol, f'unknown ({protocol})'), + status=_route_status.get(status, f'unknown ({status})'), + type=_route_type.get(route_type, f'unknown ({route_type})'), + ) + ) + + return ipv4_routes + + +def inventory_ipv4_routes(section: List[Ipv4Route]) -> InventoryResult: + path = ['networking', 'routes'] + + for ipv4_route in section: + key_columns = { + 'target': f'{ipv4_route.destination}/{ipv4_route.cidr}', + 'gateway': ipv4_route.next_hop, + } + inventory_columns = { + # 'age': render.timespan(ipv4_route.age), + 'device': ipv4_route.if_name, + 'protocol': ipv4_route.protocol, + 'status': ipv4_route.status, + 'type': ipv4_route.type, + } + if ipv4_route.age: + inventory_columns['age'] = render.timespan(ipv4_route.age) + + yield TableRow( + path=path, + key_columns=key_columns, + inventory_columns=inventory_columns + ) + + +register.snmp_section( + name='inv_ipv4_routes', + parse_function=parse_inv_ipv4_routes, + fetch=[ + SNMPTree( + base='.1.3.6.1.2.1.4.24.4.1', # IP-MIB::ipCidrRouteEntry + oids=[ + '1', # ipCidrRouteDest + '2', # ipCidrRouteMask + '4', # ipCidrRouteNextHop + '5', # ipCidrRouteIfIndex + '6', # ipCidrRouteType + '7', # ipCidrRouteProto + '8', # ipCidrRouteAge + '16' # ipCidrRouteStatus + + ] + ), + SNMPTree( + base='.1.3.6.1.2.1.31.1.1.1', # + oids=[ + OIDEnd(), # ifIndex + '1', # ifName + ]), + ], + detect=exists('.1.3.6.1.2.1.4.24.4.1.1.*'), # +) + +register.inventory_plugin( + name='inv_ipv4_routes', + inventory_function=inventory_ipv4_routes, +) + +# IP-MIB::ip.24.7.1.7.2.16.255.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.2.0.0.0.0 = INTEGER: 10501 +# FE 80 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 0 3 a4 a 2 0 0 0 0 +# IP-MIB::ip.24.7.1.7.4.20.254.128.0.0.0.0.0.0.0.0.0.0.0.0.0.0.18.0.3.164.10.2.0.0.0.0 = INTEGER: 10501 +# IP-MIB::ip.24.7.1.7.4.20.254.128.0.0.0.0.0.0.0.0.0.0.0.0.0.0.18.0.3.201.10.2.0.0.0.0 = INTEGER: 1 +# IP-MIB::ip.24.7.1.7.4.20.254.128.0.0.0.0.0.0.0.0.0.0.0.0.0.1.18.0.3.164.128.2.0.0.0.0 = INTEGER: 10501 +# IP-MIB::ip.24.7.1.7.4.20.254.128.0.0.0.0.0.0.1.146.1.104.0.0.0.1.18.0.3.201.128.2.0.0.0.0 = INTEGER: 1 + + +# IP-MIB::ip.24.7.1.7.2.16.255.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.2.0.0.0.0 = INTEGER: 10501 +# FE 80 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 0 3 a4 a 2 0 0 0 0 +# IP-MIB::ip.24.7.1.7.4.20.254.128.0.0.0.0.0.0.0.0.0.0.0.0.0.0. 18.0.3.164. 10.2.0.0.0.0 = INTEGER: 10501 +# IP-MIB::ip.24.7.1.7.4.20.254.128.0.0.0.0.0.0.0.0.0.0.0.0.0.0. 18.0.3.201. 10.2.0.0.0.0 = INTEGER: 1 +# IP-MIB::ip.24.7.1.7.4.20.254.128.0.0.0.0.0.0.0.0.0.0.0.0.0.0. 18.0.3.210. 10.2.0.0.0.0 = INTEGER: 10 +# 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 +# IP-MIB::ip.24.7.1.7.4.20.254.128.0.0.0.0.0.0.0.0.0.0.0.0.0.1.18.0.3.164.128.2.0.0.0.0 = INTEGER: 10501 +# fe 80 0 0 0 0 0 0 1 92 1 68 0 0 0 1 -> fe80::192:168:0:1 +# IP-MIB::ip.24.7.1.7.4.20.254.128.0.0.0.0.0.0.1.146.1.104.0.0.0.1 .18.0.3.201. 128.2.0.0.0.0 = INTEGER: 1 +# FE 80 0 0 0 0 0 0 B6 E9 B0 FF FE 57 FB 41 12 0 3 D2 80 2 0 0 0 0 +# IP-MIB::ip.24.7.1.7.4.20.254.128.0.0.0.0.0.0.182.233.176.255.254.87.251.65. 18.0.3.210. 128.2.0.0.0.0 = INTEGER: 10 diff --git a/mkp/inv_ipv4_routes-0.0.1-20231227.mkp b/mkp/inv_ipv4_routes-0.0.1-20231227.mkp new file mode 100644 index 0000000000000000000000000000000000000000..4570c23729a78e06d8488f74909cfa40e54d75ae Binary files /dev/null and b/mkp/inv_ipv4_routes-0.0.1-20231227.mkp differ diff --git a/packages/inv_ipv4_routes b/packages/inv_ipv4_routes new file mode 100644 index 0000000000000000000000000000000000000000..08cde07f43b5d4778eb9de6a9de51a21064a4d04 --- /dev/null +++ b/packages/inv_ipv4_routes @@ -0,0 +1,12 @@ +{'author': 'Th.L. (thl-cmk[at]outlook[dot]com)', + 'description': 'Adds the IPv4 routes of a device monitored via SNMP to the ' + 'inventory\n', + 'download_url': 'https://thl-cmk.hopto.org', + 'files': {'agent_based': ['inv_ipv4_routes.py'], + 'web': ['plugins/views/inv_ipv4_routes.py']}, + 'name': 'inv_ipv4_routes', + 'title': 'Inventory of IPv4 routes', + 'version': '0.0.1-20231227', + 'version.min_required': '2.2.0b1', + 'version.packaged': '2.2.0p14', + 'version.usable_until': '2.3.0p1'} diff --git a/web/plugins/views/inv_ipv4_routes.py b/web/plugins/views/inv_ipv4_routes.py new file mode 100644 index 0000000000000000000000000000000000000000..eb44dfb761cfdf292aaa7214239f6f20bc73bb85 --- /dev/null +++ b/web/plugins/views/inv_ipv4_routes.py @@ -0,0 +1,29 @@ +#!/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 : 2023-12-27 +# File : inv_ip_addresses.py + +from cmk.gui.views.inventory.registry import inventory_displayhints +from cmk.gui.i18n import _l + +inventory_displayhints.update({ + ".networking.routes:": { + "title": _l("Routes"), + "keyorder": ["target", "device", "type", "gateway"], + 'view': 'inviproutes_of_host', + }, + ".networking.routes:*.target": {"title": _l("Target"), "paint": "ipv4_network"}, + ".networking.routes:*.device": {"title": _l("Device")}, + ".networking.routes:*.type": {"title": _l("Type of route"), "paint": "route_type"}, + ".networking.routes:*.gateway": {"title": _l("Gateway")}, + + ".networking.routes:*.protocol": {"title": _l("Protocol")}, + ".networking.routes:*.status": {"title": _l("Status")}, + ".networking.routes:*.age": {"title": _l("Age")}, + +})