NSLOOKUP v0.1

This commit is contained in:
Jokob-sk
2024-01-26 09:23:55 +11:00
parent f40f99aac9
commit d18a59944b
10 changed files with 542 additions and 36 deletions

View File

@@ -0,0 +1,7 @@
## Overview
Plugin for device name discovery via the [nslookup](https://linux.die.net/man/1/nslookup) network utility.
### Usage
- Check the Settings page for details.

View File

@@ -0,0 +1,321 @@
{
"code_name": "nslookup_scan",
"unique_prefix": "NSLOOKUP",
"plugin_type": "other",
"enabled": true,
"data_source": "script",
"show_ui": true,
"localized": ["display_name", "description", "icon"],
"display_name": [
{
"language_code": "en_us",
"string": "NSLOOKUP (Name discovery)"
}
],
"icon": [
{
"language_code": "en_us",
"string": "<i class=\"fa-solid fa-search\"></i>"
}
],
"description": [
{
"language_code": "en_us",
"string": "A plugin to discover device names."
}
],
"params" : [
{
"name" : "ips",
"type" : "sql",
"value" : "SELECT dev_LastIP from DEVICES order by dev_MAC",
"timeoutMultiplier" : true
}
],
"settings": [
{
"function": "RUN",
"events": ["run"],
"type": "text.select",
"default_value":"on_new_device",
"options": ["disabled", "on_new_device", "once", "schedule", "always_after_scan"],
"localized": ["name", "description"],
"name" :[{
"language_code":"en_us",
"string" : "When to run"
},
{
"language_code":"es_es",
"string" : "Cuándo ejecutar"
},
{
"language_code":"de_de",
"string" : "Wann laufen"
}],
"description": [{
"language_code":"en_us",
"string" : "When the plugin should be executed. If enabled this will execute the scan until there are no <code>(unknown)</code> or <code>(name not found)</code> devices. Setting this to <code>on_new_device</code> or a daily <code>schedule</code> is recommended."
}]
},
{
"function": "CMD",
"type": "readonly",
"default_value": "python3 /home/pi/pialert/front/plugins/nslookup_scan/nslookup.py",
"options": [],
"localized": ["name", "description"],
"name": [
{
"language_code": "en_us",
"string": "Command"
},
{
"language_code": "es_es",
"string": "Comando"
},
{
"language_code": "de_de",
"string": "Befehl"
}
],
"description": [
{
"language_code": "en_us",
"string": "Command to run. This can not be changed"
},
{
"language_code": "es_es",
"string": "Comando a ejecutar. Esto no se puede cambiar"
},
{
"language_code": "de_de",
"string": "Befehl zum Ausführen. Dies kann nicht geändert werden"
}
]
},
{
"function": "RUN_SCHD",
"type": "text",
"default_value":"*/30 * * * *",
"options": [],
"localized": ["name", "description"],
"name" : [{
"language_code":"en_us",
"string" : "Schedule"
},
{
"language_code":"es_es",
"string" : "Schedule"
},
{
"language_code":"de_de",
"string" : "Schedule"
}],
"description": [{
"language_code":"en_us",
"string" : "Only enabled if you select <code>schedule</code> in the <a href=\"#NSLOOKUP_RUN\"><code>NSLOOKUP_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."
},
{
"language_code":"es_es",
"string" : "Solo está habilitado si selecciona <code>schedule</code> en la configuración <a href=\"#NSLOOKUP_RUN\"><code>NSLOOKUP_RUN</code></a>. Asegúrese de ingresar la programación en el formato similar a cron correcto (por ejemplo, valide en <a href=\"https://crontab.guru/\" target=\"_blank\">crontab.guru</a>). Por ejemplo, ingresar <code>0 4 * * *</code> ejecutará el escaneo después de las 4 a.m. en el <a onclick=\"toggleAllSettings()\" href=\"#TIMEZONE\"><code>TIMEZONE</ código> que configuró arriba</a>. Se ejecutará la PRÓXIMA vez que pase el tiempo."
},
{
"language_code":"de_de",
"string" : "Nur aktiviert, wenn Sie <code>schedule</code> in der <a href=\"#NSLOOKUP_RUN\"><code>NSLOOKUP_RUN</code>-Einstellung</a> auswählen. Stellen Sie sicher, dass Sie den Zeitplan im richtigen Cron-ähnlichen Format eingeben (z. B. validieren unter <a href=\"https://crontab.guru/\" target=\"_blank\">crontab.guru</a>). Wenn Sie beispielsweise <code>0 4 * * *</code> eingeben, wird der Scan nach 4 Uhr morgens in der <a onclick=\"toggleAllSettings()\" href=\"#TIMEZONE\"><code>TIMEZONE</ ausgeführt. Code> den Sie oben festgelegt haben</a>. Wird das NÄCHSTE Mal ausgeführt, wenn die Zeit vergeht."
}]
},
{
"function": "RUN_TIMEOUT",
"type": "integer",
"default_value": 10,
"options": [],
"localized": ["name", "description"],
"name": [
{
"language_code": "en_us",
"string": "Run timeout"
},
{
"language_code": "es_es",
"string": "Tiempo límite de ejecución"
},
{
"language_code": "de_de",
"string": "Zeitüberschreitung"
}
],
"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."
},
{
"language_code": "es_es",
"string": "Tiempo máximo en segundos para esperar a que finalice el script. Si se supera este tiempo, el script se cancela."
},
{
"language_code": "de_de",
"string": "Maximale Zeit in Sekunden, die auf den Abschluss des Skripts gewartet werden soll. Bei Überschreitung dieser Zeit wird das Skript abgebrochen."
}
]
}
],
"database_column_definitions":
[
{
"column": "Object_PrimaryID",
"css_classes": "col-sm-2",
"show": true,
"type": "device_name_mac",
"default_value": "",
"options": [],
"localized": [
"name"
],
"name": [
{
"language_code": "en_us",
"string": "MAC"
},
{
"language_code": "es_es",
"string": "MAC"
}
]
},
{
"column": "Object_SecondaryID",
"css_classes": "col-sm-2",
"show": true,
"type": "label",
"default_value": "",
"options": [],
"localized": [
"name"
],
"name": [
{
"language_code": "en_us",
"string": "IP"
},
{
"language_code": "es_es",
"string": "IP"
}
]
},
{
"column": "Watched_Value1",
"css_classes": "col-sm-2",
"show": true,
"type": "label",
"default_value": "",
"options": [],
"localized": [
"name"
],
"name": [
{
"language_code": "en_us",
"string": "Server"
}
]
},
{
"column": "Watched_Value2",
"css_classes": "col-sm-2",
"show": true,
"type": "label",
"default_value": "",
"options": [],
"localized": [
"name"
],
"name": [
{
"language_code": "en_us",
"string": "Name"
}
]
},
{
"column": "DateTimeCreated",
"css_classes": "col-sm-2",
"show": true,
"type": "label",
"default_value": "",
"options": [],
"localized": [
"name"
],
"name": [
{
"language_code": "en_us",
"string": "Created"
},
{
"language_code": "es_es",
"string": "Creado"
}
]
},
{
"column": "DateTimeChanged",
"css_classes": "col-sm-2",
"show": true,
"type": "label",
"default_value": "",
"options": [],
"localized": [
"name"
],
"name": [
{
"language_code": "en_us",
"string": "Changed"
},
{
"language_code": "es_es",
"string": "Cambiado"
}
]
},
{
"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>"
},
{
"equals": "missing-in-last-scan",
"replacement": "<div style='text-align:center'><i class='fa-solid fa-question'></i></div>"
}
],
"localized": [
"name"
],
"name": [
{
"language_code": "en_us",
"string": "Status"
},
{
"language_code": "es_es",
"string": "Estado"
}
]
}
]
}

