NetDTL — Reference Manual

Complete reference for the NetDTL v3.0 agentless network inventory and diagnostic web application.

version3.0 stackPHP 8.x / MySQL / Nmap licenseMIT authorDidier DTL Morandi

Overview

NetDTL is a self-hosted web application for agentless network discovery and inventory management on Windows infrastructure. It runs on a PHP/MySQL/Nmap stack (XAMPP or LAMP) and provides real-time scanning via Server-Sent Events, machine profiling, network diagnostics, and patch panel management — all through a dark-themed web interface with no external JavaScript dependencies.

The application is structured as a set of PHP pages, each responsible for one functional area, sharing a common database layer (db.php), a CSS stylesheet (style.php), and layout partials (topbar.php, sidebar.php).

Requirements

ComponentVersionNotes
PHP8.xExtensions required: pdo_mysql, mbstring
MySQL / MariaDBany recentUsed via PDO
Nmapany recentMust be accessible from the PHP process; path set via NMAP_PATH
XAMPP or LAMPAny standard PHP+MySQL server environment
PowerShell5.1 / 7+Required for WMI descriptions and local IP/service queries
Windows note: When the web server runs on Windows, Nmap and PowerShell commands are invoked via shell_exec. The PHP process account must have sufficient privileges, and Nmap must be in the system PATH or its full path set in db.php.

Installation

Deploy the application files to the web server document root (e.g. htdocs/netdtl/ under XAMPP, or a dedicated virtual host).

1. Create the database

CREATE DATABASE netdtl CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'netdtl'@'localhost' IDENTIFIED BY 'yourpassword';
GRANT ALL PRIVILEGES ON netdtl.* TO 'netdtl'@'localhost';
FLUSH PRIVILEGES;

2. Configure db.php

Edit the constants at the top of db.php to match your environment. The database schema is created automatically on first run by initDB().

3. First run

Open the application in a browser. initDB() will create all required tables if they do not exist. Log in with the credentials defined in AUTH_USER / AUTH_PASS.

Configuration

All configuration lives in db.php as PHP constants. There is no separate config file.

ConstantDescription
DB_HOSTMySQL host, typically localhost
DB_NAMEDatabase name
DB_USERDatabase user
DB_PASSDatabase password
AUTH_USERHTTP Basic Auth username
AUTH_PASSHTTP Basic Auth password (plaintext in current version)
NMAP_PATHFull path to the Nmap binary, e.g. C:/Program Files (x86)/Nmap/nmap.exe
DEFAULT_NETWORKPre-filled CIDR range shown on the discovery page
APP_VERSIONVersion string displayed in the sidebar footer

Database Schema

Tables are created automatically by initDB() in db.php using CREATE TABLE IF NOT EXISTS.

machines

Central inventory table. One row per IP address (unique key on ip).

ColumnTypeDescription
idINT AUTO_INCREMENTPrimary key
hostnameVARCHARShort hostname or IP if no name resolved
ipVARCHAR(45)IPv4 address — unique constraint
macVARCHAR(17)MAC address in uppercase colon-separated format
vendorVARCHARNIC manufacturer from Nmap OUI lookup
osVARCHAROS string from Nmap detection or manual entry
switch_portVARCHARSwitch port label (e.g. port1.0.3), manually set
patch_portVARCHARPatch panel port label (e.g. B31), manually set
open_portsTEXTComma-separated list of open ports from last port scan
statusENUM('up','down','unknown')Current reachability status
last_ping_msINTAverage ping RTT in milliseconds from last ping
commentTEXTFree-form note; also populated by WMI / NetBIOS enrichment
first_seenDATETIMESet at INSERT, never updated
last_seenDATETIMEUpdated on every scan hit or ping

scan_history

One row per completed discovery scan.

ColumnTypeDescription
idINT AUTO_INCREMENTPrimary key
scan_dateDATETIMETimestamp of scan completion
networkVARCHARCIDR range that was scanned
hosts_upINTNumber of hosts found up
hosts_downINTStored as 0 in current version
duration_sINTScan duration in seconds

diag_history

Log of all diagnostic operations (ping, traceroute, DNS, port scan, OS detection).

ColumnTypeDescription
idINT AUTO_INCREMENTPrimary key
actionVARCHARTool name: ping, nmap, traceroute, dns, ports, infos, services, nmap_os
targetVARCHARIP, hostname, or CIDR that was targeted
resultTEXTFirst 20 lines of command output
successTINYINTAlways 1 in current version
createdDATETIMETimestamp of the operation

patch_panel

Physical patch panel ports, typically populated by import (CSV or direct SQL).

ColumnTypeDescription
idINT AUTO_INCREMENTPrimary key
priseVARCHARWall outlet label (e.g. B31) — unique
typeVARCHARRJ45, RJ11, or other
entiteVARCHAROwning entity or department
local_nameVARCHARRoom or location name
etageVARCHARFloor
posteVARCHARWorkstation or desk reference
switchVARCHARSwitch name or identifier
port_switchVARCHARSwitch port (e.g. port1.0.3)
notesTEXTFree-form notes

patch_machines

Many-to-many join between patch panel ports and machines (a port may serve multiple IPs).

