Files
reverse-engineering-anything/tests/fixtures/pcap/pcapTestTools.ts
T
morluto 0386efd1e1 fix(pcap): retain producer contradiction diagnostics (#7937)
* fix(pcap): retain producer contradiction diagnostics

* test(pcap): align DNS fixture with empty captures
2026-10-29 08:43:14 +08:00

182 lines
6.3 KiB
TypeScript

import { chmod, writeFile } from "node:fs/promises";
import { join } from "node:path";
export const CAPINFOS_OUTPUT = [
"File name: /work/capture.pcap",
"File type: Wireshark/tcpdump/... - pcap",
"File encapsulation: Ethernet",
"Packet size limit: file hdr: 262144 bytes",
"Packet size limit: inferred: 128 bytes - 256 bytes (range)",
"Number of packets: 3",
"Capture duration: 0.123 seconds",
"Earliest packet time: 1791728020.608505",
"Latest packet time: 1791728020.981978",
].join("\n");
/** Synthetic complete UDP A response; bytes own identity, tree owns display. */
export const dnsResponseLayers = (query: string, address: string) => {
const name = Buffer.concat([
...query
.split(".")
.map((label) =>
Buffer.concat([
Buffer.from([Buffer.byteLength(label)]),
Buffer.from(label),
]),
),
Buffer.from([0]),
]);
const bytes = Buffer.concat([
Buffer.from("000181800001000100000000", "hex"),
name,
Buffer.from("00010001c00c000100010000003c0004", "hex"),
Buffer.from(address.split(".").map(Number)),
]);
return {
dns_raw: [bytes.toString("hex"), 42, bytes.length, 0, 1],
dns: {
"dns.id_raw": ["0001", 42, 2, 0, 5],
Queries: { question: { "dns.qry.name": query } },
Answers: { answer: { "dns.a": address } },
},
};
};
export const TSHARK_JSON = JSON.stringify([
{
_source: {
layers: {
"frame.number": ["1"],
"frame.protocols": ["eth:ethertype:ip:udp:dns"],
"ip.src": ["192.168.1.100"],
"ip.dst": ["8.8.8.8"],
"dns.qry.name": ["api.example.com"],
"dns.a": ["93.184.216.34"],
},
},
},
{
_source: {
layers: {
"frame.number": ["2"],
"frame.protocols": ["eth:ethertype:ip:tcp:tls"],
"ip.src": ["192.168.1.100"],
"ip.dst": ["93.184.216.34"],
"tls.handshake.extensions_server_name": ["api.example.com"],
},
},
},
{
_source: {
layers: {
"frame.number": ["3"],
"frame.protocols": ["eth:ethertype:ip:tcp:http"],
"ip.src": ["192.168.1.100"],
"ip.dst": ["93.184.216.34"],
"http.request.full_uri": ["http://api.example.com/v1/data"],
},
},
},
]);
export const TSHARK_DNS_JSON = JSON.stringify([
{
_source: {
layers: {
frame: { "frame.number": "1" },
...dnsResponseLayers("api.example.com", "93.184.216.34"),
},
},
},
]);
export interface PcapStubToolsOptions {
readonly failCapinfos?: boolean;
readonly malformedDnsJson?: boolean;
readonly dnsJson?: string;
readonly tsharkJson?: string;
readonly capinfosText?: string;
readonly httpAbsoluteUriOnly?: boolean;
readonly http2Uri?: boolean;
readonly invalidTsharkStream?: "stdout" | "stderr";
readonly invalidTsharkVersionStream?: "stdout" | "stderr";
readonly invalidCapinfosStream?: "stdout" | "stderr";
readonly invalidCapinfosVersionStream?: "stdout" | "stderr";
readonly literalReplacement?: boolean;
readonly literalTsharkVersion?: boolean;
}
/** Write caller-selected POSIX tool stubs for pcap provider and adapter tests. */
export const writeStubTools = async (
root: string,
options: PcapStubToolsOptions = {},
): Promise<{ tshark: string; capinfos: string }> => {
const tshark = join(root, "tshark");
const capinfos = join(root, "capinfos");
const tsharkOutput = options.http2Uri
? TSHARK_JSON.replace(
'"http.request.full_uri":["http://api.example.com/v1/data"]',
'"http2.request.full_uri":["http://example.test/h2"],"http2.headers.path":["/h2"]',
).replace('eth:ethertype:ip:tcp:http"', 'eth:ethertype:ip:tcp:http2"')
: options.literalReplacement
? TSHARK_JSON.replace(
"http://api.example.com/v1/data",
"http://api.example.com/�",
)
: options.httpAbsoluteUriOnly
? TSHARK_JSON.replace(
'"http.request.full_uri":["http://api.example.com/v1/data"]',
'"http.request.uri":["http://proxy.example.test/path"]',
)
: TSHARK_JSON;
await writeFile(
tshark,
`#!/bin/sh
if [ "$1" = "--version" ]; then
printf 'TShark (Wireshark) 4.6.6${options.literalTsharkVersion ? "�" : ""}-stub\\n'
${options.invalidTsharkVersionStream === "stdout" ? `printf '\\377'` : options.invalidTsharkVersionStream === "stderr" ? `printf '\\377' >&2` : ""}
exit 0
fi
[ "$1" = "-n" ] && [ "$2" = "-r" ] && [ "$4" = "-T" ] && [ "$5" = "json" ] || exit 2
case " $* " in
*" -x "*)
case " $* " in *" --no-duplicate-keys "*) ;; *) exit 2 ;; esac
case " $* " in *" -J frame dns mdns llmnr "*) ;; *) exit 2 ;; esac
case " $* " in *" -Y dns || mdns || llmnr "*) ;; *) exit 2 ;; esac
printf '%s' '${(options.malformedDnsJson ? "{" : (options.dnsJson ?? TSHARK_DNS_JSON)).replace(/'/gu, "'\\''")}'
exit 0
;;
*)
case " $* " in *" -e http.request.uri "*) ;; *) exit 2 ;; esac
case " $* " in *" -e http2.request.full_uri "*) ;; *) exit 2 ;; esac
case " $* " in *" -e http2.headers.path "*) ;; *) exit 2 ;; esac
;;
esac
${options.invalidTsharkStream === "stdout" ? `printf '%s' '[{"_source":{"layers":{"frame.number":["1"],"frame.protocols":["eth:ip:tcp:http"],"http.request.full_uri":["http://example.test/'; printf '\\377'; printf '%s' '"]}}}]'` : `printf '%s' '${(options.tsharkJson ?? tsharkOutput).replace(/'/gu, "'\\''")}'`}
${options.invalidTsharkStream === "stderr" ? `printf '\\377' >&2` : ""}
exit 0
`,
{ mode: 0o755 },
);
await writeFile(
capinfos,
`#!/bin/sh
if [ "$1" = "--version" ]; then
printf 'Capinfos (Wireshark) 4.6.6-stub\\n'
${options.invalidCapinfosVersionStream === "stdout" ? `printf '\\377'` : options.invalidCapinfosVersionStream === "stderr" ? `printf '\\377' >&2` : ""}
exit 0
fi
[ "$1" = "-M" ] && [ "$2" = "-S" ] && [ "$3" = "--" ] && [ "$#" = "4" ] || exit 2
if [ "${String(options.failCapinfos === true)}" = "true" ]; then
printf 'capinfos: The file is not a capture file' >&2; exit 1
fi
${options.invalidCapinfosStream === "stdout" ? `printf '\\377'` : options.invalidCapinfosStream === "stderr" ? `printf '\\377' >&2` : `printf '%s\\n' '${(options.capinfosText ?? CAPINFOS_OUTPUT).replace(/'/gu, "'\\''")}'`}
exit 0
`,
{ mode: 0o755 },
);
await chmod(tshark, 0o755);
await chmod(capinfos, 0o755);
return { tshark, capinfos };
};