import socket import select from threading import Thread import time import logging import logging.handlers LOGGER_HOST = "localhost" LOGGER_PORT = 514 CURRENT_THREADS = 0 MAX_THREADS = 10 BACKLOG = 50 class Logger: _instance = None def __init__(self): self.logger = logging.getLogger('PythonProxy') self.logger.setLevel(logging.DEBUG) handler = logging.handlers.SysLogHandler(address = (LOGGER_HOST, LOGGER_PORT)) self.logger.addHandler(handler) self.logger.debug('Initiating Proxy logger!') def log(self, message:str): self.logger.debug(message) print('INFO:', message) def critical(self, message:str): self.logger.critical(message) print('CRITICAL:', message) def __del__(self): self.logger.close() @classmethod def instance(self): if self._instance is None: self._instance = self() return self._instance class Server: def __init__(self, host:str, port:int): self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.bind((host, port)) self.sock.listen(BACKLOG) print(f"Listening at: http://{host}:{port}") def thread_check(self): global CURRENT_THREADS, MAX_THREADS while True: if CURRENT_THREADS >= MAX_THREADS: time.sleep(1) else: return def start(self): global CURRENT_THREADS while True: conn, client_addr = self.sock.accept() self.thread_check() CURRENT_THREADS += 1 thread = Thread(target = connectionHandle, args = (conn, client_addr, )) CURRENT_THREADS -= 1 thread.start() def __del__(self): self.sock.close() def connectionHandle(client_socket, client_address): # print(f"Connection received from {client_address[0]}:{client_address[1]}") request = client_socket.recv(16 * 1024) logger = Logger.instance() if len(request) == 0: client_socket.close() return try: raw_request = request.decode() except UnicodeDecodeError: print("UnicodeDecodeError") client_socket.close() return if "CONNECT" in raw_request: client_socket.sendall(b"HTTP/1.1 200 Connection Established\r\n\r\n") request = client_socket.recv(16 * 1024) request_url = raw_request.split(' ')[1] request_host = "" request_port = 443 if 'https' in request_url else 80 if request_url.startswith('http'): request_host = request_url.split('/')[2] else: request_host = request_url.split('/')[0] if request_host.startswith('www'): request_host = request_host[4:] if ':' in request_host: request_port = int(request_host.split(':')[1]) request_host = request_host.split(':')[0] # print(f"REQUEST [{client_address[0]}:{client_address[1]}] {raw_request}") if "monitorando" in request_url: body = "403 Acesso não autorizado! " client_socket.sendall(b"HTTP/1.1 403 Forbidden\r\n\r\n") client_socket.sendall(body.encode()) client_socket.close() return # forward the request to the destination server # print(f"Forwarding request to {request_host}:{request_port}") destination_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) destination_socket.connect((request_host, request_port)) destination_socket.sendall(request) # print(f"Waiting for response from {request_host}:{request_port}") while True: triple = select.select([client_socket, destination_socket], [], [], 20)[0] if not len(triple): break try: if client_socket in triple: data = client_socket.recv(16 * 1024) if not data: break destination_socket.send(data) if destination_socket in triple: data = destination_socket.recv(16 * 1024) if not data: break try: status_code = data.decode().split(' ')[1:] status_code = ' '.join(status_code) logger.log(f"REQUEST [{client_address[0]}:{client_address[1]}] to [{request_host}:{request_port}] - {status_code} ({len(data)} bytes)") except UnicodeDecodeError: pass client_socket.send(data) except ConnectionAbortedError: break # print(f"Closing connection with {request_host}:{request_port} and {client_address[0]}:{client_address[1]}") # close the sockets destination_socket.close() client_socket.close() # print("Connection closed") if __name__ == '__main__': ser = Server(host="0.0.0.0", port=8080) ser.start()