#!/usr/bin/env python3 """Локальный HTTP-форвардер для прокси с аутентификацией. Нужен когда инструмент (DrissionPage, etc.) не поддерживает user:pass в прокси. Принимает CONNECT/GET на 127.0.0.1:LOCAL_PORT, добавляет Proxy-Authorization: Basic, форвардит на UPSTREAM. Использование: 1. Заменить UPSTREAM_HOST, UPSTREAM_PORT, PROXY_USER, PROXY_PASS 2. Запустить: python proxy_forwarder.py 3. В конфиге браузера указать: http://127.0.0.1:9128 """ import http.server import urllib.request import base64 import socket import select UPSTREAM_HOST = 'residential-x.bpproxy.at' UPSTREAM_PORT = 1000 PROXY_USER = b'bpuser-XXX' PROXY_PASS = b'PASS_hardsession-YYY' LOCAL_PORT = 9128 UPSTREAM = f'{UPSTREAM_HOST}:{UPSTREAM_PORT}' AUTH = base64.b64encode(PROXY_USER + b':' + PROXY_PASS).decode() class Proxy(http.server.BaseHTTPRequestHandler): timeout = 30 def do_GET(self): self._forward('GET') def do_POST(self): self._forward('POST') def do_HEAD(self): self._forward('HEAD') def do_PUT(self): self._forward('PUT') def _forward(self, method): try: url = self.path req = urllib.request.Request(url, method=method) req.add_header('Proxy-Authorization', f'Basic {AUTH}') for h, v in self.headers.items(): if h.lower() not in ('host', 'proxy-connection', 'proxy-authorization'): req.add_header(h, v) if method in ('POST', 'PUT'): body = self.rfile.read(int(self.headers.get('Content-Length', 0))) req.data = body req.set_proxy(UPSTREAM, 'http') resp = urllib.request.urlopen(req, timeout=30) self.send_response(resp.status) for h, v in resp.getheaders(): self.send_header(h, v) self.end_headers() self.wfile.write(resp.read()) except Exception as e: self.send_error(502, str(e)) def do_CONNECT(self): host, port = self.path.split(':') port = int(port) try: remote = socket.create_connection( (UPSTREAM_HOST, UPSTREAM_PORT), timeout=10 ) connect_req = ( f'CONNECT {host}:{port} HTTP/1.1\r\n' f'Host: {host}:{port}\r\n' f'Proxy-Authorization: Basic {AUTH}\r\n\r\n' ) remote.send(connect_req.encode()) resp = b'' while b'\r\n\r\n' not in resp: resp += remote.recv(4096) if b'200' not in resp.split(b'\r\n')[0]: self.send_error(502, 'CONNECT failed') remote.close() return self.send_response(200, 'Connection Established') self.end_headers() self.connection.settimeout(30) remote.settimeout(30) socks = [self.connection, remote] while True: r, _, _ = select.select(socks, [], [], 30) if not r: break for s in r: try: d = s.recv(8192) if not d: return dst = remote if s is self.connection else self.connection dst.sendall(d) except Exception: return except Exception as e: self.send_error(502, str(e)) if __name__ == '__main__': print(f'[*] Proxy Forwarder: 127.0.0.1:{LOCAL_PORT} -> {UPSTREAM}', flush=True) httpd = http.server.HTTPServer(('127.0.0.1', LOCAL_PORT), Proxy) httpd.serve_forever()