Ver Fonte

Proxy VPN Robusto IPv4/IPv6

yosoyhendrix há 4 dias atrás
pai
commit
11dcc27f96
1 ficheiros alterados com 60 adições e 42 exclusões
  1. 60 42
      Proxy_VPN.py

+ 60 - 42
Proxy_VPN.py

@@ -6,41 +6,42 @@ import select
 import sys
 import time
 import itertools
+import os
 
 # --- CONFIGURACIÓN BASE ---
 LISTENING_PORT = int(sys.argv[1]) if len(sys.argv) > 1 else 8080
 SSH_HOST = '127.0.0.1'
-SSH_PORT = 223  # Compatible con Dropbear o OpenSSH local
+SSH_PORT = 22  # Compatible con Dropbear o OpenSSH local
+LOG_FILE = "/root/proxy.log"
+MAX_LOG_SIZE = 10 * 1024 * 1024  # 10MB
 
 # --- CONFIGURACIÓN DE SEGURIDAD AVANZADA ---
 MAX_CONNECTIONS = 1000
-CONNECTION_COOLDOWN = 0.5  # Segundos entre conexiones por IP
+CONNECTION_COOLDOWN = 0.5
 TIMEOUT = 60
-BUFLEN = 16384  # Tamaño óptimo para sistemas embebidos
+BUFLEN = 16384
 
 # --- FILTRADO DE ACCESO ---
-# 🛡️ LISTA BLANCA DE IPs (Vacia = Permitir todas)
 ALLOWED_IPS = [] 
-# 🚫 LISTA NEGRA DE DOMINIOS (Hosts bloqueados)
 BLOCKED_HOSTS = ['ads.doubleclick.net', 'telemetry.microsoft.com']
 
