diff --git a/api/endpoints/facts_collector.php b/api/endpoints/facts_collector.php index a5c0eb4..b168cce 100644 --- a/api/endpoints/facts_collector.php +++ b/api/endpoints/facts_collector.php @@ -312,60 +312,9 @@ function collect_all(): array { } - // ── Network Device Scan (nmap via PVE1) ─────────────────────────────── - try { - $nmapRaw = shell_exec( - "sshpass -p 'Joker1974!!!' ssh -o StrictHostKeyChecking=no -o ConnectTimeout=10 " . - "root@10.48.200.90 'nmap -sn --send-ip 10.48.200.0/24 2>/dev/null' 2>/dev/null" - ); - if ($nmapRaw) { - $discovered = []; - $cur = null; - foreach (explode("\n", $nmapRaw) as $line) { - $line = trim($line); - if (preg_match('/Nmap scan report for (?:(\S+) \()?(\d+\.\d+\.\d+\.\d+)\)?/', $line, $m)) { - if ($cur) $discovered[] = $cur; - $cur = ['hostname' => ($m[1] && $m[1] !== $m[2]) ? $m[1] : null, 'ip' => $m[2], 'mac' => null, 'vendor' => null]; - } elseif ($cur && preg_match('/MAC Address: ([0-9A-Fa-f:]{17}) \(([^)]+)\)/i', $line, $m)) { - $cur['mac'] = strtolower($m[1]); - $cur['vendor'] = $m[2] !== 'Unknown' ? $m[2] : null; - } - } - if ($cur) $discovered[] = $cur; - - $discoveredIPs = []; - foreach ($discovered as $d) { - $discoveredIPs[] = $d['ip']; - JarvisDB::execute( - 'INSERT INTO network_devices (ip, mac, hostname, status, last_seen) - VALUES (?,?,?,"online",NOW()) - ON DUPLICATE KEY UPDATE mac=VALUES(mac), hostname=COALESCE(VALUES(hostname),hostname), - status="online", last_seen=NOW()', - [$d['ip'], $d['mac'], $d['hostname'] ?? $d['vendor']] - ); - if ($d['vendor']) { - JarvisDB::execute( - 'UPDATE network_devices SET device_type=? WHERE ip=? AND (device_type IS NULL OR device_type="")', - [$d['vendor'], $d['ip']] - ); - } - } - - if (!empty($discoveredIPs)) { - $ph = implode(',', array_fill(0, count($discoveredIPs), '?')); - JarvisDB::execute( - "UPDATE network_devices SET status='offline' - WHERE ip NOT IN ($ph) AND last_seen < DATE_SUB(NOW(), INTERVAL 10 MINUTE)", - $discoveredIPs - ); - } - $results['nmap_scan'] = 'ok (' . count($discovered) . ' devices found)'; - } else { - $results['nmap_scan'] = 'skipped (PVE1 unreachable)'; - } - } catch (Exception $e) { - $results['nmap_scan'] = 'error: ' . $e->getMessage(); - } + // Network device scan is handled by PVE1 cron (/usr/local/bin/jarvis-netscan.sh) + // which POSTs nmap results to /api/netscan every 3 minutes. + $results['nmap_scan'] = 'handled by PVE1 push (jarvis-netscan.sh)'; return $results; } diff --git a/api/endpoints/netscan.php b/api/endpoints/netscan.php new file mode 100644 index 0000000..5eae700 --- /dev/null +++ b/api/endpoints/netscan.php @@ -0,0 +1,64 @@ + 'POST only']); exit; +} + +$reqKey = $_SERVER['HTTP_X_REGISTRATION_KEY'] ?? ''; +if ($reqKey !== NETSCAN_KEY) { + http_response_code(401); + echo json_encode(['error' => 'Unauthorized']); exit; +} + +$body = file_get_contents('php://input'); +$payload = json_decode($body, true); +$devices = $payload['devices'] ?? []; + +if (empty($devices)) { + echo json_encode(['error' => 'No devices in payload']); exit; +} + +$discoveredIPs = []; +$upserted = 0; +foreach ($devices as $d) { + $ip = trim($d['ip'] ?? ''); + $mac = trim($d['mac'] ?? ''); + $hostname = trim($d['hostname'] ?? ''); + $vendor = trim($d['vendor'] ?? ''); + if (!$ip) continue; + + $discoveredIPs[] = $ip; + JarvisDB::execute( + 'INSERT INTO network_devices (ip, mac, hostname, status, last_seen) + VALUES (?,?,?,"online",NOW()) + ON DUPLICATE KEY UPDATE + mac = COALESCE(NULLIF(VALUES(mac),""), mac), + hostname = COALESCE(NULLIF(VALUES(hostname),""), hostname), + status = "online", + last_seen = NOW()', + [$ip, $mac ?: null, $hostname ?: $vendor ?: null] + ); + if ($vendor) { + JarvisDB::execute( + 'UPDATE network_devices SET device_type=? WHERE ip=? AND (device_type IS NULL OR device_type="")', + [$vendor, $ip] + ); + } + $upserted++; +} + +// Mark anything NOT in this scan as offline if stale > 10 min +if (!empty($discoveredIPs)) { + $ph = implode(',', array_fill(0, count($discoveredIPs), '?')); + JarvisDB::execute( + "UPDATE network_devices SET status='offline' + WHERE ip NOT IN ($ph) AND last_seen < DATE_SUB(NOW(), INTERVAL 10 MINUTE)", + $discoveredIPs + ); +} + +echo json_encode(['ok' => true, 'upserted' => $upserted, 'total_discovered' => count($discoveredIPs)]); diff --git a/public_html/api.php b/public_html/api.php index a5d580b..15a9b6e 100644 --- a/public_html/api.php +++ b/public_html/api.php @@ -26,7 +26,7 @@ $endpoint = $parts[0] ?? ''; $action = $parts[1] ?? ''; // Auth check (except login and ping) -if ($endpoint !== 'auth' && $endpoint !== 'agent') { +if ($endpoint !== 'auth' && $endpoint !== 'agent' && $endpoint !== 'netscan') { $token = $_SESSION['jarvis_token'] ?? ($_SERVER['HTTP_X_SESSION_TOKEN'] ?? ''); if (empty($token) || $token !== ($_SESSION['jarvis_token'] ?? '')) { $localIP = $_SERVER['REMOTE_ADDR'] ?? ''; @@ -57,6 +57,9 @@ switch ($endpoint) { case 'system': require __DIR__ . '/../api/endpoints/system.php'; break; + case 'netscan': + require __DIR__ . '/../api/endpoints/netscan.php'; + break; case 'network': require __DIR__ . '/../api/endpoints/network.php'; break;