Files

115 lines
3.6 KiB
Python

import socket, threading, select, base64, json, re, sys
"""TCP proxy forwarder for authenticated upstream proxies.
Usage: python tcp_forwarder.py [proxy_json_path] [local_port]
- proxy_json_path: JSON file with proxy pool (default: C:/Users/User/tmp/bpproxy_live.json)
- local_port: local port to listen on (default: 9129)
The script picks the FIRST proxy from the pool. Edit UPSTREAM_HOST/UPSTREAM_PORT/AUTH
directly if you want a specific proxy.
Why TCP instead of HTTP-based:
http.server.HTTPServer + BaseHTTPRequestHandler breaks CONNECT tunnels for Chrome.
Chrome gets chrome-error://chromewebdata/ while curl works fine.
Raw TCP relay handles CONNECT properly.
"""
# --- CONFIG ---
DEFAULT_PROXY_POOL = r"C:\Users\User\tmp\bpproxy_live.json"
LOCAL_PORT = int(sys.argv[2]) if len(sys.argv) > 2 else 9129
# Load proxy from pool
pool_path = sys.argv[1] if len(sys.argv) > 1 else DEFAULT_PROXY_POOL
pool = json.loads(open(pool_path).read())
proxy = pool[0]['url'] if isinstance(pool[0], dict) else pool[0]
match = re.match(r'http://([^:]+):([^@]+)@([^:]+):(\d+)', proxy)
user, password, host, port = match.groups()
UPSTREAM_HOST = host
UPSTREAM_PORT = int(port)
AUTH = base64.b64encode(f'{user}:{password}'.encode()).decode()
def handle_client(client_sock):
try:
data = b''
while b'\r\n\r\n' not in data:
chunk = client_sock.recv(4096)
if not chunk:
return
data += chunk
request = data.decode('latin-1', errors='replace')
first_line = request.split('\r\n')[0]
method, target, _ = first_line.split(' ', 2)
if method == 'CONNECT':
host, port_str = target.rsplit(':', 1)
port = int(port_str)
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]:
client_sock.send(b'HTTP/1.1 502 Bad Gateway\r\n\r\n')
remote.close()
return
client_sock.send(b'HTTP/1.1 200 Connection Established\r\n\r\n')
_relay(client_sock, remote)
else:
remote = socket.create_connection((UPSTREAM_HOST, UPSTREAM_PORT), timeout=10)
remote.send(data)
_relay(client_sock, remote)
except Exception:
pass
finally:
try:
client_sock.close()
except Exception:
pass
def _relay(a, b):
a.settimeout(30)
b.settimeout(30)
socks = [a, b]
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 = b if s is a else a
dst.sendall(d)
except Exception:
return
def main():
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind(('127.0.0.1', LOCAL_PORT))
server.listen(50)
print(f'[*] TCP Proxy: 127.0.0.1:{LOCAL_PORT} -> {UPSTREAM_HOST}:{UPSTREAM_PORT}', flush=True)
while True:
client, addr = server.accept()
t = threading.Thread(target=handle_client, args=(client,), daemon=True)
t.start()
if __name__ == '__main__':
main()