mirror of
https://github.com/jokob-sk/NetAlertX.git
synced 2025-12-07 01:26:11 -08:00
NSLOOKUP v0.1
This commit is contained in:
@@ -56,9 +56,8 @@ Looking forward to your contributions if you decide to share your work with the
|
|||||||
> - [WatchYourLAN](https://github.com/aceberg/WatchYourLAN) - Lightweight network IP scanner with web GUI (Open source)
|
> - [WatchYourLAN](https://github.com/aceberg/WatchYourLAN) - Lightweight network IP scanner with web GUI (Open source)
|
||||||
> - [Fing](https://www.fing.com/) - Network scanner app for your Internet security (Commercial, Phone App, Proprietary hardware)
|
> - [Fing](https://www.fing.com/) - Network scanner app for your Internet security (Commercial, Phone App, Proprietary hardware)
|
||||||
|
|
||||||
## ❤ Support me
|
## ❤ Support me for...
|
||||||
|
|
||||||
Get:
|
|
||||||
- Regular updates to keep your data and family safe 🔄
|
- Regular updates to keep your data and family safe 🔄
|
||||||
- Better and more functionality➕
|
- Better and more functionality➕
|
||||||
- I don't get burned out and the app survives longer🔥🤯
|
- I don't get burned out and the app survives longer🔥🤯
|
||||||
|
|||||||
@@ -239,6 +239,8 @@ function main () {
|
|||||||
|
|
||||||
// get visible columns
|
// get visible columns
|
||||||
$.get('php/server/parameters.php?action=get&expireMinutes=525600&defaultValue='+defaultValue+'¶meter=Front_Devices_Columns_Visible&skipcache', function(data) {
|
$.get('php/server/parameters.php?action=get&expireMinutes=525600&defaultValue='+defaultValue+'¶meter=Front_Devices_Columns_Visible&skipcache', function(data) {
|
||||||
|
|
||||||
|
handle_locked_DB(data)
|
||||||
|
|
||||||
// save which columns are in the Devices page visible
|
// save which columns are in the Devices page visible
|
||||||
tableColumnVisible = numberArrayFromString(data);
|
tableColumnVisible = numberArrayFromString(data);
|
||||||
@@ -250,6 +252,8 @@ function main () {
|
|||||||
|
|
||||||
// get the custom order specified by the user
|
// get the custom order specified by the user
|
||||||
$.get('php/server/parameters.php?action=get&expireMinutes=525600&defaultValue='+defaultValue+'¶meter=Front_Devices_Columns_Order&skipcache', function(data) {
|
$.get('php/server/parameters.php?action=get&expireMinutes=525600&defaultValue='+defaultValue+'¶meter=Front_Devices_Columns_Order&skipcache', function(data) {
|
||||||
|
|
||||||
|
handle_locked_DB(data)
|
||||||
|
|
||||||
// save the columns order in the Devices page
|
// save the columns order in the Devices page
|
||||||
tableColumnOrder = numberArrayFromString(data);
|
tableColumnOrder = numberArrayFromString(data);
|
||||||
|
|||||||
@@ -346,10 +346,27 @@ function sanitize(data)
|
|||||||
return data.replace(/(\r\n|\n|\r)/gm,"").replace(/[^\x00-\x7F]/g, "")
|
return data.replace(/(\r\n|\n|\r)/gm,"").replace(/[^\x00-\x7F]/g, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Check and handle locked database
|
||||||
|
function handle_locked_DB(data)
|
||||||
|
{
|
||||||
|
if(data.includes('database is locked'))
|
||||||
|
{
|
||||||
|
console.log(data)
|
||||||
|
showSpinner()
|
||||||
|
|
||||||
|
setTimeout(function() {
|
||||||
|
location.reload();
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
function numberArrayFromString(data)
|
function numberArrayFromString(data)
|
||||||
{
|
{
|
||||||
console.log(data)
|
|
||||||
|
|
||||||
data = JSON.parse(sanitize(data));
|
data = JSON.parse(sanitize(data));
|
||||||
return data.replace(/\[|\]/g, '').split(',').map(Number);
|
return data.replace(/\[|\]/g, '').split(',').map(Number);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -816,6 +816,8 @@ function saveSelectedColumns () {
|
|||||||
function initializeSelectedColumns () {
|
function initializeSelectedColumns () {
|
||||||
$.get('php/server/parameters.php?action=get&expireMinutes=525600&defaultValue='+colDefaultOrderTxt+'¶meter=Front_Devices_Columns_Visible', function(data) {
|
$.get('php/server/parameters.php?action=get&expireMinutes=525600&defaultValue='+colDefaultOrderTxt+'¶meter=Front_Devices_Columns_Visible', function(data) {
|
||||||
|
|
||||||
|
handle_locked_DB(data)
|
||||||
|
|
||||||
tableColumnShow = numberArrayFromString(data);
|
tableColumnShow = numberArrayFromString(data);
|
||||||
|
|
||||||
for(i=0; i < tableColumnShow.length; i++)
|
for(i=0; i < tableColumnShow.length; i++)
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ CUR_PATH = str(pathlib.Path(__file__).parent.resolve())
|
|||||||
LOG_FILE = os.path.join(CUR_PATH, 'script.log')
|
LOG_FILE = os.path.join(CUR_PATH, 'script.log')
|
||||||
RESULT_FILE = os.path.join(CUR_PATH, 'last_result.log')
|
RESULT_FILE = os.path.join(CUR_PATH, 'last_result.log')
|
||||||
|
|
||||||
|
pluginName = 'DBCLNP'
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(description='DB cleanup tasks')
|
parser = argparse.ArgumentParser(description='DB cleanup tasks')
|
||||||
@@ -40,13 +42,13 @@ def main():
|
|||||||
DAYS_TO_KEEP_EVENTS = int(values.daystokeepevents.split('=')[1])
|
DAYS_TO_KEEP_EVENTS = int(values.daystokeepevents.split('=')[1])
|
||||||
PHOLUS_DAYS_DATA = int(values.pholuskeepdays.split('=')[1])
|
PHOLUS_DAYS_DATA = int(values.pholuskeepdays.split('=')[1])
|
||||||
|
|
||||||
mylog('verbose', ['[DBCLNP] In script'])
|
mylog('verbose', [f'[{pluginName}] In script'])
|
||||||
|
|
||||||
|
|
||||||
# Execute cleanup/upkeep
|
# Execute cleanup/upkeep
|
||||||
cleanup_database(fullDbPath, DAYS_TO_KEEP_EVENTS, PHOLUS_DAYS_DATA, HRS_TO_KEEP_NEWDEV, PLUGINS_KEEP_HIST)
|
cleanup_database(fullDbPath, DAYS_TO_KEEP_EVENTS, PHOLUS_DAYS_DATA, HRS_TO_KEEP_NEWDEV, PLUGINS_KEEP_HIST)
|
||||||
|
|
||||||
mylog('verbose', ['[DBCLNP] Cleanup complete file '])
|
mylog('verbose', [f'[{pluginName}] Cleanup complete'])
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
@@ -58,25 +60,25 @@ def cleanup_database (dbPath, DAYS_TO_KEEP_EVENTS, PHOLUS_DAYS_DATA, HRS_TO_KEEP
|
|||||||
Cleaning out old records from the tables that don't need to keep all data.
|
Cleaning out old records from the tables that don't need to keep all data.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
mylog('verbose', ['[DBCLNP] Upkeep Database:' ])
|
mylog('verbose', [f'[{pluginName}] Upkeep Database:' ])
|
||||||
|
|
||||||
# Connect to the PiAlert SQLite database
|
# Connect to the PiAlert SQLite database
|
||||||
conn = sqlite3.connect(dbPath)
|
conn = sqlite3.connect(dbPath)
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|
||||||
# Cleanup Online History
|
# Cleanup Online History
|
||||||
mylog('verbose', ['[DBCLNP] Online_History: Delete all but keep latest 150 entries'])
|
mylog('verbose', [f'[{pluginName}] Online_History: Delete all but keep latest 150 entries'])
|
||||||
cursor.execute ("""DELETE from Online_History where "Index" not in (
|
cursor.execute ("""DELETE from Online_History where "Index" not in (
|
||||||
SELECT "Index" from Online_History
|
SELECT "Index" from Online_History
|
||||||
order by Scan_Date desc limit 150)""")
|
order by Scan_Date desc limit 150)""")
|
||||||
mylog('verbose', ['[DBCLNP] Optimize Database'])
|
mylog('verbose', [f'[{pluginName}] Optimize Database'])
|
||||||
# Cleanup Events
|
# Cleanup Events
|
||||||
mylog('verbose', [f'[DBCLNP] Events: Delete all older than {str(DAYS_TO_KEEP_EVENTS)} days (DAYS_TO_KEEP_EVENTS setting)'])
|
mylog('verbose', [f'[{pluginName}] Events: Delete all older than {str(DAYS_TO_KEEP_EVENTS)} days (DAYS_TO_KEEP_EVENTS setting)'])
|
||||||
cursor.execute (f"""DELETE FROM Events
|
cursor.execute (f"""DELETE FROM Events
|
||||||
WHERE eve_DateTime <= date('now', '-{str(DAYS_TO_KEEP_EVENTS)} day')""")
|
WHERE eve_DateTime <= date('now', '-{str(DAYS_TO_KEEP_EVENTS)} day')""")
|
||||||
|
|
||||||
# Trim Plugins_History entries to less than PLUGINS_KEEP_HIST setting per unique "Plugin" column entry
|
# Trim Plugins_History entries to less than PLUGINS_KEEP_HIST setting per unique "Plugin" column entry
|
||||||
mylog('verbose', [f'[DBCLNP] Plugins_History: Trim Plugins_History entries to less than {str(PLUGINS_KEEP_HIST)} per Plugin (PLUGINS_KEEP_HIST setting)'])
|
mylog('verbose', [f'[{pluginName}] Plugins_History: Trim Plugins_History entries to less than {str(PLUGINS_KEEP_HIST)} per Plugin (PLUGINS_KEEP_HIST setting)'])
|
||||||
|
|
||||||
# Build the SQL query to delete entries that exceed the limit per unique "Plugin" column entry
|
# Build the SQL query to delete entries that exceed the limit per unique "Plugin" column entry
|
||||||
delete_query = f"""DELETE FROM Plugins_History
|
delete_query = f"""DELETE FROM Plugins_History
|
||||||
@@ -97,7 +99,7 @@ def cleanup_database (dbPath, DAYS_TO_KEEP_EVENTS, PHOLUS_DAYS_DATA, HRS_TO_KEEP
|
|||||||
|
|
||||||
histCount = get_setting_value('DBCLNP_NOTIFI_HIST')
|
histCount = get_setting_value('DBCLNP_NOTIFI_HIST')
|
||||||
|
|
||||||
mylog('verbose', [f'[DBCLNP] Plugins_History: Trim Notifications entries to less than {histCount}'])
|
mylog('verbose', [f'[{pluginName}] Plugins_History: Trim Notifications entries to less than {histCount}'])
|
||||||
|
|
||||||
# Build the SQL query to delete entries
|
# Build the SQL query to delete entries
|
||||||
delete_query = f"""DELETE FROM Notifications
|
delete_query = f"""DELETE FROM Notifications
|
||||||
@@ -115,20 +117,20 @@ def cleanup_database (dbPath, DAYS_TO_KEEP_EVENTS, PHOLUS_DAYS_DATA, HRS_TO_KEEP
|
|||||||
|
|
||||||
# Cleanup Pholus_Scan
|
# Cleanup Pholus_Scan
|
||||||
if PHOLUS_DAYS_DATA != 0:
|
if PHOLUS_DAYS_DATA != 0:
|
||||||
mylog('verbose', ['[DBCLNP] Pholus_Scan: Delete all older than ' + str(PHOLUS_DAYS_DATA) + ' days (PHOLUS_DAYS_DATA setting)'])
|
mylog('verbose', [f'[{pluginName}] Pholus_Scan: Delete all older than ' + str(PHOLUS_DAYS_DATA) + ' days (PHOLUS_DAYS_DATA setting)'])
|
||||||
# todo: improvement possibility: keep at least N per mac
|
# todo: improvement possibility: keep at least N per mac
|
||||||
cursor.execute (f"""DELETE FROM Pholus_Scan
|
cursor.execute (f"""DELETE FROM Pholus_Scan
|
||||||
WHERE Time <= date('now', '-{str(PHOLUS_DAYS_DATA)} day')""")
|
WHERE Time <= date('now', '-{str(PHOLUS_DAYS_DATA)} day')""")
|
||||||
# Cleanup New Devices
|
# Cleanup New Devices
|
||||||
if HRS_TO_KEEP_NEWDEV != 0:
|
if HRS_TO_KEEP_NEWDEV != 0:
|
||||||
mylog('verbose', [f'[DBCLNP] Devices: Delete all New Devices older than {str(HRS_TO_KEEP_NEWDEV)} hours (HRS_TO_KEEP_NEWDEV setting)'])
|
mylog('verbose', [f'[{pluginName}] Devices: Delete all New Devices older than {str(HRS_TO_KEEP_NEWDEV)} hours (HRS_TO_KEEP_NEWDEV setting)'])
|
||||||
cursor.execute (f"""DELETE FROM Devices
|
cursor.execute (f"""DELETE FROM Devices
|
||||||
WHERE dev_NewDevice = 1 AND dev_FirstConnection < date('now', '+{str(HRS_TO_KEEP_NEWDEV)} hour')""")
|
WHERE dev_NewDevice = 1 AND dev_FirstConnection < date('now', '+{str(HRS_TO_KEEP_NEWDEV)} hour')""")
|
||||||
|
|
||||||
|
|
||||||
# De-dupe (de-duplicate) from the Plugins_Objects table
|
# De-dupe (de-duplicate) from the Plugins_Objects table
|
||||||
# TODO This shouldn't be necessary - probably a concurrency bug somewhere in the code :(
|
# TODO This shouldn't be necessary - probably a concurrency bug somewhere in the code :(
|
||||||
mylog('verbose', ['[DBCLNP] Plugins_Objects: Delete all duplicates'])
|
mylog('verbose', [f'[{pluginName}] Plugins_Objects: Delete all duplicates'])
|
||||||
cursor.execute("""
|
cursor.execute("""
|
||||||
DELETE FROM Plugins_Objects
|
DELETE FROM Plugins_Objects
|
||||||
WHERE rowid > (
|
WHERE rowid > (
|
||||||
@@ -141,7 +143,7 @@ def cleanup_database (dbPath, DAYS_TO_KEEP_EVENTS, PHOLUS_DAYS_DATA, HRS_TO_KEEP
|
|||||||
""")
|
""")
|
||||||
|
|
||||||
# De-Dupe (de-duplicate - remove duplicate entries) from the Pholus_Scan table
|
# De-Dupe (de-duplicate - remove duplicate entries) from the Pholus_Scan table
|
||||||
mylog('verbose', ['[DBCLNP] Pholus_Scan: Delete all duplicates'])
|
mylog('verbose', [f'[{pluginName}] Pholus_Scan: Delete all duplicates'])
|
||||||
cursor.execute ("""DELETE FROM Pholus_Scan
|
cursor.execute ("""DELETE FROM Pholus_Scan
|
||||||
WHERE rowid > (
|
WHERE rowid > (
|
||||||
SELECT MIN(rowid) FROM Pholus_Scan p2
|
SELECT MIN(rowid) FROM Pholus_Scan p2
|
||||||
@@ -153,7 +155,7 @@ def cleanup_database (dbPath, DAYS_TO_KEEP_EVENTS, PHOLUS_DAYS_DATA, HRS_TO_KEEP
|
|||||||
conn.commit()
|
conn.commit()
|
||||||
|
|
||||||
# Shrink DB
|
# Shrink DB
|
||||||
mylog('verbose', ['[DBCLNP] Shrink Database'])
|
mylog('verbose', [f'[{pluginName}] Shrink Database'])
|
||||||
cursor.execute ("VACUUM;")
|
cursor.execute ("VACUUM;")
|
||||||
|
|
||||||
# Close the database connection
|
# Close the database connection
|
||||||
|
|||||||
7
front/plugins/nslookup_scan/README.md
Executable file
7
front/plugins/nslookup_scan/README.md
Executable 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.
|
||||||
321
front/plugins/nslookup_scan/config.json
Executable file
321
front/plugins/nslookup_scan/config.json
Executable 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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
134
front/plugins/nslookup_scan/nslookup.py
Executable file
134
front/plugins/nslookup_scan/nslookup.py
Executable 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()
|
||||||
@@ -23,6 +23,7 @@ LOG_FILE = os.path.join(CUR_PATH, 'script.log')
|
|||||||
RESULT_FILE = os.path.join(CUR_PATH, 'last_result.log')
|
RESULT_FILE = os.path.join(CUR_PATH, 'last_result.log')
|
||||||
fullPholusPath = os.path.join(CUR_PATH, 'pholus/pholus3.py')
|
fullPholusPath = os.path.join(CUR_PATH, 'pholus/pholus3.py')
|
||||||
|
|
||||||
|
pluginName = 'PHOLUS'
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
# sample
|
# sample
|
||||||
@@ -40,13 +41,13 @@ def main():
|
|||||||
plugin_objects = Plugin_Objects(RESULT_FILE)
|
plugin_objects = Plugin_Objects(RESULT_FILE)
|
||||||
|
|
||||||
# Print a message to indicate that the script is starting.
|
# Print a message to indicate that the script is starting.
|
||||||
mylog('verbose',['[PHOLUS] In script'])
|
mylog('verbose',[f'[{pluginName}] In script'])
|
||||||
|
|
||||||
# Assuming 'values' is a dictionary or object that contains a key 'userSubnets'
|
# Assuming 'values' is a dictionary or object that contains a key 'userSubnets'
|
||||||
# which holds a list of user-submitted subnets.
|
# which holds a list of user-submitted subnets.
|
||||||
# Printing the userSubnets list to check its content.
|
# Printing the userSubnets list to check its content.
|
||||||
mylog('verbose',['[PHOLUS] Subnets: ', values.userSubnets])
|
mylog('verbose',[f'[{pluginName}] Subnets: ', values.userSubnets])
|
||||||
mylog('verbose',['[PHOLUS] len Subnets: ', len(values.userSubnets)])
|
mylog('verbose',[f'[{pluginName}] len Subnets: ', len(values.userSubnets)])
|
||||||
|
|
||||||
# Extract the base64-encoded subnet information from the first element of the userSubnets list.
|
# Extract the base64-encoded subnet information from the first element of the userSubnets list.
|
||||||
# The format of the element is assumed to be like 'userSubnets=b<base64-encoded-data>'.
|
# The format of the element is assumed to be like 'userSubnets=b<base64-encoded-data>'.
|
||||||
@@ -54,14 +55,14 @@ def main():
|
|||||||
timeoutSec = values.timeoutSec[0].split('=')[1]
|
timeoutSec = values.timeoutSec[0].split('=')[1]
|
||||||
|
|
||||||
# Printing the extracted base64-encoded subnet information.
|
# Printing the extracted base64-encoded subnet information.
|
||||||
mylog('verbose', [f'[PHOLUS] { userSubnetsParamBase64 }'])
|
mylog('verbose', [f'[{pluginName}] { userSubnetsParamBase64 }'])
|
||||||
mylog('verbose', [f'[PHOLUS] { timeoutSec }'])
|
mylog('verbose', [f'[{pluginName}] { timeoutSec }'])
|
||||||
|
|
||||||
# Decode the base64-encoded subnet information to get the actual subnet information in ASCII format.
|
# Decode the base64-encoded subnet information to get the actual subnet information in ASCII format.
|
||||||
userSubnetsParam = base64.b64decode(userSubnetsParamBase64).decode('ascii')
|
userSubnetsParam = base64.b64decode(userSubnetsParamBase64).decode('ascii')
|
||||||
|
|
||||||
# Print the decoded subnet information.
|
# Print the decoded subnet information.
|
||||||
mylog('verbose', [f'[PHOLUS] userSubnetsParam { userSubnetsParam } '])
|
mylog('verbose', [f'[{pluginName}] userSubnetsParam { userSubnetsParam } '])
|
||||||
|
|
||||||
# Check if the decoded subnet information contains multiple subnets separated by commas.
|
# Check if the decoded subnet information contains multiple subnets separated by commas.
|
||||||
# If it does, split the string into a list of individual subnets.
|
# If it does, split the string into a list of individual subnets.
|
||||||
@@ -99,16 +100,15 @@ def execute_pholus_scan(userSubnets, timeoutSec):
|
|||||||
|
|
||||||
timeoutPerSubnet = float(timeoutSec) / len(userSubnets)
|
timeoutPerSubnet = float(timeoutSec) / len(userSubnets)
|
||||||
|
|
||||||
mylog('verbose', [f'[PHOLUS] { timeoutPerSubnet } '])
|
mylog('verbose', [f'[{pluginName}] { timeoutPerSubnet } '])
|
||||||
|
|
||||||
# scan each interface
|
# scan each interface
|
||||||
|
|
||||||
for interface in userSubnets:
|
for interface in userSubnets:
|
||||||
|
|
||||||
temp = interface.split("--interface=")
|
temp = interface.split("--interface=")
|
||||||
|
|
||||||
if len(temp) != 2:
|
if len(temp) != 2:
|
||||||
mylog('none', ["[PHOLUS] Skip scan (need interface in format '192.168.1.0/24 --inteface=eth0'), got: ", interface])
|
mylog('verbose', [f'[{pluginName}] Skip scan (need interface in format "192.168.1.0/24 --inteface=eth0"), got: ', interface])
|
||||||
return
|
return
|
||||||
|
|
||||||
mask = temp[0].strip()
|
mask = temp[0].strip()
|
||||||
@@ -116,14 +116,14 @@ def execute_pholus_scan(userSubnets, timeoutSec):
|
|||||||
|
|
||||||
pholus_output_list = execute_pholus_on_interface (interface, timeoutPerSubnet, mask)
|
pholus_output_list = execute_pholus_on_interface (interface, timeoutPerSubnet, mask)
|
||||||
|
|
||||||
mylog('verbose', [f'[PHOLUS] { pholus_output_list } '])
|
mylog('verbose', [f'[{pluginName}] { pholus_output_list } '])
|
||||||
|
|
||||||
|
|
||||||
result_list += pholus_output_list
|
result_list += pholus_output_list
|
||||||
|
|
||||||
|
|
||||||
mylog('verbose', ["[PHOLUS] Pholus output number of entries:", len(result_list)])
|
mylog('verbose', [f'[{pluginName}] Pholus output number of entries:', len(result_list)])
|
||||||
mylog('verbose', ["[PHOLUS] List:", result_list])
|
mylog('verbose', [f'[{pluginName}] List:', result_list])
|
||||||
|
|
||||||
return result_list
|
return result_list
|
||||||
|
|
||||||
@@ -132,8 +132,8 @@ def execute_pholus_on_interface(interface, timeoutSec, mask):
|
|||||||
|
|
||||||
# logging & updating app state
|
# logging & updating app state
|
||||||
|
|
||||||
mylog('verbose', ['[PHOLUS] Scan: Pholus for ', str(timeoutSec), 's ('+ str(round(int(timeoutSec) / 60, 1)) +'min)'])
|
mylog('verbose', [f'[{pluginName}] Scan: Pholus for ', str(timeoutSec), 's ('+ str(round(int(timeoutSec) / 60, 1)) +'min)'])
|
||||||
mylog('verbose', ["[PHOLUS] Pholus scan on [interface] ", interface, " [mask] " , mask])
|
mylog('verbose', [f'[{pluginName}] Pholus scan on [interface] ', interface, ' [mask] ' , mask])
|
||||||
|
|
||||||
# the scan always lasts 2x as long, so the desired user time from settings needs to be halved
|
# the scan always lasts 2x as long, so the desired user time from settings needs to be halved
|
||||||
adjustedTimeout = str(round(int(timeoutSec) / 2, 0))
|
adjustedTimeout = str(round(int(timeoutSec) / 2, 0))
|
||||||
@@ -149,15 +149,15 @@ def execute_pholus_on_interface(interface, timeoutSec, mask):
|
|||||||
output = subprocess.check_output (pholus_args, universal_newlines=True, stderr=subprocess.STDOUT, timeout=(timeoutSec + 30))
|
output = subprocess.check_output (pholus_args, universal_newlines=True, stderr=subprocess.STDOUT, timeout=(timeoutSec + 30))
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
# An error occured, handle it
|
# An error occured, handle it
|
||||||
mylog('none', ['[PHOLUS]', e.output])
|
mylog('verbose', [f'[{pluginName}]', e.output])
|
||||||
mylog('none', ["[PHOLUS] ⚠ ERROR - Pholus Scan - check logs"])
|
mylog('verbose', [f'[{pluginName}] ⚠ ERROR - Pholus Scan - check logs'])
|
||||||
except subprocess.TimeoutExpired as timeErr:
|
except subprocess.TimeoutExpired as timeErr:
|
||||||
mylog('none', ['[PHOLUS] Pholus TIMEOUT - the process forcefully terminated as timeout reached'])
|
mylog('verbose', [f'[{pluginName}] Pholus TIMEOUT - the process forcefully terminated as timeout reached'])
|
||||||
|
|
||||||
if output == "": # check if the subprocess failed
|
if output == "": # check if the subprocess failed
|
||||||
mylog('none', ['[PHOLUS] Scan: Pholus FAIL - check logs'])
|
mylog('verbose', [f'[{pluginName}] Scan: Pholus FAIL - check logs'])
|
||||||
else:
|
else:
|
||||||
mylog('verbose', ['[PHOLUS] Scan: Pholus SUCCESS'])
|
mylog('verbose', [f'[{pluginName}] Scan: Pholus SUCCESS'])
|
||||||
|
|
||||||
# check the last run output
|
# check the last run output
|
||||||
f = open(logPath + '/pialert_pholus_lastrun.log', 'r+')
|
f = open(logPath + '/pialert_pholus_lastrun.log', 'r+')
|
||||||
|
|||||||
@@ -8,8 +8,28 @@ from logger import mylog, print_log
|
|||||||
from const import vendorsPath
|
from const import vendorsPath
|
||||||
|
|
||||||
#-------------------------------------------------------------------------------
|
#-------------------------------------------------------------------------------
|
||||||
|
# Device object handling (WIP)
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
class Device_obj:
|
||||||
|
def __init__(self, db):
|
||||||
|
self.db = db
|
||||||
|
|
||||||
|
# Get all
|
||||||
|
def getAll(self):
|
||||||
|
self.db.sql.execute("""
|
||||||
|
SELECT * FROM Devices
|
||||||
|
""")
|
||||||
|
return self.db.sql.fetchall()
|
||||||
|
|
||||||
|
# Get all with unknown names
|
||||||
|
def getUnknown(self):
|
||||||
|
self.db.sql.execute("""
|
||||||
|
SELECT * FROM Devices WHERE dev_Name in ("(unknown)", "(name not found)", "" )
|
||||||
|
""")
|
||||||
|
return self.db.sql.fetchall()
|
||||||
|
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
def save_scanned_devices (db):
|
def save_scanned_devices (db):
|
||||||
sql = db.sql #TO-DO
|
sql = db.sql #TO-DO
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user