From ab24d246a5aafa00c4e7597a40bb0aa40cdca793 Mon Sep 17 00:00:00 2001 From: "th.l" <thl-cmk@outlook.com> Date: Wed, 11 Dec 2024 20:16:40 +0100 Subject: [PATCH] added host label nvdct/l3v6_topology:host and nvdct/l3v6_topology:router --- README.md | 2 +- mkp/inv_ip_address-0.0.6-20241210.mkp | Bin 0 -> 4126 bytes .../agent_based/inv_ip_addresses.py | 86 +++++++++++++----- source/packages/inv_ip_address | 2 +- source/web/plugins/views/inv_ip_addresses.py | 5 +- 5 files changed, 70 insertions(+), 25 deletions(-) create mode 100644 mkp/inv_ip_address-0.0.6-20241210.mkp diff --git a/README.md b/README.md index 0b3d2b2..97eea09 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[PACKAGE]: ../../raw/master/mkp/inv_ip_address-0.0.5-20241209.mkp "inv_ip_address-0.0.5-20241209.mkp" +[PACKAGE]: ../../raw/master/mkp/inv_ip_address-0.0.6-20241210.mkp "inv_ip_address-0.0.6-20241210.mkp" # Inventory of IP addresses The plugin adds the IP-addresses information to the inventory for devices monitored via SNMP. The plugin supports IPv4 and IPv6. diff --git a/mkp/inv_ip_address-0.0.6-20241210.mkp b/mkp/inv_ip_address-0.0.6-20241210.mkp new file mode 100644 index 0000000000000000000000000000000000000000..ea80d563999a5f6224b77e4a24475640e770b585 GIT binary patch literal 4126 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 CLlLh4 literal 0 HcmV?d00001 diff --git a/source/cmk_addons_plugins/inv_ip_address/agent_based/inv_ip_addresses.py b/source/cmk_addons_plugins/inv_ip_address/agent_based/inv_ip_addresses.py index 92b6d60..7ccce20 100644 --- a/source/cmk_addons_plugins/inv_ip_address/agent_based/inv_ip_addresses.py +++ b/source/cmk_addons_plugins/inv_ip_address/agent_based/inv_ip_addresses.py @@ -17,8 +17,12 @@ # 2024-12-03: added IP-MIB::ipAddressTable for IPv6 support # incompatible: renamed to inv_ip_address -> remove inv_ipv4_address.mkp before updating # 2024-12-05 changed to use ip_interface -# 2024-12-06: incompatible: changed hostlabel to nvdct/l3v4_topology:host and nvdct/l3v4_topology:router +# 2024-12-06: incompatible: changed host label to nvdct/l3v4_topology:host and nvdct/l3v4_topology:router # 2024-12-09: rewritten for CMK checkAPI 2.0 +# 2024-12-10: fixed crash in host label function (AttributeError ('dict_values' object has no attribute 'version')) +# added support for ipv6z address type +# fixed duplicate ip information in section +# added host label nvdct/l3v6_topology:host and nvdct/l3v6_topology:router from collections.abc import Mapping, MutableSequence, Sequence from ipaddress import AddressValueError, NetmaskValueError, ip_interface @@ -130,6 +134,9 @@ def parse_inv_ip_addresses(string_table: List[StringByteTable]) -> Section: except ValueError: continue + if oid_end.startswith('4.20.254.128.'): # ipv6z, link local + ip_prefix = '64' + if (prefix := ip_prefix.split('.')[-1]) == '0': # drop entries without prefix (0) -> fortinet continue @@ -156,21 +163,36 @@ def parse_inv_ip_addresses(string_table: List[StringByteTable]) -> Section: ) case '39': raw_address = ''.join([chr(int(x)) for x in raw_address.split('.')]) + case '4': # ipv6z + # [ + # ['4.20.254.128.0.0.0.0.0.0.1.146.1.104.0.16.1.65.18.0.0.2', [], '1', '.0.0'], + # ['4.20.254.128.0.0.0.0.0.0.1.146.1.104.0.16.1.65.18.0.0.3', [], '2', '.0.0'] + # ] + # IP-MIB::ipAddressIfIndex.ipv6z."fe:80:00:00:00:00:00:00:01:92:01:68:00:10:01:41%301989890" = INTEGER: 1 + # IP-MIB::ipAddressIfIndex.ipv6z."fe:80:00:00:00:00:00:00:01:92:01:68:00:10:01:41%301989891" = INTEGER: 2 + match raw_length: + case '20': + raw_address = [f'{int(x):02x}' for x in raw_address.split('.')] + scope_id = '.'.join(raw_address[16:]) + raw_address = ':'.join( + [''.join([raw_address[i], raw_address[i + 1]]) for i in range(0, len(raw_address) - 4, 2)] + ) + raw_address += f'%{scope_id}' case _: continue try: - interface = ip_interface(f'{raw_address}/{prefix}') + interface_ip = ip_interface(f'{raw_address}/{prefix}') except (AddressValueError, NetmaskValueError): continue - if interface.ip.is_loopback: # Drop localhost + if interface_ip.ip.is_loopback: # Drop localhost continue - if interface.ip.exploded == '0.0.0.0': # drop this host address + if interface_ip.ip.exploded == '0.0.0.0': # drop this host address continue - ip_infos.append({(str(interface_by_index.get(if_index, if_index))): interface}) + ip_infos.append({(str(interface_by_index.get(if_index, if_index))): interface_ip}) for entry in ip_info_20: try: @@ -179,17 +201,18 @@ def parse_inv_ip_addresses(string_table: List[StringByteTable]) -> Section: continue try: - interface = ip_interface(f'{raw_address}/{raw_netmask}') + interface_ip = ip_interface(f'{raw_address}/{raw_netmask}') except (AddressValueError, NetmaskValueError): continue - if interface.ip.is_loopback: # Drop localhost + if interface_ip.ip.is_loopback: # Drop localhost continue - if interface.ip.exploded == '0.0.0.0': # drop this host address + if interface_ip.ip.exploded == '0.0.0.0': # drop this host address continue - ip_infos.append({str(interface_by_index.get(if_index, if_index)): interface}) + if not (ip_info := {str(interface_by_index.get(if_index, if_index)): interface_ip}) in ip_infos: + ip_infos.append(ip_info) return ip_infos @@ -199,19 +222,33 @@ def host_label_inv_ip_addresses(section: Section) -> HostLabelGenerator: Host label function Labels: nvdct/l3v4_topology: - This label is set to "host" for all devices with one IPv4 address except form 127.0.0.0/8 and to - "router" for all devices with more than one IPv4 address except form 127.0.0.0/8 + "host" is set for all devices with one IPv4 address + "router" is set for all devices with more than one IPv4 address. + nvdct/l3v6_topology: + "host" is set for all devices with one IPv6 address + "router" is set for all devices with more than one IPv6 address. + + Link-local ("FE80::/64), unspecified ("::") and local-host ("127.0.0.0/8", "::1") IPs don't count. """ - non_host_ips = 0 - for entry in section: - ip_data = entry.values() - if ip_data.version == 4 and not ip_data.ip.is_loopback: - non_host_ips += 1 - if non_host_ips == 1: - yield HostLabel(name="nvdct/l3v4_topology", value="host") - if non_host_ips > 1: - yield HostLabel(name="nvdct/l3v4_topology", value="router") - return + + valid_v4_ips = 0 + valid_v6_ips = 0 + for interface_ips in section: + for interface_ip in interface_ips.values(): + if interface_ip.version == 4 and not interface_ip.is_loopback: + valid_v4_ips += 1 + if valid_v4_ips == 1: + yield HostLabel(name="nvdct/l3v4_topology", value="host") + if valid_v4_ips == 2: + yield HostLabel(name="nvdct/l3v4_topology", value="router") + + elif interface_ip.version == 6 and not interface_ip.is_loopback \ + and not interface_ip.is_link_local and not interface_ip.is_unspecified: + valid_v6_ips += 1 + if valid_v6_ips == 1: + yield HostLabel(name="nvdct/l3v6_topology", value="host") + if valid_v6_ips == 2: + yield HostLabel(name="nvdct/l3v6_topology", value="router") def inventory_ip_addresses(section: Section) -> InventoryResult: @@ -221,6 +258,11 @@ def inventory_ip_addresses(section: Section) -> InventoryResult: } for entry in section: for if_name, ip_data in entry.items(): + try: # ipv4 has no scope_id + scope_id = ip_data.scope_id + except AttributeError: + scope_id = None + yield TableRow( path=['networking', 'addresses'], key_columns={ @@ -233,6 +275,7 @@ def inventory_ip_addresses(section: Section) -> InventoryResult: 'netmask': str(ip_data.network.netmask), 'network': str(ip_data.network.network_address), 'type': address_type.get(ip_data.version).lower(), + **({"scope_id": str(scope_id)} if scope_id else {}), } ) @@ -273,3 +316,4 @@ inventory_plugin_inv_ip_address = InventoryPlugin( name='inv_ip_addresses', inventory_function=inventory_ip_addresses, ) + diff --git a/source/packages/inv_ip_address b/source/packages/inv_ip_address index e96434d..db97744 100644 --- a/source/packages/inv_ip_address +++ b/source/packages/inv_ip_address @@ -13,7 +13,7 @@ 'web': ['plugins/views/inv_ip_addresses.py']}, 'name': 'inv_ip_address', 'title': 'Inventory of IP addresses', - 'version': '0.0.5-20241209', + 'version': '0.0.6-20241210', 'version.min_required': '2.3.0b1', 'version.packaged': 'cmk-mkp-tool 0.2.0', 'version.usable_until': '2.4.0b1'} diff --git a/source/web/plugins/views/inv_ip_addresses.py b/source/web/plugins/views/inv_ip_addresses.py index 81afc04..84c70ab 100644 --- a/source/web/plugins/views/inv_ip_addresses.py +++ b/source/web/plugins/views/inv_ip_addresses.py @@ -28,9 +28,10 @@ inventory_displayhints.update({ }, '.networking.addresses:*.address': {'title': _l('Address')}, '.networking.addresses:*.broadcast': {'title': _l('Broadcast')}, - '.networking.addresses:*.cidr': {'title': _l('Prefix'), }, # 'filter': FilterInvtableIDRange}, + '.networking.addresses:*.cidr': {'title': _l('Prefix Length'), }, # 'filter': FilterInvtableIDRange}, '.networking.addresses:*.device': {'title': _l('Device')}, '.networking.addresses:*.netmask': {'title': _l('Netmask')}, '.networking.addresses:*.network': {'title': _l('Network')}, - '.networking.addresses:*.type': {'title': _l('Address Type'), 'paint': 'ip_address_type'}, + '.networking.addresses:*.type': {'title': _l('Type'), 'paint': 'ip_address_type'}, + '.networking.addresses:*.scope_id': {'title': _l('Scope ID')}, }) -- GitLab