1Show the Level 1 solution
2**A.**
31. **A** record: `api.example.com → 203.0.113.30`.
42. **CNAME**: `blog.example.com → hosting.blogplatform.net`.
53. Two **MX** records, e.g. priority 10 (main) and 20 (backup). Lower number is preferred.
64. A **TXT** record with the value the console gives you.
75. An **AAAA** record.
8
9**B.**
101. **False.** Nothing is pushed. Resolvers keep the old answer until its TTL expires, so it can take up to the old TTL.
112. **False.** DNS doesn't know a server is dead. Cached answers keep including the dead IP until the TTL runs out, unless a health-checked DNS service removes it (and even then, after the TTL).
123. **False** in standard DNS. The bare domain must hold NS and SOA records, and a CNAME can't share its name with other records. Use your provider's ALIAS or "CNAME flattening" feature, or A records.
Show the Level 2 solution
1. About one query per resolver per TTL: 10,000 ÷ 300 ≈ **33 queries a second**.
2. 60 seconds: 10,000 ÷ 60 ≈ **167 a second**. 1 day: 10,000 ÷ 86,400 ≈ **0.12 a second** (about one every 9 seconds).
3. Empty cache: 10 (user to resolver) + 3 × 30 (root, TLD, authoritative) = **100 ms**. Cached at the resolver: **10 ms**. (Cached in the browser or OS: almost 0.)
4. Up to **24 hours**, the old TTL. Some misbehaving caches may hold it even longer.
1Show the Level 3 solution
2Tested solution (Python 3):
3
4```python
5ROOT = {"com.": "tld-com"}
6SERVERS = {
7 "tld-com": {"example.com.": "ns1.example.com"},
8 "ns1.example.com": {
9 ("A", "example.com."): ("203.0.113.10", 300),
10 ("CNAME", "www.example.com."): ("example.com.", 300),
11 ("A", "shop.example.com."): ("203.0.113.20", 300),
12 },
13}
14
15
16class Resolver:
17 def __init__(self, servers=SERVERS, root=ROOT, negative_ttl=60):
18 self.servers, self.root = servers, root
19 self.cache = {} # name -> (ip or None, expires_at)
20 self.queries = 0
21 self.negative_ttl = negative_ttl
22
23 def _ask(self, server, question):
24 self.queries += 1
25 return self.servers[server].get(question)
26
27 def resolve(self, name, now=0, depth=0):
28 if depth > 8:
29 raise RuntimeError("CNAME loop")
30 hit = self.cache.get(name)
31 if hit and hit[1] > now:
32 return hit[0] # answered from cache
33
34 tld = name.rstrip(".").split(".")[-1] + "."
35 self.queries += 1 # ask the root
36 tld_server = self.root.get(tld)
37 zone = ".".join(name.rstrip(".").split(".")[-2:]) + "."
38 auth = self._ask(tld_server, zone) if tld_server else None
39 if auth is None:
40 self.cache[name] = (None, now + self.negative_ttl) # NXDOMAIN, cached briefly
41 return None
42
43 a = self._ask(auth, ("A", name))
44 if a:
45 ip, ttl = a
46 self.cache[name] = (ip, now + ttl)
47 return ip
48 cname = self._ask(auth, ("CNAME", name))
49 if cname:
50 target, ttl = cname
51 ip = self.resolve(target, now, depth + 1)
52 if ip:
53 self.cache[name] = (ip, now + ttl)
54 return ip
55 self.cache[name] = (None, now + self.negative_ttl)
56 return None
57```
58
59All five checks pass. The full file, including the checks and the Level 4 simulation, is in `code/ch04_dns.py`.
60
61*Simplification:* a real resolver also caches the referrals (root and `.com` answers), so most lookups skip straight to the authoritative server. Adding that is a good extension.
1Show the Level 4 solution
2**The bug:** the record had a **1-day TTL**, and the old servers were switched off **immediately** after changing it.
3
41. Many resolvers cached `shop.example.com → 203.0.113.20` some time in the day before the move, valid for up to 24 hours.
52. The record is changed. Nothing is pushed: those resolvers keep their cached answer.
63. The old servers are switched off right away.
74. Users behind those resolvers are sent to `203.0.113.20`, which no longer answers. **For them the site is down**, for up to a day, while the new servers sit healthy and idle.
8
9The tested simulation shows a user asking one hour after the move still gets the old IP; with the TTL lowered two days early, the same user gets the new one.
10
11**The fixed runbook:**
12```
131. At least 2 days before: lower the TTL of shop.example.com to 300 seconds.
142. Start the new servers at 198.51.100.7 and test them directly.
153. Change the A record to 198.51.100.7.
164. Keep the old servers running (or forwarding to the new ones) for at least
17 the old TTL plus a margin; watch their traffic fall to near zero.
185. Switch off the old servers.
196. Raise the TTL back to its normal value.
20```
1Show the Level 5 (sketch) solution
21. **Routing:** a managed DNS service with **geographic or latency-based routing**: users near India get the Mumbai load balancers' address, Europe gets Frankfurt, the Americas get Virginia. Load balancers inside each region spread traffic across servers (Chapter 7).
32. **Region down:** DNS **health checks** notice Frankfurt is unhealthy and stop returning it; European users get the next-nearest healthy region. With a **60 to 300 second TTL**, most move within minutes. Each region needs spare capacity to absorb another region's users (Chapter 29).
43. **TTLs:** 60 to 300 seconds for the main traffic records (fast failover); hours for MX, TXT and other stable records (less load, more resilience).
54. **DNS provider outage:** serve the zone from **two independent DNS providers** (both listed as NS records), keep moderate TTLs so cached answers survive short outages, and monitor resolution from several regions.
65. **Limit:** routing uses the **resolver's** location and changes are delayed by caching. Work around it with **anycast** addresses or a CDN in front (Chapter 26), short TTLs on routed records, and EDNS Client Subnet where supported.