prosocks 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- prosocks-1.0.0/PKG-INFO +7 -0
- prosocks-1.0.0/prosocks.egg-info/PKG-INFO +7 -0
- prosocks-1.0.0/prosocks.egg-info/SOURCES.txt +8 -0
- prosocks-1.0.0/prosocks.egg-info/dependency_links.txt +1 -0
- prosocks-1.0.0/prosocks.egg-info/entry_points.txt +2 -0
- prosocks-1.0.0/prosocks.egg-info/requires.txt +1 -0
- prosocks-1.0.0/prosocks.egg-info/top_level.txt +1 -0
- prosocks-1.0.0/prosocks.py +252 -0
- prosocks-1.0.0/setup.cfg +4 -0
- prosocks-1.0.0/setup.py +14 -0
prosocks-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
requests
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
prosocks
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
"""ProSocks - Simple SOCKS5 Proxy Agent"""
|
|
2
|
+
|
|
3
|
+
import socket
|
|
4
|
+
import threading
|
|
5
|
+
import uuid
|
|
6
|
+
import secrets
|
|
7
|
+
import requests
|
|
8
|
+
import logging
|
|
9
|
+
import json
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(message)s')
|
|
13
|
+
logger = logging.getLogger('prosocks')
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class SOCKS5Proxy:
|
|
17
|
+
"""Minimal SOCKS5 proxy server"""
|
|
18
|
+
|
|
19
|
+
def __init__(self, host='127.0.0.1', port=9050):
|
|
20
|
+
self.host = host
|
|
21
|
+
self.port = port
|
|
22
|
+
self.running = False
|
|
23
|
+
self.server = None
|
|
24
|
+
self.thread = None
|
|
25
|
+
|
|
26
|
+
def start(self):
|
|
27
|
+
"""Start SOCKS5 server"""
|
|
28
|
+
try:
|
|
29
|
+
self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
30
|
+
self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
|
31
|
+
self.server.bind((self.host, self.port))
|
|
32
|
+
self.server.listen(5)
|
|
33
|
+
self.running = True
|
|
34
|
+
|
|
35
|
+
self.thread = threading.Thread(target=self._accept, daemon=True)
|
|
36
|
+
self.thread.start()
|
|
37
|
+
|
|
38
|
+
logger.info(f'SOCKS5 Proxy started on {self.host}:{self.port}')
|
|
39
|
+
return True
|
|
40
|
+
except Exception as e:
|
|
41
|
+
logger.error(f'Failed to start proxy: {e}')
|
|
42
|
+
return False
|
|
43
|
+
|
|
44
|
+
def stop(self):
|
|
45
|
+
"""Stop SOCKS5 server"""
|
|
46
|
+
self.running = False
|
|
47
|
+
if self.server:
|
|
48
|
+
try:
|
|
49
|
+
self.server.close()
|
|
50
|
+
except:
|
|
51
|
+
pass
|
|
52
|
+
logger.info('SOCKS5 Proxy stopped')
|
|
53
|
+
|
|
54
|
+
def _accept(self):
|
|
55
|
+
"""Accept SOCKS5 connections"""
|
|
56
|
+
while self.running:
|
|
57
|
+
try:
|
|
58
|
+
client, addr = self.server.accept()
|
|
59
|
+
threading.Thread(target=self._handle, args=(client, addr), daemon=True).start()
|
|
60
|
+
except:
|
|
61
|
+
if self.running:
|
|
62
|
+
continue
|
|
63
|
+
break
|
|
64
|
+
|
|
65
|
+
def _handle(self, client, addr):
|
|
66
|
+
"""Handle SOCKS5 client"""
|
|
67
|
+
try:
|
|
68
|
+
# Version check
|
|
69
|
+
ver = client.recv(1)[0]
|
|
70
|
+
if ver != 5:
|
|
71
|
+
client.close()
|
|
72
|
+
return
|
|
73
|
+
|
|
74
|
+
# Auth methods
|
|
75
|
+
nmeth = client.recv(1)[0]
|
|
76
|
+
methods = client.recv(nmeth)
|
|
77
|
+
client.send(bytes([5, 0])) # No auth
|
|
78
|
+
|
|
79
|
+
# Request
|
|
80
|
+
req = client.recv(4)
|
|
81
|
+
if len(req) < 4:
|
|
82
|
+
client.close()
|
|
83
|
+
return
|
|
84
|
+
|
|
85
|
+
ver, cmd, _, atyp = req[0], req[1], req[2], req[3]
|
|
86
|
+
|
|
87
|
+
# Parse address
|
|
88
|
+
if atyp == 1: # IPv4
|
|
89
|
+
addr_data = client.recv(4)
|
|
90
|
+
port_data = client.recv(2)
|
|
91
|
+
target = ".".join(map(str, addr_data))
|
|
92
|
+
port = int.from_bytes(port_data, 'big')
|
|
93
|
+
elif atyp == 3: # Domain
|
|
94
|
+
alen = client.recv(1)[0]
|
|
95
|
+
target = client.recv(alen).decode()
|
|
96
|
+
port_data = client.recv(2)
|
|
97
|
+
port = int.from_bytes(port_data, 'big')
|
|
98
|
+
else:
|
|
99
|
+
client.close()
|
|
100
|
+
return
|
|
101
|
+
|
|
102
|
+
# Connect to target
|
|
103
|
+
try:
|
|
104
|
+
dest = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
105
|
+
dest.connect((target, port))
|
|
106
|
+
client.send(bytes([5, 0, 0, 1, 0, 0, 0, 0, 0, 0]))
|
|
107
|
+
|
|
108
|
+
# Relay
|
|
109
|
+
threading.Thread(target=self._relay, args=(client, dest), daemon=True).start()
|
|
110
|
+
self._relay(dest, client)
|
|
111
|
+
except:
|
|
112
|
+
client.send(bytes([5, 5, 0, 1, 0, 0, 0, 0, 0, 0]))
|
|
113
|
+
client.close()
|
|
114
|
+
except:
|
|
115
|
+
pass
|
|
116
|
+
|
|
117
|
+
def _relay(self, src, dst):
|
|
118
|
+
"""Relay data between sockets"""
|
|
119
|
+
try:
|
|
120
|
+
while self.running:
|
|
121
|
+
data = src.recv(4096)
|
|
122
|
+
if not data:
|
|
123
|
+
break
|
|
124
|
+
dst.send(data)
|
|
125
|
+
except:
|
|
126
|
+
pass
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
class ProSocksAgent:
|
|
130
|
+
"""ProSocks Agent - Registers with panel and creates proxy"""
|
|
131
|
+
|
|
132
|
+
def __init__(self, panel_url, name='prosocks'):
|
|
133
|
+
self.agent_id = str(uuid.uuid4())
|
|
134
|
+
self.agent_name = name
|
|
135
|
+
self.panel_url = panel_url.rstrip('/')
|
|
136
|
+
self.password = secrets.token_hex(8)
|
|
137
|
+
self.proxy_port = 9050
|
|
138
|
+
self.proxy = None
|
|
139
|
+
self.running = False
|
|
140
|
+
|
|
141
|
+
self.config_dir = Path.home() / '.prosocks'
|
|
142
|
+
self.config_dir.mkdir(exist_ok=True)
|
|
143
|
+
self.config_file = self.config_dir / 'agent.json'
|
|
144
|
+
|
|
145
|
+
def register(self):
|
|
146
|
+
"""Register with panel"""
|
|
147
|
+
try:
|
|
148
|
+
data = {
|
|
149
|
+
'agent_id': self.agent_id,
|
|
150
|
+
'agent_name': self.agent_name,
|
|
151
|
+
'proxy_port': self.proxy_port,
|
|
152
|
+
'password': self.password,
|
|
153
|
+
'status': 'active'
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
resp = requests.post(
|
|
157
|
+
f'{self.panel_url}/api/register',
|
|
158
|
+
json=data,
|
|
159
|
+
timeout=5
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
if resp.status_code == 200:
|
|
163
|
+
logger.info(f'Registered with panel: {self.panel_url}')
|
|
164
|
+
self._save_config()
|
|
165
|
+
return True
|
|
166
|
+
except Exception as e:
|
|
167
|
+
logger.warning(f'Registration failed: {e}')
|
|
168
|
+
|
|
169
|
+
return False
|
|
170
|
+
|
|
171
|
+
def _save_config(self):
|
|
172
|
+
"""Save agent config"""
|
|
173
|
+
config = {
|
|
174
|
+
'agent_id': self.agent_id,
|
|
175
|
+
'agent_name': self.agent_name,
|
|
176
|
+
'panel_url': self.panel_url,
|
|
177
|
+
'proxy_port': self.proxy_port,
|
|
178
|
+
'password': self.password
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
with open(self.config_file, 'w') as f:
|
|
182
|
+
json.dump(config, f, indent=2)
|
|
183
|
+
|
|
184
|
+
def start(self):
|
|
185
|
+
"""Start agent and proxy"""
|
|
186
|
+
logger.info(f'Starting ProSocks Agent: {self.agent_id}')
|
|
187
|
+
|
|
188
|
+
# Register with panel
|
|
189
|
+
self.register()
|
|
190
|
+
|
|
191
|
+
# Start proxy
|
|
192
|
+
self.proxy = SOCKS5Proxy('127.0.0.1', self.proxy_port)
|
|
193
|
+
if self.proxy.start():
|
|
194
|
+
self.running = True
|
|
195
|
+
logger.info(f'ProSocks ready! Proxy: 127.0.0.1:{self.proxy_port} Password: {self.password}')
|
|
196
|
+
return True
|
|
197
|
+
|
|
198
|
+
return False
|
|
199
|
+
|
|
200
|
+
def stop(self):
|
|
201
|
+
"""Stop agent"""
|
|
202
|
+
logger.info('Stopping ProSocks Agent')
|
|
203
|
+
if self.proxy:
|
|
204
|
+
self.proxy.stop()
|
|
205
|
+
self.running = False
|
|
206
|
+
|
|
207
|
+
# Clean config
|
|
208
|
+
try:
|
|
209
|
+
self.config_file.unlink(missing_ok=True)
|
|
210
|
+
except:
|
|
211
|
+
pass
|
|
212
|
+
|
|
213
|
+
def get_info(self):
|
|
214
|
+
"""Get agent info"""
|
|
215
|
+
return {
|
|
216
|
+
'agent_id': self.agent_id,
|
|
217
|
+
'agent_name': self.agent_name,
|
|
218
|
+
'proxy_port': self.proxy_port,
|
|
219
|
+
'password': self.password,
|
|
220
|
+
'running': self.running
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def main():
|
|
225
|
+
"""CLI interface"""
|
|
226
|
+
import sys
|
|
227
|
+
|
|
228
|
+
if len(sys.argv) < 2:
|
|
229
|
+
print('Usage: python prosocks.py <panel_url> [agent_name]')
|
|
230
|
+
print('Example: python prosocks.py https://kalnetz.store my-agent')
|
|
231
|
+
sys.exit(1)
|
|
232
|
+
|
|
233
|
+
panel_url = sys.argv[1]
|
|
234
|
+
agent_name = sys.argv[2] if len(sys.argv) > 2 else 'prosocks'
|
|
235
|
+
|
|
236
|
+
agent = ProSocksAgent(panel_url, agent_name)
|
|
237
|
+
|
|
238
|
+
if agent.start():
|
|
239
|
+
try:
|
|
240
|
+
import time
|
|
241
|
+
while True:
|
|
242
|
+
time.sleep(1)
|
|
243
|
+
except KeyboardInterrupt:
|
|
244
|
+
print('\nStopping...')
|
|
245
|
+
agent.stop()
|
|
246
|
+
else:
|
|
247
|
+
print('Failed to start agent')
|
|
248
|
+
sys.exit(1)
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
if __name__ == '__main__':
|
|
252
|
+
main()
|
prosocks-1.0.0/setup.cfg
ADDED
prosocks-1.0.0/setup.py
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from setuptools import setup
|
|
2
|
+
|
|
3
|
+
setup(
|
|
4
|
+
name='prosocks',
|
|
5
|
+
version='1.0.0',
|
|
6
|
+
description='SOCKS5 Proxy Agent',
|
|
7
|
+
py_modules=['prosocks'],
|
|
8
|
+
install_requires=['requests'],
|
|
9
|
+
entry_points={
|
|
10
|
+
'console_scripts': [
|
|
11
|
+
'prosocks=prosocks:main',
|
|
12
|
+
],
|
|
13
|
+
},
|
|
14
|
+
)
|