NMAPDEV plugin work v0.7 #645 🆕🔎

This commit is contained in:
jokob-sk
2024-04-30 23:37:05 +10:00
parent ab0d4fe259
commit cc9b08ad04
5 changed files with 76 additions and 44 deletions

View File

@@ -12,7 +12,7 @@ ENV PATH="/opt/venv/bin:$PATH"
COPY . ${INSTALL_DIR}/ COPY . ${INSTALL_DIR}/
RUN pip install requests paho-mqtt scapy cron-converter pytz json2table dhcp-leases pyunifi speedtest-cli chardet \ RUN pip install requests paho-mqtt scapy cron-converter pytz json2table dhcp-leases pyunifi speedtest-cli chardet python-nmap \
&& bash -c "find ${INSTALL_DIR} -type d -exec chmod 750 {} \;" \ && bash -c "find ${INSTALL_DIR} -type d -exec chmod 750 {} \;" \
&& bash -c "find ${INSTALL_DIR} -type f -exec chmod 640 {} \;" \ && bash -c "find ${INSTALL_DIR} -type f -exec chmod 640 {} \;" \
&& bash -c "find ${INSTALL_DIR} -type f \( -name '*.sh' -o -name '*.py' -o -name 'speedtest-cli' \) -exec chmod 750 {} \;" && bash -c "find ${INSTALL_DIR} -type f \( -name '*.sh' -o -name '*.py' -o -name 'speedtest-cli' \) -exec chmod 750 {} \;"

View File

@@ -41,7 +41,7 @@ RUN phpenmod -v 8.2 sqlite3
# Setup virtual python environment and use pip3 to install packages # Setup virtual python environment and use pip3 to install packages
RUN apt-get install -y python3-venv RUN apt-get install -y python3-venv
RUN python3 -m venv myenv RUN python3 -m venv myenv
RUN /bin/bash -c "source myenv/bin/activate && update-alternatives --install /usr/bin/python python /usr/bin/python3 10 && pip3 install requests paho-mqtt scapy cron-converter pytz json2table dhcp-leases pyunifi speedtest-cli chardet" RUN /bin/bash -c "source myenv/bin/activate && update-alternatives --install /usr/bin/python python /usr/bin/python3 10 && pip3 install requests paho-mqtt scapy cron-converter pytz json2table dhcp-leases pyunifi speedtest-cli chardet python-nmap"
# Create a buildtimestamp.txt to later check if a new version was released # Create a buildtimestamp.txt to later check if a new version was released
RUN date +%s > ${INSTALL_DIR}/front/buildtimestamp.txt RUN date +%s > ${INSTALL_DIR}/front/buildtimestamp.txt

View File

