Plugins move back

This commit is contained in:
Jokob-sk
2023-07-22 11:06:01 +10:00
parent 0446f6302e
commit 6e8bb4c2ea
38 changed files with 1183 additions and 545 deletions

View File

@@ -0,0 +1,39 @@
## Overview
A plugin for importing devices from an SNMP enabled router or switch. Using SNMP offers an efficient way to discover IPv4 devices across one or more networks/subnets/vlans.
### Usage
Specify the following settings in the Settings section of PiAlert:
- `SNMPDSC_routers` - A list of `snmpwalk` commands to execute against IP addresses of roputers/switches with SNMP turned on. For example:
- `snmpwalk -v 2c -c public -OXsq 192.168.1.1 .1.3.6.1.2.1.3.1.1.2`
- `snmpwalk -v 2c -c public -Oxsq 192.168.1.1 .1.3.6.1.2.1.3.1.1.2` (note: lower case `x`)
### Setup Cisco IOS
Enable IOS SNMP service and restrict to selected (internal) IP/Subnet.
````
! Add standard ip access-list 10
ip access-list standard 10
permit 192.168.1.0 0.0.0.255
permit host 192.168.2.10
!
! Enable IOS snmp server with Read Only community 'mysnmpcommunitysecret' name.
! Restrict connections to access-list 10
snmp-server community mysnmpcommunitysecret RO 10
````
Confirm SNMP enabled
````
show snmp
````
### Notes
- Only IPv4 supported.
- The SNMP OID `.1.1.1.3.6.1.2.1.3.1.1.2` is specifically for devices IPv4 ARP table. This OID has been tested on Cisco ISRs and other L3 devices. Support may vary between other vendors / devices.
- Expected output (ingestion) in format `iso.3.6.1.2.1.3.1.1.2.3.1.192.168.1.2 "6C 6C 6C 6C 6C 6C "`.

View File

