$h) { $row[$h] = trim($cols[$i] ?? ''); } $rows[] = $row; } } return DB::transaction(function () use ($rows, $scanner, $subnet, $createdBy) { $this->scan = NetworkScan::create([ 'subnet' => $subnet, 'source' => 'import', 'scanner' => $scanner, 'created_by' => $createdBy, ]); foreach ($rows as $row) { $this->processRow($row); } $this->scan->update([ 'total_hosts' => count($rows), 'online_hosts' => $this->onlineHosts, 'new_devices' => $this->newDevices, 'changed_devices'=> $this->changedDevices, ]); return $this->scan; }); } private function processRow(array $row): void { $ip = $this->extractColumn($row, ['IP']); $ping = $this->extractColumn($row, ['Ping']); $host = $this->extractColumn($row, ['Hostname']); $mac = $this->normalizeMAC($this->extractColumn($row, ['MAC Addresse', 'MAC Address'])); $vendor = $this->extractColumn($row, ['MAC Hersteller', 'MAC Vendor']); $ttl = (int) $this->extractColumn($row, ['TTL']) ?: null; $ports = $this->extractColumn($row, ['Ports']); $netbios= $this->extractColumn($row, ['NetBIOS Info']); $http = $this->extractColumn($row, ['HTTP Sender']); $web = $this->extractColumn($row, ['Web Erkennung', 'Web Detection']); $pingMs = null; $status = 'offline'; if (!empty($ping) && $ping !== 'n/a' && $ping !== '-') { preg_match('/(\d+)/', $ping, $m); $pingMs = isset($m[1]) ? (int)$m[1] : null; $status = 'online'; $this->onlineHosts++; } // Host-Eintrag speichern $host_record = NetworkHost::create([ 'scan_id' => $this->scan->id, 'ip_address' => $ip, 'mac_address' => $mac ?: null, 'hostname' => $host ?: null, 'mac_vendor' => $vendor ?: null, 'status' => $status, 'ping_ms' => $pingMs, 'netbios_info' => $netbios ?: null, 'ttl' => $ttl, 'ports' => $ports ?: null, 'http_sender' => $http ?: null, 'web_detection' => $web ?: null, ]); // Geräte-Master nur wenn MAC bekannt if (!empty($mac)) { $this->processDevice($host_record, $ip, $mac, $host, $vendor, $netbios, $ttl, $ports, $status); } } private function processDevice( NetworkHost $hostRecord, string $ip, string $mac, ?string $hostname, ?string $vendor, ?string $netbios, ?int $ttl, ?string $ports, string $status ): void { $device = NetworkDevice::firstOrNew(['mac_address' => $mac]); $isNew = !$device->exists; if ($isNew) { $device->fill([ 'current_ip' => $ip, 'hostname' => $hostname, 'mac_vendor' => $vendor, 'status' => $status, 'netbios_name' => $netbios, 'ttl' => $ttl, 'ports' => $ports, 'first_seen_at'=> now(), 'last_seen_at' => now(), ])->save(); NetworkDeviceEvent::create([ 'device_id' => $device->id, 'scan_id' => $this->scan->id, 'event_type' => 'new_device', 'new_value' => $ip, 'description'=> "Erstes Erscheinen: {$ip} ({$vendor})", ]); $this->newDevices++; } else { $events = []; // IP-Änderung erkennen if ($device->current_ip !== $ip) { $events[] = [ 'event_type' => 'ip_changed', 'old_value' => $device->current_ip, 'new_value' => $ip, 'description'=> "IP geändert von {$device->current_ip} zu {$ip}", ]; $this->changedDevices++; } // Online/Offline-Status if ($device->status !== $status) { $events[] = [ 'event_type' => $status === 'online' ? 'came_online' : 'went_offline', 'old_value' => $device->status, 'new_value' => $status, 'description'=> $status === 'online' ? "Gerät wieder online ({$ip})" : "Gerät offline ({$device->current_ip})", ]; } $device->update([ 'current_ip' => $ip, 'hostname' => $hostname ?? $device->hostname, 'status' => $status, 'last_seen_at' => now(), ]); foreach ($events as $event) { NetworkDeviceEvent::create(array_merge($event, [ 'device_id' => $device->id, 'scan_id' => $this->scan->id, ])); } } $hostRecord->update(['device_id' => $device->id]); } private function extractColumn(array $row, array $keys): string { foreach ($keys as $key) { if (isset($row[$key]) && $row[$key] !== '') { return $row[$key]; } } return ''; } private function normalizeMAC(string $mac): string { // Verschiedene MAC-Formate normalisieren zu XX:XX:XX:XX:XX:XX $clean = preg_replace('/[^a-fA-F0-9]/', '', $mac); if (strlen($clean) !== 12) { return ''; } return strtoupper(implode(':', str_split($clean, 2))); } }