-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathproxy_server.py
More file actions
233 lines (191 loc) · 7.87 KB
/
proxy_server.py
File metadata and controls
233 lines (191 loc) · 7.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
#!/usr/bin/env python3
"""
Simple SOCKS5 Proxy Server for Windows
Run this on your UK VPS to bypass Polymarket geo-restrictions.
"""
import asyncio
import socket
import struct
import secrets
import string
import subprocess
import sys
import os
# Configuration
PORT = 1080
USERNAME = "polymarket"
PASSWORD = None # Will be generated if None
def get_external_ip():
"""Get the external IP address of this machine."""
try:
import urllib.request
return urllib.request.urlopen('https://api.ipify.org', timeout=5).read().decode('utf-8')
except:
try:
return urllib.request.urlopen('https://ifconfig.me/ip', timeout=5).read().decode('utf-8')
except:
return "UNKNOWN (check manually)"
def generate_password(length=16):
"""Generate a secure random password."""
alphabet = string.ascii_letters + string.digits
return ''.join(secrets.choice(alphabet) for _ in range(length))
def open_firewall_port(port):
"""Open the specified port in Windows Firewall."""
try:
subprocess.run([
'netsh', 'advfirewall', 'firewall', 'add', 'rule',
'name=SOCKS5 Proxy Server',
'dir=in',
'action=allow',
'protocol=TCP',
f'localport={port}'
], capture_output=True, check=True)
print(f"[+] Firewall rule added for port {port}")
return True
except subprocess.CalledProcessError:
print(f"[!] Could not add firewall rule. Run as Administrator or add manually.")
return False
except FileNotFoundError:
print(f"[!] netsh not found (not Windows?). Add firewall rule manually.")
return False
class SOCKS5Server:
"""Simple SOCKS5 proxy server with username/password authentication."""
SOCKS_VERSION = 5
def __init__(self, username: str, password: str):
self.username = username.encode()
self.password = password.encode()
async def handle_client(self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter):
"""Handle a single client connection."""
addr = writer.get_extra_info('peername')
try:
# Step 1: Greeting - client sends supported auth methods
header = await reader.readexactly(2)
version, nmethods = struct.unpack("!BB", header)
if version != self.SOCKS_VERSION:
writer.close()
return
methods = await reader.readexactly(nmethods)
# We require username/password auth (method 0x02)
if 0x02 not in methods:
writer.write(struct.pack("!BB", self.SOCKS_VERSION, 0xFF)) # No acceptable methods
await writer.drain()
writer.close()
return
# Accept username/password auth
writer.write(struct.pack("!BB", self.SOCKS_VERSION, 0x02))
await writer.drain()
# Step 2: Username/Password authentication
auth_version = await reader.readexactly(1)
if auth_version != b'\x01':
writer.close()
return
ulen = struct.unpack("!B", await reader.readexactly(1))[0]
username = await reader.readexactly(ulen)
plen = struct.unpack("!B", await reader.readexactly(1))[0]
password = await reader.readexactly(plen)
if username != self.username or password != self.password:
writer.write(b'\x01\x01') # Auth failed
await writer.drain()
writer.close()
return
writer.write(b'\x01\x00') # Auth success
await writer.drain()
# Step 3: Connection request
header = await reader.readexactly(4)
version, cmd, _, atyp = struct.unpack("!BBBB", header)
if version != self.SOCKS_VERSION or cmd != 0x01: # Only CONNECT supported
writer.write(struct.pack("!BBBBIH", self.SOCKS_VERSION, 0x07, 0, 1, 0, 0))
await writer.drain()
writer.close()
return
# Parse destination address
if atyp == 0x01: # IPv4
dst_addr = socket.inet_ntoa(await reader.readexactly(4))
elif atyp == 0x03: # Domain name
domain_len = struct.unpack("!B", await reader.readexactly(1))[0]
dst_addr = (await reader.readexactly(domain_len)).decode()
elif atyp == 0x04: # IPv6
dst_addr = socket.inet_ntop(socket.AF_INET6, await reader.readexactly(16))
else:
writer.close()
return
dst_port = struct.unpack("!H", await reader.readexactly(2))[0]
# Step 4: Connect to destination
try:
remote_reader, remote_writer = await asyncio.wait_for(
asyncio.open_connection(dst_addr, dst_port),
timeout=10
)
except Exception as e:
# Connection failed
writer.write(struct.pack("!BBBBIH", self.SOCKS_VERSION, 0x05, 0, 1, 0, 0))
await writer.drain()
writer.close()
return
# Connection successful
bind_addr = remote_writer.get_extra_info('sockname')
bind_ip = socket.inet_aton(bind_addr[0]) if bind_addr else b'\x00\x00\x00\x00'
bind_port = bind_addr[1] if bind_addr else 0
writer.write(struct.pack("!BBBB", self.SOCKS_VERSION, 0x00, 0x00, 0x01) + bind_ip + struct.pack("!H", bind_port))
await writer.drain()
# Step 5: Relay data between client and destination
await self.relay(reader, writer, remote_reader, remote_writer)
except asyncio.IncompleteReadError:
pass
except Exception as e:
pass
finally:
writer.close()
async def relay(self, client_reader, client_writer, remote_reader, remote_writer):
"""Relay data between client and remote server."""
async def forward(src, dst):
try:
while True:
data = await src.read(4096)
if not data:
break
dst.write(data)
await dst.drain()
except:
pass
finally:
dst.close()
await asyncio.gather(
forward(client_reader, remote_writer),
forward(remote_reader, client_writer)
)
async def start(self, host='0.0.0.0', port=1080):
"""Start the SOCKS5 server."""
server = await asyncio.start_server(self.handle_client, host, port)
async with server:
await server.serve_forever()
def main():
global PASSWORD
# Generate password if not set
if PASSWORD is None:
PASSWORD = generate_password()
# Get external IP
external_ip = get_external_ip()
# Open firewall port
open_firewall_port(PORT)
# Print connection info
print("\n" + "=" * 50)
print("SOCKS5 PROXY SERVER RUNNING")
print("=" * 50)
print(f"External IP: {external_ip}")
print(f"Port: {PORT}")
print(f"Username: {USERNAME}")
print(f"Password: {PASSWORD}")
print()
print("Connection String (copy this):")
print(f"socks5://{USERNAME}:{PASSWORD}@{external_ip}:{PORT}")
print("=" * 50)
print("\nPress Ctrl+C to stop the server.\n")
# Start server
server = SOCKS5Server(USERNAME, PASSWORD)
try:
asyncio.run(server.start('0.0.0.0', PORT))
except KeyboardInterrupt:
print("\n[*] Server stopped.")
if __name__ == "__main__":
main()