round35: Vollstaendiger Portscan (1-65535) pro Geraet als Option, fuer Geraete mit vielen Diensten auf unueblichen Ports

This commit is contained in:
2026-07-24 21:21:07 +02:00
parent fedb3e9127
commit 645dcf3af8
4 changed files with 63 additions and 21 deletions

View File

@@ -1,5 +1,5 @@
import { resolveHostname, reverseLookup } from "./dns.js";
import { isPortOpen, TYPICAL_PORTS } from "./ports.js";
import { isPortOpen, scanPortsInBatches, fullPortRange, TYPICAL_PORTS } from "./ports.js";
import { probeHttp } from "./http.js";
import { detectSoftware } from "./softwareDetection.js";
import { findBestIconMatch } from "./iconDb.js";
@@ -102,17 +102,11 @@ export async function scanDeviceServices(
const candidatePorts = Array.from(new Set([80, 443, ...extraPorts, ...priorityPorts]));
// Die offenen Ports werden PARALLEL geprüft, nicht nacheinander - bei
// einem nicht erreichbaren/gefilterten Gerät (z. B. ein schlafender
// Laptop) würde ein sequenzieller Durchlauf sonst bis zu
// Portanzahl × Timeout dauern (bei 20 Ports und 800ms Timeout: 16+
// Sekunden PRO GERÄT) und den Scan wie hängengeblieben wirken lassen.
// Danach wird nur noch für die tatsächlich offenen Ports (meist wenige)
// die eigentliche HTTP-Abfrage gemacht.
const openChecks = await Promise.all(
candidatePorts.map(async (port) => ({ port, open: await isPortOpen(device.ip, port) }))
);
let openPorts = openChecks.filter((c) => c.open).map((c) => c.port);
// Batches statt alles auf einmal parallel - bei der "typischen Ports"-Liste
// (~30 Ports) macht das kaum einen Unterschied, ist aber zwingend nötig für
// den optionalen VOLLSTÄNDIGEN Portscan (1-65535, siehe Admin -> Geräte),
// wo alle Ports gleichzeitig öffnen würde.
let openPorts = await scanPortsInBatches(device.ip, candidatePorts);
// Bereits bekannte Dienst-Ports (priorityPorts, vom Aufrufer übergeben -
// siehe scan.ts), die im ersten, stark parallelen Durchlauf NICHT als

View File

@@ -36,3 +36,36 @@ export function isPortOpen(host: string, port: number, timeoutMs = 800): Promise
socket.once("error", () => finish(false));
});
}
/**
* Prüft eine (ggf. sehr lange) Liste von Ports in Batches mit begrenzter
* Parallelität - für den vollständigen Portscan (1-65535, siehe
* scanDeviceServices mit fullScan=true). Alle Ports auf einmal parallel zu
* prüfen wäre bei 65535 Ports zu viel gleichzeitig offener Sockets; komplett
* nacheinander wäre selbst bei schnellen RSTs zu langsam. Ein Batch von 500
* ist ein guter Mittelweg für ein Gerät im lokalen Netz.
*/
export async function scanPortsInBatches(
host: string,
ports: number[],
batchSize = 500,
timeoutMs = 600
): Promise<number[]> {
const open: number[] = [];
for (let i = 0; i < ports.length; i += batchSize) {
const batch = ports.slice(i, i + batchSize);
const results = await Promise.all(
batch.map(async (port) => ({ port, open: await isPortOpen(host, port, timeoutMs) }))
);
for (const r of results) if (r.open) open.push(r.port);
}
return open;
}
/** Alle Ports von 1 bis 65535 - für den vollständigen (statt nur "typische Ports") Scan eines einzelnen Geräts. */
export function fullPortRange(): number[] {
const ports: number[] = [];
for (let p = 1; p <= 65535; p++) ports.push(p);
return ports;
}