"""DNS-Propagationslogik: nicht erreichbare Nameserver (z.B. IPv6 ohne IPv6) fliegen raus.""" import pathlib import sys sys.path.insert(0, str(pathlib.Path(__file__).resolve().parent.parent)) from app import dnsutil V4A, V4B, V6 = "37.157.254.21", "5.199.143.173", "2001:4ba0:cafe:918::1" NAME = "_acme-challenge.endian.fon-aria.de" WANTED = {"value-a", "value-b"} dnsutil.time.sleep = lambda _s: None # keine echten Wartezeiten im Test # ---- reachable() ---------------------------------------------------------- assert dnsutil.reachable("127.0.0.1") is True assert dnsutil.reachable("not-an-ip") is False print("reachable ok") # ---- authoritative_servers() filtert unerreichbare Adressen --------------- dnsutil.reachable = lambda ip: ":" not in ip # so tut ein Host ohne IPv6 resolved = {"ns1.fon-aria.de": [V4A, V6], "ns2.fon-aria.de": [V4B]} class FakeAnswer(list): pass class FakeResolver: def __init__(self, *a, **kw): self.nameservers = [] self.lifetime = self.timeout = 5 def resolve(self, qname, rtype, raise_on_no_answer=False): qname = str(qname).rstrip(".") if rtype == "NS": return FakeAnswer([type("R", (), {"target": n + "."})() for n in resolved]) if rtype == "A": return FakeAnswer([ip for ip in resolved.get(qname, []) if ":" not in ip]) if rtype == "AAAA": return FakeAnswer([ip for ip in resolved.get(qname, []) if ":" in ip]) return FakeAnswer() dnsutil.dns.resolver.Resolver = FakeResolver servers = dnsutil.authoritative_servers("fon-aria.de", ["1.1.1.1"]) assert servers == [V4A, V4B], servers print("authoritative_servers ok:", servers) # ---- wait_for_txt: der tote Server darf das Ergebnis nicht blockieren ----- calls = [] def fake_txt(name, server): calls.append(server) if server == V6: return None # kein Weg dorthin return set(WANTED) # beide Werte da dnsutil.txt_values = fake_txt assert dnsutil.wait_for_txt({NAME: WANTED}, [V4A, V6, V4B], timeout=30, interval=1) is True assert V6 in calls and calls.count(V6) == 1, calls # genau einmal probiert, dann verworfen print("wait_for_txt ignoriert toten Nameserver ok") # alle tot -> sauberes False statt Absturz dnsutil.txt_values = lambda name, server: None assert dnsutil.wait_for_txt({NAME: WANTED}, [V6], timeout=30, interval=1) is False # Wert fehlt auf einem Server -> Timeout, kein Haenger state = {"n": 0} def slowly(name, server): state["n"] += 1 return set(WANTED) if state["n"] > 3 else {"value-a"} dnsutil.txt_values = slowly assert dnsutil.wait_for_txt({NAME: WANTED}, [V4A], timeout=30, interval=1) is True dnsutil.txt_values = lambda name, server: {"value-a"} assert dnsutil.wait_for_txt({NAME: WANTED}, [V4A], timeout=2, interval=1) is False print("wait_for_txt Timeout-Pfad ok") print("\nALLE DNS-TESTS BESTANDEN")