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