unified: Phantom Protocol 2025 complete archive integration
This commit is contained in:
504
release/examples/socks5-proxy.py
Normal file
504
release/examples/socks5-proxy.py
Normal file
@@ -0,0 +1,504 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Phantom SOCKS5 Proxy Server
|
||||
Создает SOCKS5 прокси сервер, который маршрутизирует трафик через Phantom сеть
|
||||
|
||||
Использование:
|
||||
python3 socks5-proxy.py --port 8080 --hops 3
|
||||
|
||||
Автор: Phantom Protocol Team 2025
|
||||
"""
|
||||
|
||||
import socket
|
||||
import threading
|
||||
import struct
|
||||
import select
|
||||
import sys
|
||||
import argparse
|
||||
import time
|
||||
import logging
|
||||
from typing import Optional, Tuple, List
|
||||
|
||||
# Настройка логирования
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s - %(levelname)s - %(message)s'
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# SOCKS5 константы
|
||||
SOCKS5_VERSION = 0x05
|
||||
SOCKS5_CONNECT = 0x01
|
||||
SOCKS5_IPV4 = 0x01
|
||||
SOCKS5_DOMAIN = 0x03
|
||||
SOCKS5_IPV6 = 0x04
|
||||
|
||||
# Коды ответов SOCKS5
|
||||
SOCKS5_SUCCESS = 0x00
|
||||
SOCKS5_GENERAL_FAILURE = 0x01
|
||||
SOCKS5_CONNECTION_NOT_ALLOWED = 0x02
|
||||
SOCKS5_NETWORK_UNREACHABLE = 0x03
|
||||
SOCKS5_HOST_UNREACHABLE = 0x04
|
||||
SOCKS5_CONNECTION_REFUSED = 0x05
|
||||
SOCKS5_TTL_EXPIRED = 0x06
|
||||
SOCKS5_COMMAND_NOT_SUPPORTED = 0x07
|
||||
SOCKS5_ADDRESS_TYPE_NOT_SUPPORTED = 0x08
|
||||
|
||||
class PhantomRoute:
|
||||
"""Представляет маршрут через Phantom сеть"""
|
||||
|
||||
def __init__(self, hops: int = 3):
|
||||
self.hops = hops
|
||||
self.nodes: List[Tuple[str, int]] = []
|
||||
self.build_route()
|
||||
|
||||
def build_route(self):
|
||||
"""Построение маршрута через Phantom узлы"""
|
||||
# В реальной реализации здесь будет запрос к Kademlia DHT
|
||||
# Сейчас используем симуляцию
|
||||
|
||||
logger.info(f"Построение маршрута через {self.hops} хопов...")
|
||||
|
||||
# Симуляция поиска узлов в Phantom сети
|
||||
available_nodes = [
|
||||
("10.0.1.100", 8050),
|
||||
("10.0.1.101", 8050),
|
||||
("10.0.1.102", 8050),
|
||||
("10.0.1.103", 8050),
|
||||
("10.0.1.104", 8050),
|
||||
]
|
||||
|
||||
# Выбор случайных узлов для маршрута
|
||||
import random
|
||||
self.nodes = random.sample(available_nodes, min(self.hops, len(available_nodes)))
|
||||
|
||||
for i, (ip, port) in enumerate(self.nodes):
|
||||
logger.info(f" Хоп {i+1}: {ip}:{port}")
|
||||
|
||||
class PhantomConnection:
|
||||
"""Подключение через Phantom сеть"""
|
||||
|
||||
def __init__(self, route: PhantomRoute):
|
||||
self.route = route
|
||||
self.socket: Optional[socket.socket] = None
|
||||
self.connected = False
|
||||
|
||||
def connect(self, target_host: str, target_port: int) -> bool:
|
||||
"""Подключение к целевому хосту через Phantom сеть"""
|
||||
try:
|
||||
logger.info(f"Подключение к {target_host}:{target_port} через Phantom сеть")
|
||||
|
||||
# Подключение к первому узлу маршрута
|
||||
if not self.route.nodes:
|
||||
logger.error("Маршрут не построен")
|
||||
return False
|
||||
|
||||
first_hop = self.route.nodes[0]
|
||||
logger.info(f"Подключение к первому хопу: {first_hop[0]}:{first_hop[1]}")
|
||||
|
||||
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.socket.settimeout(10)
|
||||
|
||||
try:
|
||||
self.socket.connect(first_hop)
|
||||
except socket.error as e:
|
||||
logger.error(f"Не удалось подключиться к первому хопу: {e}")
|
||||
# Fallback: прямое подключение для демонстрации
|
||||
logger.info(f"Fallback: прямое подключение к {target_host}:{target_port}")
|
||||
self.socket.close()
|
||||
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.socket.settimeout(10)
|
||||
self.socket.connect((target_host, target_port))
|
||||
self.connected = True
|
||||
return True
|
||||
|
||||
# Отправка команды построения туннеля
|
||||
tunnel_command = self._build_tunnel_command(target_host, target_port)
|
||||
self.socket.send(tunnel_command.encode('utf-8'))
|
||||
|
||||
# Ожидание подтверждения
|
||||
response = self.socket.recv(1024).decode('utf-8')
|
||||
if response.startswith("PHANTOM_TUNNEL_OK"):
|
||||
logger.info("Туннель через Phantom сеть установлен")
|
||||
self.connected = True
|
||||
return True
|
||||
else:
|
||||
logger.error(f"Ошибка установки туннеля: {response}")
|
||||
# Fallback: прямое подключение
|
||||
logger.info(f"Fallback: прямое подключение к {target_host}:{target_port}")
|
||||
self.socket.close()
|
||||
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.socket.settimeout(10)
|
||||
self.socket.connect((target_host, target_port))
|
||||
self.connected = True
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка подключения: {e}")
|
||||
return False
|
||||
|
||||
def _build_tunnel_command(self, target_host: str, target_port: int) -> str:
|
||||
"""Построение команды для создания туннеля"""
|
||||
command = f"PHANTOM_BUILD_TUNNEL {target_host} {target_port}"
|
||||
|
||||
# Добавление промежуточных хопов
|
||||
for i in range(1, len(self.route.nodes)):
|
||||
hop = self.route.nodes[i]
|
||||
command += f" {hop[0]}:{hop[1]}"
|
||||
|
||||
return command + "\n"
|
||||
|
||||
def send(self, data: bytes) -> int:
|
||||
"""Отправка данных через Phantom соединение"""
|
||||
if not self.connected or not self.socket:
|
||||
raise ConnectionError("Соединение не установлено")
|
||||
return self.socket.send(data)
|
||||
|
||||
def recv(self, size: int) -> bytes:
|
||||
"""Получение данных через Phantom соединение"""
|
||||
if not self.connected or not self.socket:
|
||||
raise ConnectionError("Соединение не установлено")
|
||||
return self.socket.recv(size)
|
||||
|
||||
def close(self):
|
||||
"""Закрытие соединения"""
|
||||
if self.socket:
|
||||
self.socket.close()
|
||||
self.socket = None
|
||||
self.connected = False
|
||||
|
||||
class SOCKS5Handler:
|
||||
"""Обработчик SOCKS5 протокола"""
|
||||
|
||||
def __init__(self, client_socket: socket.socket, hops: int = 3):
|
||||
self.client_socket = client_socket
|
||||
self.hops = hops
|
||||
self.phantom_connection: Optional[PhantomConnection] = None
|
||||
|
||||
def handle(self):
|
||||
"""Основная обработка SOCKS5 соединения"""
|
||||
try:
|
||||
# Этап 1: Аутентификация
|
||||
if not self._handle_authentication():
|
||||
return
|
||||
|
||||
# Этап 2: Обработка запроса подключения
|
||||
if not self._handle_connection_request():
|
||||
return
|
||||
|
||||
# Этап 3: Проксирование данных
|
||||
self._relay_data()
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка обработки SOCKS5: {e}")
|
||||
finally:
|
||||
self._cleanup()
|
||||
|
||||
def _handle_authentication(self) -> bool:
|
||||
"""Обработка этапа аутентификации SOCKS5"""
|
||||
try:
|
||||
# Получение запроса аутентификации
|
||||
data = self.client_socket.recv(256)
|
||||
if len(data) < 2:
|
||||
return False
|
||||
|
||||
version, nmethods = struct.unpack('!BB', data[:2])
|
||||
|
||||
if version != SOCKS5_VERSION:
|
||||
logger.error(f"Неподдерживаемая версия SOCKS: {version}")
|
||||
return False
|
||||
|
||||
if len(data) < 2 + nmethods:
|
||||
return False
|
||||
|
||||
methods = struct.unpack('!' + 'B' * nmethods, data[2:2+nmethods])
|
||||
|
||||
# Поддерживаем только "без аутентификации" (метод 0)
|
||||
if 0 in methods:
|
||||
# Отправка ответа: версия + выбранный метод
|
||||
response = struct.pack('!BB', SOCKS5_VERSION, 0)
|
||||
self.client_socket.send(response)
|
||||
logger.debug("Аутентификация SOCKS5 пройдена")
|
||||
return True
|
||||
else:
|
||||
# Нет поддерживаемых методов
|
||||
response = struct.pack('!BB', SOCKS5_VERSION, 0xFF)
|
||||
self.client_socket.send(response)
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка аутентификации SOCKS5: {e}")
|
||||
return False
|
||||
|
||||
def _handle_connection_request(self) -> bool:
|
||||
"""Обработка запроса подключения SOCKS5"""
|
||||
try:
|
||||
# Получение запроса подключения
|
||||
data = self.client_socket.recv(4)
|
||||
if len(data) < 4:
|
||||
return False
|
||||
|
||||
version, cmd, reserved, address_type = struct.unpack('!BBBB', data)
|
||||
|
||||
if version != SOCKS5_VERSION:
|
||||
self._send_error_response(SOCKS5_GENERAL_FAILURE)
|
||||
return False
|
||||
|
||||
if cmd != SOCKS5_CONNECT:
|
||||
self._send_error_response(SOCKS5_COMMAND_NOT_SUPPORTED)
|
||||
return False
|
||||
|
||||
# Получение адреса назначения
|
||||
target_host, target_port = self._parse_target_address(address_type)
|
||||
if not target_host:
|
||||
self._send_error_response(SOCKS5_ADDRESS_TYPE_NOT_SUPPORTED)
|
||||
return False
|
||||
|
||||
logger.info(f"SOCKS5 запрос подключения к {target_host}:{target_port}")
|
||||
|
||||
# Подключение через Phantom сеть
|
||||
route = PhantomRoute(self.hops)
|
||||
self.phantom_connection = PhantomConnection(route)
|
||||
|
||||
if self.phantom_connection.connect(target_host, target_port):
|
||||
# Отправка успешного ответа
|
||||
self._send_success_response()
|
||||
logger.info(f"SOCKS5 туннель к {target_host}:{target_port} установлен")
|
||||
return True
|
||||
else:
|
||||
self._send_error_response(SOCKS5_HOST_UNREACHABLE)
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка обработки запроса подключения: {e}")
|
||||
self._send_error_response(SOCKS5_GENERAL_FAILURE)
|
||||
return False
|
||||
|
||||
def _parse_target_address(self, address_type: int) -> Tuple[Optional[str], Optional[int]]:
|
||||
"""Парсинг адреса назначения"""
|
||||
try:
|
||||
if address_type == SOCKS5_IPV4:
|
||||
# IPv4 адрес (4 байта) + порт (2 байта)
|
||||
data = self.client_socket.recv(6)
|
||||
if len(data) < 6:
|
||||
return None, None
|
||||
|
||||
ip_bytes = data[:4]
|
||||
port_bytes = data[4:6]
|
||||
|
||||
ip = socket.inet_ntoa(ip_bytes)
|
||||
port = struct.unpack('!H', port_bytes)[0]
|
||||
|
||||
return ip, port
|
||||
|
||||
elif address_type == SOCKS5_DOMAIN:
|
||||
# Доменное имя: длина (1 байт) + имя + порт (2 байта)
|
||||
length_data = self.client_socket.recv(1)
|
||||
if len(length_data) < 1:
|
||||
return None, None
|
||||
|
||||
domain_length = struct.unpack('!B', length_data)[0]
|
||||
domain_data = self.client_socket.recv(domain_length + 2)
|
||||
|
||||
if len(domain_data) < domain_length + 2:
|
||||
return None, None
|
||||
|
||||
domain = domain_data[:domain_length].decode('utf-8')
|
||||
port = struct.unpack('!H', domain_data[domain_length:])[0]
|
||||
|
||||
return domain, port
|
||||
|
||||
elif address_type == SOCKS5_IPV6:
|
||||
# IPv6 адрес (16 байт) + порт (2 байта)
|
||||
data = self.client_socket.recv(18)
|
||||
if len(data) < 18:
|
||||
return None, None
|
||||
|
||||
ip_bytes = data[:16]
|
||||
port_bytes = data[16:18]
|
||||
|
||||
ip = socket.inet_ntop(socket.AF_INET6, ip_bytes)
|
||||
port = struct.unpack('!H', port_bytes)[0]
|
||||
|
||||
return ip, port
|
||||
|
||||
return None, None
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка парсинга адреса: {e}")
|
||||
return None, None
|
||||
|
||||
def _send_success_response(self):
|
||||
"""Отправка успешного ответа SOCKS5"""
|
||||
# Версия + статус + зарезервировано + тип адреса
|
||||
response = struct.pack('!BBBB', SOCKS5_VERSION, SOCKS5_SUCCESS, 0, SOCKS5_IPV4)
|
||||
# Связанный адрес (0.0.0.0) + порт (0)
|
||||
response += struct.pack('!IH', 0, 0)
|
||||
self.client_socket.send(response)
|
||||
|
||||
def _send_error_response(self, error_code: int):
|
||||
"""Отправка ответа об ошибке SOCKS5"""
|
||||
response = struct.pack('!BBBB', SOCKS5_VERSION, error_code, 0, SOCKS5_IPV4)
|
||||
response += struct.pack('!IH', 0, 0)
|
||||
self.client_socket.send(response)
|
||||
|
||||
def _relay_data(self):
|
||||
"""Проксирование данных между клиентом и Phantom соединением"""
|
||||
if not self.phantom_connection:
|
||||
return
|
||||
|
||||
logger.debug("Начало проксирования данных")
|
||||
|
||||
try:
|
||||
while True:
|
||||
# Ожидание данных от клиента или сервера
|
||||
ready_sockets, _, error_sockets = select.select(
|
||||
[self.client_socket, self.phantom_connection.socket],
|
||||
[],
|
||||
[self.client_socket, self.phantom_connection.socket],
|
||||
1.0 # Таймаут 1 секунда
|
||||
)
|
||||
|
||||
if error_sockets:
|
||||
logger.debug("Ошибка в сокетах, завершение проксирования")
|
||||
break
|
||||
|
||||
if not ready_sockets:
|
||||
continue
|
||||
|
||||
# Данные от клиента к серверу
|
||||
if self.client_socket in ready_sockets:
|
||||
data = self.client_socket.recv(4096)
|
||||
if not data:
|
||||
logger.debug("Клиент закрыл соединение")
|
||||
break
|
||||
|
||||
self.phantom_connection.send(data)
|
||||
logger.debug(f"Отправлено {len(data)} байт через Phantom")
|
||||
|
||||
# Данные от сервера к клиенту
|
||||
if self.phantom_connection.socket in ready_sockets:
|
||||
data = self.phantom_connection.recv(4096)
|
||||
if not data:
|
||||
logger.debug("Сервер закрыл соединение")
|
||||
break
|
||||
|
||||
self.client_socket.send(data)
|
||||
logger.debug(f"Получено {len(data)} байт от Phantom")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка проксирования данных: {e}")
|
||||
|
||||
def _cleanup(self):
|
||||
"""Очистка ресурсов"""
|
||||
try:
|
||||
if self.phantom_connection:
|
||||
self.phantom_connection.close()
|
||||
self.client_socket.close()
|
||||
except:
|
||||
pass
|
||||
|
||||
class PhantomSOCKS5Server:
|
||||
"""SOCKS5 прокси сервер через Phantom сеть"""
|
||||
|
||||
def __init__(self, host: str = '127.0.0.1', port: int = 8080, hops: int = 3):
|
||||
self.host = host
|
||||
self.port = port
|
||||
self.hops = hops
|
||||
self.server_socket: Optional[socket.socket] = None
|
||||
self.running = False
|
||||
|
||||
def start(self):
|
||||
"""Запуск SOCKS5 сервера"""
|
||||
try:
|
||||
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
self.server_socket.bind((self.host, self.port))
|
||||
self.server_socket.listen(10)
|
||||
|
||||
self.running = True
|
||||
|
||||
logger.info(f"🚀 Phantom SOCKS5 прокси запущен на {self.host}:{self.port}")
|
||||
logger.info(f" Количество хопов через Phantom сеть: {self.hops}")
|
||||
logger.info(f" Настройте ваш браузер или приложение:")
|
||||
logger.info(f" - Тип прокси: SOCKS v5")
|
||||
logger.info(f" - Адрес: {self.host}")
|
||||
logger.info(f" - Порт: {self.port}")
|
||||
logger.info(f" - Аутентификация: Нет")
|
||||
|
||||
while self.running:
|
||||
try:
|
||||
client_socket, client_address = self.server_socket.accept()
|
||||
logger.info(f"Новое SOCKS5 подключение от {client_address[0]}:{client_address[1]}")
|
||||
|
||||
# Обработка клиента в отдельном потоке
|
||||
handler = SOCKS5Handler(client_socket, self.hops)
|
||||
client_thread = threading.Thread(target=handler.handle)
|
||||
client_thread.daemon = True
|
||||
client_thread.start()
|
||||
|
||||
except socket.error as e:
|
||||
if self.running:
|
||||
logger.error(f"Ошибка принятия подключения: {e}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка запуска сервера: {e}")
|
||||
finally:
|
||||
self.stop()
|
||||
|
||||
def stop(self):
|
||||
"""Остановка SOCKS5 сервера"""
|
||||
self.running = False
|
||||
if self.server_socket:
|
||||
self.server_socket.close()
|
||||
logger.info("Phantom SOCKS5 прокси остановлен")
|
||||
|
||||
def main():
|
||||
"""Главная функция"""
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Phantom SOCKS5 Proxy - SOCKS5 прокси через Phantom сеть'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--host',
|
||||
default='127.0.0.1',
|
||||
help='IP адрес для прослушивания (по умолчанию: 127.0.0.1)'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--port',
|
||||
type=int,
|
||||
default=8080,
|
||||
help='Порт для прослушивания (по умолчанию: 8080)'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--hops',
|
||||
type=int,
|
||||
default=3,
|
||||
help='Количество хопов через Phantom сеть (по умолчанию: 3)'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--verbose',
|
||||
action='store_true',
|
||||
help='Подробный вывод'
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.verbose:
|
||||
logging.getLogger().setLevel(logging.DEBUG)
|
||||
|
||||
# Создание и запуск SOCKS5 сервера
|
||||
server = PhantomSOCKS5Server(args.host, args.port, args.hops)
|
||||
|
||||
try:
|
||||
server.start()
|
||||
except KeyboardInterrupt:
|
||||
logger.info("Получен сигнал прерывания, остановка сервера...")
|
||||
server.stop()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user