Files
DECNET/decnet/cloak/__main__.py
anti 402c1ef7a2 feat(cloak): wire cloak into the deploy path for windows* deckies
Base containers whose nmap_os has a mangle profile now build the cloak image
(FROM the per-decky distro), ship the light decnet subtree, and run
'python -m decnet.cloak' alongside holding the MACVLAN IP — netns-safe (cloak
backgrounded behind 'exec sleep infinity' so a cloak crash never tears down the
base/netns). composer injects build/command/NET_RAW/env (DECNET_NMAP_OS,
DECNET_OPEN_PORTS, DECKY_IP); deployer._sync_cloak_sources syncs the subtree;
non-windows deckies are unchanged. Mangler signal-guarded for thread use;
entry runs mangler in main thread, responder as daemon.

Verified live: real path makes nmap -O read 'Microsoft Windows Server 2012/2016'
with handshakes intact.
2026-06-20 00:22:38 -04:00

52 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
# Responder runs in a daemon thread; the mangler runs in the MAIN thread so
# its SIGTERM/SIGINT iptables-teardown handlers can be installed (signal only
# works in the main thread).
threading.Thread(
target=responder.run, args=(nmap_os, _open_ports()),
name="cloak-responder", daemon=True,
).start()
log.info("cloak: started for nmap_os=%r", nmap_os)
mangler.run(nmap_os)
return 0
if __name__ == "__main__":
raise SystemExit(main())