@@ -0,0 +1,337 @@
{
"code_name": "snmp_discovery",
"unique_prefix": "SNMPDSC",
"enabled": true,
"data_source": "pyton-script",
"data_filters": [
{
"compare_column" : "Object_PrimaryID",
"compare_operator" : "==",
"compare_field_id": "txtMacFilter",
"compare_js_template": "'{value}'.toString()",
"compare_use_quotes": true
}
],
"localized": ["display_name", "description", "icon"],
"mapped_to_table": "DHCP_Leases",
"display_name" : [{
"language_code":"en_us",
"string" : "SNMP discovery"
}],
"icon":[{
"language_code":"en_us",
"string" : "<i class=\"fa-solid fa-s\"></i>"
}],
"description": [{
"language_code":"en_us",
"string" : "This plugin is used to discover devices via the arp table(s) of a RFC1213 compliant router or switch."
}],
"params" : [
{
"name" : "routers",
"type" : "setting",
"value" : "SNMPDSC_routers"
}
],
"database_column_definitions":
[
{
"column": "Index",
"css_classes": "col-sm-2",
"show": false,
"type": "label",
"default_value":"",
"options": [],
"localized": ["name"],
"name":[{
"language_code":"en_us",
"string" : "N/A"
}]
} ,
{
"column": "Plugin",
"css_classes": "col-sm-2",
"show": false,
"type": "label",
"default_value":"",
"options": [],
"localized": ["name"],
"name":[{
"language_code":"en_us",
"string" : "N/A"
}]
},
{
"column": "Object_PrimaryID",
"mapped_to_column": "DHCP_MAC",
"css_classes": "col-sm-2",
"show": true,
"type": "devicemac",
"default_value":"",
"options": [],
"localized": ["name"],
"name":[{
"language_code":"en_us",
"string" : "MAC address"
}]
},
{
"column": "Object_SecondaryID",
"mapped_to_column": "DHCP_IP",
"css_classes": "col-sm-2",
"show": true,
"type": "deviceip",
"default_value":"",
"options": [],
"localized": ["name"],
"name":[{
"language_code":"en_us",
"string" : "IP"
}]
} ,
{
"column": "DateTimeCreated",
"css_classes": "col-sm-2",
"show": true,
"type": "label",
"default_value":"",
"options": [],
"localized": ["name"],
"name":[{
"language_code":"en_us",
"string" : "Created"
}]
},
{
"column": "DateTimeChanged",
"mapped_to_column": "DHCP_DateTime",
"css_classes": "col-sm-2",
"show": true,
"type": "label",
"default_value":"",
"options": [],
"localized": ["name"],
"name":[{
"language_code":"en_us",
"string" : "Changed"
}]
},
{
"column": "Watched_Value1",
"mapped_to_column": "DHCP_Name",
"css_classes": "col-sm-2",
"show": true,
"type": "label",
"default_value":"(unknown)",
"options": [],
"localized": ["name"],
"name":[{
"language_code":"en_us",
"string" : "Hostname"
}]
},
{
"column": "Watched_Value2",
"css_classes": "col-sm-2",
"show": true,
"type": "label",
"default_value":"",
"options": [],
"localized": ["name"],
"name":[{
"language_code":"en_us",
"string" : "Router IP"
}]
},
{
"column": "Watched_Value3",
"css_classes": "col-sm-2",
"show": false,
"type": "label",
"default_value":"",
"options": [],
"localized": ["name"],
"name":[{
"language_code":"en_us",
"string" : "Type"
}]
} ,
{
"column": "Watched_Value4",
"css_classes": "col-sm-2",
"show": false,
"type": "label",
"default_value":"",
"options": [],
"localized": ["name"],
"name":[{
"language_code":"en_us",
"string" : "Network"
}]
} ,
{
"column": "UserData",
"css_classes": "col-sm-2",
"show": false,
"type": "textboxsave",
"default_value":"",
"options": [],
"localized": ["name"],
"name":[{
"language_code":"en_us",
"string" : "Comments"
}]
},
{
"column": "Extra",
"css_classes": "col-sm-3",
"show": true,
"type": "label",
"default_value":"",
"options": [],
"localized": ["name"],
"name":[{
"language_code":"en_us",
"string" : "RAW output"
}]
},
{
"column": "Status",
"css_classes": "col-sm-1",
"show": true,
"type": "replace",
"default_value":"",
"options": [
{
"equals": "watched-not-changed",
"replacement": "<div style='text-align:center'><i class='fa-solid fa-square-check'></i><div></div>"
},
{
"equals": "watched-changed",
"replacement": "<div style='text-align:center'><i class='fa-solid fa-triangle-exclamation'></i></div>"
},
{
"equals": "new",
"replacement": "<div style='text-align:center'><i class='fa-solid fa-circle-plus'></i></div>"
}
],
"localized": ["name"],
"name":[{
"language_code":"en_us",
"string" : "Status"
}]
}
],
"settings":[
{
"function": "RUN",
"type": "text.select",
"default_value":"disabled",
"options": ["disabled", "once", "schedule", "always_after_scan", "on_new_device"],
"localized": ["name", "description"],
"name" :[{
"language_code":"en_us",
"string" : "When to run"
}],
"description": [{
"language_code":"en_us",
"string" : "Enable import of devices from a SNMP enabled device. If you select <code>schedule</code> the scheduling settings from below are applied. If you select <code>once</code> the scan is run only once on start of the application (container) or after you update your settings."
}]
},
{
"function": "CMD",
"type": "text",
"default_value":"python3 /home/pi/pialert/front/plugins/snmp_discovery/script.py routers={s-quote}{routers}{s-quote}",
"options": [],
"localized": ["name", "description"],
"name" : [{
"language_code":"en_us",
"string" : "Command"
}],
"description": [{
"language_code":"en_us",
"string" : "Command to run. Not recommended to change."
}]
},
{
"function": "routers",
"type": "list",
"default_value":["snmpwalk -v 2c -c public -OXsq 192.168.1.1 .1.3.6.1.2.1.3.1.1.2"],
"options": [],
"localized": ["name", "description"],
"name" : [{
"language_code":"en_us",
"string" : "Routers"
}],
"description": [{
"language_code":"en_us",
"string" : "A list of <code>snmpwalk</code> commands to execute against IP addresses of roputers/switches with SNMP turned on. <br/> <br/> Example with the router on the IP <code>192.168.1.1</code>: <br/> <code>snmpwalk -v 2c -c public -OXsq 192.168.1.1 .1.3.6.1.2.1.3.1.1.2</code> <br/><br/> Only IPv4 supported. Authentication is not supported. More info on the plugin <a href='https://github.com/jokob-sk/Pi.Alert/tree/main/front/plugins/snmp_discovery' target='_blank'>here</a>."
}]
},
{
"function": "RUN_SCHD",
"type": "text",
"default_value":"0 2 * * *",
"options": [],
"localized": ["name", "description"],
"name" : [{
"language_code":"en_us",
"string" : "Schedule"
}],
"description": [{
"language_code":"en_us",
"string" : "Only enabled if you select <code>schedule</code> in the <a href=\"#SNMPDSC_RUN\"><code>SNMPDSC_RUN</code> setting</a>. Make sure you enter the schedule in the correct cron-like format (e.g. validate at <a href=\"https://crontab.guru/\" target=\"_blank\">crontab.guru</a>). For example entering <code>0 4 * * *</code> will run the scan after 4 am in the <a onclick=\"toggleAllSettings()\" href=\"#TIMEZONE\"><code>TIMEZONE</code> you set above</a>. Will be run NEXT time the time passes."
}]
},
{
"function": "RUN_TIMEOUT",
"type": "integer",
"default_value":5,
"options": [],
"localized": ["name", "description"],
"name" : [{
"language_code":"en_us",
"string" : "Run timeout"
},
{
"language_code":"de_de",
"string" : "Wartezeit"
}],
"description": [{
"language_code":"en_us",
"string" : "Maximum time in seconds to wait for the script to finish. If this time is exceeded the script is aborted."
}]
},
{
"function": "WATCH",
"type": "text.multiselect",
"default_value":["Watched_Value1"],
"options": ["Watched_Value1","Watched_Value2","Watched_Value3","Watched_Value4"],
"localized": ["name", "description"],
"name" :[{
"language_code":"en_us",
"string" : "Watched"
}] ,
"description":[{
"language_code":"en_us",
"string" : "Send a notification if selected values change. Use <code>CTRL + Click</code> to select/deselect. <ul> <li><code>Watched_Value1</code> is Hostname (not discoverable) </li><li><code>Watched_Value2</code> is Router IP </li><li><code>Watched_Value3</code> is not used </li><li><code>Watched_Value4</code> is not used </li></ul>"
}]
},
{
"function": "REPORT_ON",
"type": "text.multiselect",
"default_value":["new","watched-changed"],
"options": ["new","watched-changed","watched-not-changed"],
"localized": ["name", "description"],
"name" :[{
"language_code":"en_us",
"string" : "Report on"
}] ,
"description":[{
"language_code":"en_us",
"string" : "Send a notification only on these statuses. <code>new</code> means a new unique (unique combination of PrimaryId and SecondaryId) object was discovered. <code>watched-changed</code> means that selected <code>Watched_ValueN</code> columns changed."
}]
}
]
}

