Skip to content

Split View: DNS 완벽 가이드 — 리졸버, DNSSEC, DoH/DoT, Anycast, CoreDNS 모든 것 (2025)

|

DNS 완벽 가이드 — 리졸버, DNSSEC, DoH/DoT, Anycast, CoreDNS 모든 것 (2025)

들어가며 — "It's always DNS"의 진실

SRE 커뮤니티에는 오래된 격언이 있다:

"It's always DNS. Even when it's not DNS, it's DNS."

인시던트 콜에서 가장 먼저 의심하는 게 DNS다. 왜일까? DNS가 복잡해서? 취약해서? 아니다 — DNS가 보이지 않기 때문이다. 모든 네트워크 요청의 첫 단계이면서, 대부분의 개발자가 내부를 모른다. 캐싱 계층이 여러 개 쌓여있어 변경이 반영되는 시점이 애매하고, TTL이라는 개념 하나로 수많은 버그가 설명된다.

이 글은 DNS의 모든 것을 1,500줄에 걸쳐 파헤친다. 1980년대 hosts.txt에서 출발한 이름 시스템의 역사, 쿼리 흐름의 정확한 단계, 레코드 타입들의 실제 용도, DNSSEC의 chain of trust, DoH/DoT/DoQ 암호화 DNS, Anycast가 어떻게 CDN을 빠르게 만드는지, CoreDNS가 쿠버네티스 안에서 어떻게 돌아가는지, DNS amplification 공격이 왜 그렇게 파괴적인지, 그리고 실전 운영에서 겪는 안티패턴들까지.

이 글은 TLS 1.3 + QUIC 글의 자연스러운 짝이다. HTTPS 연결이 일어나기 전에 항상 DNS가 먼저다. 그 숨은 첫 단계를 이해하자.


1. DNS의 짧은 역사

1.1 hosts.txt의 시대

1970년대 ARPANET에는 HOSTS.TXT 파일 하나로 모든 호스트 이름이 관리됐다. SRI-NIC (Stanford)에 마스터 파일이 있었고, 각 호스트가 주기적으로 FTP로 받아 동기화했다.

문제는 명확했다:

  • 네트워크가 커지면 파일이 커짐.
  • 중앙 갱신의 병목.
  • 이름 충돌 조정이 수동.
  • 새 호스트가 실제로 보이기까지 지연.

1.2 Paul Mockapetris와 DNS

1983년 USC의 Paul Mockapetris가 RFC 882/883 (나중에 RFC 1034/1035)으로 분산 계층적 이름 시스템을 제안한다. 핵심 아이디어:

  1. 계층: .com, .edu, .kr 같은 top-level domain에서 시작해 하위로 위임.
  2. 권한 위임(delegation): 상위 영역이 하위 영역의 관리를 아래로 넘김.
  3. 캐싱: 응답을 TTL 동안 캐시.
  4. 변환 양방향: 이름 → IP (forward), IP → 이름 (reverse).

이 설계가 40년이 지난 지금도 여전히 인터넷의 기반이다. 변하지 않은 이유는 변할 필요가 없었기 때문이다 — 훌륭한 추상이다.

1.3 주요 변화들

  • 1987년 RFC 1034/1035 표준화.
  • 1990년대 BIND(Berkeley Internet Name Domain) 널리 보급.
  • 1999년 DNSSEC 제안 (RFC 2535).
  • 2005년 DNSSEC 재설계 (RFC 4033).
  • 2010년 root zone 서명 시작.
  • 2018년 DoH 표준화 (RFC 8484).
  • 2022년 DoQ (DNS over QUIC) 표준화 (RFC 9250).
  • 2024년 DNS HTTPS/SVCB 레코드 본격 배포.

DNS는 느리게, 그러나 꾸준히 진화한다.


2. DNS의 이름 공간

2.1 FQDN의 구조

www.example.com. 같은 이름은 오른쪽에서 왼쪽으로 읽는다:

.               (root, 흔히 생략됨)
com.            (TLD - Top-Level Domain)
example.com.    (SLD - Second-Level Domain)
www.example.com. (subdomain / hostname)

맨 뒤의 점(dot)은 실제로는 있다 — **FQDN (Fully Qualified Domain Name)**은 root까지 명시. 평소에는 생략한다.

2.2 DNS Zone

Zone은 한 권한(authoritative) 서버가 담당하는 이름의 묶음. example.com zone은 example.com, www.example.com, mail.example.com 등을 포함할 수 있다. 하지만 sub.example.com의 관리를 다른 서버에 위임하면, sub.example.com은 별도 zone이 된다.

Zone 파일 예시(BIND 포맷):

$ORIGIN example.com.
$TTL 3600

@       IN SOA  ns1.example.com. admin.example.com. (
                2026041500 ; serial
                3600       ; refresh
                1800       ; retry
                604800     ; expire
                86400 )    ; minimum TTL

@       IN NS   ns1.example.com.
@       IN NS   ns2.example.com.
@       IN A    192.0.2.1
www     IN A    192.0.2.1
mail    IN A    192.0.2.2
@       IN MX   10 mail.example.com.

2.3 TLD의 종류

  • gTLD (generic): .com, .net, .org, .dev, .io. 2012년 이후 수천 개로 확장.
  • ccTLD (country-code): .kr, .jp, .uk. 국가 코드 기반.
  • infrastructure TLD: .arpa. 역방향 조회 전용.
  • sTLD (sponsored): .edu, .gov. 특정 기관 관리.

ICANN이 root 관리. 각 TLD는 별도 registry가 운영(Verisign이 .com, .net 등).


3. 쿼리의 실제 흐름

3.1 전체 그림

당신의 브라우저가 www.example.com을 찾을 때:

1. 브라우저 캐시 → 운영체제 캐시 → /etc/hosts → stub resolver
2. Stub resolver (libc)Recursive resolver (ISP or 1.1.1.1)
3. Recursive resolver 캐시 히트? YES → 즉시 반환
                      NO → 다음 단계
4. RecursiveRoot servers (a.root-servers.net13)
   "who runs .com?""these NS records"
5. Recursive.com TLD servers
   "who runs example.com?""ns1.example.com, ns2.example.com"
6. Recursive → ns1.example.com (authoritative)
   "what's www.example.com?""192.0.2.1"
7. Recursive가 결과를 캐시하고 stub에 반환
8. Stub이 OS에 반환, OS가 브라우저에 반환

이 과정이 "cold" 상태일 때 100–500ms 걸릴 수 있다. 캐시 히트면 1ms 미만.

3.2 Stub Resolver

OS 내장된 최소 DNS 클라이언트. getaddrinfo() 함수가 실제로 이걸 호출한다. Linux는 glibc의 resolv.conf를 읽어 어느 recursive resolver로 보낼지 결정.

# /etc/resolv.conf
nameserver 1.1.1.1
nameserver 8.8.8.8
search example.com internal.local
options ndots:2 timeout:2 attempts:3
  • nameserver: recursive resolver 주소들.
  • search: 도메인 접미사 자동 추가 후보.
  • ndots: 이름에 점이 N개 미만이면 search 도메인을 시도.
  • timeout/attempts: 각 서버 시도당 대기/반복.

현대 시스템 대부분에 systemd-resolved 같은 스텁 캐시가 로컬에 추가로 있다. resolv.conf127.0.0.53을 가리키면 그 뒤에 systemd-resolved가 있다.

3.3 Recursive Resolver

사용자를 위해 재귀적으로 쿼리를 해결해주는 서버. ISP가 운영하거나 공용 서비스(Cloudflare 1.1.1.1, Google 8.8.8.8, Quad9 9.9.9.9)를 쓴다.

주요 책임:

  • 캐시 관리 (TTL 존중).
  • Root → TLD → Authoritative 순으로 반복 쿼리.
  • 응답의 RRSIG 검증 (DNSSEC 활성 시).
  • 클라이언트에 최종 답 반환.

3.4 Root Servers

13개의 논리적 서버 (a.root-servers.net ~ m.root-servers.net). 실제로는 각각이 anycast로 수백 개 물리 장소에 분산. 전 세계 어디서든 가까운 노드로 라우팅.

root zone은 매우 작다 — TLD들의 NS 레코드만 포함. ICANN이 관리하고, 여러 조직(Verisign, University of Maryland, NASA 등)이 각 root server를 운영.

3.5 Authoritative Servers

특정 도메인의 "공식" 답을 주는 서버. 도메인 소유자가 운영하거나 위탁(Cloudflare DNS, AWS Route 53, Google Cloud DNS).

Primary(master) 하나 + Secondary(slave) 여러 개가 전형. Primary에서 zone 파일을 편집하면 AXFR/IXFR로 secondary들에 전파.

Glue Record: ns1.example.com의 IP를 얻으려면 example.com의 NS를 먼저 알아야 하는데, 그 NS가 ns1.example.com이면 순환. 이 문제를 풀기 위해 parent zone (.com)이 ns1.example.com의 A 레코드를 "glue"로 함께 제공.


4. 레코드 타입 — 무엇을 저장하는가

