#!/usr/bin/env python3 import os import selectors import signal import socket import sys LISTEN_HOST = os.getenv("LISTEN_HOST", "127.0.0.1") LISTEN_PORT = int(os.getenv("LISTEN_PORT", "6380")) REDIS_HOST = os.getenv("REDIS_HOST", "100.90.90.91") REDIS_PORT = int(os.getenv("REDIS_PORT", "6379")) REDIS_USER = os.getenv("REDIS_USER", "lisglosips") CONNECT_TIMEOUT = float(os.getenv("CONNECT_TIMEOUT", "2.0")) def credential(name: str) -> str: cred_dir = os.getenv("CREDENTIALS_DIRECTORY") if not cred_dir: raise RuntimeError("CREDENTIALS_DIRECTORY is not set") path = os.path.join(cred_dir, name) with open(path, "r", encoding="utf-8") as handle: return handle.read().strip() def resp_array(parts: list[str]) -> bytes: output = f"*{len(parts)}\r\n".encode("utf-8") for part in parts: data = part.encode("utf-8") output += f"${len(data)}\r\n".encode("utf-8") + data + b"\r\n" return output def read_line(sock: socket.socket) -> bytes: data = b"" while not data.endswith(b"\r\n"): chunk = sock.recv(1) if not chunk: break data += chunk if len(data) > 4096: break return data def connect_upstream() -> socket.socket: password = credential("redis_password") upstream = socket.create_connection((REDIS_HOST, REDIS_PORT), timeout=CONNECT_TIMEOUT) upstream.sendall(resp_array(["AUTH", REDIS_USER, password])) reply = read_line(upstream) if not reply.startswith(b"+OK"): upstream.close() raise RuntimeError("Redis AUTH failed") upstream.setblocking(False) return upstream def bridge(client: socket.socket) -> None: upstream = connect_upstream() client.setblocking(False) selector = selectors.DefaultSelector() selector.register(client, selectors.EVENT_READ, upstream) selector.register(upstream, selectors.EVENT_READ, client) try: while True: for key, _ in selector.select(timeout=30): src = key.fileobj dst = key.data data = src.recv(65536) if not data: return dst.sendall(data) finally: selector.close() client.close() upstream.close() def main() -> int: signal.signal(signal.SIGCHLD, signal.SIG_IGN) server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server.bind((LISTEN_HOST, LISTEN_PORT)) server.listen(128) print(f"lisglosips redis auth proxy listening on {LISTEN_HOST}:{LISTEN_PORT}", flush=True) while True: client, _ = server.accept() pid = os.fork() if pid == 0: server.close() try: bridge(client) except Exception as exc: print(f"redis proxy client failed: {exc}", file=sys.stderr, flush=True) return 0 client.close() if __name__ == "__main__": raise SystemExit(main())