@@ -300,7 +300,7 @@
{ {
"function": "ARGS", "function": "ARGS",
"type": "text", "type": "text",
"default_value": "sudo nmap -sn -PR -n ", "default_value": "sudo nmap -sn -PR -oX - ",
"options": [], "options": [],
"localized": [ "localized": [
"name", "name",
@@ -315,7 +315,7 @@
"description": [ "description": [
{ {
"language_code": "en_us", "language_code": "en_us",
"string": "Arguments to run nmap-scan with. Recommended and tested only with the setting: <br/> <code>sudo nmap -sn -PR -n </code>. <br/><br/> Note: The plugin attaches the interface and network mask, for example <code> -e eth1 192.168.1.0/24</code> and performs a separate scan for each interface specified in the <a onclick=\"toggleAllSettings()\" href=\"#SCAN_SUBNETS\"><code>SCAN_SUBNETS</code> setting</a>." "string": "Arguments to run nmap-scan with. Recommended and tested only with the setting: <br/> <code>sudo nmap -sn -PR -oX - </code>. <br/><br/> Note: The plugin attaches the interface and network mask, for example <code> -e eth1 192.168.1.0/24</code> and performs a separate scan for each interface specified in the <a onclick=\"toggleAllSettings()\" href=\"#SCAN_SUBNETS\"><code>SCAN_SUBNETS</code> setting</a>."
} }
] ]
} }

View File

@@ -11,6 +11,7 @@ import hashlib
import csv import csv
import sqlite3 import sqlite3
import re import re
import nmap
from io import StringIO from io import StringIO
from datetime import datetime from datetime import datetime
@@ -77,48 +78,29 @@ def main():
#=============================================================================== #===============================================================================
# Execute scan # Execute scan
#=============================================================================== #===============================================================================
def execute_scan (subnets_list, timeout): def execute_scan(subnets_list, timeout):
# output of possible multiple interfaces
scan_output = ""
devices_list = [] devices_list = []
# scan each interface
for interface in subnets_list: for interface in subnets_list:
nmap_output = execute_scan_on_interface(interface, timeout) nmap_output = execute_scan_on_interface(interface, timeout)
mylog('verbose', [f'[{pluginName}] nmap_output: ', nmap_output]) mylog('verbose', [f"[{pluginName}] nmap_output: ", nmap_output])
if nmap_output is not None: if nmap_output: # Proceed only if nmap output is not empty
nmap_output_ent = nmap_output.split('Nmap scan report for') # Parse the XML output using python-nmap
# loop thru entries for individual devices devices = parse_nmap_xml(nmap_output, interface)
for ent in nmap_output_ent:
lines = ent.split('\n') for device in devices:
# Append to devices_list only if both IP and MAC addresses are present
if len(lines) >= 3: if device.get('ip') and device.get('mac'):
# lines[0] can be DESKTOP-DIHOG0E.localdomain (192.168.1.121) or 192.168.1.255 devices_list.append(device)
# lines[1] can be Host is up (0.21s latency).
# lines[2] can be MAC Address: 6C:4A:4A:7B:4A:43 (Motorola Mobility, a Lenovo Company)
ip_addresses = extract_ip_addresses(lines[0])
host_name = extract_between_strings(lines[0], ' ', ' ')
vendor = extract_between_strings(lines[2], '(', ')')
mac_addresses = extract_mac_addresses(lines[2])
# only include results with a MAC address and IPs as it's used as a unique ID
if len(mac_addresses) == 1 and len(ip_addresses) == 1:
devices_list.append({'name' : host_name,
'ip' : ip_addresses[0],
'mac' : mac_addresses[0],
'vendor' : vendor,
'interface': interface})
else:
mylog('verbose', [f"[{pluginName}] Skipped (Couldn't parse MAC or IP): ", lines])
else: else:
mylog('verbose', [f"[{pluginName}] Skipped (Not enough info in output): ", lines]) # Log an error if either IP or MAC address is missing
mylog('verbose', [f"[{pluginName}] Skipped (Not enough info in output): ", device])
else:
# Log an error if nmap output is empty
mylog('verbose', [f"[{pluginName}] No output received for interface: ", interface])
return devices_list return devices_list
@@ -128,17 +110,67 @@ def execute_scan_on_interface (interface, timeout):
scan_args = get_setting_value('NMAPDEV_ARGS').split() + interface.replace('--interface=','-e ').split() scan_args = get_setting_value('NMAPDEV_ARGS').split() + interface.replace('--interface=','-e ').split()
mylog('verbose', [f'[{pluginName}] scan_args: ', scan_args]) mylog('verbose', [f'[{pluginName}] scan_args: ', scan_args])
# Execute command
try: try:
# try running a subprocess safely
result = subprocess.check_output(scan_args, universal_newlines=True) result = subprocess.check_output(scan_args, universal_newlines=True)
except subprocess.CalledProcessError as e: except subprocess.CalledProcessError as e:
# An error occurred, handle it error_type = type(e).__name__
error_type = type(e).__name__ # Capture the error type
result = "" result = ""
mylog('verbose', [f'[{pluginName}] ERROR: ', error_type])
return result return result
def parse_nmap_xml(xml_output, interface):
devices_list = []
try:
nm = nmap.PortScanner()
nm.analyse_nmap_xml_scan(xml_output)
mylog('verbose', [f'[{pluginName}] Number of hosts: ', len(nm.all_hosts())])
for host in nm.all_hosts():
hostname = nm[host].hostname() or '(unknown)'
ip = nm[host]['addresses']['ipv4'] if 'ipv4' in nm[host]['addresses'] else ''
mac = nm[host]['addresses']['mac'] if 'mac' in nm[host]['addresses'] else ''
mylog('verbose', [f'[{pluginName}] nm[host]: ', nm[host]])
vendor = ''
if nm[host]['vendor']:
mylog('verbose', [f'[{pluginName}] entry: ', nm[host]['vendor']])
for key, value in nm[host]['vendor'].items():
vendor = value
break
# Log debug information
mylog('verbose', [f"[{pluginName}] Hostname: {hostname}, IP: {ip}, MAC: {mac}, Vendor: {vendor}"])
# Only include devices with both IP and MAC addresses
if ip != '' and mac != '':
devices_list.append({
'name': hostname,
'ip': ip,
'mac': mac,
'vendor': vendor,
'interface': interface
})
else:
# MAC or IP missing
mylog('verbose', [f"[{pluginName}] Skipping: {hostname}, IP or MAC missing"])
except Exception as e:
mylog('verbose', [f"[{pluginName}] Error parsing nmap XML: ", str(e)])
return devices_list

View File

@@ -30,4 +30,4 @@ source myenv/bin/activate
update-alternatives --install /usr/bin/python python /usr/bin/python3 10 update-alternatives --install /usr/bin/python python /usr/bin/python3 10
# install packages thru pip3 # install packages thru pip3
pip3 install requests paho-mqtt scapy cron-converter pytz json2table dhcp-leases pyunifi speedtest-cli chardet pip3 install requests paho-mqtt scapy cron-converter pytz json2table dhcp-leases pyunifi speedtest-cli chardet python-nmap