| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321 |
- #!/usr/bin/env python3
- # -*- coding: utf-8 -*-
- """
- =============================================================================
- PROXY VPN DUAL (TCP + TLS) - ULTIMATE PYTHON EDITION
- Características: IPv4 & IPv6 (Dual-Stack), Multiplexación 80/443,
- Fake Web Nginx, Anti-Flood en RAM, Mensajes Rotativos y Custom Headers.
- =============================================================================
- """
- import socket
- import ssl
- import threading
- import select
- import time
- import datetime
- import os
- import sys
- import signal # <--- ¡AQUÍ ESTÁ LA LIBRERÍA QUE FALTABA!
- # --- CONFIGURACIÓN BASE ---
- PORT_TCP = 80
- PORT_TLS = 443
- SSH_HOST = "127.0.0.1"
- SSH_PORT = 22
- CERT_FILE = "/root/cert.pem"
- KEY_FILE = "/root/key.pem"
- LOG_FILE = "/root/proxy-dual-python.log"
- # --- SEGURIDAD ANTI-FLOOD Y BANEO ---
- AUTO_BAN_STRIKES = 20 # Límite de conexiones por segundo exacto (tolera navegadores)
- BAN_TIME = 3600 # Castigo de 1 hora en segundos
- ip_database = {} # Base de datos en memoria RAM
- db_lock = threading.Lock()
- # --- FAKE WEB RESPONSES ---
- FAKE_WEB_TCP = (
- b"HTTP/1.1 400 Bad Request\r\n"
- b"Server: nginx/1.24.0\r\n"
- b"Content-Type: text/html\r\n"
- b"Connection: close\r\n\r\n"
- b"<html><body><center><h1>400 Bad Request</h1></center><hr><center>nginx/1.24.0</center></body></html>\r\n"
- )
- FAKE_WEB_TLS = (
- b"HTTP/1.1 400 OK\r\n"
- b"Server: nginx/1.21.0\r\n"
- b"Content-Type: text/html\r\n"
- b"Connection: close\r\n\r\n"
- b"<html><body><center><h1>400 Bad Request</h1></center></body></html>\r\n"
- )
- # --- MENSAJES ROTATIVOS ---
- MENSAJES = [
- "🚀 CONEXION ESTABLECIDA",
- "🛡️ CIFRADO MILITAR ACTIVO",
- "🔋 MODO SIGILO SSL OK",
- "Pfsense",
- "OPNsense",
- "VyOS",
- "Claro",
- "Google",
- "TNSR",
- "🌐 BYPASS DE FIREWALL OK"
- ]
- msg_idx = 0
- msg_lock = threading.Lock()
- # --- FUNCIONES DE REGISTRO (LOGS) ---
- def write_log(ip, proto, msg):
- try:
- # Limpiar la etiqueta de IPv4-mapped-IPv6 para que el log se vea limpio
- if ip and ip.startswith("::ffff:"):
- ip = ip.replace("::ffff:", "")
-
- timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
- log_line = f"[{timestamp}] [{proto}] [{ip if ip else 'SISTEMA'}] {msg}"
-
- print(log_line)
- with open(LOG_FILE, "a") as f:
- f.write(log_line + "\n")
- except Exception:
- pass
- # --- MOTOR ANTI-FLOOD (AUTO-BAN) ---
- def check_and_update_ip(ip):
- global ip_database
- now = time.time()
-
- with db_lock:
- # Limpieza periódica de IPs viejas para no saturar la RAM
- if len(ip_database) > 1000:
- ip_database = {k: v for k, v in ip_database.items() if v["ban_until"] > now or (now - v["last_connect"] < 60)}
- if ip not in ip_database:
- ip_database[ip] = {"last_connect": now, "strikes": 1, "ban_until": 0}
- return 1
- record = ip_database[ip]
- # ¿Está baneado?
- if record["ban_until"] > now:
- return 0
- # Tolerancia por segundo exacto
- if int(now) == int(record["last_connect"]):
- record["strikes"] += 1
- if record["strikes"] > AUTO_BAN_STRIKES:
- record["ban_until"] = now + BAN_TIME
- return -1 # Acaba de ser baneado
- else:
- # Nuevo segundo, resetear contador
- record["strikes"] = 1
- record["last_connect"] = now
- return 1
- # --- MANEJADOR PRINCIPAL DE CONEXIONES ---
- def connection_handler(client_sock, client_addr, is_tls):
- proto_name = "TLS" if is_tls else "TCP"
- client_ip = client_addr[0]
-
- # Extraer IP limpia para los logs
- clean_ip = client_ip.replace("::ffff:", "") if client_ip.startswith("::ffff:") else client_ip
- # 1. Filtro de Seguridad
- sec_status = check_and_update_ip(client_ip)
- if sec_status == 0:
- client_sock.close()
- return
- elif sec_status == -1:
- write_log(clean_ip, proto_name, "⛔ IP Baneada (Intento de Flood bloqueado)")
- client_sock.close()
- return
- # 2. Envoltura SSL (Solo para el puerto 443)
- if is_tls:
- try:
- context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
- context.load_cert_chain(certfile=CERT_FILE, keyfile=KEY_FILE)
- client_sock.settimeout(5.0) # Tiempo máximo para el handshake
- client_sock = context.wrap_socket(client_sock, server_side=True)
- except ssl.SSLError:
- # Probablemente un escáner escaneando puertos SSL con texto plano
- client_sock.close()
- return
- except Exception as e:
- client_sock.close()
- return
- # 3. Lectura del Payload (Con Timeout para soportar NetMod)
- client_sock.settimeout(3.0)
- try:
- buffer = client_sock.recv(16384)
- except socket.timeout:
- buffer = b"" # Túnel Silencioso (NetMod)
- except Exception:
- client_sock.close()
- return
- # 4. Conectar al destino SSH Local
- try:
- target_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- target_sock.settimeout(5.0)
- target_sock.connect((SSH_HOST, SSH_PORT))
- except Exception:
- write_log(clean_ip, proto_name, "❌ Error conectando a servidor SSH interno")
- client_sock.close()
- return
- # 5. Lógica de Enrutamiento y Camuflaje
- if buffer:
- if buffer.startswith(b"SSH-"):
- write_log(clean_ip, proto_name, "✅ Túnel Directo SSH")
- target_sock.sendall(buffer)
-
- elif b"HTTP/" in buffer and b"Upgrade: websocket" not in buffer:
- # Es un navegador web o un bot escáner
- write_log(clean_ip, proto_name, "🕵️ Escáner detectado. Respondiendo Fake Web (400 OK).")
- fake_resp = FAKE_WEB_TLS if is_tls else FAKE_WEB_TCP
- client_sock.sendall(fake_resp)
- client_sock.close()
- target_sock.close()
- return
-
- else:
- # Es una petición de inyección (NetMod / HTTP Custom)
- global msg_idx
- with msg_lock:
- status_msg = MENSAJES[msg_idx]
- msg_idx = (msg_idx + 1) % len(MENSAJES)
- srv_header = "nginx/1.21.0" if is_tls else "nginx/1.24.0"
- agent_header = "Gemini-Ultimate-Python-TLS" if is_tls else "Gemini-Ultimate-Python-TCP"
-
- response = (
- f"HTTP/1.1 101 {status_msg}\r\n"
- f"Server: {srv_header}\r\n"
- f"X-Forwarded-For: 127.0.0.1\r\n"
- f"Content-Type: text/html; charset=UTF-8\r\n"
- f"Proxy-Connection: keep-alive\r\n"
- f"Cache-Control: no-cache\r\n"
- f"X-Proxy-Agent: {agent_header}\r\n"
- f"Connection: Upgrade\r\n"
- f"Upgrade: websocket\r\n\r\n"
- )
-
- client_sock.sendall(response.encode('utf-8'))
- write_log(clean_ip, proto_name, f"✅ Túnel Inyectado Establecido: {status_msg}")
- # Reenviar si el cliente mandó carga SSH extra junto con el Header HTTP
- partes = buffer.split(b"\r\n\r\n", 1)
- if len(partes) > 1 and partes[1]:
- target_sock.sendall(partes[1])
- else:
- # Buffer vacío (Timeout)
- write_log(clean_ip, proto_name, "✅ Túnel Modo Silencioso (Stunnel)")
- # 6. Bucle Multiplexor (El Puente de Red)
- client_sock.settimeout(None)
- target_sock.settimeout(None)
- sockets = [client_sock, target_sock]
-
- tx_bytes = 0
- rx_bytes = 0
- try:
- while True:
- r, _, _ = select.select(sockets, [], [], 300) # 5 minutos de inactividad max
- if not r:
- break
-
- if client_sock in r:
- data = client_sock.recv(16384)
- if not data:
- break
- target_sock.sendall(data)
- rx_bytes += len(data)
-
- if target_sock in r:
- data = target_sock.recv(16384)
- if not data:
- break
- client_sock.sendall(data)
- tx_bytes += len(data)
- except Exception:
- pass
- finally:
- total_mb = (tx_bytes + rx_bytes) / (1024 * 1024)
- if total_mb > 0.05:
- write_log(clean_ip, proto_name, f"[*] Conexión finalizada. Tráfico: {total_mb:.2f} MB")
- client_sock.close()
- target_sock.close()
- # --- SERVIDORES DE ESCUCHA (DUAL-STACK IPv4 e IPv6) ---
- def server_listener(port, is_tls):
- proto_name = "TLS" if is_tls else "TCP"
- try:
- # MAGIA DUAL-STACK: AF_INET6 con IPV6_V6ONLY en 0 escucha IPv4 e IPv6 simultáneamente
- server = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
- server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
-
- # Desactivar exclusividad IPv6 (Permite mapear IPv4 a IPv6)
- try:
- server.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0)
- except AttributeError:
- pass # Si el sistema no lo soporta, sigue adelante
-
- server.bind(("", port))
- server.listen(500)
-
- write_log(None, proto_name, f"Escuchando en puerto {port} (IPv4 e IPv6)...")
-
- while True:
- client_sock, client_addr = server.accept()
- # Desplegar un hilo por cada cliente conectado
- t = threading.Thread(target=connection_handler, args=(client_sock, client_addr, is_tls))
- t.daemon = True
- t.start()
-
- except Exception as e:
- write_log(None, "SISTEMA", f"❌ Error fatal en puerto {port}: {e}")
- sys.exit(1)
- # --- HILO MAESTRO ORQUESTADOR ---
- if __name__ == "__main__":
- # Ignorar errores de "Broken Pipe" que crashean los servidores
- if hasattr(signal, 'SIGPIPE'):
- signal.signal(signal.SIGPIPE, signal.SIG_IGN)
- if not os.path.exists(CERT_FILE) or not os.path.exists(KEY_FILE):
- write_log(None, "SISTEMA", f"⚠️ ADVERTENCIA: No se encontraron los certificados en {CERT_FILE}. TLS fallará.")
- write_log(None, "SISTEMA", "=========================================================")
- write_log(None, "SISTEMA", "🚀 PROXY DUAL PYTHON INICIADO (Ultimate Edition)")
- write_log(None, "SISTEMA", "🛡️ IPv4/IPv6 Dual-Stack | Anti-Flood RAM | Fake Web Nginx")
- write_log(None, "SISTEMA", "=========================================================")
- # Lanzar servidor TCP (Puerto 80)
- t_tcp = threading.Thread(target=server_listener, args=(PORT_TCP, False))
- t_tcp.daemon = True
- t_tcp.start()
- # Lanzar servidor TLS (Puerto 443)
- t_tls = threading.Thread(target=server_listener, args=(PORT_TLS, True))
- t_tls.daemon = True
- t_tls.start()
- # Mantener el script vivo infinitamente
- try:
- while True:
- time.sleep(86400)
- except KeyboardInterrupt:
- write_log(None, "SISTEMA", "Apagando el servidor Proxy Dual...")
- sys.exit(0)
|