|
#!/usr/bin/env python3 |
|
"""Reverse proxy: plain HTTP locally -> TLS 1.1 to target device. |
|
Usage: python3 tls11_proxy.py <target-host:port> [local-port] |
|
""" |
|
import http.server, ssl, urllib.request, sys, warnings |
|
warnings.filterwarnings("ignore", category=DeprecationWarning) |
|
|
|
TARGET = sys.argv[1] if len(sys.argv) > 1 else "localhost:19443" |
|
PORT = int(sys.argv[2]) if len(sys.argv) > 2 else 8080 |
|
|
|
def make_ctx(): |
|
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) |
|
ctx.minimum_version = ssl.TLSVersion.TLSv1_1 |
|
ctx.maximum_version = ssl.TLSVersion.TLSv1_1 |
|
ctx.check_hostname = False |
|
ctx.verify_mode = ssl.CERT_NONE |
|
ctx.set_ciphers('DEFAULT:@SECLEVEL=0') |
|
return ctx |
|
|
|
class H(http.server.BaseHTTPRequestHandler): |
|
def do_GET(self): self._p("GET") |
|
def do_POST(self): self._p("POST") |
|
def do_PUT(self): self._p("PUT") |
|
def do_HEAD(self): self._p("HEAD") |
|
def do_DELETE(self): self._p("DELETE") |
|
def _p(self, m): |
|
url = f"https://{TARGET}{self.path}" |
|
body = None |
|
if m in ("POST","PUT"): |
|
body = self.rfile.read(int(self.headers.get("Content-Length",0))) or None |
|
req = urllib.request.Request(url, data=body, method=m) |
|
for k,v in self.headers.items(): |
|
if k.lower() not in ("host","connection"): req.add_header(k,v) |
|
try: |
|
r = urllib.request.urlopen(req, context=make_ctx(), timeout=10) |
|
self.send_response(r.status) |
|
for k,v in r.headers.items(): |
|
if k.lower() != "transfer-encoding": self.send_header(k,v) |
|
self.end_headers() |
|
self.wfile.write(r.read()) |
|
except Exception as e: |
|
self.send_response(502) |
|
self.end_headers() |
|
self.wfile.write(f"Proxy error: {e}".encode()) |
|
def log_message(self, fmt, *a): print(f"[proxy] {a[0]}") |
|
|
|
print(f"TLS 1.1 Proxy: http://localhost:{PORT} -> https://{TARGET}") |
|
http.server.HTTPServer(("127.0.0.1", PORT), H).serve_forever() |