Commit 5: Scanner-Engine (DNS, Portscan, Titel/Favicon, Softwareerkennung, FritzBox TR-064)

This commit is contained in:
2026-07-19 02:22:54 +02:00
parent 129b4253b5
commit 28bccb9d16
13 changed files with 744 additions and 18 deletions

View File

@@ -0,0 +1,66 @@
import { soapRequest, type DigestAuthOptions } from "./digestAuth.js";
const SERVICE_TYPE = "urn:dslforum-org:service:Hosts:1";
function actionEnvelope(action: string, params: Record<string, string | number> = {}): string {
const args = Object.entries(params)
.map(([key, value]) => `<${key}>${value}</${key}>`)
.join("");
return (
`<?xml version="1.0" encoding="utf-8"?>` +
`<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" ` +
`s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">` +
`<s:Body><u:${action} xmlns:u="${SERVICE_TYPE}">${args}</u:${action}></s:Body>` +
`</s:Envelope>`
);
}
function extractTag(xml: string, tag: string): string | null {
const match = xml.match(new RegExp(`<${tag}>([^<]*)</${tag}>`, "i"));
return match ? match[1] : null;
}
export interface FritzBoxHost {
ip: string;
mac: string | null;
hostname: string;
online: boolean;
}
/**
* Liest die vollständige Geräteliste der FritzBox über die TR-064-Aktionen
* GetHostNumberOfEntries + GetGenericHostEntry (urn:dslforum-org:service:Hosts:1).
*/
export async function fetchFritzBoxHosts(options: DigestAuthOptions): Promise<FritzBoxHost[]> {
const countXml = await soapRequest(
options,
`${SERVICE_TYPE}#GetHostNumberOfEntries`,
actionEnvelope("GetHostNumberOfEntries")
);
const countStr = extractTag(countXml, "NewHostNumberOfEntries");
const count = countStr ? parseInt(countStr, 10) : 0;
const hosts: FritzBoxHost[] = [];
for (let index = 0; index < count; index++) {
const entryXml = await soapRequest(
options,
`${SERVICE_TYPE}#GetGenericHostEntry`,
actionEnvelope("GetGenericHostEntry", { NewIndex: index })
);
const ip = extractTag(entryXml, "NewIPAddress");
const hostname = extractTag(entryXml, "NewHostName");
if (!ip || !hostname) continue; // inaktive/unvollständige Einträge überspringen
hosts.push({
ip,
mac: extractTag(entryXml, "NewMACAddress"),
hostname,
online: extractTag(entryXml, "NewActive") === "1",
});
}
return hosts;
}