Prechádzať zdrojové kódy

Actualizar 'Proxy-ssl.py'

Versión 7 - Resiliente (Anti-Bots)
yosoyhendrix 3 dní pred
rodič
commit
d76ae784e7
1 zmenil súbory, kde vykonal 128 pridanie a 147 odobranie
  1. 128 147
      Proxy-ssl.py

+ 128 - 147
Proxy-ssl.py

@@ -9,231 +9,212 @@ import itertools
 import os
 import ssl
 
-# --- CONFIGURACIÓN BASE ---
+# ==============================================================================
+# CONFIGURACIÓN DEL SISTEMA
+# ==============================================================================
 LISTENING_PORT = int(sys.argv[1]) if len(sys.argv) > 1 else 443
 SSH_HOST = '127.0.0.1'
-SSH_PORT = 22  # Asegúrate de que este es tu puerto SSH/Dropbear
+SSH_PORT = 22  # Cambiar a 223 si usas Dropbear modificado
 LOG_FILE = "/root/proxy.log"
-MAX_LOG_SIZE = 10 * 1024 * 1024
+MAX_LOG_SIZE = 10 * 1024 * 1024 # 10MB antes de rotar
 
-# --- CONFIGURACIÓN SSL/TLS ---
-USE_SSL = True  
+# RUTAS DE CERTIFICADOS SSL (Deben existir en el servidor)
 CERT_FILE = "/root/cert.pem"
 KEY_FILE = "/root/key.pem"
 
-# --- CONFIGURACIÓN DE SEGURIDAD AVANZADA ---
-MAX_CONNECTIONS = 150 # Ligeramente aumentado
-CONNECTION_COOLDOWN = 0.5
+# ==============================================================================
+# PARÁMETROS DE RESILIENCIA Y SEGURIDAD
+# ==============================================================================
+MAX_CONNECTIONS = 200
+CONNECTION_COOLDOWN = 0.7
 BUFLEN = 16384
+TIMEOUT_HTTP = 3.0
+
+# SISTEMA DE AUTO-BANEO TEMPORAL
 AUTO_BAN_STRIKES = 3  
-BAN_TIME = 3600       
-banned_ips_memory = {} 
+BAN_TIME = 3600 # 1 hora de baneo
+banned_ips = {} 
 ip_strikes = {}
-ALLOWED_IPS = [] 
 
-# --- RESPUESTA FAKE WEB (ANTI ACTIVE PROBING) ---
-FAKE_WEB_RESPONSE = (
+# RESPUESTA WEB FALSA (Para engañar a escáneres como Shodan)
+FAKE_WEB = (
     b"HTTP/1.1 200 OK\r\n"
-    b"Server: nginx/1.21.0\r\n"
+    b"Server: nginx/1.24.0\r\n"
     b"Content-Type: text/html; charset=UTF-8\r\n"
     b"Connection: close\r\n\r\n"
-    b"<!DOCTYPE html>\n<html>\n<head><title>Bienvenido</title></head>\n"
-    b"<body style='text-align:center; padding:50px; font-family:sans-serif;'>\n"
-    b"<h1>Hola</h1>\n<p>Servicio en funcionamiento.</p>\n"
-    b"</body>\n</html>\n"
+    b"<!DOCTYPE html><html><head><title>Welcome</title></head>"
+    b"<body style='font-family:sans-serif;text-align:center;padding:50px;'>"
+    b"<h1>404 Not Found</h1><p>The requested resource was not found.</p>"
+    b"</body></html>"
 )
 
-# --- CUSTOM HEADERS PARA VPN ---
-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",
-    "X-Proxy-Agent": "Gemini-Ultra-Robust-v7-HA",
-    "X-Forwarded-For-Proxy": "True"
-}
-
+# MENSAJES PARA LA INYECCIÓN HTTP (NetMod)
 MENSAJES = [
     "🚀 CONEXION TLS ESTABLECIDA",
     "🛡️ CIFRADO MILITAR ACTIVO",
     "🔋 MODO SIGILO SSL OK",
+    "Pfsense",
+    "OPNsense",
+    "VyOS",
+    "Claro",
+    "Windows Server",
+    "BSD Free",
+    "VyOS",
+    "Altice",
+    "Viva",
+    "Google",
+    "VyOS",
+    "TNSR",
     "🌐 BYPASS DE FIREWALL OK"
 ]
 mensaje_cycle = itertools.cycle(MENSAJES)
 cycle_lock = threading.Lock()
 
-def log(msg, addr=None):
+# ==============================================================================
+# FUNCIONES DE SOPORTE
+# ==============================================================================
+def write_log(msg, addr=None):
     try:
         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\n")
