N E T H R A N. W E D A G E

Loading

Cybersecurity undergraduate and web developer based in Sri Lanka, passionate about penetration testing, VAPT, and ethical hacking.

Home / Portfolio / Python / Network Inventory Script — Timex
cat ~/python/network-inventory-script.md
Python

Network Inventory Script — Timex

01 Oct 2024 Linux/Windows Deployed Practical

Bash/Python automation that scans the local network, identifies active hosts, pulls MAC addresses and hostnames, and logs results to a CSV for IT audit.

Python Bash Network IT Automation

Network Inventory Script — Timex

This writeup documents the development of a custom Python-based network inventory script built for Timex. The tool was created to automate the discovery and documentation of all devices on the Timex internal network — replacing a manually maintained spreadsheet that was frequently outdated and inaccurate. It scans the network, identifies hosts, resolves hostnames, fingerprints operating systems, and exports a structured inventory report as HTML and CSV for the IT team.

Project Info

  • Client: Timex
  • Type: Internal Network Inventory Automation Tool
  • Language: Python 3
  • Dependencies: python-nmap, scapy, Jinja2, csv, socket

Step 1 — Requirements Gathering

The Timex IT team outlined the following requirements before development began:

  • Automatically discover all live hosts on the internal subnet
  • Resolve hostnames and MAC addresses for each device
  • Identify the operating system and open services per host
  • Flag devices that are new or unrecognised against a known baseline
  • Export results as CSV for asset management and HTML for management review
  • Run on a scheduled basis via cron without manual intervention

A baseline CSV of known devices was provided by the client at project start — new devices discovered during scans are automatically flagged as UNKNOWN in the output report.

Step 2 — Project Structure

The tool was structured as a single scheduled script with modular functions for discovery, fingerprinting, and reporting:

/timex-inventory
  inventory.py        -- main entry point and scheduler
  discovery.py        -- ARP sweep and host discovery
  fingerprint.py      -- OS and service fingerprinting
  reporter.py         -- HTML and CSV report generation
  baseline.csv        -- known device registry
  templates/
    inventory.html    -- Jinja2 HTML report template
  logs/               -- scan logs per run
  requirements.txt

Scan logs are written per run with a timestamp filename — allowing the IT team to compare results across runs and track when new devices first appeared on the network.

Step 3 — Host Discovery (ARP Sweep)

ARP is used for host discovery on the local subnet — faster and more reliable than ICMP ping which is frequently blocked by Windows firewall rules:

# discovery.py
from scapy.all import ARP, Ether, srp
import socket, datetime

def arp_sweep(subnet):
    print(f"[*] Scanning subnet: {subnet}")
    arp = ARP(pdst=subnet)
    ether = Ether(dst="ff:ff:ff:ff:ff:ff")
    packet = ether / arp

    result = srp(packet, timeout=3,
                 verbose=False)[0]
    hosts = []
    for sent, received in result:
        try:
            hostname = socket.gethostbyaddr(
                received.psrc)[0]
        except socket.herror:
            hostname = "unknown"

        hosts.append({
            "ip":       received.psrc,
            "mac":      received.hwsrc,
            "hostname": hostname,
            "discovered": datetime.datetime.now()
                          .strftime("%Y-%m-%d %H:%M")
        })
    print(f"[*] {len(hosts)} hosts discovered")
    return hosts

MAC addresses are captured alongside IPs — allowing the tool to track devices even if they change IP via DHCP between scans.

Step 4 — OS and Service Fingerprinting

Each discovered host is passed to Nmap for OS detection and top-port service enumeration:

# fingerprint.py
import nmap

def fingerprint_host(ip):
    nm = nmap.PortScanner()
    nm.scan(ip, arguments="-O --top-ports 20 -T4")

    result = {
        "os":       "unknown",
        "services": []
    }

    if ip in nm.all_hosts():
        host = nm[ip]

        # OS detection
        if "osmatch" in host and host["osmatch"]:
            result["os"] = \
              host["osmatch"][0]["name"]

        # Open services
        for proto in host.all_protocols():
            for port in host[proto].keys():
                svc = host[proto][port]
                if svc["state"] == "open":
                    result["services"].append(
                        f"{port}/{proto} "
                        f"({svc['name']})"
                    )
    return result

OS detection requires root or administrator privileges. The script checks for elevated permissions on startup and exits with a clear error message if not satisfied.

Step 5 — Baseline Comparison

Each discovered host is checked against the known device baseline CSV. Unrecognised MAC addresses are flagged as UNKNOWN in the report:

# inventory.py
import csv