4.1 기본 레코드들

  • A: IPv4 주소. example.com. IN A 192.0.2.1
  • AAAA: IPv6 주소. example.com. IN AAAA 2001:db8::1
  • CNAME: 정규 이름(canonical name). www.example.com. IN CNAME example.com.
    • 주의: CNAME이 가리키는 이름에는 다른 레코드가 있을 수 없다. apex(zone 최상단)에 CNAME은 금지.
  • NS: 이 zone의 권한 서버. example.com. IN NS ns1.example.com.
  • SOA (Start of Authority): zone의 메타데이터 — primary, admin email, serial, refresh/retry/expire/minimum.
  • MX: 메일 교환 서버. 우선순위 값 포함. example.com. IN MX 10 mail.example.com.
  • TXT: 임의 텍스트. SPF, DKIM, DMARC, 도메인 검증에 사용.
  • PTR: 역방향 조회(IP → 이름). 1.2.0.192.in-addr.arpa. IN PTR example.com.
  • SRV: 서비스 위치. _sip._tcp.example.com. IN SRV 0 5 5060 sipserver.example.com.
  • CAA: 인증서 발급 정책. 어느 CA가 인증서를 발급할 수 있는지.

4.2 최근 추가된 레코드들

  • HTTPS/SVCB (RFC 9460): 2024년부터 보편화. HTTP/3 지원, IP 힌트, ECH 공개키 등을 한 레코드에 담음.
example.com. HTTPS 1 . alpn="h3,h2" ipv4hint=192.0.2.1 ech=AEX+...

브라우저가 이 레코드를 보면 즉시 HTTP/3로 접속 시도, IP는 힌트로 미리 확보, ECH는 TLS 핸드셰이크의 SNI 암호화에 사용. 한 번의 DNS 조회로 많은 걸 해결.

  • SVCB: 일반 서비스 바인딩. HTTPS는 SVCB의 특화 형태.

4.3 DNSSEC 전용 레코드

  • DNSKEY: zone의 공개키.
  • RRSIG: 레코드셋의 서명.
  • DS (Delegation Signer): parent zone에 저장되는 child의 키 해시.
  • NSEC / NSEC3: "이 이름은 존재하지 않음"의 증명.

4.4 CNAME 체인의 현실

CNAME이 A로 풀릴 때까지 여러 단계를 거칠 수 있다:

www.example.com. CNAME cdn.example.com.
cdn.example.com. CNAME xyz.cloudfront.net.
xyz.cloudfront.net. CNAME d123.cloudfront.net.
d123.cloudfront.net. A 192.0.2.10

브라우저는 보통 한 번에 최종 A를 받지만, resolver가 각 단계를 추적해야 한다. 체인이 길면 조회가 느려지고 실패 지점이 늘어난다. 최대 3–4단계 이하로 유지가 권장사항.

또 apex 도메인(example.com 자체)에는 CNAME을 못 쓰는 문제. CDN을 apex에 붙이려면:

  • ALIAS 레코드 (DNS 제공자 고유 기능, Route 53/Cloudflare/NS1).
  • ANAME (일부 제공자).
  • CNAME flattening (Cloudflare): apex CNAME처럼 동작시키고, 실제로는 서버에서 A로 풀어 응답.

RFC 표준이 아니라 각 제공자가 구현한 hack. 2024년 RFC 9460(HTTPS 레코드)이 이 문제를 부분적으로 해결하지만 완전한 대안은 아직 없다.


5. 메시지 포맷 — 바이트 수준에서

5.1 DNS 패킷 구조

전체는 헤더 + 4개 섹션:

+---------------------+
|        Header       |
+---------------------+
|       Question      | — 무엇을 물어보는가
+---------------------+
|        Answer       | — 실제 답변
+---------------------+
|      Authority      | — authoritative NS
+---------------------+
|      Additional     | — 보너스 정보 (A records for NSes)
+---------------------+

5.2 헤더

                                1  1  1  1  1  1
  0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                      ID                       |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    QDCOUNT                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    ANCOUNT                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    NSCOUNT                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    ARCOUNT                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  • ID: 트랜잭션 ID. 응답은 같은 ID로 돌아옴.
  • QR: 0=query, 1=response.
  • Opcode: 0=standard query, 5=update (dynamic DNS).
  • AA: authoritative answer.
  • TC: truncated — UDP 512바이트 넘어 잘림.
  • RD: recursion desired.
  • RA: recursion available.
  • RCODE: 0=NOERROR, 2=SERVFAIL, 3=NXDOMAIN, 5=REFUSED.
  • QDCOUNT/ANCOUNT/NSCOUNT/ARCOUNT: 각 섹션의 레코드 수.

5.3 Name Compression

같은 이름이 패킷에 여러 번 등장할 수 있다. 이를 압축하기 위해 "포인터" 형식: 첫 2비트가 11이면 나머지 14비트가 패킷 내 오프셋.

[0x03]www[0x07]example[0x03]com[0x00]    -- 첫 등장
[0xC0 0x00]                                -- "offset 0에 있는 이름" 참조

16KB 패킷 한계 내에서만 유효하지만 대부분의 DNS 패킷이 충분히 작아 효과적.

5.4 UDP 512바이트 한계와 TC 비트

전통 DNS는 UDP 포트 53. 단일 메시지는 512바이트 한계. 이를 넘으면 TC 비트 세우고 클라이언트에게 "TCP로 다시 와"라고 암묵적으로 알린다.

DNSSEC 응답은 RRSIG 때문에 쉽게 512바이트를 넘는다. 그래서 **EDNS0 (Extension Mechanisms for DNS)**가 필수:

5.5 EDNS0

OPT 레코드로 확장 필드 운반. 주요 기능:

  • UDP payload size 협상: 클라이언트가 "나는 4096바이트까지 받을 수 있음"을 광고. 서버가 그 이하면 UDP로, 넘으면 TC+TCP.
  • DO (DNSSEC OK) flag: DNSSEC 응답 원함.
  • extended RCODE: 4비트 이상의 에러 코드.
  • Client Subnet (EDNS-CSUBNET): 실제 사용자의 서브넷을 authoritative에 전달 → CDN 지오 라우팅 정확도.

EDNS0 없이는 현대 DNS가 거의 동작 못 한다. 아주 오래된 미들박스가 EDNS0 못 알아보고 드롭하면 DNSSEC 검증 실패 → 체감상 "사이트 안 열림".


6. 캐싱과 TTL — 인터넷이 스케일되는 이유

6.1 TTL의 의미

모든 DNS 응답은 **TTL (Time To Live)**을 포함. "이 응답을 N초 동안 캐시해도 됨".

www.example.com. 300 IN A 192.0.2.1
                 ^^^
                 TTL: 300= 5

TTL이 작으면:

  • 변경 반영 빠름.
  • Recursive resolver 부하 증가.
  • Authoritative 서버 부하 증가.

TTL이 크면:

  • 변경 반영 느림 (최대 TTL + recursive가 캐시 리프레시 주기).
  • 부하 감소.

6.2 여러 레벨의 캐시

실제로는 캐시가 여러 층에 쌓여있다:

브라우저 캐시      (보통 자체 TTL, 분 단위)
운영체제 캐시     (Windows, macOS의 DNS Client)
systemd-resolved  (Linux)
Recursive resolver (ISP/Cloudflare)
Authoritative (실제 답)

한 단계에서 캐시 히트면 위층 캐시도 그 답을 받아 캐싱. 변경 전파는 이 모든 층의 TTL 만료를 기다려야 한다.

그래서 "DNS 바꿨는데 아직 옛날 IP로 갑니다"가 흔한 불평. 실제로는 체인의 어디선가 캐시가 유효한 것. 인내심이 DNS의 주 덕목.

6.3 Negative Caching

NXDOMAIN (없음) 응답도 캐시된다. SOA 레코드의 minimum 필드 값이 캐시 시간:

SOA ... ( ... 86400 )   ; 86400 = NXDOMAIN 캐시 1

너무 크면 "내가 새로 만든 도메인이 아직 안 보임" 문제. 너무 작으면 공격자가 존재하지 않는 이름을 반복 조회해 부하 유발.

6.4 TTL 튜닝 전략

  • 일반 서비스 레코드: 300–3600초 (5분–1시간).
  • 이전 예정 있는 것: 60–300초로 미리 낮춤 (며칠 전).
  • 거의 변하지 않는 NS: 86400–172800초 (1–2일).
  • 극단적 안정성 필요 (root zone): 2일.

마이그레이션 직전에 TTL을 낮춰두는 것이 기본 기술. 변경 후 다시 올려 부하 감소.


7. DNSSEC — 서명된 DNS

7.1 왜 DNSSEC인가

기본 DNS는 신뢰가 없다. 응답이 중간에서 변조돼도 알 방법 없음. DNS hijacking, cache poisoning, Kaminsky 공격 등이 현실.

DNSSEC는 각 RRset에 디지털 서명을 붙여 무결성 보장.

7.2 구성 요소

  • DNSKEY: zone의 공개키 (ZSK - Zone Signing Key, KSK - Key Signing Key).
  • RRSIG: 각 RRset의 서명 (ZSK로 서명).
  • DS: parent zone이 child의 KSK 해시를 보관.
  • NSEC / NSEC3: 부재 증명.

7.3 Chain of Trust

Root zone KSK (전 세계 공개, ICANN 관리)
Root zone이 .com의 DS를 서명
.com zone의 KSKDS로 검증됨
.com zone이 example.com의 DS를 서명
 → example.com zone의 KSKDS로 검증됨
 → example.com의 ZSKKSK로 서명됨
 → 실제 레코드들이 ZSK로 서명됨

클라이언트(validating resolver)는 root KSK만 내장하면, 이 체인을 타고 내려가 모든 레코드의 무결성을 검증할 수 있다.

7.4 RRSIG의 구조

www.example.com. 300 IN A 192.0.2.1
www.example.com. 300 IN RRSIG A 8 3 300 (
    20260501000000 20260415000000 12345 example.com.
    SIGNATURE_BYTES )
  • 알고리즘 (8 = RSA/SHA-256).
  • Labels 수 (3 = www.example.com.의 라벨 수).
  • Original TTL.
  • Signature expiration / inception.
  • Key tag (DNSKEY 식별자).
  • Signer's name.
  • 실제 서명.

서명 유효 기간이 한정되어(보통 며칠~몇 주) 정기적 재서명 필요. 이 갱신을 automatic signing으로 자동화 (BIND, PowerDNS, Knot의 기본 기능).

7.5 NSEC와 NSEC3 — 부재 증명

"foo.example.com은 없음"을 어떻게 증명하는가? sorted linked list 접근:

alpha.example.com.  NSEC  beta.example.com. A RRSIG NSEC
beta.example.com.   NSEC  charlie.example.com. A RRSIG NSEC
...

Resolver가 delta를 물으면, 서버가 charlie.example.com NSEC epsilon.example.com를 반환. "delta는 charlie와 epsilon 사이에 없음". 이 NSEC도 RRSIG로 서명됨 → 무결성 확인.

문제: 이 체인을 따라가면 zone의 모든 이름을 열거할 수 있음 (zone walking). 프라이버시 침해.

NSEC3: 이름을 해시해서 순서 짓기. 해시된 이름끼리 linked list. 역산 어려움 → zone walking 완화 (but not eliminated - 2011년 NSEC3 walker 공개).

최신 대안 NSEC5black lies (Cloudflare의 DNSSEC 라이브 서명) 등으로 진화 중.

7.6 실전 배포의 현실

DNSSEC 배포율은 아직 낮다. 2026년 현재:

  • TLD 수준: 대부분 배포됨 (.com, .net, .org, .dev 등).
  • SLD 수준: 전체 도메인의 10–30% 정도만 서명.
  • Validating resolver: Cloudflare, Google, Quad9가 기본 검증.

왜 배포가 느린가?

  • 키 관리 복잡 (ZSK rotation, KSK rollover는 parent와 조율 필요).
  • 잘못 설정하면 SERVFAIL → 사이트 완전 다운.
  • 대형 CA가 이미 MITM 보호 제공 (HTTPS 인증서) → 필요성 약해 보임.

그럼에도 DNSSEC는 인증서 생태계와 다른 가치를 준다. 인증서는 TLS 핸드셰이크 후에 검증. DNSSEC는 그 전 단계에서 이름 해결의 무결성을 보장. DANE(DNS-based Authentication of Named Entities, RFC 6698) 같은 기술은 DNSSEC 위에 인증서 고정을 올림. 완전한 보안은 두 계층의 결합.


8. DoH / DoT / DoQ — 암호화 DNS

8.1 문제

기본 DNS는 UDP/TCP 53번 포트, 평문. 누구나 감청 가능:

  • ISP가 어느 사이트에 접속하는지 봄.
  • 공공 Wi-Fi의 스니퍼.
  • 국가 단위 DNS 기반 차단.

8.2 DoT (DNS over TLS) — RFC 7858

DNS 쿼리를 TLS로 감쌈. 포트 853. 간단하고 방화벽 친화적.

Client  (TLS)DoT Resolver  (plain)Authoritative

클라이언트와 recursive 사이만 암호화. 그 뒤는 여전히 평문.

8.3 DoH (DNS over HTTPS) — RFC 8484

더 과격한 접근. DNS 쿼리를 HTTP POST/GET으로 감쌈. 포트 443. 일반 웹 트래픽과 구분 불가.

POST /dns-query HTTP/2
Host: cloudflare-dns.com
Content-Type: application/dns-message

장점:

  • 방화벽이 웹 트래픽과 구분 못 함 → 차단 우회.
  • HTTP/2, HTTP/3 장점 그대로 (multiplexing, 1-RTT).
  • 브라우저가 직접 구현 가능.

단점:

  • 운영자가 내부 DNS 정책을 실행 어려움 (DoH가 enterprise DNS를 우회).
  • 프라이버시는 resolver에 의존 — Cloudflare/Google에 모든 쿼리 몰림.

Firefox가 2019년 TRR (Trusted Recursive Resolver)로 미국에서 Cloudflare DoH를 기본 활성화. 논쟁이 있었지만 프라이버시 관점에서 진전.

8.4 DoQ (DNS over QUIC) — RFC 9250

2022년 표준화. QUIC 위에 DNS를 얹음. DoT보다:

  • 0-RTT 재개로 더 빠름.
  • Connection migration 지원.
  • Head-of-line blocking 없음.

모바일과 Cloudflare 1.1.1.1이 지원. 아직 배포는 제한적이지만 방향성은 명확하다.

8.5 ODoH (Oblivious DoH) — 극한의 프라이버시

Cloudflare + Apple이 개발. DoH resolver가 내용은 복호화하지만 누가 물어봤는지 모름:

ClientProxy (TLS)Target Resolver
          ↑                ↑
          IP 보임      내용 보임
          (내용 모름)   (IP 모름)

Client가 쿼리를 target resolver의 공개키로 암호화 → proxy를 통해 전달. Proxy는 client IP를 보지만 내용은 모름. Target resolver는 내용을 풀지만 client IP를 모름.

Apple Private Relay, Cloudflare ODoH가 실전 배포 중. 국가 단위 감시에 강한 저항.

8.6 Encrypted Client Hello (ECH)와의 조합

TLS/QUIC 글에서 다뤘던 ECH는 TLS 핸드셰이크의 SNI를 숨긴다. DoH + ECH 조합이면:

  1. DNS 조회가 암호화 → ISP는 어느 도메인 조회하는지 모름.
  2. TLS 핸드셰이크의 SNI 암호화 → ISP는 연결 중 어느 사이트인지 모름.

ISP에게는 "어딘가에 HTTPS 연결 중"만 보임. 진정한 프라이버시의 한 단계.


9. Anycast — 왜 CDN의 DNS가 빠른가

9.1 Unicast vs Anycast

  • Unicast: IP 주소 하나 = 서버 하나. 평범한 모델.
  • Anycast: 같은 IP 주소를 여러 지역의 서버가 광고. BGP 라우팅이 "가장 가까운" 서버로 연결.
Cloudflare 1.1.1.1
  ├── Tokyo PoP
  ├── Frankfurt PoP
  ├── Sao Paulo PoP
  ├── ... 300+ cities

Tokyo 사용자가 1.1.1.1에 쿼리 → BGP가 Tokyo PoP로 라우팅 → 수 ms 응답. 동시에 독일 사용자가 같은 IP에 쿼리 → Frankfurt PoP로 라우팅.

9.2 DNS에 적합한 이유

DNS 쿼리/응답은 매우 작고(UDP ~100B), 상태 없음(stateless). 어느 PoP에 도착해도 같은 답 제공 가능. Anycast의 "어느 노드든 답할 수 있음" 특성과 완벽한 궁합.

TCP connection-oriented 서비스는 anycast가 까다롭다 (route flap이 연결 끊김). 하지만 요청-응답 한 쌍이 UDP면 문제 없음.

9.3 13 Root Server — 안에 수천 개

"root server는 13개"라는 말은 논리적 이름 기준. 각 a~m root server는 실제로 anycast로 수백 개 PoP에 분산. 전체 물리 서버는 2000개 넘음.

그래서 어느 ISP에서도 root 쿼리가 수 ms에 해결. DNS의 전역 가용성과 성능이 anycast에 빚지고 있다.

9.4 Route 53, Cloudflare DNS의 현실

AWS Route 53는 전 세계 100+ locations에 anycast. 한 도메인의 NS 레코드 4개가 서로 다른 자리 조합 → 한 지역 장애에도 다른 지역으로 자동 페일오버.

Cloudflare는 이를 극단으로 밀어 300+ PoP. 도메인을 Cloudflare DNS로 옮기면 TTFB (Time To First Byte)가 체감상 달라진다.

9.5 ECS (EDNS Client Subnet)

Authoritative가 "요청자가 실제 어디 있는지"를 알면 지리 최적 라우팅 가능. Recursive resolver가 client IP의 /24를 authoritative에 전달하는 것이 ECS.

RecursiveAuthoritative
  "who's www.example.com, for client in 192.0.2.0/24?"

Authoritative가 해당 지역 CDN PoP의 IP를 반환. DNS 기반 지오 라우팅이 이걸로 동작.

프라이버시 trade-off: client IP의 일부가 authoritative까지 전달됨. 완전 프라이버시 원하면 ECS 비활성. 대신 라우팅 정확도 떨어짐.


10. CoreDNS — Kubernetes의 이름 서비스

10.1 CoreDNS의 위치

Kubernetes 안에서 my-service.my-namespace.svc.cluster.local 같은 이름을 해석하는 게 CoreDNS. kube-dns의 후계자이자 CNCF 졸업 프로젝트.

Pod의 /etc/resolv.conf:

search my-namespace.svc.cluster.local svc.cluster.local cluster.local
nameserver 10.96.0.10  # kube-dns ClusterIP
options ndots:5

my-service만 쿼리해도 search domain 덕에 my-service.my-namespace.svc.cluster.local이 해석됨.

10.2 플러그인 기반 아키텍처

CoreDNS는 Caddy 웹서버와 같은 저자(Miek Gieben)가 설계. 플러그인 체인 방식.

# Corefile
.:53 {
    errors
    health
    ready
    kubernetes cluster.local in-addr.arpa ip6.arpa {
        pods insecure
        fallthrough in-addr.arpa ip6.arpa
    }
    prometheus :9153
    forward . /etc/resolv.conf
    cache 30
    loop
    reload
    loadbalance
}

각 플러그인이 쿼리 처리 파이프라인의 한 단계. 필요한 것만 켜서 사용. kubernetes 플러그인이 Kubernetes API 서버에서 Service/Endpoint 정보를 받아 DNS 응답 생성.

10.3 ndots의 함정

ndots:5는 "이름에 점이 5개 미만이면 search 먼저". 그래서 google.com (점 1개)도 search domain 시도부터 한다:

google.com.my-namespace.svc.cluster.localNXDOMAIN
google.com.svc.cluster.localNXDOMAIN
google.com.cluster.localNXDOMAIN
google.com → 실제 답

외부 호스트 조회마다 3–4번의 추가 쿼리. 대용량 트래픽에서 CoreDNS 부하 폭증. 개선책:

  • Pod의 dnsConfigndots: 2 (일반적으로 충분).
  • NodeLocal DNSCache (노드별 캐시 daemon).
  • Stub domains로 외부 네임만 직접 외부로.

NodeLocal DNSCache는 최근 쿠버 설치의 기본. CoreDNS 부하를 노드별로 분산 + 캐시 → 효과가 극적.

10.4 Service의 종류와 DNS

  • ClusterIP Service: my-service.ns.svc.cluster.local → ClusterIP A 레코드.
  • Headless Service (clusterIP=None): A 레코드가 Pod IP들을 직접 반환. StatefulSet에 자주 씀.
  • ExternalName: CNAME 리턴. 외부 FQDN으로 매핑.

StatefulSet은 각 Pod에 고유 DNS 이름도 할당: pod-0.my-service.ns.svc.cluster.local.

10.5 DNS 디버깅

# Pod 안에서
nslookup my-service
nslookup my-service.other-namespace.svc.cluster.local
dig @10.96.0.10 my-service.ns.svc.cluster.local

# CoreDNS 로그 체크
kubectl logs -n kube-system deploy/coredns

"내 서비스가 안 보여요" 인시던트의 90%는:

  • Service 이름/namespace 오타.
  • Selector가 Pod의 label과 안 맞음.
  • Endpoint가 비어있음 (Pod가 Ready 아님).

11. DNS 공격과 방어

11.1 Cache Poisoning

1990년대 고전 공격. Recursive resolver의 캐시에 위조 응답을 넣으면, 그 뒤로 모든 쿼리가 가짜 답으로 간다.

Kaminsky 공격 (2008): DNS 트랜잭션 ID는 16비트 → 공격자가 많은 가짜 응답을 보내면 타이밍 맞추기 가능. 공격 대상: recursive resolver.

완화책:

  • Source port randomization (트랜잭션 ID 16-bit + src port 16-bit = 32-bit 추측 필요).
  • DNSSEC 검증.
  • 0x20 encoding (query name의 대소문자를 랜덤화 → 응답이 일치해야 유효).

11.2 DNS Amplification DDoS

공격자가 작은 쿼리로 큰 응답을 유발. 대상 IP로 응답이 쏟아짐.

공격자  (spoofed src IP = 피해자)DNS 서버
                       피해자  (큰 응답)

증폭률 50–100배도 흔함. DNSSEC 응답이 특히 크다.

완화:

  • Open resolver 제거 (authoritative만 외부에 노출).
  • RRL (Response Rate Limiting): 같은 IP에서의 반복 쿼리 제한.
  • BCP 38 (Ingress filtering): ISP가 spoofed src IP 필터링.
  • DDoS scrubbing service (Cloudflare, Akamai 등).

11.3 Subdomain Takeover

예전에 CNAME으로 app.example.commyapp.herokuapp.com을 설정했다가 Heroku 앱을 삭제. 공격자가 myapp을 다시 등록하면 app.example.com 트래픽을 가로챔.

예방:

  • 사용 안 하는 CNAME은 삭제.
  • Monitoring: 가리키는 target이 존재하는지 주기 체크.
  • CAA 레코드로 인증서 발급 제한.

11.4 DNS Rebinding

브라우저의 same-origin policy 우회 공격. 공격자가 자기 도메인의 DNS A 레코드를 피해자 내부 IP(예: 192.168.1.1)로 빠르게 변경 → 브라우저가 공격자 도메인으로 페치한 JS가 피해자 내부 네트워크에 접근.

완화:

  • 공공 recursive resolver의 "private IP 필터링" (1.1.1.1, 8.8.8.8 기본).
  • 방화벽에서 DNS 응답의 private IP 필터링.
  • 웹 앱에서 Host 헤더 검증.

11.5 DNS Tunneling

DNS 쿼리의 페이로드로 임의 데이터 전송. 원래는 방화벽 우회의 수단 (DNS는 거의 항상 열림).

Malware가 C2(Command & Control) 채널로 활용. 이상한 TXT 쿼리가 대량 발생하면 의심.

방어:

  • DNS 트래픽 분석 (패킷 크기, 쿼리 패턴).
  • 블랙리스트 기반 필터링.
  • Cisco Umbrella, Cloudflare Gateway 같은 DNS 필터링 서비스.

12. 실전 운영

12.1 좋은 DNS 설계

  • 여러 NS: 최소 2개, 다른 지리/네트워크. Route 53이나 Cloudflare 같은 전역 anycast 추천.
  • 적절한 TTL: 일반 3600, 변경 전 낮춤.
  • Wildcard 신중히: *.example.com은 의도치 않은 이름도 매칭.
  • SPF/DKIM/DMARC: 이메일 인증. 없으면 스팸 등급 악화.
  • CAA 레코드: example.com. CAA 0 issue "letsencrypt.org"로 인증서 발급 제한.
  • DNSSEC: 가능하면 배포, 자동 서명 툴 활용.

12.2 모니터링

  • NS 서버 가용성: 외부 probe로 다수 지역에서 체크.
  • SOA serial: secondary가 primary와 일치하는지.
  • 응답 시간: p99 체크. 비정상 시 anycast 라우팅 이슈 의심.
  • NXDOMAIN 증가: 오타/공격/만료.
  • DNSSEC 서명 만료: 유효기간 끝나면 SERVFAIL → 전체 다운.

12.3 주요 사고 패턴

  • DNSSEC 키 롤오버 실수: parent의 DS와 child의 KSK가 어긋나면 모든 리졸버가 SERVFAIL. 사이트 완전 다운. KeyTrap (2024년 발견된 공격), KSK rollover 2018년 지연 등 실제 사고 많음.
  • TTL 너무 큼 + 변경 필요: 마이그레이션 전날에 TTL 낮춰야 함. 새 IP로 72시간이 지나야 모두 반영.
  • CNAME chain 너무 길거나 순환.
  • Wildcard 중복: *.example.com*.a.example.com 둘 다 있으면 의도치 않은 매칭.
  • apex CNAME 시도: 표준 아님. CNAME flattening 되는 제공자 사용 필수.
  • Private IP leak: 내부용 도메인의 A 레코드가 public DNS에 실수로 공개.

12.4 도구들

  • dig: 표준 도구.
dig example.com
dig +trace example.com          # root부터 추적
dig +dnssec example.com          # DNSSEC 레코드 포함
dig @1.1.1.1 example.com ANY    # 특정 resolver 지정
dig -x 192.0.2.1                 # reverse lookup
  • drill: dig의 대안, NLnet Labs 것.
  • kdig (Knot Resolver의 툴): 현대적 출력 포맷.
  • mtr / traceroute: DNS와 함께 네트워크 경로 디버그.
  • dnsperf: authoritative 부하 테스트.