-        timestamp = time.strftime("%Y-%m-%d %H:%M:%S")
-        client_info = f" [{addr[0]}]" if addr else ""
-        log_entry = f"[{timestamp}]{client_info} {msg}\n"
-        with open(LOG_FILE, 'a') as f: f.write(log_entry)
+            with open(LOG_FILE, 'w') as f: f.write("--- LOG REINICIADO ---\n")
+        
+        ts = time.strftime("%Y-%m-%d %H:%M:%S")
+        ip_info = f" [{addr[0]}]" if addr else ""
+        log_line = f"[{ts}]{ip_info} {msg}\n"
+        
+        with open(LOG_FILE, 'a') as f: f.write(log_line)
+        print(log_line.strip())
     except: pass
 
-active_connections = 0
-conn_lock = threading.Lock()
+active_conn_count = 0
+conn_count_lock = threading.Lock()
 
-class ConnectionHandler(threading.Thread):
+class ProxyHandler(threading.Thread):
     def __init__(self, client_socket, addr):
         super().__init__(daemon=True)
         self.client = client_socket
         self.addr = addr
         self.target = None
-        self.tx_bytes = 0
-        self.rx_bytes = 0
-
-    def build_http_response(self, status_msg):
-        headers_str = "".join([f"{k}: {v}\r\n" for k, v in CUSTOM_HEADERS.items()])
-        return (f"HTTP/1.1 101 {status_msg}\r\n{headers_str}Connection: Upgrade\r\nUpgrade: websocket\r\n\r\n").encode('utf-8')
 
     def run(self):
-        global active_connections
+        global active_conn_count
         client_ip = self.addr[0]
-        
-        try:
-            if client_ip in banned_ips_memory:
-                if time.time() > banned_ips_memory[client_ip]:
-                    del banned_ips_memory[client_ip]
-                    if client_ip in ip_strikes: del ip_strikes[client_ip]
-                else: return
-                
-            now = time.time()
-            if client_ip in ip_strikes and (now - ip_strikes.get('last_time', 0)) < CONNECTION_COOLDOWN:
-                ip_strikes[client_ip] = ip_strikes.get(client_ip, 0) + 1
-                if ip_strikes[client_ip] >= AUTO_BAN_STRIKES:
-                    banned_ips_memory[client_ip] = time.time() + BAN_TIME
-                    log(f"⛔ IP Baneada por Flood/Escaneo: {client_ip}", self.addr)
-                return
-                
-            ip_strikes['last_time'] = now
-            ip_strikes[client_ip] = 0
 
-            self.client.settimeout(2.0)
-            payload = b""
-            try:
-                payload = self.client.recv(BUFLEN)
-            except socket.timeout:
-                pass # NetMod en silencio
-            except Exception:
-                return
+        try:
+            # 1. Verificar Baneo
+            if client_ip in banned_ips:
+                if time.time() < banned_ips[client_ip]: return
+                else: del banned_ips[client_ip]
 
+            # 2. Leer Petición inicial
+            self.client.settimeout(TIMEOUT_HTTP)
             try:
-                self.target = socket.create_connection((SSH_HOST, SSH_PORT), timeout=10)
-            except Exception as e:
-                log(f"❌ Error interno destino SSH: {e}", self.addr)
-                return
-
-            if payload:
-                if payload.startswith(b"SSH-"):
-                    self.target.sendall(payload)
-                elif b"HTTP/" in payload and b"Upgrade: websocket" not in payload:
-                    log(f"🕵️ Escáner detectado. Respondiendo Fake Web.", self.addr)
-                    self.client.sendall(FAKE_WEB_RESPONSE)
-                    return 
+                data = self.client.recv(BUFLEN)
+            except: data = b""
+
+            # 3. Lógica de Detección de Protocolo
+            if data:
+                # Si es un navegador/escáner buscando web
+                if b"HTTP/" in data and b"Upgrade: websocket" not in data:
+                    write_log("🕵️ Escáner detectado. Enviando Fake Web.", self.addr)
+                    self.client.sendall(FAKE_WEB)
+                    return
+                
+                # Si es tráfico SSH directo (sin inyector)
+                if data.startswith(b"SSH-"):
+                    self.target = socket.create_connection((SSH_HOST, SSH_PORT), timeout=5)
+                    self.target.sendall(data)
                 else:
-                    with cycle_lock: current_status = next(mensaje_cycle)
-                    self.client.sendall(self.build_http_response(current_status))
-            
-            self.tunnel()
+                    # Es un Inyector (NetMod/NekoBox)
+                    with cycle_lock: current_msg = next(mensaje_cycle)
+                    resp = f"HTTP/1.1 101 {current_msg}\r\nConnection: Upgrade\r\nUpgrade: websocket\r\n\r\n"
+                    self.client.sendall(resp.encode('utf-8'))
+                    self.target = socket.create_connection((SSH_HOST, SSH_PORT), timeout=5)
+            else:
+                # Conexión vacía (posible probe silencioso)
+                self.target = socket.create_connection((SSH_HOST, SSH_PORT), timeout=5)
+
+            # 4. Iniciar Túnel
+            self.bridge()
 
-        except Exception as e: pass
+        except Exception as e:
+            pass
         finally:
