deadshadow

proofs

tl;dr

traffic to deadshadow passes through an offshore gre tunnel before reaching our server. the gre endpoint forwards requests without preserving the original public source ip: nginx sees only an internal tunnel address (10.10.10.x) as $remote_addr. nginx then rewrites x-forwarded-for to 0.0.0.0 before passing to synapse. the verification below uses a nonce to confirm both layers are working and that your real ip does not appear at either point in the chain.


verification
commands
$ # 1 — note your real public ip
YOUR_IP="$(curl -s https://ifconfig.me)"
echo "your ip: $YOUR_IP"
$ # 2 — create a nonce
NONCE="$(openssl rand -hex 16)"
$ # 3 — what nginx receives
curl -sS \
  -H "X-Proof-Nonce: $NONCE" \
  https://deadshadow.org/proof/raw
$ # 4 — what synapse receives
curl -sS \
  -H "X-Proof-Nonce: $NONCE" \
  https://deadshadow.org/proof/upstream
step 3 — expected

remote_addr_nginx is 10.10.10.x — the internal gre tunnel address. your real ip does not appear anywhere in this response. your nonce appears in incoming_x_proof_nonce, confirming this is a live response and not cached output.

step 4 — expected

headers.X-Forwarded-For is 0.0.0.0. your nonce still appears in headers.X-Proof-Nonce, confirming your real ip does not appear at the upstream either.

what this proves
  • layer 1: the gre tunnel removes the public source ip before nginx
  • layer 2: nginx removes the tunnel address before synapse
  • the nonce prevents pre-computed or cached responses
  • the upstream is a separate service from nginx, acting as independent witness

nginx implementation

add these blocks inside your tls server { }. /proof/raw returns what nginx directly received. /proof/upstream forwards to the local echo service with x-forwarded-for forced to 0.0.0.0.

# /proof/raw — what NGINX receives from the GRE tunnel
location = /proof/raw {
    default_type application/json;
    add_header Cache-Control "no-store" always;
    return 200
'{
  "remote_addr_nginx": "$remote_addr",
  "incoming_x_forwarded_for": "$http_x_forwarded_for",
  "incoming_x_proof_nonce": "$http_x_proof_nonce",
  "host": "$host",
  "scheme": "$scheme"
}';
}

# /proof/upstream — what a separate upstream app receives
location = /proof/upstream {
    proxy_pass http://127.0.0.1:18010/;
    proxy_set_header X-Forwarded-For 0.0.0.0;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header Host $host;
}
reload
sudo nginx -t && sudo systemctl reload nginx

upstream echo service

bound to 127.0.0.1:18010. returns received headers as json. logging is disabled. operates independently from nginx.

# /opt/deadshadow/proof-echo.py
#!/usr/bin/env python3
from http.server import BaseHTTPRequestHandler, HTTPServer
import json

class Handler(BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path != "/":
            self.send_response(404); self.end_headers(); return
        payload = {
            "client_addr_seen_by_app": self.client_address[0],
            "method": self.command,
            "path": self.path,
            "headers": {k: v for k, v in self.headers.items()},
        }
        body = (json.dumps(payload, indent=2, sort_keys=True) + "\n").encode()
        self.send_response(200)
        self.send_header("Content-Type", "application/json")
        self.send_header("Cache-Control", "no-store")
        self.send_header("Content-Length", str(len(body)))
        self.end_headers()
        self.wfile.write(body)

    def log_message(self, format, *args):
        return

HTTPServer(("127.0.0.1", 18010), Handler).serve_forever()
# /etc/systemd/system/deadshadow-proof-echo.service
[Unit]
Description=Deadshadow proof echo upstream
After=network.target

[Service]
ExecStart=/usr/bin/python3 /opt/deadshadow/proof-echo.py
User=nobody
Group=nogroup
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
Restart=always
RestartSec=2

[Install]
WantedBy=multi-user.target
enable
sudo systemctl daemon-reload
sudo systemctl enable --now deadshadow-proof-echo

scope