dpl/verify-maps.py

86 lines
3.5 KiB
Python

#!/usr/bin/env python3
"""Exercise real Nginx mapping and Origin/Referer isolation using localhost only."""
import importlib.util
import pathlib
import shutil
import socket
import subprocess
import tempfile
import time
import urllib.request
spec = importlib.util.spec_from_file_location('render', pathlib.Path(__file__).with_name('render.py'))
render = importlib.util.module_from_spec(spec)
spec.loader.exec_module(render)
nginx = shutil.which('nginx')
if not nginx:
raise SystemExit('Nginx is required for this isolated integration check')
with tempfile.TemporaryDirectory(prefix='gateway-proxy-maps-') as folder:
root = pathlib.Path(folder)
with socket.socket() as sock:
sock.bind(('127.0.0.1', 0))
port = sock.getsockname()[1]
maps = render.render_white('https', '/unused')['00-gateway-admin-proxy-maps.conf']
config = root / 'nginx.conf'
config.write_text(f'''daemon off;
pid {root}/nginx.pid;
error_log {root}/error.log;
events {{ worker_connections 64; }}
http {{
access_log off;
{maps}
server {{
listen 127.0.0.1:{port};
location / {{
return 200 "$gateway_admin_origin_host|$gateway_admin_origin|$gateway_admin_referer";
}}
}}
}}
''')
subprocess.run([nginx, '-t', '-c', str(config), '-p', folder], check=True,
capture_output=True, text=True)
process = subprocess.Popen([nginx, '-c', str(config), '-p', folder],
stdout=subprocess.DEVNULL, stderr=subprocess.PIPE, text=True)
try:
for _ in range(40):
try:
with socket.create_connection(('127.0.0.1', port), timeout=.1):
break
except OSError:
if process.poll() is not None:
raise RuntimeError(process.stderr.read())
time.sleep(.05)
cases = [
('tomshell.online', 'gemcook.net'),
('getway-fuc.tomshell.online', 'getway-fuc.gemcook.net'),
('getway-dpl.tomshell.online', 'getway-dpl.gemcook.net'),
('nasa.tomshell.com.de', 'nasa.diaodu.us'),
('tomshell.com.de', 'diaodu.us'),
('dpl.tomtojapan.online', 'dp-link.net'),
('fuc.tomtojapan.online', 'xn--9kqy16h.com'),
('not-registered.example', ''),
('two.levels.tomshell.online', ''),
]
assertions = 0
for host, upstream in cases:
for origin in ['https://' + host, 'https://other.tomshell.online', 'https://outside.example']:
referer = origin + '/example?keep=1'
req = urllib.request.Request('http://127.0.0.1:' + str(port) + '/',
headers={'Host': host, 'Origin': origin, 'Referer': referer})
with urllib.request.urlopen(req, timeout=3) as response:
actual = response.read().decode().split('|')
assert actual[0] == upstream, (host, actual[0], upstream)
own = origin == 'https://' + host
assert actual[1] == ('https://' + upstream if own else origin), (host, origin, actual[1])
assert actual[2] == ('https://' + upstream + '/example?keep=1' if own else referer)
assertions += 3
print(f'PASS: {assertions} real-Nginx map/header checks; localhost fixture only, no origin requests')
finally:
process.terminate()
try:
process.wait(timeout=5)
except subprocess.TimeoutExpired:
process.kill()
process.wait()