LabHub

네트워크 기초 — 리눅스 VM 에서 손으로 · 라우팅과 DNS · 이론

길과 이름 — 라우팅 테이블과 DNS 의 층

LabHub 에서 이어서 보기

한 줄 요약

라우팅은 "이 목적지는 어느 인터페이스로, 누구를 거쳐" 를 최장 접두사 일치로 고르는 것이고, 리눅스는 ip_forward 를 켜야 남의 패킷을 넘긴다. 이름 해석은 /etc/hosts → 스텁 → 상류 서버의 여러 층이고, dig 는 그중 마지막 층만 본다.

왜 이게 필요했나

서브넷 밖으로 나가는 패킷은 게이트웨이에게 맡겨진다. 그 게이트웨이는 다시 자기 라우팅 테이블을 보고 다음 게이트웨이를 고른다. 이 연쇄가 인터넷이다. 각 홉이 아는 것은 "이 대역은 저쪽" 뿐이고, 전체 경로를 아는 장치는 없다. 그래서 라우팅 사고는 한 홉이 한 대역을 모르는 것에서 난다 — 가는 길은 있는데 돌아오는 길이 없는 경우가 특히 흔하고, 증상은 그냥 timeout 이라 구별되지 않는다.

이름도 마찬가지로 층이 있다. 옛날엔 /etc/resolv.conf 에 서버 주소가 있고 그것으로 끝이었다. 지금 우분투는 systemd-resolved127.0.0.53 에서 스텁으로 듣고, 링크마다 다른 상류 서버로 넘기며, ~domain 라우팅 규칙으로 특정 도메인만 특정 서버에 보낼 수 있다. VPN 이 회사 도메인만 회사 DNS 로 보내는 것이 이 장치다. 편리하지만, 어느 층이 답했는지 모르면 "dig 는 되는데 curl 은 안 된다" 를 설명할 수 없다.

어떻게 동작하나

라우팅 테이블에 default via 10.20.1.110.99.0.0/24 via 10.20.2.10 이 있으면 10.99.0.5 는 뒤의 줄로 간다. 더 긴 프리픽스가 이기고, 적힌 순서는 상관없다. ip route get 10.99.0.5 는 이 판정을 커널에게 직접 물어 답을 받는다 — 사람이 테이블을 읽고 추론하는 것보다 정확하다.

리눅스는 기본으로 라우터가 아니다. 자기 주소가 아닌 패킷은 버린다. net.ipv4.ip_forward=1 이 그것을 바꾸고, 네임스페이스마다 값이 따로다. 도커 호스트·쿠버네티스 노드·VPN 서버가 전부 이 값이 1 이다.

이름 해석은 애플리케이션이 libc 의 getaddrinfo 를 부르면서 시작한다. /etc/nsswitch.confhosts: files dns 순서대로 /etc/hosts 를 먼저 보고, 없으면 resolv.conf 의 스텁에 묻고, 스텁은 링크 설정을 보고 상류로 넘긴다. dig 는 이 층을 다 건너뛰고 서버에 직접 묻는다. 그래서 서버가 무엇을 답하는지는 dig, 애플리케이션이 무엇을 보는지는 getent hosts 로 본다.

현장에서 만나는 모습

돌아오는 길. 새 대역을 붙이고 라우터에 경로를 넣었다. ping 이 안 된다. 상대 쪽 라우터가 새 대역으로 돌아오는 경로를 모른다. 요청은 도착했고 응답이 길을 잃었다. 양쪽에서 ip route get 을 해 보면 한쪽만 default 로 엉뚱한 곳을 가리킨다.

포트 53 충돌. dnsmasq 를 깔았는데 안 뜬다. ss -ulpn 'sport = :53' 을 보면 systemd-resolve 가 127.0.0.53 을 잡고 있다. 해결은 dnsmasq 에 listen-addressbind-interfaces 로 자기 주소만 잡게 하는 것이다.

다음 실습에서 할 것

네임스페이스 셋으로 호스트–라우터–호스트를 세워 기본 경로·ip_forward·정적 경로를 넣고 traceroute 로 홉을 센다. 그다음 dnsmasq 로 내 DNS 서버를 세우고 resolved 의 라우팅 도메인에 물려, /etc/hosts 가 DNS 를 이기는 것을 getentdig 로 나란히 확인한다.