CH-J Server ManagerSerververwaltung über SSH
Menü
Veröffentlichte Quellen

CH-J Server Manager

Durchsuchen Sie Verzeichnisse und Dateien einer bestimmten Anwendungsausgabe.

Quellen als ZIP herunterladen
CH-J Proprietary Software License 1.14

Die Quellen werden unter der CH-J Proprietary Software License 1.14 bereitgestellt. Ihre Verfügbarkeit ändert die Lizenzbedingungen nicht und gewährt keine zusätzlichen Rechte.

9,9 KB · 102 ZeilenDatei herunterladen
1"use strict";
2const test = require("node:test");
3const assert = require("node:assert/strict");
4const dgram = require("node:dgram");
5const net = require("node:net");
6const { once } = require("node:events");
7const { DnsDiagnostics, TYPES, parseResponse, readName, reverseName } = require("../src/main/diagnostics/dnsDiagnostics");
8const { pingCommand, tracerouteCommand, parsePingReply, parseHop, ping, traceroute, runProcess } = require("../src/main/diagnostics/processTools");
9const { normalizeOptions } = require("../src/main/diagnostics/common");
10function name(value) { return Buffer.concat([...value.split(".").map((part) => Buffer.concat([Buffer.from([part.length]), Buffer.from(part)])), Buffer.from([0])]); }
11function answer(packet, code = 0, records = []) {
12 const header = Buffer.from(packet.subarray(0, 12)); header.writeUInt16BE(0x8180 | code, 2); header.writeUInt16BE(records.length, 6);
13 return Buffer.concat([header, packet.subarray(12), ...records.map(([type, data]) => {
14 const fields = Buffer.alloc(12); fields.writeUInt16BE(0xc00c); fields.writeUInt16BE(TYPES[type], 2); fields.writeUInt16BE(1, 4); fields.writeUInt32BE(60, 6); fields.writeUInt16BE(data.length, 10);
15 return Buffer.concat([fields, data]);
16 })]);
18const options = normalizeOptions({ target: "example.test", tools: ["dns"], timeoutMs: 250, resolver: "custom", customDns: "127.0.0.1" });
19const signal = () => new AbortController().signal;
20test("DNS wire decoding retains TTL, NXDOMAIN/NODATA/SERVFAIL, DNSSEC records and never claims validation", () => {
21 const header = Buffer.alloc(12); header.writeUInt16BE(1234); header.writeUInt16BE(1, 4);
22 const packet = Buffer.concat([header, name("example.test"), Buffer.from([0, 1, 0, 1])]);
23 const decoded = parseResponse(answer(packet, 0, [["A", Buffer.from([127,0,0,1])], ["DS", Buffer.from([0,1,8,2,0xab,0xcd])], ["DNSKEY", Buffer.from([1,1,3,8,1,2,3])]]), 1234, "A");
24 assert.equal(decoded.records[0].ttl, 60); assert.equal(decoded.questionName, "example.test"); assert.equal(decoded.records[1].value.digest, "abcd"); assert.equal(decoded.dnssec, "not-validated");
25 assert.equal(parseResponse(answer(packet, 3), 1234, "A").status, "nxdomain");
26 assert.equal(parseResponse(answer(packet, 2), 1234, "A").status, "servfail");
27 assert.equal(parseResponse(answer(packet), 1234, "A").status, "nodata");
28 assert.throws(() => parseResponse(answer(packet), 999, "A")); assert.throws(() => readName(Buffer.from([0xc0,0]), 0));
29 assert.equal(reverseName("127.0.0.1"), "1.0.0.127.in-addr.arpa"); assert.ok(reverseName("::1").endsWith("ip6.arpa")); assert.equal(reverseName("::ffff:127.0.0.1").split(".").length, 34);
30});
31test("local DNS handles UDP, truncated-response TCP fallback, IPv4-only/IPv6-only/dual-stack and timeout", async (t) => {
32 const udp = dgram.createSocket("udp4"), tcp = net.createServer(); let tcpQueries = 0;
33 udp.bind(0, "127.0.0.1"); await once(udp, "listening"); const port = udp.address().port;
34 await new Promise((resolve) => tcp.listen(port, "127.0.0.1", resolve));
35 t.after(async () => { udp.close(); await new Promise((resolve) => tcp.close(resolve)); });
36 const respond = (packet) => {
37 const query = readName(packet, 12), type = packet.readUInt16BE(query.end), host = query.name;
38 if (host === "missing.test") return answer(packet, 3);
39 const records = [];
40 if (type === TYPES.A && host !== "v6.test") records.push(["A", Buffer.from([127,0,0,1])]);
41 if (type === TYPES.AAAA && host !== "v4.test") { const data = Buffer.alloc(16); data[15] = 1; records.push(["AAAA", data]); }
42 return answer(packet, 0, records);
43 };
44 udp.on("message", (packet, remote) => {
45 const host = readName(packet, 12).name; if (host === "timeout.test") return;
46 const response = host === "tcp.test" ? answer(packet) : respond(packet); if (host === "tcp.test") response[2] |= 2;
47 udp.send(response, remote.port, remote.address);
48 });
49 tcp.on("connection", (socket) => { socket.once("data", (data) => { tcpQueries++; const response = respond(data.subarray(2)), size = Buffer.alloc(2); size.writeUInt16BE(response.length); socket.end(Buffer.concat([size, response])); }); });
50 const dns = new DnsDiagnostics(); dns.servers = () => [`127.0.0.1:${port}`];
51 assert.equal((await dns.resolve("v4.test", options, signal())).length, 1);
52 assert.equal((await dns.resolve("v6.test", options, signal()))[0].family, 6);
53 assert.equal((await dns.resolve("dual.test", options, signal())).length, 2);
54 await assert.rejects(dns.resolve("missing.test", options, signal()), { code: "DNS_NO_ADDRESS" });
55 assert.equal((await dns.query("tcp.test", "A", options, signal())).records[0].value, "127.0.0.1"); assert.equal(tcpQueries, 1);
56 await assert.rejects(dns.query("timeout.test", "A", options, signal()), { code: "TIMEOUT" });
57 const controller = new AbortController(); controller.abort(); await assert.rejects(dns.query("timeout.test", "A", options, controller.signal), { code: "CANCELLED" });
58});
59test("DNS detects CNAME chains and compares repeated answers from the chosen resolver", async () => {
60 const dns = new DnsDiagnostics(); let aQueries = 0;
61 dns.query = async (host, type) => ({ name: host, type, status: "success", durationMs: 1, records: host === "alias.test" && ["A", "CNAME"].includes(type) ? [{ name: host, type: "CNAME", value: "target.test", section: "answer", ttl: 60 }] : host === "target.test" && type === "A" ? [{ name: host, type, value: "127.0.0.1", section: "answer", ttl: 60 }] : type === "AAAA" ? [{ name: host, type, value: (++aQueries > 1 ? "::2" : "::1"), section: "answer" }] : [] });
62 assert.equal((await dns.resolve("alias.test", { ...options, mode: "ipv4" }, signal()))[0].address, "127.0.0.1");
63 const result = await dns.run("alias.test", options, signal(), () => {}); assert.deepEqual(result.cnameChain, ["alias.test → target.test"]); assert.equal(result.consistency.find((r) => r.type === "AAAA").status, "changed");
64});
65test("OS command arguments and localized ping/traceroute parsers handle both IP families", () => {
66 for (const platform of ["win32", "darwin", "linux"]) for (const address of ["127.0.0.1", "::1"]) {
67 const ping = pingCommand(address, 500, platform), trace = tracerouteCommand(address, { timeoutMs: 500, maxHops: 3 }, platform);
68 assert.equal(ping.args.at(-1), address); assert.equal(trace.args.at(-1), address); assert.ok(trace.args.includes("3"));
69 }
70 assert.throws(() => pingCommand("localhost;bad", 500, "linux"));
71 assert.equal(parsePingReply("Antwort von 127.0.0.1: Bytes=32 Zeit=1,25ms TTL=64").rttMs, 1.25);
72 assert.equal(parsePingReply("Reply: time<1ms TTL=128").rttMs, null); assert.equal(parsePingReply("Reply: time<1ms TTL=128").received, true);
73 assert.equal(parsePingReply("64 bytes from ::1: icmp_seq=0 hlim=64 time=0.032 ms").ttl, 64);
74 const hop = parseHop(" 2 192.0.2.1 1.20 ms * 1.40 ms"); assert.equal(hop.hop, 2); assert.equal(hop.probes.length, 3); assert.ok(Math.abs(hop.averageMs - 1.3) < 1e-12);
75 assert.equal(parseHop(" 3 <1 ms 2 ms * 2001:db8::1").addresses[0], "2001:db8::1");
76 assert.equal(parseHop("traceroute to example"), null);
77});
78test("ICMP absence and missing tools do not claim a server is offline; traceroute updates are progressive", async () => {
79 const settings = { ...options, count: 1, repetitions: 1, continuous: false, maxHops: 3 }, events = [];
80 const blocked = await ping("127.0.0.1", settings, signal(), (event) => events.push(event), async () => ({ code: 1, stdout: Buffer.from("Request timed out."), stderr: "" }));
81 assert.equal(blocked.status, "warning"); assert.equal(blocked.packets[0].status, "timeout"); assert.equal(blocked.lossPercent, 100); assert.equal(blocked.packets[0].rttMs, null); assert.ok(blocked.packets[0].measuredAt);
82 const missing = await ping("127.0.0.1", settings, signal(), () => {}, async () => { throw Object.assign(new Error("missing"), { code: "ENOENT" }); }); assert.equal(missing.status, "unavailable");
83 const trace = await traceroute("127.0.0.1", settings, signal(), (event) => events.push(event), async (_exe, _args, { onLine }) => { onLine("1 * * *"); onLine("2 127.0.0.1 0.1 ms 0.2 ms 0.3 ms"); return { code: 0, stdout: Buffer.from("trace"), stderr: "" }; });
84 assert.equal(trace.status, "success"); assert.equal(trace.routes[0].hops.length, 2); assert.equal(events.filter((e) => e.kind === "trace-hop").length, 2);
85});
86test("process runner uses argument arrays with shell disabled and terminates on timeout, abort and output limit", async () => {
87 const { spawn } = require("node:child_process"); let config;
88 const result = await runProcess(process.execPath, ["-e", "process.stdout.write('ok')"], { spawnImpl: (exe, args, options) => { config = options; return spawn(exe, args, options); } });
89 assert.equal(result.stdout.toString(), "ok"); assert.equal(config.shell, false);
90 await assert.rejects(runProcess(process.execPath, ["-e", "setInterval(()=>{},1000)"], { timeoutMs: 30 }), { code: "TIMEOUT" });
91 await assert.rejects(runProcess(process.execPath, ["-e", "process.stdout.write('x'.repeat(10000))"], { maxBytes: 50 }), { code: "OUTPUT_LIMIT" });
92 const controller = new AbortController(), work = runProcess(process.execPath, ["-e", "setInterval(()=>{},1000)"], { signal: controller.signal }); controller.abort(); await assert.rejects(work, { code: "CANCELLED" });
93 await assert.rejects(runProcess("chj-nonexistent-diagnostic-tool", []), { code: "ENOENT" });
94});
96test("system resolution honors localhost/hosts-file entries and remains timeout/cancel bounded", async () => {
97 const dns = new DnsDiagnostics(); const addresses = await dns.resolve("localhost", { ...options, resolver: "system", timeoutMs: 1000 }, signal());
98 assert.ok(addresses.some((a) => ["127.0.0.1", "::1"].includes(a.address)));
99 const hanging = new DnsDiagnostics({ lookup() {} });
100 await assert.rejects(hanging.resolve("localhost", { ...options, resolver: "system", timeoutMs: 20 }, signal()), { code: "TIMEOUT" });
101 const controller = new AbortController(), work = hanging.resolve("localhost", { ...options, resolver: "system" }, controller.signal); controller.abort(); await assert.rejects(work);
102});

SHA-256: 74705216e71251bfd578d0bf831f581f0c5cf30457a231fe9f957deab8467f76

SHA-256 des Archivs: 5ac91caf4fa32a6fdb114f2430deed486fbe7489d5eea343d1f034169fafb5e0