def load_baseline(filepath="baseline.csv"):
    baseline = {}
    with open(filepath, newline="") as f:
        reader = csv.DictReader(f)
        for row in reader:
            baseline[row["mac"].lower()] = {
                "label":  row["label"],
                "owner":  row["owner"],
                "type":   row["type"]
            }
    return baseline

def check_baseline(host, baseline):
    mac = host["mac"].lower()
    if mac in baseline:
        host.update(baseline[mac])
        host["status"] = "KNOWN"
    else:
        host["label"]  = "Unrecognised Device"
        host["owner"]  = "—"
        host["type"]   = "—"
        host["status"] = "UNKNOWN"
    return host

Unknown devices trigger a warning entry in the scan log and are highlighted in red in the HTML report — giving the IT team immediate visibility of rogue or new devices.

Step 6 — HTML and CSV Report Generation

Scan results are exported as a timestamped HTML report for management review and a CSV for the asset register:

# reporter.py
from jinja2 import Environment, FileSystemLoader
import csv, datetime, os

def generate_report(hosts, output_dir="reports"):
    os.makedirs(output_dir, exist_ok=True)
    ts = datetime.datetime.now().strftime("%Y%m%d_%H%M")

    # HTML report
    env = Environment(
        loader=FileSystemLoader("templates"))
    tmpl = env.get_template("inventory.html")
    html = tmpl.render(
        hosts=hosts,
        generated=ts,
        total=len(hosts),
        unknown=sum(
            1 for h in hosts
            if h["status"] == "UNKNOWN")
    )
    with open(f"{output_dir}/inventory_{ts}.html","w") as f:
        f.write(html)

    # CSV export
    with open(f"{output_dir}/inventory_{ts}.csv",
              "w", newline="") as f:
        w = csv.writer(f)
        w.writerow(["IP","MAC","Hostname","OS",
                    "Services","Label","Owner",
                    "Type","Status","Discovered"])
        for h in hosts:
            w.writerow([
                h["ip"], h["mac"], h["hostname"],
                h["os"],
                " | ".join(h["services"]),
                h["label"], h["owner"],
                h["type"], h["status"],
                h["discovered"]
            ])

The HTML report includes a summary banner showing total hosts found, known devices, and unknown device count — colour coded green for known and red for unknown.

Step 7 — Scheduled Execution (Cron)

The script was configured to run automatically every night at 02:00 via cron on the Timex IT server:

# Add to crontab — run as root for OS detection
sudo crontab -e

# Run nightly at 02:00
0 2 * * * /usr/bin/python3 \
  /opt/timex-inventory/inventory.py \
  --subnet 192.168.1.0/24 \
  >> /opt/timex-inventory/logs/cron.log 2>&1

# Verify the job is registered
sudo crontab -l

Each nightly run produces a new timestamped report in the reports/ directory. The IT team configured a shared network drive mount so reports are accessible from any workstation on the Timex network without logging into the scan server.

Step 8 — Installation and Usage

The tool installs into any Python 3 environment with Nmap present on the system:

# Clone or copy the project to the server
cd /opt/timex-inventory

# Install Python dependencies
pip3 install -r requirements.txt

# requirements.txt
python-nmap==0.7.1
scapy==2.5.0
Jinja2==3.1.2

# Ensure Nmap is installed
nmap --version

# Run a manual scan
sudo python3 inventory.py \
  --subnet 192.168.1.0/24

# Run against multiple subnets
sudo python3 inventory.py \
  --subnet 192.168.1.0/24 192.168.2.0/24

# Output: reports/inventory_20240115_0200.html
#         reports/inventory_20240115_0200.csv

Key Takeaways

  • ARP sweeps are faster and more reliable than ICMP ping for local subnet discovery
  • Tracking MAC addresses alongside IPs identifies devices even when DHCP reassigns their IP
  • Baseline comparison immediately surfaces rogue or unrecognised devices on the network
  • Timestamped reports per run allow the IT team to track when new devices first appeared
  • Cron scheduling removes the human dependency — inventory stays current without manual effort
  • Exporting both HTML and CSV covers management reporting and asset register updates simultaneously

Tools Used

  • Python 3 — core language for the inventory tool
  • Scapy — ARP sweep for host and MAC address discovery
  • python-nmap — OS fingerprinting and service enumeration
  • Jinja2 — HTML report templating
  • csv / socket — baseline comparison and hostname resolution
  • cron — scheduled nightly execution
  • VS Code — development environment
Project Info
Category Python
Difficulty Practical
OS / Target Linux/Windows
Points Deployed
Date 01 Oct 2024
Tools Used
Python 3 Bash Nmap CSV