ColumnTypeDescription
idINT AUTO_INCREMENTPrimary key
priseVARCHARForeign reference to patch_panel.prise
machine_ipVARCHARIP address of the machine at this port
hostnameVARCHARHostname at time of association

Pages

Dashboard

index.php
Entry point and overview page. Displays global inventory statistics, the 8 most recently seen machines, and the 5 most recent diagnostic operations.
Access

Requires authentication via requireAuth(). Default landing page after login.

Data queries
No POST actions

Read-only page. All actions (ping, add, delete) are on inventory.php and machine.php.

Inventory

inventory.php
Full machine list with search, status filtering, inline ping, manual add, delete, and CSV export. The primary management interface for the machines table.
GET parameters
ParameterDescription
qFree-text search across hostname, IP, OS, comment
statusFilter by status: up, down, or unknown
export=csvTriggers CSV download of the full inventory (bypasses all filters)
POST actions
FieldAction
add_machineInserts a new machine row. Required fields: hostname, ip (valid IP). Optional: os, comment, switch_port, patch_port.
delete_idDeletes the machine with the given ID. Asks for confirmation via JavaScript before submission.
ping_idRuns a ping against the machine's IP via runPing(), updates status, last_ping_ms, last_seen.
ping_allPings every machine in the inventory sequentially. Updates all status fields.
CSV export

Triggered by ?export=csv. Outputs all machines ordered by INET_ATON(ip) (numerical IP sort). Columns: Hostname, IP, MAC, Vendor, Switch port, Patch port, OS, Status, Open ports, Ping (ms), Last seen, Comment. BOM prepended for Excel UTF-8 compatibility.

Server IP detection: The inventory page detects the web server's own IP via $_SERVER['SERVER_ADDR'] and replaces its MAC field display with ce PC (italicised) to avoid confusion with Nmap's own MAC (which Nmap cannot read for the scanning machine itself).

Machine detail

machine.php
Per-machine profile page. Displays full network information, allows editing of OS, switch port, patch port and comment, and provides quick diagnostic actions. All diagnostic results are displayed in a terminal block and logged to diag_history.
GET parameters
ParameterDescription
idMachine ID (integer). Redirects to inventory.php if not found.
POST actions
Field / valueAction
saveUpdates os, switch_port, patch_port, comment for the machine.
diag=pingRuns ping via runPing(). Updates status and last_ping_ms.
diag=portsRuns nmap -p 21,22,23,25,80,110,143,443,445,3306,3389,5900,8080. Updates open_ports in DB.
diag=tracerouteRuns tracert (Windows).
diag=dnsRuns nslookup.
diag=nmap_osRuns nmap -O --host-timeout 10s. Extracts and saves OS details line to machines.os.
Terminal output rendering

Each output line is classified and colour-coded: lines matching TTL, Reply, or open are green; timeout / unreachable / filtered are amber; error / failed are red. A hidden <pre id="raw-output"> element holds the plain text for clipboard copy.

OS detection requires elevated privileges: nmap -O requires the PHP process to run as Administrator (Windows) or root (Linux).

Network discovery

discovery.php
Discovery page. The user enters a CIDR range, selects optional enrichment options, and starts a scan. Results are streamed in real time via Server-Sent Events from scan_stream.php. Discovered hosts are automatically upserted into the machines table.
UI controls
ControlDescription
Network inputCIDR range (e.g. 192.168.1.0/24). Pre-filled with DEFAULT_NETWORK.
Ports communsIf checked, runs an additional port scan on each discovered host (?ports=1).
Détection OSAdds -O to the Nmap command (?os=1). Requires admin/root.
Identifier NetBIOSRuns a second pass of nbstat queries after the main scan (?nbstat=1).
Descriptions WMIQueries each up host via PowerShell WMI for OS description (?wmi=1).
SSE event flow

The page opens an EventSource connection to scan_stream.php with query parameters reflecting the selected options. Events are handled by handleEvent(data) in JavaScript.

Event typeDescription
lineRaw Nmap output line. Colour-classified and appended to the terminal block.
host_savedA host has been upserted. Adds a row to the discovered hosts table in the UI.
macMAC address and vendor resolved for an IP. Updates the corresponding table row.
osOS string detected. Updates the corresponding table row.
nbstatNetBIOS name resolved. Updates the description column in the hosts table.
wmiWMI description retrieved. Appended to the description column in the hosts table.
doneScan complete. Updates stats (host count, duration), adds a row to the scan history table, completes the progress bar.
errorFatal error from the server side. Closes the EventSource, displays the error message.
Scan history

The bottom of the page displays the 10 most recent scan_history entries. A new row is appended dynamically in JavaScript when the done event is received, without page reload.

Discovery SSE endpoint

scan_stream.php
Server-Sent Events endpoint consumed exclusively by discovery.php. Executes Nmap, parses its output line by line, upserts machines into the database, and optionally runs NetBIOS and WMI enrichment passes. Not intended to be accessed directly.
GET parameters
ParameterDefaultDescription
networkDEFAULT_NETWORKCIDR range to scan. Validated by isValidTarget() before use.
ports0If 1, runs a port scan on each discovered host after the ping sweep.
os0If 1, uses nmap -sS -O instead of nmap -sn. Requires elevated privileges.
nbstat0If 1, runs a NetBIOS pass after the main scan.
wmi0If 1, queries WMI descriptions via PowerShell after the main scan.
Scan phases
Database upsert

