""" This plugin provides a command to get random SOCKS5 proxies. """ import os import logging import random import requests import socket import time from datetime import datetime, timedelta import concurrent.futures import simplematrixbotlib as botlib import sqlite3 import ipaddress from plugins.utils import is_public_destination SOCKS5_LIST_URL = 'https://raw.githubusercontent.com/TheSpeedX/SOCKS-List/master/socks5.txt' MAX_TRIES = 64 PROXY_LIST_FILENAME = 'socks5.txt' PROXY_LIST_EXPIRATION = timedelta(hours=8) MAX_THREADS = 128 PROXIES_DB_FILE = 'proxies.db' MAX_PROXIES_IN_DB = 10 logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') def test_proxy(proxy): """Test a SOCKS5 proxy and return the outcome.""" try: ip, port = proxy.split(':') logging.info(f"Testing SOCKS5 proxy: {ip}:{port}") start_time = time.time() with socket.create_connection((ip, int(port)), timeout=12) as client: client.sendall(b'\x05\x01\x00') response = client.recv(2) if response == b'\x05\x00': latency = int(round((time.time() - start_time) * 1000, 0)) return True, proxy, latency else: return False, proxy, None except Exception as e: return False, proxy, None async def download_proxy_list(): try: if not os.path.exists(PROXY_LIST_FILENAME) or \ datetime.now() - datetime.fromtimestamp(os.path.getctime(PROXY_LIST_FILENAME)) > PROXY_LIST_EXPIRATION: logging.info("Downloading SOCKS5 proxy list") response = requests.get(SOCKS5_LIST_URL, timeout=5) with open(PROXY_LIST_FILENAME, 'w') as f: f.write(response.text) logging.info("Proxy list downloaded successfully") return True else: logging.info("Proxy list already exists and is up-to-date") return True except Exception as e: logging.error(f"Error downloading proxy list: {e}") return False def check_db_for_proxy(): try: with sqlite3.connect(PROXIES_DB_FILE) as conn: cursor = conn.cursor() cursor.execute(""" CREATE TABLE IF NOT EXISTS proxies ( id INTEGER PRIMARY KEY AUTOINCREMENT, proxy TEXT, latency INTEGER, status TEXT ) """) cursor.execute("SELECT proxy, latency FROM proxies WHERE status = 'working' AND latency < 3000 ORDER BY RANDOM() LIMIT 1") result = cursor.fetchone() if result: proxy, latency = result success, _, _ = test_proxy(proxy) if success: return proxy, latency else: cursor.execute("DELETE FROM proxies WHERE proxy = ?", (proxy,)) conn.commit() logging.info(f"Removed non-working proxy from the database: {proxy}") return None, None else: return None, None except Exception as e: logging.error(f"Error checking proxies database: {e}") return None, None def save_proxy_to_db(proxy, latency): try: with sqlite3.connect(PROXIES_DB_FILE) as conn: cursor = conn.cursor() cursor.execute(""" CREATE TABLE IF NOT EXISTS proxies ( id INTEGER PRIMARY KEY AUTOINCREMENT, proxy TEXT, latency INTEGER, status TEXT ) """) cursor.execute("INSERT INTO proxies (proxy, latency, status) VALUES (?, ?, 'working')", (proxy, latency)) conn.commit() except Exception as e: logging.error(f"Error saving proxy to database: {e}") async def handle_command(room, message, bot, prefix, config): match = botlib.MessageMatch(room, message, bot, prefix) if match.is_not_from_this_bot() and match.prefix() and match.command("proxy"): logging.info("Received !proxy command") working_proxy, latency = check_db_for_proxy() if working_proxy: await bot.api.send_markdown_message(room.room_id, f"✅ Using cached working SOCKS5 Proxy: **{working_proxy}** - Latency: **{latency} ms**") return else: if not await download_proxy_list(): await bot.api.send_markdown_message(room.room_id, "Error downloading proxy list") return try: with open(PROXY_LIST_FILENAME, 'r') as f: socks5_proxies = [line.replace("socks5://", "") for line in f.read().splitlines()] # Filter out private/internal proxies before testing socks5_proxies = [p for p in socks5_proxies if is_public_destination(p.split(':')[0])] random.shuffle(socks5_proxies) tested_proxies = 0 with concurrent.futures.ThreadPoolExecutor(max_workers=MAX_THREADS) as executor: futures = [] for proxy in socks5_proxies[:MAX_TRIES]: futures.append(executor.submit(test_proxy, proxy)) for future in concurrent.futures.as_completed(futures): success, proxy, latency = future.result() if success: await bot.api.send_markdown_message(room.room_id, f"✅ Anonymous SOCKS5 Proxy: **{proxy}** - Latency: **{latency} ms**") save_proxy_to_db(proxy, latency) tested_proxies += 1 if tested_proxies >= MAX_PROXIES_IN_DB: break working_proxy, latency = check_db_for_proxy() if working_proxy: await bot.api.send_markdown_message(room.room_id, f"✅ Using cached working SOCKS5 Proxy: **{working_proxy}** - Latency: **{latency} ms**") else: await bot.api.send_markdown_message(room.room_id, "❌ No working anonymous SOCKS5 proxy found") except Exception as e: logging.error(f"Error handling !proxy command: {e}") await bot.api.send_markdown_message(room.room_id, "❌ Error handling !proxy command") # --------------------------------------------------------------------------- # Plugin Metadata # --------------------------------------------------------------------------- __version__ = "1.0.1" __author__ = "Funguy Bot" __description__ = "Working SOCKS5 proxy finder (SSRF‑safe)" __help__ = """
!proxy – Random working SOCKS5 proxy

Fetches, tests, and returns a random working SOCKS5 proxy with latency. Caches good proxies in SQLite.

"""