LabHub
배우기 러닝패스 코스

The certificate was renewed, but the browser still showed the old one

The authority changed, but the cache serves the old answer

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

목표

파이썬으로 권한 DNS 서버와 캐시 서버를 띄우고, dig 로 TTL·CNAME·부정 응답을 읽은 뒤 "존은 바꿨는데 캐시는 옛 답을 준다" 를 직접 재현합니다.

왜 중요한가

DNS 장애는 대부분 "누가 무엇을 얼마 동안 기억하고 있는가" 의 문제입니다. /etc/hosts 는 DNS 보다 먼저 답하고, 캐시는 권한 서버가 준 TTL 만큼 옛 답을 돌려주며, 없는 이름조차 SOA 가 정한 시간만큼 기억됩니다. 이 실습은 그 세 층을 각각 손으로 만져 봅니다. 재료 서버 /opt/app/minidns.py 는 표준 라이브러리로 만든 작은 DNS 로, 권한 모드는 질의마다 존 파일을 다시 읽고 캐시 모드는 TTL 을 줄여 가며 답합니다.

단계

  1. 존 파일 /root/dns/zone.txt 를 만드세요. lab.internal. 의 SOA(마지막 필드 minimum 은 60), www.lab.internal. A 10.0.0.10 TTL 120, api.lab.internal. CNAME www.lab.internal. 이 있어야 합니다. 권한 서버를 python3 /opt/app/minidns.py auth --zone /root/dns/zone.txt --port 5300 으로 띄우고(로그는 /root/dns/auth.log 로), dig @127.0.0.1 -p 5300 www.lab.internal A +noall +answer 의 결과를 /root/dns/01-auth.txt 에 저장하세요.
  2. /etc/hosts10.0.0.99 www.lab.internal 을 추가하고, getent hosts www.lab.internal 의 결과와 /etc/nsswitch.confhosts: 줄을 /root/dns/02-hosts.txt 에 저장하세요.
  3. 캐시 서버를 python3 /opt/app/minidns.py cache --upstream 127.0.0.1:5300 --port 5301 로 띄우고, www.lab.internal 을 캐시(5301)에 몇 초 간격으로 두 번 물어 두 answer 를 모두 /root/dns/03-ttl.txt 에 저장하세요.
  4. 캐시에 api.lab.internal 의 A 를 물어 answer 를 /root/dns/04-cname.txt 에 저장하세요.
  5. 없는 이름 nope.lab.internal 을 캐시에 +comments +authority 로 몇 초 간격으로 두 번 물어 /root/dns/05-nx.txt 에 저장하고, 부정 응답이 캐시에 남는 초를 /root/dns/05-negttl.txt 에 숫자 하나로 적으세요.
  6. 캐시에 www 를 한 번 물어 채운 뒤, 존 파일의 www.lab.internal.10.0.0.11 로 바꾸고 SOA serial 을 올리세요. 그리고 120초 안에 권한 서버(5300)와 캐시(5301)에 차례로 물어 두 answer 를 /root/dns/06-stale.txt 에 저장하세요.
  7. 캐시 서버를 끝내고 다시 띄운 뒤 www 의 answer 를 /root/dns/07-after.txt 에 저장하세요. 캐시를 비울 수 없었다면 옛 답이 최대 몇 초까지 남을 수 있는지 /root/dns/07-window.txt 에 숫자 하나로 적으세요.
  8. dig @127.0.0.1 -p 5300 +search +domain=lab.internal +ndots=5 api.lab A 로 짧은 이름을 물은 뒤, 권한 서버 로그(/root/dns/auth.log)에서 api.lab 이 들어간 QUERY 줄을 뽑아 /root/dns/08-search.txt 에 저장하세요.
  9. /root/dns/09-report.md 에 정리하세요. /etc/hosts 가 왜 먼저인지, 이전 시 최악의 전파 시간(초), 부정 캐시 시간(초), ndots 가 만드는 추가 질의를 담아야 합니다.

참고

존 파일과 권한 서버

/root/dns/zone.txt 를 만들고 권한 서버를 5300 에 띄운 뒤 www.lab.internal 의 answer 를 /root/dns/01-auth.txt 에 저장하세요.

존 파일은 한 줄에 이름 TTL 타입 값 입니다. 이름은 끝에 점을 붙인 절대 이름으로 적으세요. SOA 값은 주서버 관리자 serial refresh retry expire minimum 일곱 항목이고 마지막 minimum 이 부정 응답 캐시 시간입니다. 서버는 nohup ... > /root/dns/auth.log 2>&1 & 로 뒤에 두세요.

