generated from Dicken/dickendock
round50: masscan/httpx laufen im Sammel-Scan nur noch einmal fuer alle Geraete statt pro Geraet, Rate deutlich erhoeht
This commit is contained in:
@@ -4,8 +4,10 @@ import * as serviceRepo from "../db/repositories/services.js";
|
||||
import * as categoryRepo from "../db/repositories/categories.js";
|
||||
import * as logRepo from "../db/repositories/logs.js";
|
||||
import * as settingsRepo from "../db/repositories/settings.js";
|
||||
import { scanDeviceServices } from "../scanner/networkScanner.js";
|
||||
import { scanDeviceServices, type PreFetchedScanData } from "../scanner/networkScanner.js";
|
||||
import { fullPortRange } from "../scanner/ports.js";
|
||||
import { scanHostsWithMasscan, getMasscanLastError } from "../scanner/masscan.js";
|
||||
import { probeManyWithHttpx, getHttpxLastError, type HttpxResult } from "../scanner/httpx.js";
|
||||
import { fetchFritzBoxHosts, type FritzBoxHost } from "../scanner/fritzbox.js";
|
||||
import {
|
||||
startJob,
|
||||
@@ -54,7 +56,7 @@ function formatToolsUsed(toolsUsed: {
|
||||
* Einzelgerät-Endpunkt als auch der Sammel-Scan (siehe /api/scan/devices/all
|
||||
* weiter unten) dieselbe Logik nutzen, ohne sie zu duplizieren.
|
||||
*/
|
||||
async function performDeviceScan(device: Device, fullScan = false) {
|
||||
async function performDeviceScan(device: Device, fullScan = false, preFetched?: PreFetchedScanData) {
|
||||
// Bestehende Dienste dieses Geräts VOR dem Scan merken, um danach zu
|
||||
// erkennen, welche davon diesmal nicht mehr gefunden wurden ("stale").
|
||||
const servicesBeforeScan = serviceRepo.listServicesByDevice(device.id);
|
||||
@@ -62,7 +64,8 @@ async function performDeviceScan(device: Device, fullScan = false) {
|
||||
const { services: discovered, suggestedHostname, toolsUsed } = await scanDeviceServices(
|
||||
device,
|
||||
fullScan ? fullPortRange() : undefined,
|
||||
servicesBeforeScan.map((s) => s.port)
|
||||
servicesBeforeScan.map((s) => s.port),
|
||||
preFetched
|
||||
);
|
||||
|
||||
// Jede erkannte Kategorie auch in der categories-Tabelle anlegen, damit
|
||||
@@ -230,10 +233,48 @@ export async function scanRoutes(app: FastifyInstance): Promise<void> {
|
||||
let cancelled = false;
|
||||
|
||||
try {
|
||||
// NEU (round50): Bis round49 startete JEDES Gerät seinen eigenen
|
||||
// masscan- bzw. httpx-Prozess - bei bis zu 10 gleichzeitig
|
||||
// gescannten Geräten (siehe CONCURRENT_DEVICES unten) liefen dadurch
|
||||
// bis zu 10 masscan- und 10 httpx-Prozesse parallel, die sich
|
||||
// gegenseitig die Netzwerkschnittstelle streitig machten und in den
|
||||
// Timeout liefen (siehe Bugreport: "Flaschenhals").
|
||||
//
|
||||
// Jetzt läuft masscan EINMAL für ALLE Geräte dieses Scan-Laufs
|
||||
// gemeinsam (masscan unterstützt mehrere Ziel-IPs nativ in einem
|
||||
// Prozess) und httpx EINMAL für die Vereinigung aller dabei
|
||||
// gefundenen offenen Ports über alle Geräte hinweg. Das Ergebnis
|
||||
// wird unten pro Gerät als "preFetched" an performDeviceScan
|
||||
// durchgereicht - der eigentliche Geräte-Scan macht dann selbst
|
||||
// keine masscan-/httpx-Aufrufe mehr, nur noch die (leichtgewichtigen,
|
||||
// reinen HTTP-)Detailabfragen pro Port (Titel, Favicon,
|
||||
// Softwareerkennung).
|
||||
const deviceIps = devices.map((d) => d.ip);
|
||||
const masscanBatch = await scanHostsWithMasscan(deviceIps, "1-65535");
|
||||
const masscanBatchError = masscanBatch === null ? getMasscanLastError() : null;
|
||||
|
||||
// httpx nur für die Geräte vorab bündeln, für die masscan Ergebnisse
|
||||
// geliefert hat - ist masscan für den GESAMTEN Batch fehlgeschlagen
|
||||
// (masscanBatch === null), kennen wir die offenen Ports noch nicht
|
||||
// und jedes Gerät ermittelt sie unten wie gewohnt selbst per
|
||||
// TCP-Fallback (scanPortsInBatches) samt eigenem httpx-Aufruf -
|
||||
// langsamer als der Idealfall, aber weiterhin korrekt.
|
||||
let httpxBatch: Map<string, HttpxResult> | null = null;
|
||||
let httpxBatchError: string | null = null;
|
||||
if (masscanBatch) {
|
||||
const httpxTargets: Array<{ ip: string; port: number }> = [];
|
||||
for (const device of devices) {
|
||||
const ports = masscanBatch.get(device.ip) ?? [];
|
||||
for (const port of ports) httpxTargets.push({ ip: device.ip, port });
|
||||
}
|
||||
httpxBatch = await probeManyWithHttpx(httpxTargets);
|
||||
if (httpxBatch === null) httpxBatchError = getHttpxLastError();
|
||||
}
|
||||
|
||||
// Mehrere Geräte GLEICHZEITIG scannen statt strikt nacheinander -
|
||||
// bei z. B. 118 Geräten und je 10-30 Sekunden pro vollständigem
|
||||
// Portscan hätte ein rein sequenzieller Durchlauf zusammen leicht
|
||||
// 30+ Minuten gedauert. Batch-Größe bewusst moderat (nicht alle
|
||||
// bei z. B. 118 Geräten hätte ein rein sequenzieller Durchlauf der
|
||||
// (jetzt viel schnelleren, weil rein HTTP-basierten) Detailabfragen
|
||||
// trotzdem lange gedauert. Batch-Größe bewusst moderat (nicht alle
|
||||
// Geräte auf einmal): jeder einzelne Geräte-Scan öffnet intern schon
|
||||
// bis zu 1000 gleichzeitige Verbindungen (siehe ports.ts) - zu viele
|
||||
// Geräte gleichzeitig könnte das eigene Netz/den Docker-Host
|
||||
@@ -258,7 +299,28 @@ export async function scanRoutes(app: FastifyInstance): Promise<void> {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const result = await performDeviceScan(device, true);
|
||||
const masscanPorts = masscanBatch?.get(device.ip);
|
||||
const preFetched: PreFetchedScanData = {
|
||||
masscanAttempted: true,
|
||||
masscanPorts,
|
||||
masscanError: masscanPorts ? null : masscanBatchError,
|
||||
httpxResults: masscanPorts
|
||||
? (() => {
|
||||
// Aus der großen, geräteübergreifenden httpx-Map nur
|
||||
// die Treffer DIESES Geräts herausfiltern.
|
||||
if (httpxBatch === null) return null;
|
||||
const map = new Map<number, HttpxResult>();
|
||||
for (const port of masscanPorts) {
|
||||
const hit = httpxBatch.get(`${device.ip}:${port}`);
|
||||
if (hit) map.set(port, hit);
|
||||
}
|
||||
return map;
|
||||
})()
|
||||
: undefined,
|
||||
httpxError: masscanPorts ? httpxBatchError : null,
|
||||
};
|
||||
|
||||
const result = await performDeviceScan(device, true, preFetched);
|
||||
created += result.created;
|
||||
updated += result.updated;
|
||||
allStale.push(...result.staleServices);
|
||||
|
||||
Reference in New Issue
Block a user