From eaa9ea35a830f47a3bd65684e74cdc455e5a0d01 Mon Sep 17 00:00:00 2001 From: Sasha Romijn Date: Wed, 3 Apr 2024 13:25:50 +0200 Subject: [PATCH] Fix #1376 - Initialise ub_ctx in views on usage, not import --- interface/views/connection.py | 4 +++- interface/views/shared.py | 44 ++++++++++++++++++++++++----------- 2 files changed, 33 insertions(+), 15 deletions(-) diff --git a/interface/views/connection.py b/interface/views/connection.py index 52c115eaa..03f7955d8 100644 --- a/interface/views/connection.py +++ b/interface/views/connection.py @@ -19,7 +19,7 @@ from checks.scoring import STATUS_FAIL, STATUS_INFO, STATUS_NOT_TESTED, STATUS_NOTICE, STATUS_SUCCESS from checks.tasks.routing import TeamCymruIPtoASN, BGPSourceUnavailableError from interface import redis_id -from interface.views.shared import get_client_ip, get_javascript_retries, ub_ctx +from interface.views.shared import get_client_ip, get_javascript_retries, get_ub_ctx probe_ipv6 = Probe("ipv6", "conn", scorename="ipv6", nourl=True, maxscore=100) probe_resolver = Probe("resolver", "conn", scorename="dnssec", nourl=True, maxscore=100, reportfield="reportdnssec") @@ -354,6 +354,7 @@ def find_AS_by_IP(ip): :returns: AS number or None on error """ + ub_ctx = get_ub_ctx() try: asns_prefixes = TeamCymruIPtoASN.asn_prefix_pairs_for_ip(None, ip) (asn, _) = asns_prefixes[0] @@ -407,6 +408,7 @@ def unbound_ptr(qname): Return the PTR records for `qname` from unbound. """ + ub_ctx = get_ub_ctx() status, result = ub_ctx.resolve(qname, unbound.RR_TYPE_PTR, unbound.RR_CLASS_IN) if status == 0 and result.havedata: return result.data.domain_list diff --git a/interface/views/shared.py b/interface/views/shared.py index d6e26bb76..89956c441 100644 --- a/interface/views/shared.py +++ b/interface/views/shared.py @@ -28,24 +28,38 @@ from statshog.defaults.django import statsd -ub_ctx = unbound.ub_ctx() -ub_ctx.set_fwd(settings.IPV4_IP_RESOLVER_INTERNAL_PERMISSIVE) +_ub_ctx = None -if settings.INTEGRATION_TESTS: - # forward the .test zone used in integration tests - ub_ctx.zone_add("test.", "transparent") -if settings.DEBUG_LOG_UNBOUND: - ub_ctx.set_option("log-queries:", "yes") - ub_ctx.set_option("verbosity:", "2") +def get_ub_ctx(): + """ + Wrapper around ub_ctx initialisation for https://github.com/internetstandards/Internet.nl/issues/1376 + """ + global _ub_ctx + if _ub_ctx: + return _ub_ctx + + _ub_ctx = unbound.ub_ctx() + _ub_ctx.set_fwd(settings.IPV4_IP_RESOLVER_INTERNAL_PERMISSIVE) + + if settings.INTEGRATION_TESTS: + # forward the .test zone used in integration tests + _ub_ctx.zone_add("test.", "transparent") -# XXX: Remove for now; inconsistency with applying settings on celery. -# YYY: Removal caused infinite waiting on pipe to unbound. Added again. -ub_ctx.set_async(True) -ub_ctx.set_option("rrset-roundrobin:", "no") + if settings.DEBUG_LOG_UNBOUND: + _ub_ctx.set_option("log-queries:", "yes") + _ub_ctx.set_option("verbosity:", "2") + + # XXX: Remove for now; inconsistency with applying settings on celery. + # YYY: Removal caused infinite waiting on pipe to unbound. Added again. + _ub_ctx.set_async(True) + _ub_ctx.set_option("rrset-roundrobin:", "no") + + # fire an initial DNS query to start unbound background worker and prevent race conditions that can occur + _ub_ctx.resolve_async("internet.nl", {}, lambda x, y, z: None, unbound.RR_TYPE_A, unbound.RR_CLASS_IN) + + return _ub_ctx -# fire an initial DNS query to start unbound background worker and prevent race conditions that can occur -ub_ctx.resolve_async("internet.nl", {}, lambda x, y, z: None, unbound.RR_TYPE_A, unbound.RR_CLASS_IN) # See: https://stackoverflow.com/a/53875771 for a good summary of the various # RFCs and other rulings that combine to define what is a valid domain name. @@ -286,6 +300,8 @@ def get_retest_time(report): @statsd.timer("ub_resolve_with_timeout") def ub_resolve_with_timeout(qname, qtype, rr_class, timeout): + ub_ctx = get_ub_ctx() + def ub_callback(data, status, result): if status == 0 and result.havedata: data["data"] = result.data