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.
This commit is contained in:
2026-06-20 00:22:38 -04:00
parent f715ac6bcd
commit 402c1ef7a2
8 changed files with 258 additions and 13 deletions

View File

@@ -18,6 +18,7 @@ import os
import signal
import subprocess # nosec B404 — fixed-arg iptables, no shell
import sys
import threading
from typing import Any
from decnet.logging import get_logger
@@ -120,8 +121,12 @@ def run(nmap_os: str) -> int:
finally:
sys.exit(0)
signal.signal(signal.SIGTERM, _cleanup)
signal.signal(signal.SIGINT, _cleanup)
# signal.signal() only works in the main thread; the `finally` below still
# removes the rule on a normal exit, and on container stop the netns (and
# its iptables rules) are torn down regardless.
if threading.current_thread() is threading.main_thread():
signal.signal(signal.SIGTERM, _cleanup)
signal.signal(signal.SIGINT, _cleanup)
log.info("cloak.mangler: rewriting SYN-ACK -> %s (window=%#x ipid=%s)",
nmap_os, profile.window, profile.ipid)
try: