ops: verify AnyTLS relay and allow validated certificate chains
This commit is contained in:
parent
c6febc2c02
commit
dbe730cdc4
@ -27,6 +27,9 @@ http {
|
|||||||
ssl_certificate /etc/nginx/ssl/cert.pem;
|
ssl_certificate /etc/nginx/ssl/cert.pem;
|
||||||
ssl_certificate_key /etc/nginx/ssl/key.pem;
|
ssl_certificate_key /etc/nginx/ssl/key.pem;
|
||||||
ssl_protocols TLSv1.2 TLSv1.3;
|
ssl_protocols TLSv1.2 TLSv1.3;
|
||||||
|
proxy_ssl_verify on;
|
||||||
|
proxy_ssl_verify_depth 3;
|
||||||
|
proxy_ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt;
|
||||||
include /etc/nginx/subscribe/blacklist.conf;
|
include /etc/nginx/subscribe/blacklist.conf;
|
||||||
include /etc/nginx/subscribe/protect.conf;
|
include /etc/nginx/subscribe/protect.conf;
|
||||||
location / { return 404; }
|
location / { return 404; }
|
||||||
|
|||||||
@ -17,6 +17,7 @@ location ^~ /api/v1/client/subscribe {
|
|||||||
proxy_ssl_server_name on;
|
proxy_ssl_server_name on;
|
||||||
proxy_ssl_name ${V2B_HOST};
|
proxy_ssl_name ${V2B_HOST};
|
||||||
proxy_ssl_verify on;
|
proxy_ssl_verify on;
|
||||||
|
proxy_ssl_verify_depth 3;
|
||||||
proxy_ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt;
|
proxy_ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt;
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
proxy_connect_timeout 10s;
|
proxy_connect_timeout 10s;
|
||||||
|
|||||||
@ -6,6 +6,7 @@ proxy_http_version 1.1;
|
|||||||
proxy_ssl_server_name on;
|
proxy_ssl_server_name on;
|
||||||
proxy_ssl_name c2.deeplink-subscribe.com;
|
proxy_ssl_name c2.deeplink-subscribe.com;
|
||||||
proxy_ssl_verify on;
|
proxy_ssl_verify on;
|
||||||
|
proxy_ssl_verify_depth 3;
|
||||||
proxy_ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt;
|
proxy_ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt;
|
||||||
proxy_connect_timeout 10s;
|
proxy_connect_timeout 10s;
|
||||||
proxy_read_timeout 60s;
|
proxy_read_timeout 60s;
|
||||||
|
|||||||
55
verify-node.py
Normal file
55
verify-node.py
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Run an isolated SOCKS client with strict TLS; never print QA credentials."""
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import pathlib
|
||||||
|
import socket
|
||||||
|
import subprocess
|
||||||
|
import tempfile
|
||||||
|
import time
|
||||||
|
|
||||||
|
p = argparse.ArgumentParser()
|
||||||
|
p.add_argument('--qa', required=True)
|
||||||
|
p.add_argument('--binary', required=True)
|
||||||
|
p.add_argument('--expected-exit', required=True)
|
||||||
|
p.add_argument('--port', type=int, default=19080)
|
||||||
|
a = p.parse_args()
|
||||||
|
q = json.loads(pathlib.Path(a.qa).read_text())
|
||||||
|
c = {'log': {'level': 'error'}, 'dns': {'servers': [{'type': 'local', 'tag': 'local'}]},
|
||||||
|
'inbounds': [{'type': 'mixed', 'listen': '127.0.0.1', 'listen_port': a.port}],
|
||||||
|
'outbounds': [{'type': 'anytls', 'tag': 'qa', 'server': q['host'], 'server_port': q['port'],
|
||||||
|
'password': q['uuid'], 'tls': {'enabled': True, 'server_name': q['sni'], 'insecure': False}}],
|
||||||
|
'route': {'default_domain_resolver': 'local', 'final': 'qa'}}
|
||||||
|
os.umask(0o077)
|
||||||
|
with tempfile.TemporaryDirectory(prefix='dpl-client-') as d:
|
||||||
|
config = pathlib.Path(d) / 'client.json'
|
||||||
|
config.write_text(json.dumps(c))
|
||||||
|
env = dict(os.environ, GOMEMLIMIT='64MiB', GOGC='75')
|
||||||
|
with (pathlib.Path(d) / 'client.log').open('wb') as log:
|
||||||
|
proc = subprocess.Popen([a.binary, 'run', '-c', str(config)], env=env, stdout=log, stderr=log)
|
||||||
|
try:
|
||||||
|
for _ in range(50):
|
||||||
|
assert proc.poll() is None, 'Client exited during startup'
|
||||||
|
try:
|
||||||
|
with socket.create_connection(('127.0.0.1', a.port), 0.1):
|
||||||
|
break
|
||||||
|
except OSError:
|
||||||
|
time.sleep(0.1)
|
||||||
|
command = ['curl', '-q', '--fail', '--silent', '--show-error', '--max-time', '30',
|
||||||
|
'--socks5-hostname', f'127.0.0.1:{a.port}']
|
||||||
|
result = subprocess.run(command + ['https://api.ipify.org'], capture_output=True, text=True, check=True)
|
||||||
|
ip = result.stdout.strip()
|
||||||
|
assert ip == a.expected_exit, 'Unexpected exit IP'
|
||||||
|
result = subprocess.run(command + ['https://www.cloudflare.com/cdn-cgi/trace'], capture_output=True, text=True, check=True)
|
||||||
|
trace = dict(line.split('=', 1) for line in result.stdout.splitlines() if '=' in line)
|
||||||
|
assert trace.get('ip') == a.expected_exit, 'Second exit check mismatch'
|
||||||
|
print(json.dumps({'anytls': True, 'relay': q['host'], 'port': q['port'], 'strict_tls': True,
|
||||||
|
'exit_ip': ip, 'country': trace.get('loc'), 'https_tls': trace.get('tls')}, ensure_ascii=False))
|
||||||
|
finally:
|
||||||
|
proc.terminate()
|
||||||
|
try:
|
||||||
|
proc.wait(timeout=5)
|
||||||
|
except subprocess.TimeoutExpired:
|
||||||
|
proc.kill()
|
||||||
|
proc.wait()
|
||||||
Loading…
Reference in New Issue
Block a user