#!/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.")