feat(templates): per-instance stealth via instance_seed in service servers

Every service template now pulls version strings, cluster/node UUIDs, auth
salts, greeting banners, and uptime from the seeded per-instance RNG instead
of hard-coded defaults. Scanners sweeping the fleet now see legitimately
diverging fingerprints per decky while each decky's own responses stay
internally consistent across restarts.

Covers elasticsearch, ftp, http, https, ldap, mongodb, mqtt, mssql, mysql,
postgres, redis, and smtp templates.
This commit is contained in:
2026-04-22 09:24:16 -04:00
parent 51e9e263ca
commit 3fb84ac5d0
12 changed files with 755 additions and 156 deletions

View File

@@ -9,6 +9,8 @@ received messages as JSON.
import asyncio
import os
import struct
import instance_seed as _seed
from syslog_bridge import syslog_line, write_syslog_file, forward_syslog
NODE_NAME = os.environ.get("NODE_NAME", "mongodb")
@@ -16,6 +18,25 @@ SERVICE_NAME = "mongodb"
LOG_TARGET = os.environ.get("LOG_TARGET", "")
PORT = int(os.environ.get("PORT", "27017"))
# Per-instance (version, maxWireVersion) — paired per real MongoDB release.
# Wire version is locked to major/minor per upstream release notes.
_MONGO_RELEASES = [
("4.4.22", 9),
("5.0.25", 13),
("6.0.5", 17),
("6.0.14", 17),
("7.0.5", 21),
("7.0.8", 21),
("7.0.11", 21),
]
_MONGO_VERSION, _MONGO_WIRE = _seed.pick(_MONGO_RELEASES)
_MONGO_SET_NAME = os.environ.get("MONGO_REPL_SET", "") # empty = standalone
def _new_objectid() -> bytes:
"""12-byte BSON ObjectId — fresh per call."""
return _seed.fresh_bytes(12)
# Minimal BSON helpers
def _bson_str(key: str, val: str) -> bytes:
k = key.encode() + b"\x00"
@@ -98,14 +119,23 @@ class MongoDBProtocol(asyncio.Protocol):
opcode = struct.unpack("<I", msg[12:16])[0]
_log("message", src=self._peer[0], opcode=opcode, length=len(msg))
# Build a generic isMaster-style OK response
reply_doc = _bson_doc(
# Build a generic isMaster-style OK response with this instance's
# version pair. Fresh topologyVersion on every reply (matches real
# mongod behavior — clients use this to detect failover).
fields = [
_bson_bool("ismaster", True),
_bson_int32("maxWireVersion", 17),
_bson_bool("helloOk", True),
_bson_int32("maxBsonObjectSize", 16777216),
_bson_int32("maxMessageSizeBytes", 48000000),
_bson_int32("maxWriteBatchSize", 100000),
_bson_int32("maxWireVersion", _MONGO_WIRE),
_bson_int32("minWireVersion", 0),
_bson_str("version", "6.0.5"),
_bson_str("version", _MONGO_VERSION),
_bson_int32("ok", 1),
)
]
if _MONGO_SET_NAME:
fields.insert(1, _bson_str("setName", _MONGO_SET_NAME))
reply_doc = _bson_doc(*fields)
if opcode == 2013: # OP_MSG
self._transport.write(_op_msg(request_id, reply_doc))
else: