diff --git a/compose.yaml b/compose.yaml index bdab249..b863dec 100644 --- a/compose.yaml +++ b/compose.yaml @@ -22,6 +22,7 @@ services: REDIRECT_URL: "${GUIDE_REDIRECT_URL:-http://192.168.20.30:8000/}" FORWARDED_DOMAINS: "${FORWARDED_DOMAINS:-homebrew.page,itsplk.github.io,store.spectrumlibrary.online,api.github.com,github.com,raw.githubusercontent.com,release-assets.githubusercontent.com,prosperopatches.com,cdn.prosperopatches.com,image.api.playstation.com,gmedia.playstation.com}" UPSTREAM_DNS: "${UPSTREAM_DNS:-1.1.1.1}" + ALLOWED_CLIENTS: "${ALLOWED_CLIENTS:-192.168.40.0/28}" ports: - "${GATEWAY_BIND_IP:-192.168.20.30}:53:8053/udp" - "${GATEWAY_BIND_IP:-192.168.20.30}:53:8053/tcp" diff --git a/docker/guide_gateway.py b/docker/guide_gateway.py index 29e56bd..d2c63b7 100644 --- a/docker/guide_gateway.py +++ b/docker/guide_gateway.py @@ -26,10 +26,28 @@ FORWARDED_DOMAINS = frozenset( ) UPSTREAM_DNS = str(ipaddress.ip_address(os.environ.get("UPSTREAM_DNS", "1.1.1.1"))) UPSTREAM_TIMEOUT = 3.0 +# Source networks allowed to query the DNS service (PS5 VLAN by default). +# Accepts comma-separated individual addresses and CIDR ranges; empty disables +# the filter and serves every client. +ALLOWED_CLIENTS = tuple( + ipaddress.ip_network(entry.strip(), strict=False) + for entry in os.environ.get("ALLOWED_CLIENTS", "192.168.40.0/28").split(",") + if entry.strip() +) CERTIFICATE = "/srv/certificates/manuals.crt" PRIVATE_KEY = "/srv/certificates/manuals.key" +def client_allowed(address): + if not ALLOWED_CLIENTS: + return True + try: + client = ipaddress.ip_address(address) + except ValueError: + return False + return any(client in network for network in ALLOWED_CLIENTS) + + def parse_question(packet): if len(packet) < 17: raise ValueError("short DNS query") @@ -150,6 +168,9 @@ class ThreadingTCPServer(socketserver.ThreadingTCPServer): class UDPDNSHandler(socketserver.BaseRequestHandler): def handle(self): packet, connection = self.request + if not client_allowed(self.client_address[0]): + print(f"DNS UDP {self.client_address[0]} denied", flush=True) + return try: name, qtype, _, _ = parse_question(packet) print(f"DNS UDP {self.client_address[0]} {name} type={qtype}", flush=True) @@ -162,6 +183,9 @@ class UDPDNSHandler(socketserver.BaseRequestHandler): class TCPDNSHandler(socketserver.BaseRequestHandler): def handle(self): + if not client_allowed(self.client_address[0]): + print(f"DNS TCP {self.client_address[0]} denied", flush=True) + return length_bytes = self._receive_exactly(2) if length_bytes is None: return @@ -248,7 +272,8 @@ if __name__ == "__main__": print( f"PS5 guide gateway: {TARGET_DOMAIN} -> {GATEWAY_IP}; redirect -> {REDIRECT_URL}; " - f"forward {','.join(sorted(FORWARDED_DOMAINS))} -> {UPSTREAM_DNS}", + f"forward {','.join(sorted(FORWARDED_DOMAINS))} -> {UPSTREAM_DNS}; " + f"clients {','.join(str(network) for network in ALLOWED_CLIENTS) or 'any'}", flush=True, ) diff --git a/docs/HANDOFF.md b/docs/HANDOFF.md index bb9ac72..931f84b 100644 --- a/docs/HANDOFF.md +++ b/docs/HANDOFF.md @@ -163,10 +163,12 @@ successful smoke test; user selection is separate from evidence. ## PS5 and DNS state -The PS5 now uses the static address: +Two authorized consoles now use static addresses on the console VLAN +`192.168.40.0/28`: ```text -192.168.40.14 +PS5PRO 192.168.40.14 +PS5FAT 192.168.40.13 ``` The local HTTP endpoint is available and verified at: @@ -191,6 +193,14 @@ Library and BlackBox while continuing to block PSN and update resolution. The PS sends DNS only to `net-utils01`; that host must be allowed to reach the configured upstream resolver on UDP/TCP 53. +The gateway additionally restricts which source clients it answers. `ALLOWED_CLIENTS` +defaults to the console VLAN `192.168.40.0/28`; queries from any other source address +are dropped and logged as `denied`, on both UDP and TCP. The value accepts a +comma-separated mix of individual addresses and CIDR ranges, and an empty value +disables the filter. This keeps the service dedicated to the two authorized consoles +and prevents other LAN hosts from using it as an open resolver for the allowlisted +names. + The Payload Manager review used upstream commit `e4e72dc9d831dd09ee8fabc222ad1e7f5139050e` and the official catalog current on 2026-10-07. Its fixed catalog URL uses `itsplk.github.io`; all 25 catalog download @@ -218,8 +228,10 @@ Vikingfile and their download infrastructure are intentionally excluded: they se third-party game files, many catalog entries have no SHA-256, and those hosts are not required for catalog browsing or BlackBox updates. The PS5 was previously identified as `192.168.10.26`; requests from -`192.168.10.6` seen at that time were from a different client. Those addresses -are historical and must not be used as the current payload destination. +`192.168.10.6` seen at that time were from the operator's own workstation, not a +console, before the consoles were moved onto VLAN 40. All `192.168.10.0/24` +addresses are historical and must not be used as the current payload destination; +with `ALLOWED_CLIENTS` set to `192.168.40.0/28` they can no longer query the gateway. The PS5 ELF loader listens on TCP port `9021` after a successful exploit run. On 2026-10-01, a connection-only probe from `net-utils01` to diff --git a/docs/PS5_SETUP.md b/docs/PS5_SETUP.md index 94057d6..e6ba7e2 100644 --- a/docs/PS5_SETUP.md +++ b/docs/PS5_SETUP.md @@ -20,7 +20,8 @@ Na rede onde este projeto foi inicialmente instalado: - porta publicada: `8000`. - DNS local: `192.168.20.30:53` (UDP e TCP); - gateway do Guia: `192.168.20.30:80` e `192.168.20.30:443`. -- IP estático atual da PS5: `192.168.40.14`. +- consolas autorizadas (VLAN `192.168.40.0/28`): PS5PRO `192.168.40.14`, + PS5FAT `192.168.40.13`. A porta 8080 do host já pertence ao UniFi e não deve ser reutilizada. @@ -146,6 +147,9 @@ O Compose inclui um DNS controlado no `net-utils01` que: Manager, Spectrum Library e BlackBox; - devolva `NXDOMAIN` para todos os restantes nomes, mantendo PSN, updates e telemetria bloqueados por DNS; +- responda apenas a clientes na VLAN das consolas (`192.168.40.0/28` por + defeito, via `ALLOWED_CLIENTS`), descartando consultas de qualquer outra + origem; - registe as consultas nos logs do container; - apresente um gateway HTTPS local e redirecione o browser para o exploit em `http://192.168.20.30:8000/`. @@ -173,6 +177,13 @@ não um hostname. A firewall deve permitir UDP e TCP `53` de `net-utils01` para resolvedor. A consola continua a precisar apenas de UDP/TCP `53` para `192.168.20.30`; não deve consultar diretamente um DNS público. +O gateway só responde a consultas DNS vindas das redes listadas em `ALLOWED_CLIENTS` +(por defeito `192.168.40.0/28`, a VLAN das consolas). O valor aceita uma lista +separada por vírgulas de endereços individuais e/ou intervalos CIDR — por exemplo, +`192.168.40.13,192.168.40.14` para trancar apenas às duas PS5 autorizadas (PS5FAT e +PS5PRO). Um valor vazio desativa o filtro e serve todos os clientes. Consultas de +origens não permitidas são descartadas e registadas como `denied`. + O acesso WAN da consola pode ficar limitado a TCP `443` para os domínios permitidos. Não são necessárias regras WAN de entrada. Se faltarem ícones, consultar os logs da firewall: um URL de ícone apontado pelo catálogo para outro domínio será