A CNAME is an alias: www.example.com β example.com. Resolvers chase the chain until they reach an A record. But a misconfigured zone can loop (a β b β a), so you must detect that and give up.
Refactor into _lookup(name, seen) that returns a list of A values for a name, following CNAMEs, tracking visited names to break loops. resolve(name) returns the first of those values (or None).
import time
class DNSResolver:
def __init__(self, zone=None, clock=time.time):
self.zone = zone if zone is not None else {}
self.clock = clock
def _lookup(self, name, seen=None):
"""Return the list of A values for name, following CNAMEs; [] if none/loop."""
seen = seen or set()
if name in seen:
return [] # loop guard
seen.add(name)
records = self.zone.get(name, [])
a_values = [r["value"] for r in records if r["type"] == "A"]
if a_values:
return a_values
# TODO: no A records here, if there's a CNAME, follow it:
# for r in records:
# if r["type"] == "CNAME":
# return self._lookup(r["value"], seen)
# return []
pass
def resolve(self, name):
values = self._lookup(name)
return values[0] if values else None
The editor and the test runner need a wide screen. Open this page on a desktop browser and your progress will be waiting.
A CNAME is an alias: www.example.com β example.com. Resolvers chase the chain until they reach an A record. But a misconfigured zone can loop (a β b β a), so you must detect that and give up.
Refactor into _lookup(name, seen) that returns a list of A values for a name, following CNAMEs, tracking visited names to break loops. resolve(name) returns the first of those values (or None).
Press Run Tests or ββ© to check your solution.