/etc/hosts 가 먼저다

/etc/hosts10.0.0.99 www.lab.internal 을 넣고 getent hosts www.lab.internal 결과와 nsswitch 의 hosts: 줄을 /root/dns/02-hosts.txt 에 저장하세요.

getent 는 프로그램과 같은 경로(nsswitch)로 이름을 풉니다. hosts: 줄에서 files 가 dns 앞에 있으면 /etc/hosts 가 이깁니다. grep '^hosts:' /etc/nsswitch.conf 로 그 줄만 뽑을 수 있습니다.

캐시는 TTL 을 줄여 가며 답한다

캐시 서버를 5301 에 띄우고 www.lab.internal 을 몇 초 간격으로 두 번 물어 두 answer 를 /root/dns/03-ttl.txt 에 저장하세요.

캐시 모드는 minidns.py cache --upstream 127.0.0.1:5300 --port 5301 입니다. 첫 질의는 상류에 묻고 저장하며, 두 번째부터는 남은 TTL 을 줄여 돌려줍니다. 두 번째 결과는 >> 로 이어 붙이세요.

CNAME 사슬은 한 답에 온다

캐시에 api.lab.internal 의 A 를 물어 answer 를 /root/dns/04-cname.txt 에 저장하세요.

CNAME 을 만난 리졸버는 사슬 끝의 A 까지 따라가 두 레코드를 한 answer 에 넣습니다. 한 줄만 보이면 타입을 CNAME 으로 물은 것입니다 — A 로 물으세요.

없는 이름도 기억된다

nope.lab.internal 을 캐시에 +comments +authority 로 몇 초 간격으로 두 번 물어 /root/dns/05-nx.txt 에 저장하고, 부정 응답이 캐시에 남는 초를 /root/dns/05-negttl.txt 에 적으세요.

NXDOMAIN 답에는 answer 가 없고 authority 절에 SOA 가 옵니다. 그 SOA 의 TTL 이 이 부정 응답의 캐시 시간이고, RFC 2308 대로 SOA minimum 과 SOA 자체 TTL 중 작은 값입니다. 두 번 물어 그 TTL 이 줄어드는 것까지 남기세요.

존은 바뀌었는데 캐시는 옛 답

캐시에 www 를 물어 채운 뒤 존의 www.lab.internal.10.0.0.11 로 바꾸고 serial 을 올리세요. 120초 안에 권한 서버와 캐시에 차례로 물어 두 answer 를 /root/dns/06-stale.txt 에 저장하세요.

권한 서버는 파일을 바로 읽으니 새 주소를 주고, 캐시는 저장해 둔 옛 답을 TTL 이 다할 때까지 줍니다. 순서가 중요합니다 — 캐시를 먼저 채우고, 고치고, 바로 두 곳에 물으세요. serial 은 sed 로 한 자리만 올리면 됩니다.

캐시를 비우면, 못 비우면

캐시 서버를 끝내고 다시 띄운 뒤 www 의 answer 를 /root/dns/07-after.txt 에, 캐시를 못 비울 때 옛 답이 남을 수 있는 최대 초를 /root/dns/07-window.txt 에 적으세요.

이 캐시는 메모리에만 저장하므로 프로세스를 끝내면 비워집니다(pkill -f 'minidns.py cache'). 남의 캐시(고객의 ISP)는 비울 수 없고, 그때 기다려야 하는 시간은 바꾸기 전 레코드의 TTL 입니다.

ndots 가 만드는 추가 질의

+search +domain=lab.internal +ndots=5 api.lab 으로 물은 뒤 권한 서버 로그에서 api.lab 이 든 QUERY 줄을 /root/dns/08-search.txt 에 저장하세요.

점이 ndots 보다 적은 이름에는 검색 도메인이 먼저 붙습니다. 그래서 로그에 api.lab.lab.internal. 질의가 먼저, 실패한 뒤 api.lab. 질의가 나옵니다. grep 'QUERY api\.lab' /root/dns/auth.log 로 뽑으세요.

정리 보고서

/root/dns/09-report.md/etc/hosts 우선순위, 최악의 전파 시간(초), 부정 캐시 시간(초), ndots 가 만드는 추가 질의를 정리하세요.

이 실습에서 직접 잰 숫자를 쓰세요. 전파 시간은 7단계, 부정 캐시는 5단계의 값입니다. ndots 는 8단계 로그에서 본 질의 순서를 그대로 적으면 됩니다.