-            with conn_lock: active_connections -= 1
+            with conn_count_lock: active_conn_count -= 1
             self.cleanup()
 
-    def tunnel(self):
+    def bridge(self):
         self.client.settimeout(None)
         self.target.settimeout(None)
         sockets = [self.client, self.target]
         while True:
-            readable, _, error = select.select(sockets, [], sockets, 300)
-            if error or not readable: break
-            for s in readable:
+            r, _, e = select.select(sockets, [], sockets, 300)
+            if e or not r: break
+            for s in r:
                 try:
                     data = s.recv(BUFLEN)
                     if not data: return
-                    if s is self.client:
-                        self.target.sendall(data)
-                        self.tx_bytes += len(data)
-                    else:
-                        self.client.sendall(data)
-                        self.rx_bytes += len(data)
+                    (self.target if s is self.client else self.client).sendall(data)
                 except: return
 
     def cleanup(self):
-        total_mb = (self.tx_bytes + self.rx_bytes) / (1024 * 1024)
-        if total_mb > 0.05: log(f"[*] Tráfico finalizado: {total_mb:.2f} MB", self.addr)
         for s in [self.client, self.target]:
             if s:
                 try: s.close()
                 except: pass
 
 def main():
-    global active_connections
-    ssl_context = None
-    if USE_SSL:
-        try:
-            ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
-            ssl_context.load_cert_chain(certfile=CERT_FILE, keyfile=KEY_FILE)
-        except Exception as e:
-            print(f"Error crítico cargando certificados SSL: {e}")
-            sys.exit(1)
+    global active_conn_count
+    
+    # Configuración de Contexto SSL Flexible (Compatible con NetMod)
+    context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
+    try:
+        context.load_cert_chain(certfile=CERT_FILE, keyfile=KEY_FILE)
+    except Exception as e:
+        print(f"Error cargando certificados: {e}")
+        sys.exit(1)
 
+    # Creación del Socket Servidor (Dual Stack IPv4/IPv6)
     try:
-        addr_info = socket.getaddrinfo(None, LISTENING_PORT, socket.AF_UNSPEC, socket.SOCK_STREAM, 0, socket.AI_PASSIVE)
-        addr_info.sort(key=lambda x: x[0] == socket.AF_INET6, reverse=True)
-        af, socktype, proto, canonname, sa = addr_info[0]
-        
-        server = socket.socket(af, socktype, proto)
+        server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
         server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
-        if af == socket.AF_INET6:
-            try: server.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0)
-            except: pass
-
-        server.bind(sa)
-        server.listen(500) # Aumentado el backlog para soportar ráfagas de bots
+        server.bind(('', LISTENING_PORT))
+        server.listen(500)
         
         print(f"=====================================================")
-        print(f"🔥 Servidor Robusto INMORTAL Iniciado - Puerto {LISTENING_PORT}")
-        print(f"🛡️ Motor SSL/TLS & Anti-Crash: ACTIVADO")
+        print(f"🚀 PROXY V7 RESILIENTE INICIADO - PUERTO {LISTENING_PORT}")
+        print(f"🛡️  MOTOR ANTI-CRASH Y FAKE WEB ACTIVADOS")
         print(f"=====================================================")
 
-        # EL BUCLE PRINCIPAL AHORA ES BLINDADO
         while True:
             try:
-                client, addr = server.accept()
+                raw_client, addr = server.accept()
                 
-                if USE_SSL:
-                    try:
-                        client = ssl_context.wrap_socket(client, server_side=True)
-                    except Exception:
-                        # Si el bot manda basura en lugar de un handshake SSL, se cierra y se ignora silenciosamente.
-                        client.close()
-                        continue
+                # 5. Envolver conexión en SSL
+                try:
+                    client = context.wrap_socket(raw_client, server_side=True)
+                except:
+                    raw_client.close()
+                    continue
 
-                with conn_lock:
-                    if active_connections >= MAX_CONNECTIONS:
+                with conn_count_lock:
+                    if active_conn_count >= MAX_CONNECTIONS:
                         client.close()
                         continue
-                    active_connections += 1
-                    
-                ConnectionHandler(client, addr).start()
+                    active_conn_count += 1
                 
-            except socket.error as e:
-                # Si Linux se queda sin recursos por 1 segundo por un ataque DDoS, 
-                # esperamos 50ms y volvemos a intentarlo en lugar de apagar el script.
-                time.sleep(0.05)
+                ProxyHandler(client, addr).start()
+
+            except socket.error:
+                time.sleep(0.05) # Pausa ante saturación de sockets
                 continue
-            except Exception as e:
-                time.sleep(1)
+            except Exception:
+                time.sleep(0.5)
                 continue
-            
-    except Exception as e: 
-        print(f"Error fatal: {e}")
-    finally: 
+
+    except Exception as e:
+        print(f"Error crítico: {e}")
+    finally:
         server.close()
 
 if __name__ == "__main__":