権威サーバは変わったのにキャッシュは古い答えを返す
한국어 원문으로 표시합니다.
목표
파이썬으로 권한 DNS 서버와 캐시 서버를 띄우고, dig 로 TTL·CNAME·부정 응답을 읽은 뒤 "존은 바꿨는데 캐시는 옛 답을 준다" 를 직접 재현합니다.
왜 중요한가
DNS 장애는 대부분 "누가 무엇을 얼마 동안 기억하고 있는가" 의 문제입니다. /etc/hosts 는 DNS 보다 먼저 답하고, 캐시는 권한 서버가 준 TTL 만큼 옛 답을 돌려주며, 없는 이름조차 SOA 가 정한 시간만큼 기억됩니다. 이 실습은 그 세 층을 각각 손으로 만져 봅니다. 재료 서버 /opt/app/minidns.py 는 표준 라이브러리로 만든 작은 DNS 로, 권한 모드는 질의마다 존 파일을 다시 읽고 캐시 모드는 TTL 을 줄여 가며 답합니다.
단계
- 존 파일
/root/dns/zone.txt를 만드세요.lab.internal.의 SOA(마지막 필드 minimum 은60),www.lab.internal.A10.0.0.10TTL120,api.lab.internal.CNAMEwww.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에 저장하세요. /etc/hosts에10.0.0.99 www.lab.internal을 추가하고,getent hosts www.lab.internal의 결과와/etc/nsswitch.conf의hosts:줄을/root/dns/02-hosts.txt에 저장하세요.- 캐시 서버를
python3 /opt/app/minidns.py cache --upstream 127.0.0.1:5300 --port 5301로 띄우고,www.lab.internal을 캐시(5301)에 몇 초 간격으로 두 번 물어 두 answer 를 모두/root/dns/03-ttl.txt에 저장하세요. - 캐시에
api.lab.internal의 A 를 물어 answer 를/root/dns/04-cname.txt에 저장하세요. - 없는 이름
nope.lab.internal을 캐시에+comments +authority로 몇 초 간격으로 두 번 물어/root/dns/05-nx.txt에 저장하고, 부정 응답이 캐시에 남는 초를/root/dns/05-negttl.txt에 숫자 하나로 적으세요. - 캐시에
www를 한 번 물어 채운 뒤, 존 파일의www.lab.internal.을10.0.0.11로 바꾸고 SOA serial 을 올리세요. 그리고 120초 안에 권한 서버(5300)와 캐시(5301)에 차례로 물어 두 answer 를/root/dns/06-stale.txt에 저장하세요. - 캐시 서버를 끝내고 다시 띄운 뒤
www의 answer 를/root/dns/07-after.txt에 저장하세요. 캐시를 비울 수 없었다면 옛 답이 최대 몇 초까지 남을 수 있는지/root/dns/07-window.txt에 숫자 하나로 적으세요. 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에 저장하세요./root/dns/09-report.md에 정리하세요./etc/hosts가 왜 먼저인지, 이전 시 최악의 전파 시간(초), 부정 캐시 시간(초),ndots가 만드는 추가 질의를 담아야 합니다.
참고
dig의+noall +answer는 answer 절만,+comments +authority는 상태줄과 authority 절을 보여 줍니다.- 권한 서버는 존 파일을 질의마다 다시 읽습니다. 고친 뒤 재기동할 필요가 없습니다. 캐시 서버는 재기동해야 비워집니다.
- 6단계의 "캐시는 옛 답" 은 캐시를 채운 뒤 TTL(120초) 안에 관찰해야 보입니다. 시간이 지났으면 캐시를 다시 채우고 다시 하세요.
- 흔한 실수: 캐시(5301)가 아니라 권한 서버(5300)에 두 번 물으면 TTL 이 줄지 않습니다. 권한 서버는 항상 존의 TTL 을 그대로 줍니다.
존 파일과 권한 서버
/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/hosts 에 10.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단계 로그에서 본 질의 순서를 그대로 적으면 됩니다.