COMPUTER NETWORKS / 4. DNS — THE INTERNET'S PHONE BOOK

DNS — Domain Name System

How google.com becomes 142.250.80.46 in milliseconds


EXPLANATION

DNS is the distributed database that maps human-readable domain names to machine-readable IP addresses. Without DNS, you'd need to memorize IP addresses for every website.

DNS is hierarchical and distributed — no single server knows everything. The hierarchy:
• Root nameservers (13 sets, labeled a-m.root-servers.net) — know where all TLD servers are
• TLD nameservers (.com, .org, .in, .io) — know where all second-level domain servers are
• Authoritative nameservers — know the actual DNS records for a specific domain
• Recursive resolver (your ISP or 8.8.8.8) — does the legwork of querying the hierarchy on your behalf

DNS Resolution walk-through for "google.com":
① Your browser checks its DNS cache → not found
② OS checks /etc/hosts file → not found
③ OS asks your recursive resolver (8.8.8.8)
④ Resolver checks its cache → not found
⑤ Resolver asks a Root nameserver: "Where's .com?"
⑥ Root says: "Ask ns1.verisign.net (the .com TLD server)"
⑦ Resolver asks .com TLD: "Where's google.com?"
⑧ TLD says: "Ask ns1.google.com (Google's authoritative server)"
⑨ Resolver asks Google's NS: "What's the IP for google.com?"
⑩ Google's NS responds: "142.250.80.46, TTL=300"
⑪ Resolver caches this, returns to your browser
⑫ Browser connects to 142.250.80.46

All this happens in ~50–100ms on first query. Cached queries: <1ms.

DNS Record Types:
• A → hostname to IPv4 address
• AAAA → hostname to IPv6 address
• CNAME → alias (one name points to another name)
• MX → mail exchange servers (for email delivery)
• TXT → arbitrary text (used for SPF, DKIM, domain verification)
• NS → nameserver records (which servers are authoritative)
• SOA → Start of Authority (metadata about the zone)
• PTR → reverse DNS (IP to hostname)

TTL (Time To Live): every DNS record has a TTL in seconds. Resolvers and browsers cache records until TTL expires. Changing DNS doesn't take effect instantly — you must wait for old TTL to expire across all caches globally. This is "DNS propagation."

DIAGRAM

DNS RESOLUTION HIERARCHY:

            Root (.)
              │
       ┌──────┴──────┐
      .com           .org   .in  ...
       │
  google.com ← Authoritative Nameserver
       │
  www.google.com → 142.250.80.46 (A record)

  RESOLUTION FLOW:
  Browser → OS → Recursive Resolver
                       │
                  ① Root NS: "Ask .com"
                       │
                  ② .com NS: "Ask google.com NS"
                       │
                  ③ google NS: "IP = 142.250.80.46"
                       │
  Browser ← OS ← Resolver (caches result for TTL seconds)

  RECORD TYPES:
  google.com      A      142.250.80.46
  google.com      AAAA   2607:f8b0:4004::200e
  www.google.com  CNAME  google.com
  google.com      MX  10 smtp.google.com
  google.com      TXT    "v=spf1 include:_spf.google.com ~all"

CODE

PYTHON
1import socket
2import dns.resolver # pip install dnspython
3
4# ── Basic DNS lookup ───────────────────────────────────
5hostname = "google.com"
6ip = socket.gethostbyname(hostname)
7print(f"{hostname} {ip}")
8
9# ── Rich DNS queries with dnspython ───────────────────
10def query_dns(domain: str, record_type: str):
11 try:
12 answers = dns.resolver.resolve(domain, record_type)
13 print(f"
14{domain} {record_type} records:")
15 for rdata in answers:
16 print(f" {rdata}")
17 print(f" TTL: {answers.rrset.ttl} seconds")
18 except Exception as e:
19 print(f" {record_type}: {e}")
20
21query_dns("google.com", "A")
22query_dns("google.com", "AAAA")
23query_dns("google.com", "MX")
24query_dns("google.com", "TXT")
25query_dns("github.com", "NS")
26
27# ── Reverse DNS (IP → hostname) ────────────────────────
28def reverse_dns(ip: str):
29 try:
30 hostname = socket.gethostbyaddr(ip)[0]
31 print(f"{ip} {hostname}")
32 except socket.herror:
33 print(f"{ip} No reverse DNS")
34
35reverse_dns("8.8.8.8") # dns.google
36reverse_dns("1.1.1.1") # one.one.one.one
37reverse_dns("142.250.80.46") # some google server
38
39# ── DIY DNS resolver using raw UDP ────────────────────
40import struct
41
42def build_dns_query(domain: str) -> bytes:
43 # Header: ID=1234, QR=0, Opcode=0, RD=1 (recursion desired)
44 header = struct.pack(">HHHHHH", 1234, 0x0100, 1, 0, 0, 0)
45 # Question: encode domain as length-prefixed labels
46 labels = b""
47 for part in domain.split("."):
48 labels += bytes([len(part)]) + part.encode()
49 labels += b"" # root label
50 question = labels + struct.pack(">HH", 1, 1) # QTYPE=A, QCLASS=IN
51 return header + question
52
53query = build_dns_query("google.com")
54sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
55sock.settimeout(2)
56sock.sendto(query, ("8.8.8.8", 53))
57response, _ = sock.recvfrom(512)
58print(f"
59Raw DNS response ({len(response)} bytes): {response.hex()[:80]}...")
60sock.close()
← PREV3. Transport Layer — TCP & UDPNEXT →5. HTTP & HTTPS