Prechádzať zdrojové kódy

Añadir 'Proxy3.py'

yosoyhendrix 1 týždeň pred
rodič
commit
eae819c986
1 zmenil súbory, kde vykonal 268 pridanie a 0 odobranie
  1. 268 0
      Proxy3.py

+ 268 - 0
Proxy3.py

@@ -0,0 +1,268 @@
+# -*- coding: utf-8 -*-
+
+# ==============================================================================
+# SCRIPT DE PROXY MULTIFILAMENTADO CON RESPUESTAS ROTATIVAS
+#
+# - Basado en la versión robusta y estable.
+# - Añade rotación dinámica del mensaje de estado en la respuesta HTTP 101.
+# - Utiliza un iterador cíclico para cambiar el mensaje en cada nueva conexión.
+#
+# Creado por Gemini
+# ==============================================================================
+#screen -dmS badvpn2 /bin/badvpn-udpgw --listen-addr 127.0.0.1:7300 --max-clients 1000 --max-connections-for-client 100
+#screen -dmS pydic-80 python3 /etc/VPS-MX/protocolo/Pythonv1.py 8080
+import socket
+import threading
+import select
+import sys
+import time
+import os
+import logging
+import logging.handlers
+import itertools  # 💡 Importado para la rotación de mensajes
+
+# ==============================================================================
+# CONFIGURACIÓN GLOBAL Y SETUP DE LOGGING
+# ==============================================================================
+IPV4_ADDR = '0.0.0.0'
+IPV6_ADDR = '::'
+
+if sys.argv[1:]:
+    LISTENING_PORT = int(sys.argv[1])
+else:
+    LISTENING_PORT = 8080
+
+PASS = ''
+PRIORITIZE_IPV4 = True
+CONNECTION_COOLDOWN_TIME = 10
+MAX_CONNECTIONS = 1000 
+
+# Constantes de red
+BUFLEN = 4096 * 4
+TIMEOUT = 60
+DEFAULT_HOST = '127.0.0.1:223'
+
+# 💡 LISTA DE MENSAJES PARA ROTAR
+# Puedes añadir todos los que quieras aquí.
+MENSAJES_ROTATIVOS = [
+    "Pfsense",
+    "OPNsense",
+    "VyOS",
+    "TNSR"
+]
+
+# Creamos un iterador infinito que rota sobre la lista anterior
+mensaje_iterator = itertools.cycle(MENSAJES_ROTATIVOS)
+# Lock para asegurar que la extracción del siguiente mensaje sea segura entre hilos
+iterator_lock = threading.Lock()
+
+# Configuración del log
+LOG_FILE = '/root/proxy.log'
+MAX_LOG_SIZE = 5 * 1024 * 1024 
+BACKUP_COUNT = 5 
+
+def setup_logging():
+    log_format = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
+    file_handler = logging.handlers.RotatingFileHandler(LOG_FILE, maxBytes=MAX_LOG_SIZE, backupCount=BACKUP_COUNT)
+    file_handler.setFormatter(log_format)
+    console_handler = logging.StreamHandler()
+    console_handler.setFormatter(log_format)
+    logger = logging.getLogger()
+    logger.setLevel(logging.INFO)
+    logger.addHandler(file_handler)
+    logger.addHandler(console_handler)
+    return logger
+
+logger = setup_logging()
+
+last_connection_times = {}
+last_connection_lock = threading.Lock()
+connection_limit_semaphore = threading.Semaphore(MAX_CONNECTIONS)
+
+# ==============================================================================
+# CLASE DEL SERVIDOR
+# ==============================================================================
+class Server(threading.Thread):
+    def __init__(self, port):
+        super().__init__()
+        self.running = False
+        self.port = port
+        self.threads = []
+        self.threads_lock = threading.Lock()
+        self.ipv4_socket = None
+        self.ipv6_socket = None
+
+    def run(self):
+        logger.info("\n:-------PythonProxy-------:\n")
+        logger.info(f"Listening port: {self.port}")
+        logger.info(f"Mensajes configurados: {len(MENSAJES_ROTATIVOS)}\n")
+        logger.info(":-------------------------:\n")
+
+        try:
+            self.ipv4_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+            self.ipv4_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+            self.ipv4_socket.bind((IPV4_ADDR, self.port))
+            self.ipv4_socket.listen(0)
+        except socket.error as e:
+            logger.error(f"Error IPv4: {e}")
+            self.ipv4_socket = None
+
+        try:
+            self.ipv6_socket = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
+            self.ipv6_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+            self.ipv6_socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)
+            self.ipv6_socket.bind((IPV6_ADDR, self.port, 0, 0))
+            self.ipv6_socket.listen(0)
+        except socket.error as e:
+            logger.error(f"Error IPv6: {e}")
+            self.ipv6_socket = None
+
+        if not self.ipv4_socket and not self.ipv6_socket:
+            return
+
+        self.running = True
+        active_sockets = [s for s in [self.ipv4_socket, self.ipv6_socket] if s]
+
+        try:
+            while self.running:
+                readable, _, _ = select.select(active_sockets, [], [], 2)
+                for sock in readable:
+                    c, addr = sock.accept()
+                    client_ip = addr[0]
+                    current_time = time.time()
+
+                    with last_connection_lock:
+                        last_time = last_connection_times.get(client_ip, 0)
+                        if current_time - last_time < CONNECTION_COOLDOWN_TIME:
+                            c.close()
+                            continue
+                        last_connection_times[client_ip] = current_time
+
+                    if not connection_limit_semaphore.acquire(timeout=0):
+                            c.close()
+                            continue
+
+                    c.setblocking(1)
+                    conn = ConnectionHandler(c, self, addr)
+                    conn.start()
+                    self.add_conn(conn)
+        except Exception as e:
+            logger.error(f"Error servidor: {e}")
+        finally:
+            self.running = False
+
+    def add_conn(self, conn):
+        with self.threads_lock:
+            if self.running: self.threads.append(conn)
+
+    def remove_conn(self, conn):
+        with self.threads_lock:
+            if conn in self.threads: self.threads.remove(conn)
+
+    def close(self):
+        self.running = False
+        with self.threads_lock:
+            for c in list(self.threads): c.close()
+
+# ==============================================================================
+# CLASE MANEJADORA DE CONEXIONES
+# ==============================================================================
+class ConnectionHandler(threading.Thread):
+    def __init__(self, client_socket, server, addr):
+        super().__init__()
+        self.client = client_socket
+        self.server = server
+        self.addr = addr
+        self.log_prefix = f"{addr[0]}:{addr[1]}"
+        self.target = None
+        self.client_closed = False
+        self.target_closed = True
+
+    def close(self):
+        try:
+            if not self.client_closed:
+                self.client.close()
+        except: pass
+        finally: self.client_closed = True
+
+        try:
+            if not self.target_closed:
+                self.target.close()
+        except: pass
+        finally: self.target_closed = True
+        
+        connection_limit_semaphore.release()
+
+    def run(self):
+        try:
+            data = self.client.recv(BUFLEN)
+            if not data: return
+            headers = data.decode('latin-1')
+            host_port = self.find_header(headers, 'X-Real-Host') or DEFAULT_HOST
+
+            # 💡 Lógica de rotación: obtenemos el siguiente mensaje de la lista
+            with iterator_lock:
+                mensaje_actual = next(mensaje_iterator)
+            
+            # Construimos la respuesta HTTP dinámica
+            response_dinamica = f"HTTP/1.1 101 {mensaje_actual}\r\nConnection: Upgrade\r\nUpgrade: websocket\r\n\r\n".encode()
+
+            logger.info(f"[{self.log_prefix}] Usando mensaje: '{mensaje_actual}'")
+            
+            self.connect_target(host_port)
+            self.client.sendall(response_dinamica)
+            self.do_tunnel()
+
+        except Exception as e:
+            logger.error(f"Error en {self.log_prefix}: {e}")
+        finally:
+            self.close()
+            self.server.remove_conn(self)
+
+    def find_header(self, head, header):
+        aux = head.find(header + ': ')
+        if aux == -1: return ''
+        head = head[aux + len(header) + 2:]
+        aux = head.find('\r\n')
+        return head[:aux]
+
+    def connect_target(self, host_port):
+        i = host_port.find(':')
+        host = host_port[:i] if i != -1 else host_port
+        port = int(host_port[i+1:]) if i != -1 else 22
+        
+        addr_info = socket.getaddrinfo(host, port, socket.AF_UNSPEC, socket.SOCK_STREAM)
+        for res in addr_info:
+            af, socktype, proto, _, sa = res
+            try:
+                self.target = socket.socket(af, socktype, proto)
+                self.target.connect(sa)
+                self.target_closed = False
+                return
+            except:
+                if self.target: self.target.close()
+        raise RuntimeError("No se pudo conectar al destino")
+
+    def do_tunnel(self):
+        socs = [self.client, self.target]
+        while True:
+            readable, _, _ = select.select(socs, [], [], TIMEOUT)
+            if not readable: break
+            for sock in readable:
+                data = sock.recv(BUFLEN)
+                if not data: return
+                if sock is self.target:
+                    self.client.send(data)
+                else:
+                    self.target.sendall(data)
+
+def main():
+    server = Server(LISTENING_PORT)
+    server.start()
+    try:
+        while True: time.sleep(2)
+    except KeyboardInterrupt:
+        server.close()
+
+if __name__ == '__main__':
+    main()