12.5 마이그레이션 전략

DNS 제공자 이전 체크리스트:

  1. 현 TTL 파악. NS 레코드는 보통 2일.
  2. 몇 주 전 TTL 낮춤 (300–600초).
  3. 새 제공자에 모든 zone 복제.
  4. 외부에서 새 NS 응답 검증.
  5. Registrar에서 NS 변경.
  6. 이전 NS를 TTL * 2 이상 유지 (혹시 caching).
  7. 최종 확인 후 이전 NS 내림.

대형 마이그레이션은 한달 걸리는 게 정상. 조급함이 가장 큰 적.


13. 재미있는 일화들

13.1 Facebook 2021년 6시간 다운

2021년 10월 4일, Facebook/Instagram/WhatsApp이 6시간 다운. 원인: BGP 광고가 잘못 업데이트 → authoritative NS 서버가 인터넷에서 사라짐 → Facebook 전체 DNS가 해석 안 됨.

더 나쁜 건: 내부 복구 도구도 DNS에 의존했다. 엔지니어가 물리적으로 데이터센터에 가서 문제를 고쳐야 했다. 심지어 건물 출입 배지도 DNS에 의존해서 들어가지 못했다는 얘기까지 나왔다.

교훈: 복구 도구는 DNS에 의존하지 말 것.

13.2 DYN 2016

Mirai 봇넷이 Dyn(주요 DNS 제공자)을 1Tbps로 DDoS → GitHub, Twitter, Netflix, Reddit 등 수시간 다운. 하나의 DNS 제공자 의존이 단일 실패 지점.

그 이후 대형 기업들이 multi-DNS 전략 (Dyn + Route 53 + Cloudflare 병렬)을 채택.

13.3 Cloudflare 1.1.1.1의 사연

Cloudflare가 2018년 April Fool's Day에 1.1.1.1 발표. 이 IP의 기상천외한 역사:

  • 너무 간단해서 예전에 많은 기업이 내부/테스트 용도로 사용.
  • 실제로 Cloudflare가 공식 resolver로 만들기 전에 인터넷 곳곳에서 이상한 트래픽이 이미 이 IP로 향하고 있었음.
  • Cloudflare가 APNIC과 파트너십으로 쓰게 됐고, 트래픽 패턴을 연구에 활용.

지금은 무료 공공 DoH/DoT resolver의 대표. 1.1.1.1 (primary), 1.0.0.1 (secondary).


맺음 — 보이지 않는 인프라

DNS는 인터넷의 가장 기초적이고 가장 보이지 않는 부분이다. 웹이 동작한다는 것의 전제이자, 모든 서비스의 첫 단계. 그러면서도 40년간 기본 설계를 바꾸지 않고 지금도 작동한다는 점에서 경이롭다.

운영자로서 본능적으로 체크할 세 가지:

  1. TTL을 계획의 일부로 두라. 변경은 TTL 시간에 반영된다. 마이그레이션 전 낮추고, 안정 후 올려라.
  2. DNS 서비스를 이중화하라. 단일 제공자 의존은 단일 실패 지점. Multi-NS, multi-provider.
  3. "It's always DNS"를 부정하지 말라. 문제 날 때 DNS부터 의심하라. dig +trace가 첫 단계.

DNS를 이해하면 보이지 않던 인프라가 보인다. 그러면 인시던트 콜에서 먼저 답을 내는 사람이 된다.

다음 글은 CDN의 내부 구조 — Cache, Edge Compute, Origin Shield, Cache Key를 다룬다. DNS가 사용자를 어느 edge PoP으로 라우팅한 다음에 일어나는 일. Edge로 밀려 나가는 현대 웹의 아키텍처를 바이트 수준에서 그린다.

The Complete DNS Guide — Resolvers, DNSSEC, DoH/DoT, Anycast, CoreDNS, and Everything Else (2025)

Intro — The Truth of "It's Always DNS"

There's an old saying in the SRE community:

"It's always DNS. Even when it's not DNS, it's DNS."

DNS is the first thing anyone suspects on an incident call. Why? Because DNS is complex? Fragile? No — because DNS is invisible. It's the first step of every network request, yet most developers don't know its internals. There are multiple layers of caching, so the moment changes take effect is ambiguous, and the single concept of TTL explains a huge number of bugs.

This article tears DNS apart across 1,500 lines. The history of the name system starting with hosts.txt in the 1980s, the exact stages of query flow, what record types are actually used for, the DNSSEC chain of trust, encrypted DNS with DoH/DoT/DoQ, how anycast makes CDNs fast, how CoreDNS runs inside Kubernetes, why DNS amplification attacks are so destructive, and the antipatterns we live with in real operations.

This article is a natural companion to the TLS 1.3 + QUIC post. Before any HTTPS connection, DNS always comes first. Let's understand that hidden first step.


1. A Brief History of DNS

1.1 The hosts.txt Era

In the 1970s ARPANET, every host name was managed in a single HOSTS.TXT file. The master file lived at SRI-NIC (Stanford), and each host fetched it periodically via FTP to stay in sync.

The problems were obvious:

  • Larger networks meant larger files.
  • A central update bottleneck.
  • Manual coordination of name collisions.
  • A delay before new hosts actually became visible.

1.2 Paul Mockapetris and DNS

In 1983, Paul Mockapetris at USC proposed a distributed hierarchical name system in RFC 882/883 (later RFC 1034/1035). The key ideas:

  1. Hierarchy: Start from top-level domains like .com, .edu, .kr and delegate downward.
  2. Delegation of authority: Parent zones hand administration of child zones off to someone else.
  3. Caching: Responses are cached for the TTL duration.
  4. Bidirectional translation: name to IP (forward), IP to name (reverse).

This design is still the foundation of the internet 40 years later. It hasn't changed because it hasn't needed to — it is an excellent abstraction.

1.3 Major Milestones

  • 1987: RFC 1034/1035 standardization.
  • 1990s: BIND (Berkeley Internet Name Domain) becomes widespread.
  • 1999: DNSSEC proposed (RFC 2535).
  • 2005: DNSSEC redesigned (RFC 4033).
  • 2010: Root zone signing begins.
  • 2018: DoH standardized (RFC 8484).
  • 2022: DoQ (DNS over QUIC) standardized (RFC 9250).
  • 2024: Full rollout of DNS HTTPS/SVCB records.

DNS evolves slowly but steadily.


2. The DNS Namespace

2.1 FQDN Structure

A name like www.example.com. is read right to left:

.               (root, usually omitted)
com.            (TLD - Top-Level Domain)
example.com.    (SLD - Second-Level Domain)
www.example.com. (subdomain / hostname)

The trailing dot really is there — an FQDN (Fully Qualified Domain Name) is explicit all the way to the root. It's usually left off in conversation.

2.2 DNS Zone

A zone is the set of names managed by one authoritative server. The example.com zone might include example.com, www.example.com, mail.example.com. But if you delegate sub.example.com to a different server, sub.example.com becomes a separate zone.

Zone file example (BIND format):

$ORIGIN example.com.
$TTL 3600

@       IN SOA  ns1.example.com. admin.example.com. (
                2026041500 ; serial
                3600       ; refresh
                1800       ; retry
                604800     ; expire
                86400 )    ; minimum TTL

@       IN NS   ns1.example.com.
@       IN NS   ns2.example.com.
@       IN A    192.0.2.1
www     IN A    192.0.2.1
mail    IN A    192.0.2.2
@       IN MX   10 mail.example.com.

2.3 TLD Types

  • gTLD (generic): .com, .net, .org, .dev, .io. Expanded into the thousands after 2012.
  • ccTLD (country-code): .kr, .jp, .uk. Based on country codes.
  • infrastructure TLD: .arpa. Reserved for reverse lookups.
  • sTLD (sponsored): .edu, .gov. Managed by specific organizations.

ICANN manages the root. Each TLD is operated by a separate registry (Verisign runs .com, .net, etc.).


3. How a Query Actually Flows

3.1 The Big Picture

When your browser resolves www.example.com:

1. Browser cache → OS cache → /etc/hosts → stub resolver
2. Stub resolver (libc)Recursive resolver (ISP or 1.1.1.1, etc.)
3. Recursive resolver cache hit? YESreturn immediately
                      NO → next step
4. RecursiveRoot servers (13 including a.root-servers.net)
   "who runs .com?""these NS records"
5. Recursive.com TLD servers
   "who runs example.com?""ns1.example.com, ns2.example.com"
6. Recursive → ns1.example.com (authoritative)
   "what's www.example.com?""192.0.2.1"
7. Recursive caches the result and returns it to the stub
8. Stub returns to OS, OS returns to browser

This can take 100–500 ms when "cold." Under 1 ms on a cache hit.

3.2 Stub Resolver

A minimal DNS client built into the OS. getaddrinfo() actually calls this. On Linux, glibc reads resolv.conf to decide which recursive resolver to send to.