-# --- SECCIÓN DE CUSTOM HEADERS ---
-# Estos se añaden a la respuesta HTTP 101 enviada a NetMod
+# --- SECCIÓN DE CUSTOM HEADERS (Inyectados en la respuesta 101) ---
 CUSTOM_HEADERS = {
     "Server": "nginx/1.21.0",
     "X-Forwarded-For": "127.0.0.1",
     "Content-Type": "text/html; charset=UTF-8",
     "Proxy-Connection": "keep-alive",
-    "Cache-Control": "no-cache"
+    "Cache-Control": "no-cache",
+    "X-Real-IP": "127.0.0.1"
 }
 
 # --- MENSAJES ROTATIVOS (Status 101) ---
 MENSAJES = [
     "🚀 CONEXION ESTABLECIDA",
     "🛡️ SEGURIDAD ACTIVA",
-    "🔋 OPTIMIZACION",
-    "🌐 ACCESO OK",
-	"Pfsense",
+    "🔋 OPTIMIZACION DROPBEAR",
+    "🌐 ACCESO NETMOD OK",
+  	"Pfsense",
     "OPNsense",
     "VyOS",
     "Claro",
@@ -56,13 +57,26 @@ MENSAJES = [
 mensaje_cycle = itertools.cycle(MENSAJES)
 cycle_lock = threading.Lock()
 
-# --- SISTEMA DE LOGS ---
+# --- SISTEMA DE LOGS CON AUTO-LIMPIEZA ---
 def log(msg, addr=None):
+    # Verificar tamaño del log y limpiar si excede el límite
+    if os.path.exists(LOG_FILE) and os.path.getsize(LOG_FILE) > MAX_LOG_SIZE:
+        with open(LOG_FILE, 'w') as f:
+            f.write(f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] LOG REINICIADO (Límite 10MB alcanzado)\n")
+
     timestamp = time.strftime("%Y-%m-%d %H:%M:%S")
     client_info = f" [{addr[0]}]" if addr else ""
-    print(f"[{timestamp}]{client_info} {msg}")
+    log_entry = f"[{timestamp}]{client_info} {msg}\n"
+    
+    # Escribir en archivo y consola
+    try:
+        with open(LOG_FILE, 'a') as f:
+            f.write(log_entry)
+        print(log_entry.strip())
+    except Exception as e:
+        print(f"Error escribiendo log: {e}")
 
-# --- GESTIÓN DE ESTADO GLOBAL ---
+# --- GESTIÓN DE ESTADO ---
 active_connections = 0
 conn_lock = threading.Lock()
 ip_cooldowns = {}
@@ -75,7 +89,6 @@ class ConnectionHandler(threading.Thread):
         self.target = None
 
     def build_http_response(self, status_msg):
-        """Construye la respuesta HTTP compatible con NetMod"""
         headers_str = "".join([f"{k}: {v}\r\n" for k, v in CUSTOM_HEADERS.items()])
         response = (
             f"HTTP/1.1 101 {status_msg}\r\n"
@@ -88,56 +101,59 @@ class ConnectionHandler(threading.Thread):
     def run(self):
         global active_connections
         try:
-            # 1. Validación de IP (Lista Blanca)
+            log("--- Nueva conexión recibida ---", self.addr)
+
+            # 1. Validación de IP
             if ALLOWED_IPS and self.addr[0] not in ALLOWED_IPS:
-                log("🚫 IP No autorizada bloqueada.", self.addr)
+                log("🚫 Conexión rechazada: IP no autorizada", self.addr)
                 return
 
-            # 2. Control de Cooldown (Anti-Flood)
+            # 2. Control de Rate-Limiting / Cooldown
             now = time.time()
             if self.addr[0] in ip_cooldowns and (now - ip_cooldowns[self.addr[0]]) < CONNECTION_COOLDOWN:
+                log("⚠️ Conexión rechazada por rate-limiting", self.addr)
                 return
             ip_cooldowns[self.addr[0]] = now
 
-            # 3. Recibir Payload inicial de NetMod
-            self.client.settimeout(5)
+            # 3. Payload inicial
+            self.client.settimeout(10)
             payload = self.client.recv(BUFLEN)
             if not payload:
                 return
 
-            # 4. Rotar mensaje de status
+            # 4. Conexión al destino (Dropbear/SSH)
             with cycle_lock:
                 current_status = next(mensaje_cycle)
 
-            # 5. Conectar al servicio local (Dropbear)
-            self.target = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-            self.target.settimeout(TIMEOUT)
-            self.target.connect((SSH_HOST, SSH_PORT))
+            log(f"Intentando conectar a {SSH_HOST}:{SSH_PORT}...", self.addr)
+            
+            # Soporte IPv4/IPv6 para la conexión interna
+            self.target = socket.create_connection((SSH_HOST, SSH_PORT), timeout=TIMEOUT)
+            
+            log("Conexión exitosa al destino SSH", self.addr)
 
-            # 6. Enviar respuesta HTTP con Headers a NetMod
+            # 5. Respuesta HTTP 101
             self.client.sendall(self.build_http_response(current_status))
-            
-            log(f"✅ Inyectado: {current_status}", self.addr)
+            log(f"✅ Protocolo Upgrade: {current_status}", self.addr)
 
-            # 7. Iniciar Túnel Bidireccional
+            # 6. Túnel bidireccional
             self.tunnel()
 
         except Exception as e:
-            log(f"⚠️ Error: {str(e)[:50]}", self.addr)
+            log(f"❌ Error: {str(e)}", self.addr)
         finally:
             with conn_lock:
                 active_connections -= 1
             self.cleanup()
 
     def tunnel(self):
-        """Maneja el tráfico binario SSH optimizado para CPU baja"""
         self.client.settimeout(None)
         self.target.settimeout(None)
-        inputs = [self.client, self.target]
+        sockets = [self.client, self.target]
         
         while True:
-            readable, _, exceptional = select.select(inputs, [], inputs, TIMEOUT)
-            if exceptional or not readable:
+            readable, _, error = select.select(sockets, [], sockets, TIMEOUT)
+            if error or not readable:
                 break
             
             for s in readable:
@@ -146,9 +162,8 @@ class ConnectionHandler(threading.Thread):
                     if not data:
                         return
                     
-                    # Enviar al extremo opuesto
-                    out = self.target if s is self.client else self.client
-                    out.sendall(data)
+                    dest = self.target if s is self.client else self.client
+                    dest.sendall(data)
                 except:
                     return
 
@@ -162,14 +177,17 @@ class ConnectionHandler(threading.Thread):
 
 def main():
     global active_connections
-    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-    server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
     
+    # Configuración de Socket Dual (IPv4 e IPv6)
     try:
-        server.bind(('0.0.0.0', LISTENING_PORT))
+        if socket.has_dualstack_ipv6():
+            server = socket.create_server(('::', LISTENING_PORT), family=socket.AF_INET6, dualstack_ipv6=True)
+        else:
+            server = socket.create_server(('0.0.0.0', LISTENING_PORT), family=socket.AF_INET)
+        
         server.listen(200)
-        log(f"🔥 PROXY INICIADO EN PUERTO {LISTENING_PORT}")
-        log(f"🎯 DESTINO: {SSH_HOST}:{SSH_PORT} (Dropbear)")
+        log(f"🔥 Servidor Robusto Iniciado en Puerto {LISTENING_PORT} (Dual IPv4/IPv6)")
+        log(f"🛡️ Logs: {LOG_FILE} (Autolimitado a 10MB)")
 
         while True:
             client, addr = server.accept()