The saveMachineStream() function uses INSERT ... ON DUPLICATE KEY UPDATE on the ip column. Existing values for MAC, vendor, and OS are preserved with COALESCE(VALUES(col), col) — a scan will not erase manually entered data with a null value.

Encoding

Nmap output on Windows is typically CP850. Each line is converted to UTF-8 via mb_convert_encoding($raw, 'UTF-8', 'CP850') before being emitted as a JSON SSE payload.

Execution time: set_time_limit(600) is called. Large networks or slow hosts may approach this limit. Output buffering is disabled (ob_end_flush()) to ensure events are streamed as they arrive.

Patch panel

patch.php
Read-only view of the physical patch panel. Displays wall outlet records from the patch_panel table joined with associated machine IPs and hostnames from patch_machines. Supports filtering by switch, entity, and free-text search.
GET parameters
ParameterDescription
qFree-text search across port label, room name, workstation, IP, hostname
switchFilter by switch identifier
entiteFilter by entity / department
Data population

The patch_panel table is not populated by NetDTL itself. It is intended to be filled by external import (CSV, SQL script, or the NetDTL Installer's patch panel engine). The application provides the read and filter interface only.

IP and hostname resolution

For each port, associated machines are retrieved from patch_machines via a GROUP_CONCAT join. Multiple IPs and hostnames per port are displayed as comma-separated lists.

Badge colouring

Port types are colour-coded: RJ45 in blue, RJ11 in amber, unknown in grey. Entity badges are distinguished between local equipment (teal) and delegated (green) based on a case-insensitive match on the word locale in the entity name.

Shared Components

Database & helpers

db.php
Central include file. Defines all configuration constants, database connection, schema initialisation, authentication, and helper functions. Included at the top of every page.
Key functions
FunctionDescription
getDB()Returns a singleton PDO connection. Throws on failure.
initDB()Creates all tables if they do not exist.
requireAuth()Sends a WWW-Authenticate: Basic challenge if credentials are absent or wrong. Exits on failure.
runCommand(string $cmd)Executes a shell command via shell_exec(), converts encoding from CP850 to UTF-8, returns an array of non-empty lines.
runPing(string $ip)Runs ping -n 4 (Windows) or ping -c 4 (Linux). Returns output lines.
parsePingStats(array $lines)Parses ping output and returns ['sent', 'recv', 'lost_pct', 'avg_ms'].
isValidTarget(string $t)Returns true if $t is a valid IP, hostname, or CIDR range.
timeAgo(string $date)Returns a human-readable relative time string (e.g. "3 minutes ago").

Stylesheet

style.php
Outputs a <link> tag for Google Fonts (IBM Plex Mono + IBM Plex Sans) and a full <style> block containing all shared CSS. Included in the <head> of every page via <?php include __DIR__ . '/style.php'; ?>.
Design tokens (CSS variables)
VariableValueUsage
--bg#0d1117Page background
--bg2#161b22Panels, sidebar, topbar
--bg3#1c2230Table headers, stat cards
--accent#3fb950Green — active states, "up" badges, success
--accent2#58a6ffBlue — links, IP addresses, port values
--warn#d29922Amber — warnings, unknown status, switch labels
--err#f85149Red — errors, "down" badges
--purple#bc8cffPatch panel port labels
--teal#64c8c8Local entity badges, infos/services history
--txt#c9d1d9Primary text
--txt2#8b949eSecondary / muted text
--txt3#484f58Placeholder / very muted text
--monoIBM Plex MonoAll monospace content (IPs, ports, terminal)
--sansIBM Plex SansLabels, badges, UI chrome

Top navigation bar

topbar.php
Renders the sticky top bar with the NetDTL logo, main navigation links (Dashboard, Inventory, Discovery, Patch panel, Diagnostics), and the currently authenticated username. Active state is set by comparing basename($_SERVER['PHP_SELF'], '.php') against each link's target. The Inventory link is also active when on machine.php.

Left sidebar

sidebar.php
Renders the fixed left navigation sidebar with two sections: Navigation (Dashboard, Inventory, Discovery, Patch panel) and Diagnostics (all seven tools). The version string from APP_VERSION and the PHP version are shown at the bottom. Active states follow the same logic as topbar.php; for diagnostic tool links, the active tool is read from $action (set in menu.php) or from $_GET['tool'].

Security

NetDTL uses HTTP Basic Authentication implemented in requireAuth(). Credentials are stored in plain text in db.php. This is acceptable for a trusted local network deployment but should not be exposed to the public internet without additional protection (reverse proxy with TLS, IP filtering, etc.).

Credentials: The AUTH_PASS constant is stored in plaintext. Do not reuse a sensitive password. For production environments, consider replacing requireAuth() with session-based authentication or delegating authentication to the web server.

Known Limitations

 

NetDTL Web site