yosoyhendrix 3 дней назад
Родитель
Сommit
6ff50bbce5
1 измененных файлов с 309 добавлено и 0 удалено
  1. 309 0
      proxy_python.2.7.py

+ 309 - 0
proxy_python.2.7.py

@@ -0,0 +1,309 @@
+#!/usr/bin/env python2.7
+# -*- coding: utf-8 -*-
+import socket, threading, thread, select, signal, sys, time, getopt
+
+# ==============================================================================
+# SCRIPT DE PROXY MULTIFILAMENTADO CON SOPORTE PARA IPV4 E IPV6
+# - Solucionado el error "Address already in use" con la opción IPV6_V6ONLY.
+# - Modificado por Gemini.
+# ==============================================================================
+
+# Listen
+# Se usan direcciones específicas para evitar errores de getaddrinfo.
+IPV4_ADDR = '0.0.0.0'
+IPV6_ADDR = '::'
+
+if sys.argv[1:]:
+  LISTENING_PORT = sys.argv[1]
+else:
+  LISTENING_PORT = 80
+#Pass
+PASS = ''
+
+# CONST
+BUFLEN = 4096 * 4
+TIMEOUT = 60
+DEFAULT_HOST = '127.0.0.1:22'
+RESPONSE = 'HTTP/1.1 101 pfSense <strong>nftables 1.1.2</strong>\r\n\r\n'
+
+class Server(threading.Thread):
+    def __init__(self, host, port):
+        threading.Thread.__init__(self)
+        self.running = False
+        self.host = host
+        self.port = port
+        self.threads = []
+        self.threadsLock = threading.Lock()
+        self.logLock = threading.Lock()
+        self.soc = None
+        self.soc_v6 = None
+        
+    def run(self):
+        self.printLog("\n:-------PythonProxy-------:\n")
+        self.printLog("Listening addr: " + IPV4_ADDR + " and " + IPV6_ADDR)
+        self.printLog("Listening port: " + str(self.port) + "\n")
+        self.printLog(":-------------------------:\n")
+
+        # Intentar enlazar a IPv4
+        try:
+            self.soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+            self.soc.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+            self.soc.settimeout(2)
+            self.soc.bind((IPV4_ADDR, int(self.port)))
+            self.soc.listen(0)
+            self.printLog("Esperando conexiones IPv4 en %s:%s" % (IPV4_ADDR, self.port))
+        except socket.error as e:
+            self.printLog("No se pudo enlazar a IPv4 (%s)" % e)
+            if self.soc:
+                self.soc.close()
+            self.soc = None
+
+        # Intentar enlazar a IPv6
+        try:
+            self.soc_v6 = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
+            self.soc_v6.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+            # 💡 SOLUCIÓN: Establecer la opción IPV6_V6ONLY para evitar conflictos con IPv4.
+            # Esto fuerza al socket IPv6 a solo aceptar conexiones IPv6.
+            self.soc_v6.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)
+            self.soc_v6.settimeout(2)
+            self.soc_v6.bind((IPV6_ADDR, int(self.port), 0, 0))
+            self.soc_v6.listen(0)
+            self.printLog("Esperando conexiones IPv6 en %s:%s" % (IPV6_ADDR, self.port))
+        except socket.error as e:
+            self.printLog("No se pudo enlazar a IPv6 (%s)" % e)
+            if self.soc_v6:
+                self.soc_v6.close()
+            self.soc_v6 = None
+
+        if not self.soc and not self.soc_v6:
+            self.printLog("No se pudo iniciar el servidor. Saliendo.")
+            return
+
+        self.running = True
+        
+        active_sockets = []
+        if self.soc:
+            active_sockets.append(self.soc)
+        if self.soc_v6:
+            active_sockets.append(self.soc_v6)
+
+        try:
+            while self.running:
+                try:
+                    readable, _, _ = select.select(active_sockets, [], [], 2)
+                    for sock in readable:
+                        c, addr = sock.accept()
+                        c.setblocking(1)
+                        conn = ConnectionHandler(c, self, addr)
+                        conn.start()
+                        self.addConn(conn)
+                except socket.timeout:
+                    continue
+                except socket.error as e:
+                    if self.running:
+                        self.printLog("Error al aceptar conexión: %s" % e)
+                    continue
+
+        finally:
+            self.running = False
+            if self.soc:
+                self.soc.close()
+            if self.soc_v6:
+                self.soc_v6.close()
+
+    def printLog(self, log):
+        self.logLock.acquire()
+        print log
+        self.logLock.release()
+
+    def addConn(self, conn):
+        try:
+            self.threadsLock.acquire()
+            if self.running:
+                self.threads.append(conn)
+        finally:
+            self.threadsLock.release()
+
+    def removeConn(self, conn):
+        try:
+            self.threadsLock.acquire()
+            self.threads.remove(conn)
+        finally:
+            self.threadsLock.release()
+
+    def close(self):
+        try:
+            self.running = False
+            self.threadsLock.acquire()
+            threads = list(self.threads)
+            for c in threads:
+                c.close()
+        finally:
+            self.threadsLock.release()
+
+class ConnectionHandler(threading.Thread):
+    def __init__(self, socClient, server, addr):
+        threading.Thread.__init__(self)
+        self.clientClosed = False
+        self.targetClosed = True
+        self.client = socClient
+        self.client_buffer = ''
+        self.server = server
+        self.log = 'Connection: ' + str(addr)
+
+    def close(self):
+        try:
+            if not self.clientClosed:
+                self.client.shutdown(socket.SHUT_RDWR)
+                self.client.close()
+        except:
+            pass
+        finally:
+            self.clientClosed = True
+
+        try:
+            if not self.targetClosed:
+                self.target.shutdown(socket.SHUT_RDWR)
+                self.target.close()
+        except:
+            pass
+        finally:
+            self.targetClosed = True
+
+    def run(self):
+        try:
+            self.client_buffer = self.client.recv(BUFLEN)
+            hostPort = self.findHeader(self.client_buffer, 'X-Real-Host')
+            if hostPort == '':
+                hostPort = DEFAULT_HOST
+
+            split = self.findHeader(self.client_buffer, 'X-Split')
+            if split != '':
+                self.client.recv(BUFLEN)
+
+            if hostPort != '':
+                passwd = self.findHeader(self.client_buffer, 'X-Pass')
+                if len(PASS) != 0 and passwd == PASS:
+                    self.method_CONNECT(hostPort)
+                elif len(PASS) != 0 and passwd != PASS:
+                    self.client.send('HTTP/1.1 400 WrongPass!\r\n\r\n')
+                elif hostPort.startswith('127.0.0.1') or hostPort.startswith('localhost'):
+                    self.method_CONNECT(hostPort)
+                else:
+                    self.client.send('HTTP/1.1 403 Forbidden!\r\n\r\n')
+            else:
+                self.server.printLog('- No X-Real-Host!')
+                self.client.send('HTTP/1.1 400 NoXRealHost!\r\n\r\n')
+
+        except Exception as e:
+            self.log += ' - error: ' + str(e)
+            self.server.printLog(self.log)
+            pass
+        finally:
+            self.close()
+            self.server.removeConn(self)
+
+    def findHeader(self, head, header):
+        aux = head.find(header + ': ')
+        if aux == -1:
+            return ''
+
+        aux = head.find(':', aux)
+        head = head[aux+2:]
+        aux = head.find('\r\n')
+
+        if aux == -1:
+            return ''
+        return head[:aux];
+
+    def connect_target(self, host):
+        i = host.find(':')
+        if i != -1:
+            port = int(host[i+1:])
+            host = host[:i]
+        else:
+            if self.method=='CONNECT':
+                port = 22
+            else:
+                port = int(sys.argv[1])
+
+        (soc_family, soc_type, proto, _, address) = socket.getaddrinfo(host, port, socket.AF_UNSPEC, socket.SOCK_STREAM)[0]
+        self.target = socket.socket(soc_family, soc_type, proto)
+        self.targetClosed = False
+        self.target.connect(address)
+
+    def method_CONNECT(self, path):
+        self.log += ' - CONNECT ' + path
+        self.connect_target(path)
+        self.client.sendall(RESPONSE)
+        self.client_buffer = ''
+        self.server.printLog(self.log)
+        self.doCONNECT()
+
+    def doCONNECT(self):
+        socs = [self.client, self.target]
+        count = 0
+        error = False
+        while True:
+            count += 1
+            (recv, _, err) = select.select(socs, [], socs, 3)
+            if err:
+                error = True
+            if recv:
+                for in_ in recv:
+                    try:
+                        data = in_.recv(BUFLEN)
+                        if data:
+                            if in_ is self.target:
+                                self.client.send(data)
+                            else:
+                                while data:
+                                    byte = self.target.send(data)
+                                    data = data[byte:]
+                            count = 0
+                        else:
+                            break
+                    except:
+                        error = True
+                        break
+            if count == TIMEOUT:
+                error = True
+            if error:
+                break
+
+def print_usage():
+    print 'Usage: proxy.py -p <port>'
+    print '       proxy.py -b <bindAddr> -p <port>'
+    print '       proxy.py -b 0.0.0.0 -p 80'
+
+def parse_args(argv):
+    global IPV4_ADDR
+    global IPV6_ADDR
+    global LISTENING_PORT
+    try:
+        opts, args = getopt.getopt(argv,"hb:p:",["bind=","port="])
+    except getopt.GetoptError:
+        print_usage()
+        sys.exit(2)
+    for opt, arg in opts:
+        if opt == '-h':
+            print_usage()
+            sys.exit()
+        elif opt in ("-b", "--bind"):
+            pass
+        elif opt in ("-p", "--port"):
+            LISTENING_PORT = int(arg)
+
+def main(port=LISTENING_PORT):
+    server = Server(None, port)
+    server.start()
+    while True:
+        try:
+            time.sleep(2)
+        except KeyboardInterrupt:
+            print 'Stopping...'
+            server.close()
+            break
+
+if __name__ == '__main__':
+    main()