Files
DECNET/decnet/cloak/__main__.py
anti f715ac6bcd feat(cloak): egress SYN-ACK mangler + T2/T3 probe-response synthesizer
In-decky-netns NFQUEUE rewriter (window/option-order/IP-ID) and raw-socket
synthesizer for nmap probes Linux drops but the target OS answers (T2/T3),
driven by os_fingerprint.OS_MANGLE. Packet-shaping logic is pure and unit-tested
offline; scapy/netfilterqueue import lazily in the runtime loops. Entry:
python -m decnet.cloak (run by the base container; CAP_NET_ADMIN).
2026-06-19 21:32:50 -04:00

54 lines
1.6 KiB
Python

# SPDX-License-Identifier: AGPL-3.0-or-later
"""
Cloak entrypoint — run inside the decky base container (CAP_NET_ADMIN).
python -m decnet.cloak
Config via env (set by the composer when nmap_os has a mangle profile):
DECNET_NMAP_OS nmap_os slug (e.g. "windows", "windows_server")
DECNET_OPEN_PORTS comma-separated TCP ports the decky serves (for T2/T3)
DECKY_IP this decky's IP (BPF scope for the responder)
Starts the mangler and responder, each in its own thread. A slug with no mangle
profile exits 0 immediately — harmless to launch unconditionally.
"""
from __future__ import annotations
import os
import threading
from decnet.cloak import mangler, responder
from decnet.logging import get_logger
from decnet.os_fingerprint import get_os_mangle
log = get_logger("cloak")
def _open_ports() -> frozenset[int]:
raw = os.environ.get("DECNET_OPEN_PORTS", "")
return frozenset(int(p) for p in raw.split(",") if p.strip().isdigit())
def main() -> int:
nmap_os = os.environ.get("DECNET_NMAP_OS", "linux")
if get_os_mangle(nmap_os) is None:
log.info("cloak: no mangle profile for %r — exiting", nmap_os)
return 0
threads = [
threading.Thread(target=mangler.run, args=(nmap_os,),
name="cloak-mangler", daemon=True),
threading.Thread(target=responder.run, args=(nmap_os, _open_ports()),
name="cloak-responder", daemon=True),
]
for t in threads:
t.start()
log.info("cloak: started for nmap_os=%r", nmap_os)
for t in threads:
t.join()
return 0
if __name__ == "__main__":
raise SystemExit(main())