Networking Tutorial · Core Protocols · Lesson 11 of 28

DNS

How a name like www.example.com becomes an IP address: resolvers, the DNS hierarchy, caching and TTLs.

Create a free account to save this page, take notes and track your progress. Sign in

What DNS does

DNS (Domain Name System) maps names to addresses and other data. It is a distributed database: no single server knows every name.

How a lookup works

  1. Your app asks the operating system, which asks a recursive resolver (your provider's, the cloud's, or a public one such as 1.1.1.1 or 8.8.8.8).
  2. If the answer isn't cached, the resolver asks a root server where .com lives,
  3. then a .com TLD server where example.com lives,
  4. then example.com's authoritative name server, which returns the record.
  5. The resolver caches the answer for its TTL (time to live) and returns it.
A recursive lookup, step by stepTry it yourself
ZONES = {
    ".": {"com.": "a.gtld-servers.net"},
    "com.": {"example.com.": "ns1.example-dns.net"},
    "example.com.": {"www.example.com.": ("A", "93.184.215.14", 3600)},
}

def resolve(name):
    zone = "."
    for step in ["root", "TLD", "authoritative"]:
        answer = next(v for k, v in ZONES[zone].items() if name.endswith(k))
        print(f"ask {step:13} ({zone:12}) -> {answer}")
        if isinstance(answer, tuple):
            return answer
        zone = next(k for k in ZONES[zone] if name.endswith(k))

print("answer:", resolve("www.example.com."))

Output

ask root          (.           ) -> a.gtld-servers.net
ask TLD           (com.        ) -> ns1.example-dns.net
ask authoritative (example.com.) -> ('A', '93.184.215.14', 3600)
answer: ('A', '93.184.215.14', 3600)

TTL and caching

Every record has a TTL in seconds. Caching makes DNS fast, but it also means a change you make isn't seen everywhere until old cached copies expire. Before a migration, lower the TTL (for example to 60 s) at least one old-TTL period in advance.

TTL caching delays changesTry it yourself
cache = {}

def lookup(name, now, records):
    hit = cache.get(name)
    if hit and hit["expires"] > now:
        return hit["ip"], "cached"
    ip, ttl = records[name]
    cache[name] = {"ip": ip, "expires": now + ttl}
    return ip, "fresh"

records = {"api.shop.example": ("10.0.1.10", 300)}
print("t=0  ", lookup("api.shop.example", 0, records))
records["api.shop.example"] = ("10.0.9.99", 300)          # we migrate the server
print("t=120", lookup("api.shop.example", 120, records), "<- old address until the TTL expires")
print("t=301", lookup("api.shop.example", 301, records))

Output

t=0   ('10.0.1.10', 'fresh')
t=120 ('10.0.1.10', 'cached') <- old address until the TTL expires
t=301 ('10.0.9.99', 'fresh')

Try it

$ dig +short www.example.com
93.184.215.14
$ dig www.example.com +trace     # follow the lookup from the root servers
$ nslookup www.example.com       # also available on Windows

Applications cache too: the JVM, some HTTP clients and connection pools may keep using an old address long after the DNS TTL expired.

Test yourself

You will move a site to a new IP. The A record's TTL is 86400 (one day). What should you do first?

  1. Lower the TTL a day or more before the move
  2. Change the IP and restart the DNS server
  3. Set the TTL to 0 at the moment of the move
  4. Nothing; DNS changes are instant
Show answer

Answer: Lower the TTL a day or more before the move

Caches keep the old record for up to the old TTL. Lower it in advance so that, at cut-over time, caches expire within minutes.

Was this page helpful?