View File

@@ -0,0 +1,134 @@
#!/usr/bin/env python
# test script by running:
# tbc
import os
import pathlib
import argparse
import subprocess
import sys
import hashlib
import csv
import sqlite3
import re
from io import StringIO
from datetime import datetime
sys.path.append("/home/pi/pialert/front/plugins")
sys.path.append('/home/pi/pialert/pialert')
from plugin_helper import Plugin_Object, Plugin_Objects, decodeBase64
from logger import mylog, append_line_to_file
from helper import timeNowTZ, get_setting_value
from const import logPath, pialertPath, fullDbPath
from database import DB
from device import Device_obj
CUR_PATH = str(pathlib.Path(__file__).parent.resolve())
LOG_FILE = os.path.join(CUR_PATH, 'script.log')
RESULT_FILE = os.path.join(CUR_PATH, 'last_result.log')
pluginName = 'NSLOOKUP'
def main():
mylog('verbose', [f'[{pluginName}] In script'])
timeout = get_setting_value('NSLOOKUP_RUN_TIMEOUT')
# Create a database connection
db = DB() # instance of class DB
db.open()
# Initialize the Plugin obj output file
plugin_objects = Plugin_Objects(RESULT_FILE)
# Create a Device_obj instance
device_handler = Device_obj(db)
# Retrieve devices
unknown_devices = device_handler.getUnknown()
for device in unknown_devices:
domain_name, dns_server = execute_nslookup(device['dev_LastIP'], timeout)
if domain_name != '':
plugin_objects.add_object(
# "MAC", "IP", "Server", "Name"
primaryId = device['dev_MAC'],
secondaryId = device['dev_LastIP'],
watched1 = dns_server,
watched2 = domain_name,
watched3 = '',
watched4 = '',
extra = '',
foreignKey = device['dev_MAC'])
plugin_objects.write_result_file()
mylog('verbose', [f'[{pluginName}] Script finished'])
return 0
#===============================================================================
# Execute scan
#===============================================================================
def execute_nslookup (ip, timeout):
"""
Execute the NSLOOKUP command on IP.
"""
nslookup_args = ['nslookup', ip]
# Execute command
output = ""
try:
# try runnning a subprocess with a forced (timeout) in case the subprocess hangs
output = subprocess.check_output (nslookup_args, universal_newlines=True, stderr=subprocess.STDOUT, timeout=(timeout), text=True)
domain_name = ''
dns_server = ''
# Parse output using regular expressions
domain_pattern = re.compile(r'Name:\s+(.+)')
server_pattern = re.compile(r'Server:\s+(.+)')
domain_match = domain_pattern.search(output.stdout)
server_match = server_pattern.search(output.stdout)
if domain_match:
domain_name = domain_match.group(1)
mylog('verbose', [f'[{pluginName}] Domain Name: {domain_name}'])
if server_match:
dns_server = server_match.group(1)
mylog('verbose', [f'[{pluginName}] DNS Server: {dns_server}'])
return domain_name, dns_server
except subprocess.CalledProcessError as e:
# An error occured, handle it
mylog('verbose', [f'[{pluginName}]', e.output])
mylog('verbose', [f'[{pluginName}] ⚠ ERROR - check logs'])
except subprocess.TimeoutExpired as timeErr:
mylog('verbose', [f'[{pluginName}] TIMEOUT - the process forcefully terminated as timeout reached'])
if output == "": # check if the subprocess failed
mylog('verbose', [f'[{pluginName}] Scan: FAIL - check logs'])
else:
mylog('verbose', [f'[{pluginName}] Scan: SUCCESS'])
return '', ''
#===============================================================================
# BEGIN
#===============================================================================
if __name__ == '__main__':
main()