diff --git a/Fix-use-dedicated-kdcproxy-logger.patch b/Fix-use-dedicated-kdcproxy-logger.patch new file mode 100644 index 0000000000000000000000000000000000000000..2e41fa88234ae122709c857e2b219ae6d270b21d --- /dev/null +++ b/Fix-use-dedicated-kdcproxy-logger.patch @@ -0,0 +1,69 @@ +From c7d7ea970d073a6653a3401bc19ae0f453fe4b19 Mon Dec 17 00:00:00 2001 +From: zhuhongbo +Date: Mon, 30 Dec 2024 15:24:27 +0800 +Subject: [PATCH] fix use dedicated kdcproxy logger + +--- + kdcproxy/__init__.py | 7 +++++-- + kdcproxy/config/__init__.py | 7 +++++-- + 2 files changed, 10 insertions(+), 4 deletions(-) + +diff --git a/kdcproxy/__init__.py b/kdcproxy/__init__.py +index 9e33bfb..c30df87 100644 +--- a/kdcproxy/__init__.py ++++ b/kdcproxy/__init__.py +@@ -37,6 +37,9 @@ except ImportError: # Python 2.x + import kdcproxy.codec as codec + from kdcproxy.config import MetaResolver + ++logging.basicConfig() ++logger = logging.getLogger('kdcproxy') ++ + + class HTTPException(Exception): + +@@ -322,8 +325,8 @@ class Application: + fail_socktype = self.addr2socktypename(fail_addr) + fail_ip = fail_addr[4][0] + fail_port = fail_addr[4][1] +- logging.warning("Exchange with %s:[%s]:%d failed: %s", +- fail_socktype, fail_ip, fail_port, e) ++ logger.warning("Exchange with %s:[%s]:%d failed: %s", ++ fail_socktype, fail_ip, fail_port, e) + if reply is not None: + break + +diff --git a/kdcproxy/config/__init__.py b/kdcproxy/config/__init__.py +index 5bff159..93af69a 100644 +--- a/kdcproxy/config/__init__.py ++++ b/kdcproxy/config/__init__.py +@@ -32,6 +32,9 @@ except ImportError: # Python 2.x + import dns.rdatatype + import dns.resolver + ++logging.basicConfig() ++logger = logging.getLogger('kdcproxy') ++ + + class IResolver(object): + +@@ -60,14 +63,14 @@ class KDCProxyConfig(IConfig): + try: + self.__cp.read(filename) + except configparser.Error: +- logging.error("Unable to read config file: %s", filename) ++ logger.error("Unable to read config file: %s", filename) + + try: + mod = self.__cp.get(self.GLOBAL, "configs") + try: + importlib.import_module("kdcproxy.config." + mod) + except ImportError as e: +- logging.log(logging.ERROR, "Error reading config: %s" % e) ++ logger.log(logging.ERROR, "Error reading config: %s" % e) + except configparser.Error: + pass + +-- +2.46.0 + diff --git a/Fix-use-exponential-backoff.patch b/Fix-use-exponential-backoff.patch new file mode 100644 index 0000000000000000000000000000000000000000..e9e32c934e826da514419a8898e1464c78e8c146 --- /dev/null +++ b/Fix-use-exponential-backoff.patch @@ -0,0 +1,147 @@ +From c7d7ea970d073a6653a3401bc19ae0f453fe4b19 Mon Dec 17 00:00:00 2001 +From: zhuhongbo +Date: Mon, 30 Dec 2024 15:24:27 +0800 +Subject: [PATCH] fix use exponential backoff + +--- + kdcproxy/__init__.py | 63 +++++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 60 insertions(+), 3 deletions(-) + +diff --git a/kdcproxy/__init__.py b/kdcproxy/__init__.py +index 67680c5..9e33bfb 100644 +--- a/kdcproxy/__init__.py ++++ b/kdcproxy/__init__.py +@@ -60,6 +60,13 @@ class HTTPException(Exception): + return "%d %s" % (self.code, httplib.responses[self.code]) + + ++class SocketException(Exception): ++ ++ def __init__(self, message, sock): ++ super(Exception, self).__init__(message) ++ self.sockfno = sock.fileno() ++ ++ + class Application: + MAX_LENGTH = 128 * 1024 + SOCKTYPES = { +@@ -67,10 +74,23 @@ class Application: + "udp": socket.SOCK_DGRAM, + } + ++ def addr2socktypename(self, addr): ++ ret = None ++ for name in self.SOCKTYPES: ++ if self.SOCKTYPES[name] == addr[1]: ++ ret = name ++ break ++ return ret ++ + def __init__(self): + self.__resolver = MetaResolver() + + def __await_reply(self, pr, rsocks, wsocks, timeout): ++ starting_time = time.time() ++ send_error = None ++ recv_error = None ++ failing_sock = None ++ reactivations = {} + extra = 0 + read_buffers = {} + while (timeout + extra) > time.time(): +@@ -91,6 +111,12 @@ class Application: + pass + + for sock in w: ++ # Fetch reactivation tuple: ++ # 1st element: reactivation index (-1 = first activation) ++ # 2nd element: planned reactivation time (0.0 = now) ++ (rn, rt) = reactivations.get(sock, (-1, 0.0)) ++ if rt > time.time(): ++ continue + try: + if self.sock_type(sock) == socket.SOCK_DGRAM: + # If we proxy over UDP, remove the 4-byte length +@@ -100,8 +126,13 @@ class Application: + sock.sendall(pr.request) + extra = 10 # New connections get 10 extra seconds + except Exception as e: +- logging.warning("Conection broken while writing (%s)", e) ++ send_error = e ++ failing_sock = sock ++ reactivations[sock] = (rn + 1, ++ time.time() + 2.0**(rn + 1) / 10) + continue ++ if sock in reactivations: ++ del reactivations[sock] + rsocks.append(sock) + wsocks.remove(sock) + +@@ -109,7 +140,8 @@ class Application: + try: + reply = self.__handle_recv(sock, read_buffers) + except Exception as e: +- logging.warning("Connection broken while reading (%s)", e) ++ recv_error = e ++ failing_sock = sock + if self.sock_type(sock) == socket.SOCK_STREAM: + # Remove broken TCP socket from readers + rsocks.remove(sock) +@@ -117,6 +149,21 @@ class Application: + if reply is not None: + return reply + ++ if reactivations: ++ raise SocketException("Timeout while sending packets after %.2fs " ++ "and %d tries: %s" % ( ++ (timeout + extra) - starting_time, ++ sum(map(lambda r: r[0], ++ reactivations.values())), ++ send_error), ++ failing_sock) ++ elif recv_error is not None: ++ raise SocketException("Timeout while receiving packets after " ++ "%.2fs: %s" % ( ++ (timeout + extra) - starting_time, ++ recv_error), ++ failing_sock) ++ + return None + + def __handle_recv(self, sock, read_buffers): +@@ -211,6 +258,7 @@ class Application: + reply = None + wsocks = [] + rsocks = [] ++ sockfno2addr = {} + for server in map(urlparse.urlparse, servers): + # Enforce valid, supported URIs + scheme = server.scheme.lower().split("+", 1) +@@ -256,6 +304,7 @@ class Application: + continue + except io.BlockingIOError: + pass ++ sockfno2addr[sock.fileno()] = addr + wsocks.append(sock) + + # Resend packets to UDP servers +@@ -266,7 +315,15 @@ class Application: + + # Call select() + timeout = time.time() + (15 if addr is None else 2) +- reply = self.__await_reply(pr, rsocks, wsocks, timeout) ++ try: ++ reply = self.__await_reply(pr, rsocks, wsocks, timeout) ++ except SocketException as e: ++ fail_addr = sockfno2addr[e.sockfno] ++ fail_socktype = self.addr2socktypename(fail_addr) ++ fail_ip = fail_addr[4][0] ++ fail_port = fail_addr[4][1] ++ logging.warning("Exchange with %s:[%s]:%d failed: %s", ++ fail_socktype, fail_ip, fail_port, e) + if reply is not None: + break + +-- +2.46.0 + diff --git a/python-kdcproxy.spec b/python-kdcproxy.spec index 16fdbc1f0e2d9fa1d84b1ebff1c6bbeb63b41f71..c951cc5e93ffba2d032255242f914af6f419d47b 100644 --- a/python-kdcproxy.spec +++ b/python-kdcproxy.spec @@ -1,8 +1,9 @@ %global realname kdcproxy +%global __python /usr/bin/python2 Name: python-%{realname} Version: 0.3.2 -Release: 3%{?dist} +Release: 3%{?dist}.1 Summary: MS-KKDCP (kerberos proxy) WSGI module License: MIT @@ -14,6 +15,8 @@ BuildRequires: python2-devel Patch0: Downgrade-socket-problems-to-warnings.patch Patch1: Always-buffer-TCP-data-in-__handle_recv.patch +Patch2: Fix-use-exponential-backoff.patch +Patch3: Fix-use-dedicated-kdcproxy-logger.patch %if 0%{?rhel} == 0 BuildRequires: python-tox @@ -57,6 +60,8 @@ minimal configuration. %setup -q -n %{realname}-%{version} %patch0 -p1 -b .Downgrade-socket-problems-to-warnings %patch1 -p1 -b .Always-buffer-TCP-data-in-__handle_recv +%patch2 -p1 -b .Fix-use-exponential-backoff +%patch3 -p1 -b .Fix-use-dedicated-kdcproxy-logger %build %{__python} setup.py build @@ -89,6 +94,9 @@ tox --sitepackages -e py27,py34 %endif %changelog +* Mon Dec 30 2024 zhuhongbo - 0.3.2-3.1 +- fix: Fix use exponential backoff + * Tue Sep 03 2019 Robbie Harwood - 0.3.2-3 - Always buffer TCP data in __handle_recv() - Resolves: #1746107