#!/usr/bin/env python import os import pathlib import sys import json import sqlite3 import subprocess # Define the installation path and extend the system path for plugin imports INSTALL_PATH = "/app" sys.path.extend([f"{INSTALL_PATH}/front/plugins", f"{INSTALL_PATH}/server"]) from plugin_helper import Plugin_Object, Plugin_Objects, decodeBase64 from plugin_utils import get_plugins_configs from logger import mylog, Logger from const import pluginsPath, fullDbPath, logPath from helper import timeNowTZ, get_setting_value from notification import write_notification from database import DB from device import Device_obj import conf from pytz import timezone # Make sure the TIMEZONE for logging is correct conf.tz = timezone(get_setting_value('TIMEZONE')) # Make sure log level is initialized correctly Logger(get_setting_value('LOG_LEVEL')) pluginName = 'NBTSCAN' # Define the current path and log file paths LOG_PATH = logPath + '/plugins' LOG_FILE = os.path.join(LOG_PATH, f'script.{pluginName}.log') RESULT_FILE = os.path.join(LOG_PATH, f'last_result.{pluginName}.log') # Initialize the Plugin obj output file plugin_objects = Plugin_Objects(RESULT_FILE) def main(): mylog('verbose', [f'[{pluginName}] In script']) # timeout = get_setting_value('NBLOOKUP_RUN_TIMEOUT') timeout = 20 # 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() mylog('verbose', [f'[{pluginName}] Unknown devices count: {len(unknown_devices)}']) # TEST - below is a WINDOWS host IP # execute_name_lookup('192.168.1.121', timeout) for device in unknown_devices: domain_name, dns_server = execute_name_lookup(device['devLastIP'], timeout) if domain_name != '': plugin_objects.add_object( # "MAC", "IP", "Server", "Name" primaryId = device['devMac'], secondaryId = device['devLastIP'], watched1 = dns_server, watched2 = domain_name, watched3 = '', watched4 = '', extra = '', foreignKey = device['devMac']) plugin_objects.write_result_file() mylog('verbose', [f'[{pluginName}] Script finished']) return 0 #=============================================================================== # Execute scan #=============================================================================== def execute_name_lookup (ip, timeout): """ Execute the NBTSCAN command on IP. """ args = ['nbtscan', ip] # Execute command output = "" try: mylog('verbose', [f'[{pluginName}] DEBUG CMD :', args]) # try runnning a subprocess with a forced (timeout) in case the subprocess hangs output = subprocess.check_output (args, universal_newlines=True, stderr=subprocess.STDOUT, timeout=(timeout), text=True) mylog('verbose', [f'[{pluginName}] DEBUG OUTPUT : {output}']) domain_name = '' dns_server = '' # Split the output into lines lines = output.splitlines() # Look for the first line containing a valid NetBIOS name entry index = 0 for line in lines: if 'Doing NBT name scan' not in line and ip in line: # Split the line and extract the primary NetBIOS name parts = line.split() if len(parts) > 1: domain_name = parts[1] else: mylog('verbose', [f'[{pluginName}] ⚠ ERROR - Unexpected output format: {line}']) mylog('verbose', [f'[{pluginName}] Domain Name: {domain_name}']) return domain_name, dns_server except subprocess.CalledProcessError as e: # An error occurred, handle it # if "NXDOMAIN" in e.output: # mylog('verbose', [f'[{pluginName}]', f"No PTR record found for IP: {ip}"]) # else: mylog('verbose', [f'[{pluginName}] ⚠ ERROR - {e.output}']) 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 '', '' if __name__ == '__main__': main()