# /etc/resolv.conf
nameserver 1.1.1.1
nameserver 8.8.8.8
search example.com internal.local
options ndots:2 timeout:2 attempts:3
  • nameserver: recursive resolver addresses.
  • search: domain suffixes to try.
  • ndots: if the name has fewer than N dots, try the search domains.
  • timeout/attempts: wait and retry per server.

Most modern systems also have a local stub cache like systemd-resolved. If resolv.conf points at 127.0.0.53, systemd-resolved sits behind it.

3.3 Recursive Resolver

A server that recursively resolves queries on a user's behalf. Run by ISPs or public services (Cloudflare 1.1.1.1, Google 8.8.8.8, Quad9 9.9.9.9).

Key responsibilities:

  • Cache management (respecting TTL).
  • Iterative queries in Root → TLD → Authoritative order.
  • RRSIG validation on responses (when DNSSEC is enabled).
  • Return the final answer to the client.

3.4 Root Servers

13 logical servers (a.root-servers.net through m.root-servers.net). Each is physically distributed via anycast across hundreds of sites. Anywhere in the world routes to the nearest node.

The root zone is very small — it contains only NS records for TLDs. ICANN manages it, and several organizations (Verisign, University of Maryland, NASA, etc.) operate individual root servers.

3.5 Authoritative Servers

Servers that give the "official" answer for a specific domain. Operated by the domain owner or outsourced (Cloudflare DNS, AWS Route 53, Google Cloud DNS).

Typical setup: one primary (master) plus multiple secondary (slave) servers. Edits to the zone file on the primary are propagated to secondaries via AXFR/IXFR.

Glue Record: To get the IP of ns1.example.com, you first need the NS records for example.com. But if that NS is ns1.example.com itself, you have a cycle. The parent zone (.com) solves this by bundling the A record for ns1.example.com as a "glue" record.


4. Record Types — What Gets Stored

4.1 Basic Records

  • A: IPv4 address. example.com. IN A 192.0.2.1
  • AAAA: IPv6 address. example.com. IN AAAA 2001:db8::1
  • CNAME: Canonical name. www.example.com. IN CNAME example.com.
    • Caveat: a name pointed to by a CNAME cannot have other records. CNAMEs at the apex (top of a zone) are forbidden.
  • NS: Authoritative server for this zone. example.com. IN NS ns1.example.com.
  • SOA (Start of Authority): Zone metadata — primary, admin email, serial, refresh/retry/expire/minimum.
  • MX: Mail exchange server. Includes priority. example.com. IN MX 10 mail.example.com.
  • TXT: Arbitrary text. Used for SPF, DKIM, DMARC, domain verification.
  • PTR: Reverse lookup (IP to name). 1.2.0.192.in-addr.arpa. IN PTR example.com.
  • SRV: Service location. _sip._tcp.example.com. IN SRV 0 5 5060 sipserver.example.com.
  • CAA: Certificate issuance policy. Which CAs are allowed to issue certificates.

4.2 Recent Additions

  • HTTPS/SVCB (RFC 9460): Ubiquitous since 2024. One record carries HTTP/3 support, IP hints, ECH public keys, and more.
example.com. HTTPS 1 . alpn="h3,h2" ipv4hint=192.0.2.1 ech=AEX+...

When a browser sees this record, it tries HTTP/3 immediately, has IP hints already, and uses ECH for SNI encryption in the TLS handshake. One DNS lookup solves a lot.

  • SVCB: General service binding. HTTPS is the specialized form of SVCB.

4.3 DNSSEC-Only Records

  • DNSKEY: Zone's public key.
  • RRSIG: Signature over an RRset.
  • DS (Delegation Signer): Hash of the child's key, stored in the parent zone.
  • NSEC / NSEC3: Proof that "this name does not exist."

4.4 The Reality of CNAME Chains

A CNAME can go through several hops before resolving to an A record:

www.example.com. CNAME cdn.example.com.
cdn.example.com. CNAME xyz.cloudfront.net.
xyz.cloudfront.net. CNAME d123.cloudfront.net.
d123.cloudfront.net. A 192.0.2.10

Browsers usually get the final A record in one go, but the resolver has to chase each step. Long chains slow the lookup and increase failure points. Keep it to 3–4 hops at most is the common guidance.

There's also the problem that apex domains (example.com itself) cannot use CNAME. To attach a CDN at the apex you need:

  • ALIAS records (DNS-provider-specific feature — Route 53, Cloudflare, NS1).
  • ANAME (some providers).
  • CNAME flattening (Cloudflare): behaves like an apex CNAME; the server resolves it to an A record before answering.

These aren't RFC standards, they're hacks each provider implements. RFC 9460 (HTTPS records) in 2024 partially solves this, but a complete alternative still doesn't exist.


5. Message Format — At the Byte Level

5.1 DNS Packet Structure

A header plus four sections:

+---------------------+
|        Header       |
+---------------------+
|       Question      | — what's being asked
+---------------------+
|        Answer       | — the actual answer
+---------------------+
|      Authority      | — authoritative NS
+---------------------+
|      Additional     | — bonus info (A records for NSes)
+---------------------+

5.2 Header

                                1  1  1  1  1  1
  0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                      ID                       |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    QDCOUNT                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    ANCOUNT                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    NSCOUNT                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    ARCOUNT                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  • ID: Transaction ID. The response comes back with the same ID.
  • QR: 0=query, 1=response.
  • Opcode: 0=standard query, 5=update (dynamic DNS).
  • AA: authoritative answer.
  • TC: truncated — cut off past the 512-byte UDP limit.
  • RD: recursion desired.
  • RA: recursion available.
  • RCODE: 0=NOERROR, 2=SERVFAIL, 3=NXDOMAIN, 5=REFUSED.
  • QDCOUNT/ANCOUNT/NSCOUNT/ARCOUNT: record counts for each section.

5.3 Name Compression

The same name can appear many times in a packet. DNS compresses them with "pointers": if the first two bits are 11, the remaining 14 bits are an offset inside the packet.

[0x03]www[0x07]example[0x03]com[0x00]    -- first appearance
[0xC0 0x00]                                -- reference to "the name at offset 0"

Only valid within the 16KB packet limit, but most DNS packets are small enough that this is effective.

5.4 The 512-Byte UDP Limit and the TC Bit

Classic DNS runs over UDP port 53. A single message is capped at 512 bytes. Past that, the TC bit is set to implicitly tell the client "come back over TCP."

DNSSEC responses easily exceed 512 bytes thanks to RRSIGs. So EDNS0 (Extension Mechanisms for DNS) is essential.

5.5 EDNS0

Carries extension fields via an OPT record. Main features:

  • UDP payload size negotiation: Client advertises "I can receive up to 4096 bytes." If the server's response is smaller, it goes over UDP; if bigger, TC plus TCP.
  • DO (DNSSEC OK) flag: Client wants DNSSEC responses.
  • Extended RCODE: Error codes beyond 4 bits.
  • Client Subnet (EDNS-CSUBNET): Passes the user's actual subnet to the authoritative server, improving CDN geo-routing accuracy.

Modern DNS barely works without EDNS0. If a very old middlebox drops packets it doesn't recognize as EDNS0, DNSSEC validation fails and users experience "the site won't load."


6. Caching and TTL — Why the Internet Scales

6.1 What TTL Means

Every DNS response includes a TTL (Time To Live) — "you may cache this response for N seconds."

www.example.com. 300 IN A 192.0.2.1
                 ^^^
                 TTL: 300 seconds = 5 minutes

Small TTL:

  • Changes propagate fast.
  • More load on recursive resolvers.
  • More load on authoritative servers.

Large TTL:

  • Slow propagation (up to TTL + recursive's refresh interval).
  • Less load.

6.2 Multiple Layers of Cache

Caching actually stacks across many levels:

Browser cache      (its own TTL, typically minutes)
OS cache           (DNS Client on Windows/macOS)
systemd-resolved   (Linux)
Recursive resolver (ISP/Cloudflare)
Authoritative (the real answer)

A cache hit at any level means higher layers also receive and cache that answer. Change propagation has to wait for TTLs at every one of these layers to expire.

That's why "I changed DNS but it still goes to the old IP" is such a common complaint. Something, somewhere in the chain still has a valid cache. Patience is DNS's main virtue.

6.3 Negative Caching

NXDOMAIN (no such name) responses are cached too. The SOA record's minimum field sets the cache duration:

SOA ... ( ... 86400 )   ; 86400 = NXDOMAIN cached for 1 day

Too large and "my newly created domain isn't visible yet" becomes a problem. Too small and attackers can trigger load by querying nonexistent names in a loop.

6.4 TTL Tuning Strategy

  • Ordinary service records: 300–3600 seconds (5 minutes to 1 hour).
  • Records about to change: 60–300 seconds, lowered several days in advance.
  • NS records that rarely change: 86400–172800 seconds (1–2 days).
  • Extreme stability (root zone): 2 days.

Lowering TTL before a migration is a basic technique. Raise it back after the change to reduce load.


7. DNSSEC — Signed DNS

7.1 Why DNSSEC

Plain DNS has no trust. You can't tell if a response was tampered with in transit. DNS hijacking, cache poisoning, the Kaminsky attack — all real.

DNSSEC attaches a digital signature to each RRset to guarantee integrity.

7.2 Components

  • DNSKEY: Zone's public keys (ZSK — Zone Signing Key, KSK — Key Signing Key).
  • RRSIG: Signatures over each RRset (signed with the ZSK).
  • DS: Parent zone holds a hash of the child's KSK.
  • NSEC / NSEC3: Proof of non-existence.

7.3 Chain of Trust

Root zone KSK (published globally, managed by ICANN)
Root zone signs .com's DS
.com zone's KSK is validated by that DS
.com zone signs example.com's DS
 → example.com zone's KSK is validated by that DS
 → example.com's ZSK is signed by its KSK
 → actual records are signed by the ZSK

A validating resolver only needs the root KSK baked in, and can walk down this chain to verify every record's integrity.

7.4 Structure of RRSIG

www.example.com. 300 IN A 192.0.2.1
www.example.com. 300 IN RRSIG A 8 3 300 (
    20260501000000 20260415000000 12345 example.com.
    SIGNATURE_BYTES )
  • Algorithm (8 = RSA/SHA-256).
  • Number of labels (3 = number of labels in www.example.com.).
  • Original TTL.
  • Signature expiration / inception.
  • Key tag (DNSKEY identifier).
  • Signer's name.
  • The actual signature.

Signatures have limited validity (days to weeks), so periodic re-signing is required. This renewal is usually automated via automatic signing (a default feature of BIND, PowerDNS, Knot).

7.5 NSEC and NSEC3 — Proof of Non-existence

How do you prove that "foo.example.com doesn't exist"? Via a sorted linked list:

alpha.example.com.  NSEC  beta.example.com. A RRSIG NSEC
beta.example.com.   NSEC  charlie.example.com. A RRSIG NSEC
...

When the resolver asks for delta, the server returns charlie.example.com NSEC epsilon.example.com — "delta is not between charlie and epsilon." That NSEC is itself signed with an RRSIG, so integrity is verifiable.

Problem: Following this chain lets you enumerate every name in the zone (zone walking). That's a privacy leak.

NSEC3: Order by hashed names, so the linked list is over hashes. Hard to reverse, which mitigates zone walking (but doesn't eliminate it — a public NSEC3 walker appeared in 2011).

Evolving toward newer options like NSEC5 or black lies (Cloudflare's live-signing DNSSEC).

7.6 The Reality of Deployment

DNSSEC adoption is still low. As of 2026:

  • TLD level: mostly deployed (.com, .net, .org, .dev, etc.).
  • SLD level: only 10–30% of domains are signed.
  • Validating resolvers: Cloudflare, Google, Quad9 validate by default.

Why is rollout slow?

  • Key management is complex (ZSK rotation, KSK rollover requires coordination with the parent).
  • A misconfiguration causes SERVFAIL, which takes the whole site down.
  • Large CAs already provide MITM protection (HTTPS certs), so the perceived need is weaker.

Even so, DNSSEC offers value distinct from the certificate ecosystem. Certificates are validated after the TLS handshake. DNSSEC guarantees integrity of name resolution in the step before. Technologies like DANE (DNS-based Authentication of Named Entities, RFC 6698) stack certificate pinning on top of DNSSEC. True security is the combination of both layers.


8. DoH / DoT / DoQ — Encrypted DNS

8.1 The Problem

Plain DNS uses UDP/TCP port 53 and is cleartext. Anyone can eavesdrop:

  • ISPs see which sites you visit.
  • Sniffers on public Wi-Fi.
  • Nation-state DNS-based blocking.

8.2 DoT (DNS over TLS) — RFC 7858

Wraps DNS queries in TLS. Port 853. Simple and firewall-friendly.

Client  (TLS)DoT Resolver  (plain)Authoritative

Only the segment between the client and the recursive is encrypted. Everything past that is still plaintext.

8.3 DoH (DNS over HTTPS) — RFC 8484

A more radical approach. Wrap DNS queries in HTTP POST/GET. Port 443. Indistinguishable from normal web traffic.

POST /dns-query HTTP/2
Host: cloudflare-dns.com
Content-Type: application/dns-message

Pros:

  • Firewalls can't distinguish it from web traffic, so it bypasses blocks.
  • Inherits HTTP/2 and HTTP/3 benefits (multiplexing, 1-RTT).
  • Browsers can implement it directly.

Cons:

  • Operators can't easily enforce internal DNS policies (DoH bypasses enterprise DNS).
  • Privacy depends on the resolver — all queries concentrated at Cloudflare/Google.

In 2019 Firefox enabled Cloudflare DoH by default in the US via TRR (Trusted Recursive Resolver). It was controversial, but a privacy step forward.

8.4 DoQ (DNS over QUIC) — RFC 9250

Standardized in 2022. DNS over QUIC. Compared to DoT:

  • Faster with 0-RTT resumption.
  • Connection migration support.
  • No head-of-line blocking.

Supported on mobile and at Cloudflare 1.1.1.1. Rollout is still limited, but the direction is clear.

8.5 ODoH (Oblivious DoH) — Extreme Privacy

Developed by Cloudflare and Apple. The DoH resolver decrypts the content but doesn't know who asked:

ClientProxy (TLS)Target Resolver
          ↑                ↑
          sees IP       sees content
          (no content)  (no IP)

The client encrypts the query with the target resolver's public key and sends it via the proxy. The proxy sees the client IP but not the content. The target resolver decrypts the content but doesn't know the client IP.

Deployed in production as Apple Private Relay and Cloudflare ODoH. Strong resistance to nation-state surveillance.

8.6 Combined with Encrypted Client Hello (ECH)

ECH, covered in the TLS/QUIC post, hides the SNI in the TLS handshake. Combine DoH and ECH:

  1. DNS lookups are encrypted, so the ISP doesn't know which domain is being resolved.
  2. SNI is encrypted in the TLS handshake, so the ISP doesn't know which site is being accessed.

From the ISP's view, only "some HTTPS connection somewhere" is visible. A real step toward privacy.


9. Anycast — Why CDN DNS Is Fast

9.1 Unicast vs Anycast

  • Unicast: one IP equals one server. The ordinary model.
  • Anycast: the same IP is announced by servers in multiple regions. BGP routing sends traffic to the "closest" server.
Cloudflare 1.1.1.1
  ├── Tokyo PoP
  ├── Frankfurt PoP
  ├── Sao Paulo PoP
  ├── ... 300+ cities

A Tokyo user querying 1.1.1.1 is routed by BGP to the Tokyo PoP and gets a response in a few ms. Meanwhile a German user querying the same IP is routed to Frankfurt.

9.2 Why It Fits DNS

DNS queries and responses are tiny (UDP around 100 B) and stateless. Any PoP can answer identically. The "any node can respond" property of anycast is a perfect fit.

Connection-oriented TCP services are tricky on anycast (route flaps break connections). But a single request-response pair over UDP is fine.

9.3 13 Root Servers — Thousands Inside

"13 root servers" refers to logical names. Each of the a through m root servers is actually distributed via anycast across hundreds of PoPs. Total physical servers exceed 2,000.

That's why a root query resolves in milliseconds from any ISP. DNS's global availability and performance owe a lot to anycast.

9.4 Route 53 and Cloudflare DNS in Practice

AWS Route 53 runs anycast across 100+ locations. A domain's four NS records cover different location combinations, so a regional outage automatically fails over.

Cloudflare takes it to an extreme with 300+ PoPs. Moving a domain to Cloudflare DNS perceptibly changes TTFB (Time To First Byte).

9.5 ECS (EDNS Client Subnet)

If the authoritative knows "where the requester actually is," it can do geo-optimal routing. ECS has the recursive resolver pass the client IP's /24 to the authoritative.

RecursiveAuthoritative
  "who's www.example.com, for client in 192.0.2.0/24?"

The authoritative returns the IP of a CDN PoP in that region. DNS-based geo routing works via this.

Privacy tradeoff: part of the client IP reaches the authoritative. If you want full privacy, disable ECS — at the cost of routing accuracy.


10. CoreDNS — Kubernetes's Name Service

10.1 Where CoreDNS Fits

Inside Kubernetes, names like my-service.my-namespace.svc.cluster.local are resolved by CoreDNS. It's the successor to kube-dns and a CNCF graduated project.

A Pod's /etc/resolv.conf:

search my-namespace.svc.cluster.local svc.cluster.local cluster.local
nameserver 10.96.0.10  # kube-dns ClusterIP
options ndots:5

Querying just my-service resolves to my-service.my-namespace.svc.cluster.local thanks to the search domains.

10.2 Plugin-Based Architecture

CoreDNS was designed by Miek Gieben, the same author as the Caddy web server. It uses a plugin-chain model.

# Corefile
.:53 {
    errors
    health
    ready
    kubernetes cluster.local in-addr.arpa ip6.arpa {
        pods insecure
        fallthrough in-addr.arpa ip6.arpa
    }
    prometheus :9153
    forward . /etc/resolv.conf
    cache 30
    loop
    reload
    loadbalance
}

Each plugin is a step in the query pipeline. Enable only what you need. The kubernetes plugin pulls Service and Endpoint info from the Kubernetes API server and produces DNS responses.

10.3 The ndots Trap

ndots:5 means "if the name has fewer than 5 dots, try search domains first." So even google.com (1 dot) tries search domains first:

google.com.my-namespace.svc.cluster.localNXDOMAIN
google.com.svc.cluster.localNXDOMAIN
google.com.cluster.localNXDOMAIN
google.com → the real answer

Every external lookup triggers 3–4 extra queries. Under high traffic this explodes CoreDNS load. Mitigations:

  • Set ndots: 2 in the Pod's dnsConfig (usually enough).
  • NodeLocal DNSCache (per-node caching daemon).
  • Stub domains to send external names directly out.

NodeLocal DNSCache is the default in recent Kubernetes installs. It spreads CoreDNS load per node and caches aggressively — effect is dramatic.

10.4 Service Types and DNS

  • ClusterIP Service: my-service.ns.svc.cluster.local returns an A record for the ClusterIP.
  • Headless Service (clusterIP=None): A records directly return Pod IPs. Common for StatefulSets.
  • ExternalName: Returns a CNAME. Maps to an external FQDN.

Each Pod of a StatefulSet also gets its own DNS name: pod-0.my-service.ns.svc.cluster.local.

10.5 DNS Debugging

# Inside a Pod
nslookup my-service
nslookup my-service.other-namespace.svc.cluster.local
dig @10.96.0.10 my-service.ns.svc.cluster.local

# Check CoreDNS logs
kubectl logs -n kube-system deploy/coredns

90% of "my service can't be found" incidents are:

  • Typo in Service name or namespace.
  • Selector doesn't match the Pod's labels.
  • Empty endpoints (Pod isn't Ready).

11. DNS Attacks and Defenses

11.1 Cache Poisoning

A classic 1990s attack. Inject a forged response into a recursive resolver's cache, and every subsequent query gets the bad answer.

The Kaminsky attack (2008): DNS transaction IDs are 16 bits — send enough forged responses and timing alignment becomes feasible. Target: recursive resolvers.

Mitigations:

  • Source port randomization (transaction ID 16 bits + src port 16 bits = 32 bits to guess).
  • DNSSEC validation.
  • 0x20 encoding (randomize the case of query name, response must match to be valid).

11.2 DNS Amplification DDoS

An attacker triggers a large response with a small query. The responses rain down on the target IP.

Attacker  (spoofed src IP = victim)DNS server
                           Victim  (large response)

Amplification of 50–100x is common. DNSSEC responses are especially large.

Mitigations:

  • Remove open resolvers (expose only authoritatives externally).
  • RRL (Response Rate Limiting): limit repeated queries from the same IP.
  • BCP 38 (ingress filtering): ISPs filter spoofed source IPs.
  • DDoS scrubbing services (Cloudflare, Akamai, etc.).

11.3 Subdomain Takeover

Suppose you CNAMEd app.example.com to myapp.herokuapp.com, then deleted the Heroku app. An attacker registers myapp and hijacks app.example.com traffic.

Prevention:

  • Delete unused CNAMEs.
  • Monitoring: periodically check that the target exists.
  • CAA records to restrict certificate issuance.

11.4 DNS Rebinding

An attack that bypasses the browser's same-origin policy. The attacker rapidly changes the A record of their domain to an internal victim IP like 192.168.1.1, so JS fetched from the attacker's domain can reach the victim's internal network.

Mitigations:

  • "Private IP filtering" in public recursive resolvers (on by default in 1.1.1.1, 8.8.8.8).
  • Filter private IPs in DNS responses at the firewall.
  • Validate the Host header in web apps.

11.5 DNS Tunneling

Ship arbitrary data in the payload of DNS queries. Originally used to bypass firewalls (DNS is almost always open).

Malware uses it as a C2 (Command and Control) channel. Large volumes of unusual TXT queries are suspicious.

Defenses:

  • DNS traffic analysis (packet sizes, query patterns).
  • Blacklist-based filtering.
  • DNS filtering services like Cisco Umbrella, Cloudflare Gateway.

12. Real-World Operations

12.1 Good DNS Design

  • Multiple NS: at least two, in different geographies and networks. Global anycast providers like Route 53 or Cloudflare are recommended.
  • Appropriate TTL: default 3600, lowered before changes.
  • Wildcards with care: *.example.com matches unintended names too.
  • SPF/DKIM/DMARC: email authentication. Without them spam scores worsen.
  • CAA records: example.com. CAA 0 issue "letsencrypt.org" restricts cert issuance.
  • DNSSEC: deploy if possible, using automated signing tools.

12.2 Monitoring

  • NS server availability: probe from multiple regions externally.
  • SOA serial: confirm secondaries match the primary.
  • Response time: watch p99. Abnormal values suggest anycast routing issues.
  • NXDOMAIN growth: typos/attacks/expired names.
  • DNSSEC signature expiry: once the validity window ends, everything SERVFAILs — total outage.

12.3 Common Incident Patterns

  • DNSSEC key rollover mistakes: if the parent's DS and the child's KSK get misaligned, every resolver SERVFAILs. Full site outage. Real incidents include KeyTrap (discovered in 2024) and the 2018 delay of the KSK rollover.
  • TTL too high plus a needed change: lower TTL the day before a migration. Otherwise it's 72 hours until everyone sees the new IP.
  • CNAME chain too long or looped.
  • Overlapping wildcards: if both *.example.com and *.a.example.com exist, you get unintended matches.
  • Apex CNAME attempts: not standard. Required to use a provider that supports CNAME flattening.
  • Private IP leaks: accidentally publishing A records for internal-only domains in public DNS.

12.4 Tools

  • dig: the standard tool.
dig example.com
dig +trace example.com          # trace from root
dig +dnssec example.com          # include DNSSEC records
dig @1.1.1.1 example.com ANY    # specify a resolver
dig -x 192.0.2.1                 # reverse lookup
  • drill: alternative to dig, from NLnet Labs.
  • kdig (Knot Resolver's tool): modern output format.
  • mtr / traceroute: debug network paths alongside DNS.
  • dnsperf: load-test authoritative servers.

12.5 Migration Strategy

Checklist for migrating a DNS provider:

  1. Measure current TTL. NS records are typically 2 days.
  2. A few weeks out, lower TTL (300–600 seconds).
  3. Replicate all zones at the new provider.
  4. Verify new NS responses from outside.
  5. Change NS at the registrar.
  6. Keep the old NS live for at least 2x the TTL (in case of caching).
  7. Confirm and only then decommission the old NS.

Large migrations taking a month is normal. Impatience is the biggest enemy.


13. Fun Stories

13.1 Facebook's 6-Hour Outage in 2021

On October 4, 2021, Facebook/Instagram/WhatsApp were down for six hours. Cause: a bad BGP announcement update made the authoritative NS servers vanish from the internet, so all Facebook DNS stopped resolving.

Worse: internal recovery tools also depended on DNS. Engineers had to physically go to data centers to fix it. There were even stories that building access badges depended on DNS, and they couldn't get inside.

Lesson: don't make recovery tools depend on DNS.

13.2 Dyn 2016

The Mirai botnet DDoSed Dyn (a major DNS provider) at 1 Tbps, taking GitHub, Twitter, Netflix, Reddit, and more down for hours. Depending on a single DNS provider is a single point of failure.

After that, large enterprises adopted a multi-DNS strategy (Dyn + Route 53 + Cloudflare in parallel).

13.3 The Story of Cloudflare's 1.1.1.1

Cloudflare announced 1.1.1.1 on April Fool's Day 2018. The bizarre history of this IP:

  • So simple that many companies had been using it internally or as a test IP.
  • Even before Cloudflare made it an official resolver, weird traffic was already flowing to this IP from all over the internet.
  • Cloudflare got use of it in partnership with APNIC, and used traffic patterns for research.

Today it's the flagship free public DoH/DoT resolver. 1.1.1.1 (primary), 1.0.0.1 (secondary).


Closing — Invisible Infrastructure

DNS is the most foundational and most invisible part of the internet. It's the precondition for the web working and the first step of every service. That it has run for 40 years without changing its base design is astonishing.

As an operator, three things to instinctively check:

  1. Make TTL part of your plan. Changes take effect on TTL time. Lower it before migrations, raise it again once stable.
  2. Redundant DNS service. Depending on a single provider is a single point of failure. Multi-NS, multi-provider.
  3. Don't deny "It's always DNS." When something breaks, suspect DNS first. dig +trace is the first step.

Understanding DNS makes invisible infrastructure visible. Then you become the person who answers first on the incident call.

The next post covers the internal structure of CDNs — Cache, Edge Compute, Origin Shield, Cache Key. What happens after DNS routes users to an edge PoP. A byte-level look at the modern web architecture that pushes everything to the edge.