commit b70c4c923b8f73a32de1931b42bf88c4faf02e1c Author: perco Date: Sun Jun 28 11:53:51 2026 +0200 init: NetMap — scanner réseau local avec interface web Scan nmap de 192.168.1.10-150, affichage IP/MAC/fabricant/hostname, nommage personnalisé par appareil (JSON), serveur HTTP Python stdlib. Co-Authored-By: Claude Sonnet 4.6 diff --git a/netmap.py b/netmap.py new file mode 100755 index 0000000..be2e5fb --- /dev/null +++ b/netmap.py @@ -0,0 +1,262 @@ +#!/usr/bin/env python3 +"""NetMap - Scan et nommage des appareils réseau 192.168.1.10-150""" + +import json +import os +import re +import subprocess +import sys +from http.server import BaseHTTPRequestHandler, HTTPServer +from urllib.parse import urlparse, parse_qs + +DATA_FILE = os.path.join(os.path.dirname(__file__), "devices.json") +IP_START = "192.168.1.10" +IP_END = "192.168.1.150" +NMAP_RANGE = f"192.168.1.10-150" +PORT = 8787 + + +def load_devices(): + if os.path.exists(DATA_FILE): + with open(DATA_FILE) as f: + return json.load(f) + return {} + + +def save_devices(data): + with open(DATA_FILE, "w") as f: + json.dump(data, f, indent=2) + + +def run_scan(): + """Lance nmap et retourne la liste des hôtes détectés.""" + try: + result = subprocess.run( + ["nmap", "-sn", "-T4", "--host-timeout", "2s", NMAP_RANGE], + capture_output=True, text=True, timeout=120 + ) + return parse_nmap_output(result.stdout) + except Exception as e: + return {"error": str(e)} + + +def parse_nmap_output(output): + hosts = [] + current = {} + for line in output.splitlines(): + m_host = re.search(r"Nmap scan report for (.+)", line) + if m_host: + if current.get("ip"): + hosts.append(current) + raw = m_host.group(1) + # "hostname (ip)" ou juste "ip" + ip_match = re.search(r"\((\d+\.\d+\.\d+\.\d+)\)", raw) + if ip_match: + current = {"ip": ip_match.group(1), "hostname": raw.split("(")[0].strip()} + else: + current = {"ip": raw.strip(), "hostname": ""} + current["mac"] = "" + current["vendor"] = "" + continue + m_mac = re.search(r"MAC Address: ([0-9A-F:]+)\s*(?:\((.+)\))?", line, re.I) + if m_mac: + current["mac"] = m_mac.group(1) + current["vendor"] = m_mac.group(2) or "" + if current.get("ip"): + hosts.append(current) + return hosts + + +HTML = r""" + + + + +NetMap — Réseau local + + + +
+

🌐 NetMap

+ 192.168.1.10 — 192.168.1.150 +
+
+
+ + Cliquez sur Scanner pour démarrer +
+
+
+ + +""" + + +class Handler(BaseHTTPRequestHandler): + def log_message(self, fmt, *args): + pass # Silence les logs HTTP + + def send_json(self, data, code=200): + body = json.dumps(data).encode() + self.send_response(code) + self.send_header("Content-Type", "application/json") + self.send_header("Content-Length", len(body)) + self.end_headers() + self.wfile.write(body) + + def do_GET(self): + path = urlparse(self.path).path + if path == "/" or path == "/index.html": + body = HTML.encode() + self.send_response(200) + self.send_header("Content-Type", "text/html; charset=utf-8") + self.send_header("Content-Length", len(body)) + self.end_headers() + self.wfile.write(body) + elif path == "/scan": + hosts = run_scan() + if isinstance(hosts, dict) and "error" in hosts: + self.send_json({"error": hosts["error"], "hosts": [], "names": {}}) + else: + names = load_devices() + self.send_json({"hosts": hosts, "names": names}) + elif path == "/names": + self.send_json(load_devices()) + else: + self.send_response(404) + self.end_headers() + + def do_POST(self): + if self.path == "/name": + length = int(self.headers.get("Content-Length", 0)) + body = json.loads(self.rfile.read(length)) + ip = body.get("ip", "").strip() + name = body.get("name", "").strip() + if re.match(r"^\d+\.\d+\.\d+\.\d+$", ip): + data = load_devices() + if name: + data[ip] = name + elif ip in data: + del data[ip] + save_devices(data) + self.send_json({"ok": True}) + else: + self.send_json({"ok": False, "error": "IP invalide"}, 400) + else: + self.send_response(404) + self.end_headers() + + +if __name__ == "__main__": + server = HTTPServer(("0.0.0.0", PORT), Handler) + print(f"NetMap démarré → http://localhost:{PORT}") + print("Ctrl+C pour arrêter") + try: + server.serve_forever() + except KeyboardInterrupt: + print("\nArrêt.") diff --git a/start.sh b/start.sh new file mode 100755 index 0000000..fc84363 --- /dev/null +++ b/start.sh @@ -0,0 +1,4 @@ +#!/bin/bash +cd "$(dirname "$0")" +echo "NetMap → http://localhost:8787" +sudo python3 netmap.py