From 968ccdeeda3f258d00b01064bbfd84d612079a11 Mon Sep 17 00:00:00 2001 From: Michal Nowak Date: Thu, 21 May 2026 07:31:15 +0000 Subject: [PATCH] Tolerate dnspython post-2038 timestamp overflow on 32-bit dnspython's RRSIG.to_text() converts the signature inception/expiration fields by calling time.gmtime(), which on 32-bit platforms raises OverflowError for values past 2038-01-19 (INT32_MAX). Several DNSSEC test fixtures use far-future expirations: the precomputed RRSIGs in the dnssec test's rsasha1.example.db.in zone expire in 2093, ans4 of the chain test hardcodes 2090, and ans10 of the dnssec test uses 2**32-1 (year 2106). Whenever a response carrying such an RRSIG is formatted with str()/to_text() the overflow propagates out and either fails the test (when triggered in isctest.query's debug logging) or kills the asyncserver-based ans* server (when triggered in its response logger), which in turn cascades into "Failed to stop servers" teardown errors and SERVFAIL responses for subsequent tests. Wrap the to_text() calls in isctest/query.py and the str(response) call in asyncserver's _log_response() with try/except OverflowError, falling back to a placeholder message. The conversions are only used for debug logging, so losing the human-readable form there does not affect what the tests actually validate. Assisted-by: Claude:claude-opus-4-7 --- bin/tests/system/isctest/asyncserver.py | 6 +++++- bin/tests/system/isctest/query.py | 15 +++++++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/bin/tests/system/isctest/asyncserver.py b/bin/tests/system/isctest/asyncserver.py index dd9f623916..fefd03bb27 100644 --- a/bin/tests/system/isctest/asyncserver.py +++ b/bin/tests/system/isctest/asyncserver.py @@ -1375,8 +1375,12 @@ class AsyncDnsServer(AsyncServer): qctx.socket, qctx.protocol.name, ) + try: + response_text = str(response) + except OverflowError: + response_text = "" logging.debug( - "\n".join([f"[OUT] {l}" for l in [""] + str(response).splitlines()]) + "\n".join([f"[OUT] {l}" for l in [""] + response_text.splitlines()]) ) return diff --git a/bin/tests/system/isctest/query.py b/bin/tests/system/isctest/query.py index a7e862b7f6..650c1fc637 100644 --- a/bin/tests/system/isctest/query.py +++ b/bin/tests/system/isctest/query.py @@ -44,6 +44,17 @@ def generic_query( log_response: bool = True, ) -> Any: + def _safe_to_text(msg: dns.message.Message) -> str: + """ + Convert a DNS message to text, tolerating dnspython's failure to render + RRSIG inception/expiration timestamps that overflow the platform's + time_t (e.g. post-2038 values on 32-bit systems). + """ + try: + return msg.to_text() + except OverflowError: + return "" + def log_querymsg(exception: Exception | None = None) -> None: """ Helper for logging query message. Call this *after* query_func() has @@ -54,7 +65,7 @@ def generic_query( nonlocal log_query if log_query: isctest.log.debug( - f"isc.query.{query_func.__name__}(): query\n{message.to_text()}" + f"isc.query.{query_func.__name__}(): query\n{_safe_to_text(message)}" ) log_query = False # only log query once @@ -99,7 +110,7 @@ def generic_query( if res: if log_response: isctest.log.debug( - f"isc.query.{query_func.__name__}(): response\n{res.to_text()}" + f"isc.query.{query_func.__name__}(): response\n{_safe_to_text(res)}" ) if res.rcode() == expected_rcode or expected_rcode is None: return res