Add nmap OS spoof per decky via TCP/IP stack sysctls

Each decky base container now receives a set of Linux kernel sysctls
(net.ipv4.ip_default_ttl, net.ipv4.tcp_syn_retries, etc.) tuned to
match the claimed OS family, making nmap OS detection return the
expected OS rather than the Linux host.

- decnet/os_fingerprint.py: OS profile table (linux/windows/bsd/embedded/cisco)
  keyed by TTL and TCP tuning knobs
- decnet/archetypes.py: Archetype gains nmap_os field; windows-* → "windows",
  printer/iot/industrial → "embedded", rest → "linux"
- decnet/config.py: DeckyConfig gains nmap_os field (default "linux")
- decnet/cli.py: nmap_os resolved from archetype → DeckyConfig in both CLI
  and INI build paths
- decnet/composer.py: base container gets sysctls + cap_add: [NET_ADMIN];
  service containers inherit via shared network namespace
- tests/test_os_fingerprint.py: 48 new tests covering profiles, compose
  injection, archetype coverage, and CLI propagation

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-04 13:19:06 -03:00
parent bbb5fa7a7e
commit 6610856749
6 changed files with 329 additions and 0 deletions

View File

@@ -14,6 +14,7 @@ import yaml
from decnet.config import DecnetConfig
from decnet.network import MACVLAN_NETWORK_NAME
from decnet.os_fingerprint import get_os_sysctls
from decnet.services.registry import get_service
_CONTAINER_LOG_DIR = "/var/log/decnet"
@@ -63,6 +64,13 @@ def generate_compose(config: DecnetConfig) -> dict:
}
if config.log_target:
base["networks"][_LOG_NETWORK] = {}
# Inject TCP/IP stack sysctls to spoof the claimed OS fingerprint.
# Only the base container needs this — service containers inherit the
# same network namespace via network_mode: "service:<base>".
base["sysctls"] = get_os_sysctls(decky.nmap_os)
base["cap_add"] = ["NET_ADMIN"]
services[base_key] = base
# --- Service containers: share base network namespace ---