View File

@@ -0,0 +1,21 @@
DC:A6:32:73:8A:B1|192.168.1.9 |2023-06-24 06:54:16|(unknown)|192.168.1.1|null|null|iso.3.6.1.2.1.3.1.1.2.3.1.192.168.1.9 "DC A6 32 73 8A B1 "|null
00:F6:20:82:88:F1|192.168.1.16 |2023-06-24 06:54:16|(unknown)|192.168.1.1|null|null|iso.3.6.1.2.1.3.1.1.2.3.1.192.168.1.16 "00 F6 20 82 88 F1 "|null
3C:8D:20:F1:9F:04|192.168.1.17 |2023-06-24 06:54:16|(unknown)|192.168.1.1|null|null|iso.3.6.1.2.1.3.1.1.2.3.1.192.168.1.17 "3C 8D 20 F1 9F 04 "|null
B8:27:EB:EC:F6:66|192.168.1.19 |2023-06-24 06:54:16|(unknown)|192.168.1.1|null|null|iso.3.6.1.2.1.3.1.1.2.3.1.192.168.1.19 "B8 27 EB EC F6 66 "|null
74:AC:B9:AD:C3:30|192.168.1.21 |2023-06-24 06:54:16|(unknown)|192.168.1.1|null|null|iso.3.6.1.2.1.3.1.1.2.3.1.192.168.1.21 "74 AC B9 AD C3 30 "|null
B0:A4:60:1E:BF:A4|192.168.1.45 |2023-06-24 06:54:16|(unknown)|192.168.1.1|null|null|iso.3.6.1.2.1.3.1.1.2.3.1.192.168.1.45 "B0 A4 60 1E BF A4 "|null
F4:92:BF:A3:F3:56|192.168.1.57 |2023-06-24 06:54:16|(unknown)|192.168.1.1|null|null|iso.3.6.1.2.1.3.1.1.2.3.1.192.168.1.57 "F4 92 BF A3 F3 56 "|null
1C:69:7A:A2:34:7B|192.168.1.58 |2023-06-24 06:54:16|(unknown)|192.168.1.1|null|null|iso.3.6.1.2.1.3.1.1.2.3.1.192.168.1.58 "1C 69 7A A2 34 7B "|null
C0:06:C3:09:E4:46|192.168.1.66 |2023-06-24 06:54:16|(unknown)|192.168.1.1|null|null|iso.3.6.1.2.1.3.1.1.2.3.1.192.168.1.66 "C0 06 C3 09 E4 46 "|null
00:11:32:EF:A5:6C|192.168.1.82 |2023-06-24 06:54:16|(unknown)|192.168.1.1|null|null|iso.3.6.1.2.1.3.1.1.2.3.1.192.168.1.82 "00 11 32 EF A5 6C "|null
3A:9D:69:E0:29:28|192.168.1.92 |2023-06-24 06:54:16|(unknown)|192.168.1.1|null|null|iso.3.6.1.2.1.3.1.1.2.3.1.192.168.1.92 "3A 9D 69 E0 29 28 "|null
14:C1:4E:2E:A3:3F|192.168.1.94 |2023-06-24 06:54:16|(unknown)|192.168.1.1|null|null|iso.3.6.1.2.1.3.1.1.2.3.1.192.168.1.94 "14 C1 4E 2E A3 3F "|null
48:B0:2D:5C:79:0D|192.168.1.105 |2023-06-24 06:54:16|(unknown)|192.168.1.1|null|null|iso.3.6.1.2.1.3.1.1.2.3.1.192.168.1.105 "48 B0 2D 5C 79 0D "|null
C0:06:C3:09:DE:E2|192.168.1.119 |2023-06-24 06:54:16|(unknown)|192.168.1.1|null|null|iso.3.6.1.2.1.3.1.1.2.3.1.192.168.1.119 "C0 06 C3 09 DE E2 "|null
2C:F0:5D:9E:73:2C|192.168.1.121 |2023-06-24 06:54:16|(unknown)|192.168.1.1|null|null|iso.3.6.1.2.1.3.1.1.2.3.1.192.168.1.121 "2C F0 5D 9E 73 2C "|null
D0:21:F9:B4:CA:0B|192.168.1.138 |2023-06-24 06:54:16|(unknown)|192.168.1.1|null|null|iso.3.6.1.2.1.3.1.1.2.3.1.192.168.1.138 "D0 21 F9 B4 CA 0B "|null
D0:21:F9:8C:59:F9|192.168.1.139 |2023-06-24 06:54:16|(unknown)|192.168.1.1|null|null|iso.3.6.1.2.1.3.1.1.2.3.1.192.168.1.139 "D0 21 F9 8C 59 F9 "|null
28:87:BA:76:ED:03|192.168.1.163 |2023-06-24 06:54:16|(unknown)|192.168.1.1|null|null|iso.3.6.1.2.1.3.1.1.2.3.1.192.168.1.163 "28 87 BA 76 ED 03 "|null
6C:97:6D:7B:4A:43|192.168.1.167 |2023-06-24 06:54:16|(unknown)|192.168.1.1|null|null|iso.3.6.1.2.1.3.1.1.2.3.1.192.168.1.167 "6C 97 6D 7B 4A 43 "|null
58:B6:23:70:D6:B4|192.168.1.169 |2023-06-24 06:54:16|(unknown)|192.168.1.1|null|null|iso.3.6.1.2.1.3.1.1.2.3.1.192.168.1.169 "58 B6 23 70 D6 B4 "|null
3E:33:4E:7C:E1:C3|192.168.1.170 |2023-06-24 06:54:16|(unknown)|192.168.1.1|null|null|iso.3.6.1.2.1.3.1.1.2.3.1.192.168.1.170 "3E 33 4E 7C E1 C3 "|null

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,172 @@
#!/usr/bin/env python
# Example call
# python3 /home/pi/pialert/front/plugins/snmp_discovery/script.py routers='snmpwalk -v 2c -c public -OXsq 192.168.1.1 .1.3.6.1.2.1.3.1.1.2'
from __future__ import unicode_literals
from time import sleep, time, strftime
import requests
from requests import Request, Session, packages
import pathlib
import threading
import subprocess
import socket
import json
import argparse
import io
import sys
from requests.packages.urllib3.exceptions import InsecureRequestWarning
import pwd
import os
curPath = str(pathlib.Path(__file__).parent.resolve())
log_file = curPath + '/script.log'
last_run = curPath + '/last_result.log'
# Workflow
def main():
# init global variables
global ROUTERS
# empty file
open(last_run , 'w').close()
last_run_logfile = open(last_run, 'a')
parser = argparse.ArgumentParser(description='This plugin is used to discover devices via the arp table(s) of a RFC1213 compliant router or switch.')
parser.add_argument('routers', action="store", help="IP(s) of routers, separated by comma (,) if passing multiple")
values = parser.parse_args()
# parse output
newEntries = []
if values.routers:
ROUTERS = values.routers.split('=')[1].replace('\'','')
newEntries = get_entries(newEntries)
for e in newEntries:
# Insert list into the log
service_monitoring_log(e.primaryId, e.secondaryId, e.created, e.watched1, e.watched2, e.watched3, e.watched4, e.extra, e.foreignKey )
# -----------------------------------------------------------------------------
def get_entries(newEntries):
routers = []
if ',' in ROUTERS:
# multiple
routers = ROUTERS.split(',')
else:
# only one
routers.append(ROUTERS)
for router in routers:
# snmpwalk -v 2c -c public -OXsq 192.168.1.1 .1.3.6.1.2.1.3.1.1.2
print(router)
timeoutSec = 10
snmpwalkArgs = router.split(' ')
# Execute N probes and insert in list
probes = 1 # N probes
newLines = []
for _ in range(probes):
output = subprocess.check_output (snmpwalkArgs, universal_newlines=True, stderr=subprocess.STDOUT, timeout=(timeoutSec ))
newLines = newLines + output.split("\n")
# Process outputs
# Sample: iso.3.6.1.2.1.3.1.1.2.3.1.192.168.1.2 "6C 6C 6C 6C 6C 6C "
with open(log_file, 'a') as run_logfile:
for line in newLines:
# debug
run_logfile.write(line)
tmpSplt = line.split('"')
if len(tmpSplt) == 3:
ipStr = tmpSplt[0].split('.')[-4:] # Get the last 4 elements to extract the IP
macStr = tmpSplt[1].strip().split(' ') # Remove leading/trailing spaces from MAC
if 'iso.' in line and len(ipStr) == 4:
macAddress = ':'.join(macStr)
ipAddress = '.'.join(ipStr)
tmpEntry = plugin_object_class(
macAddress,
ipAddress,
watched1='(unknown)',
watched2=snmpwalkArgs[6], # router IP
extra=line
)
newEntries.append(tmpEntry)
return newEntries
# -------------------------------------------------------------------
class plugin_object_class:
def __init__(self, primaryId = '',secondaryId = '', watched1 = '',watched2 = '',watched3 = '',watched4 = '',extra = '',foreignKey = ''):
self.pluginPref = ''
self.primaryId = primaryId
self.secondaryId = secondaryId
self.created = strftime("%Y-%m-%d %H:%M:%S")
self.changed = ''
self.watched1 = watched1
self.watched2 = watched2
self.watched3 = watched3
self.watched4 = watched4
self.status = ''
self.extra = extra
self.userData = ''
self.foreignKey = foreignKey
# -----------------------------------------------------------------------------
def service_monitoring_log(primaryId, secondaryId, created, watched1, watched2 = 'null', watched3 = 'null', watched4 = 'null', extra ='null', foreignKey ='null' ):
if watched1 == '':
watched1 = 'null'
if watched2 == '':
watched2 = 'null'
if watched3 == '':
watched3 = 'null'
if watched4 == '':
watched4 = 'null'
if extra == '':
extra = 'null'
if foreignKey == '':
foreignKey = 'null'
with open(last_run, 'a') as last_run_logfile:
last_run_logfile.write("{}|{}|{}|{}|{}|{}|{}|{}|{}\n".format(
primaryId,
secondaryId,
created,
watched1,
watched2,
watched3,
watched4,
extra,
foreignKey
)
)
#===============================================================================
# BEGIN
#===============================================================================
if __name__ == '__main__':
main()