Proxy3.py 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. # -*- coding: utf-8 -*-
  2. # ==============================================================================
  3. # SCRIPT DE PROXY MULTIFILAMENTADO CON RESPUESTAS ROTATIVAS
  4. #
  5. # - Basado en la versión robusta y estable.
  6. # - Añade rotación dinámica del mensaje de estado en la respuesta HTTP 101.
  7. # - Utiliza un iterador cíclico para cambiar el mensaje en cada nueva conexión.
  8. #
  9. # Creado por Gemini
  10. # ==============================================================================
  11. #screen -dmS badvpn2 /bin/badvpn-udpgw --listen-addr 127.0.0.1:7300 --max-clients 1000 --max-connections-for-client 100
  12. #screen -dmS pydic-80 python3 /etc/VPS-MX/protocolo/Pythonv1.py 8080
  13. import socket
  14. import threading
  15. import select
  16. import sys
  17. import time
  18. import os
  19. import logging
  20. import logging.handlers
  21. import itertools # 💡 Importado para la rotación de mensajes
  22. # ==============================================================================
  23. # CONFIGURACIÓN GLOBAL Y SETUP DE LOGGING
  24. # ==============================================================================
  25. IPV4_ADDR = '0.0.0.0'
  26. IPV6_ADDR = '::'
  27. if sys.argv[1:]:
  28. LISTENING_PORT = int(sys.argv[1])
  29. else:
  30. LISTENING_PORT = 8080
  31. PASS = ''
  32. PRIORITIZE_IPV4 = True
  33. CONNECTION_COOLDOWN_TIME = 10
  34. MAX_CONNECTIONS = 1000
  35. # Constantes de red
  36. BUFLEN = 4096 * 4
  37. TIMEOUT = 60
  38. DEFAULT_HOST = '127.0.0.1:223'
  39. # 💡 LISTA DE MENSAJES PARA ROTAR
  40. # Puedes añadir todos los que quieras aquí.
  41. MENSAJES_ROTATIVOS = [
  42. "Pfsense",
  43. "OPNsense",
  44. "VyOS",
  45. "TNSR"
  46. ]
  47. # Creamos un iterador infinito que rota sobre la lista anterior
  48. mensaje_iterator = itertools.cycle(MENSAJES_ROTATIVOS)
  49. # Lock para asegurar que la extracción del siguiente mensaje sea segura entre hilos
  50. iterator_lock = threading.Lock()
  51. # Configuración del log
  52. LOG_FILE = '/root/proxy.log'
  53. MAX_LOG_SIZE = 5 * 1024 * 1024
  54. BACKUP_COUNT = 5
  55. def setup_logging():
  56. log_format = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
  57. file_handler = logging.handlers.RotatingFileHandler(LOG_FILE, maxBytes=MAX_LOG_SIZE, backupCount=BACKUP_COUNT)
  58. file_handler.setFormatter(log_format)
  59. console_handler = logging.StreamHandler()
  60. console_handler.setFormatter(log_format)
  61. logger = logging.getLogger()
  62. logger.setLevel(logging.INFO)
  63. logger.addHandler(file_handler)
  64. logger.addHandler(console_handler)
  65. return logger
  66. logger = setup_logging()
  67. last_connection_times = {}
  68. last_connection_lock = threading.Lock()
  69. connection_limit_semaphore = threading.Semaphore(MAX_CONNECTIONS)
  70. # ==============================================================================
  71. # CLASE DEL SERVIDOR
  72. # ==============================================================================
  73. class Server(threading.Thread):
  74. def __init__(self, port):
  75. super().__init__()
  76. self.running = False
  77. self.port = port
  78. self.threads = []
  79. self.threads_lock = threading.Lock()
  80. self.ipv4_socket = None
  81. self.ipv6_socket = None
  82. def run(self):
  83. logger.info("\n:-------PythonProxy-------:\n")
  84. logger.info(f"Listening port: {self.port}")
  85. logger.info(f"Mensajes configurados: {len(MENSAJES_ROTATIVOS)}\n")
  86. logger.info(":-------------------------:\n")
  87. try:
  88. self.ipv4_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  89. self.ipv4_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  90. self.ipv4_socket.bind((IPV4_ADDR, self.port))
  91. self.ipv4_socket.listen(0)
  92. except socket.error as e:
  93. logger.error(f"Error IPv4: {e}")
  94. self.ipv4_socket = None
  95. try:
  96. self.ipv6_socket = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
  97. self.ipv6_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  98. self.ipv6_socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)
  99. self.ipv6_socket.bind((IPV6_ADDR, self.port, 0, 0))
  100. self.ipv6_socket.listen(0)
  101. except socket.error as e:
  102. logger.error(f"Error IPv6: {e}")
  103. self.ipv6_socket = None
  104. if not self.ipv4_socket and not self.ipv6_socket:
  105. return
  106. self.running = True
  107. active_sockets = [s for s in [self.ipv4_socket, self.ipv6_socket] if s]
  108. try:
  109. while self.running:
  110. readable, _, _ = select.select(active_sockets, [], [], 2)
  111. for sock in readable:
  112. c, addr = sock.accept()
  113. client_ip = addr[0]
  114. current_time = time.time()
  115. with last_connection_lock:
  116. last_time = last_connection_times.get(client_ip, 0)
  117. if current_time - last_time < CONNECTION_COOLDOWN_TIME:
  118. c.close()
  119. continue
  120. last_connection_times[client_ip] = current_time
  121. if not connection_limit_semaphore.acquire(timeout=0):
  122. c.close()
  123. continue
  124. c.setblocking(1)
  125. conn = ConnectionHandler(c, self, addr)
  126. conn.start()
  127. self.add_conn(conn)
  128. except Exception as e:
  129. logger.error(f"Error servidor: {e}")
  130. finally:
  131. self.running = False
  132. def add_conn(self, conn):
  133. with self.threads_lock:
  134. if self.running: self.threads.append(conn)
  135. def remove_conn(self, conn):
  136. with self.threads_lock:
  137. if conn in self.threads: self.threads.remove(conn)
  138. def close(self):
  139. self.running = False
  140. with self.threads_lock:
  141. for c in list(self.threads): c.close()
  142. # ==============================================================================
  143. # CLASE MANEJADORA DE CONEXIONES
  144. # ==============================================================================
  145. class ConnectionHandler(threading.Thread):
  146. def __init__(self, client_socket, server, addr):
  147. super().__init__()
  148. self.client = client_socket
  149. self.server = server
  150. self.addr = addr
  151. self.log_prefix = f"{addr[0]}:{addr[1]}"
  152. self.target = None
  153. self.client_closed = False
  154. self.target_closed = True
  155. def close(self):
  156. try:
  157. if not self.client_closed:
  158. self.client.close()
  159. except: pass
  160. finally: self.client_closed = True
  161. try:
  162. if not self.target_closed:
  163. self.target.close()
  164. except: pass
  165. finally: self.target_closed = True
  166. connection_limit_semaphore.release()
  167. def run(self):
  168. try:
  169. data = self.client.recv(BUFLEN)
  170. if not data: return
  171. headers = data.decode('latin-1')
  172. host_port = self.find_header(headers, 'X-Real-Host') or DEFAULT_HOST
  173. # 💡 Lógica de rotación: obtenemos el siguiente mensaje de la lista
  174. with iterator_lock:
  175. mensaje_actual = next(mensaje_iterator)
  176. # Construimos la respuesta HTTP dinámica
  177. response_dinamica = f"HTTP/1.1 101 {mensaje_actual}\r\nConnection: Upgrade\r\nUpgrade: websocket\r\n\r\n".encode()
  178. logger.info(f"[{self.log_prefix}] Usando mensaje: '{mensaje_actual}'")
  179. self.connect_target(host_port)
  180. self.client.sendall(response_dinamica)
  181. self.do_tunnel()
  182. except Exception as e:
  183. logger.error(f"Error en {self.log_prefix}: {e}")
  184. finally:
  185. self.close()
  186. self.server.remove_conn(self)
  187. def find_header(self, head, header):
  188. aux = head.find(header + ': ')
  189. if aux == -1: return ''
  190. head = head[aux + len(header) + 2:]
  191. aux = head.find('\r\n')
  192. return head[:aux]
  193. def connect_target(self, host_port):
  194. i = host_port.find(':')
  195. host = host_port[:i] if i != -1 else host_port
  196. port = int(host_port[i+1:]) if i != -1 else 22
  197. addr_info = socket.getaddrinfo(host, port, socket.AF_UNSPEC, socket.SOCK_STREAM)
  198. for res in addr_info:
  199. af, socktype, proto, _, sa = res
  200. try:
  201. self.target = socket.socket(af, socktype, proto)
  202. self.target.connect(sa)
  203. self.target_closed = False
  204. return
  205. except:
  206. if self.target: self.target.close()
  207. raise RuntimeError("No se pudo conectar al destino")
  208. def do_tunnel(self):
  209. socs = [self.client, self.target]
  210. while True:
  211. readable, _, _ = select.select(socs, [], [], TIMEOUT)
  212. if not readable: break
  213. for sock in readable:
  214. data = sock.recv(BUFLEN)
  215. if not data: return
  216. if sock is self.target:
  217. self.client.send(data)
  218. else:
  219. self.target.sendall(data)
  220. def main():
  221. server = Server(LISTENING_PORT)
  222. server.start()
  223. try:
  224. while True: time.sleep(2)
  225. except KeyboardInterrupt:
  226. server.close()
  227. if __name__ == '__main__':
  228. main()