정적 경로를 게이트웨이 이름으로 향하게 하면 주소가 바뀌어도 살아남을 것 같지만 실제로는 그렇지 않습니다. 이름은 DNS에 살고, 경로는 클라이언트의 라우팅 테이블에 숫자 형태의 다음 홉으로 앉아 있습니다. Pi가 다른 주소로 옮겨 가면, 이미 옛 홉을 설치한 모든 소비자는 계속 같은 번호로 트래픽을 보냅니다. 포워딩 테이블에 연결된 리졸버는 없으므로 그 항목을 대신 다시 써 주는 것은 없습니다.

DNS 응답과 경로는 서로 다른 객체입니다

Pi가 vpn-gw.lan에 응답하고 10.44.0.0/16을 터널로 전달한다고 해 봅시다. 192.168.30.0/24의 클라이언트는 정적 경로를 통해 그곳에 도달합니다. Pi의 주소가 192.168.30.4에서 192.168.30.11로 옮겨 갔을 때, 레코드는 TTL 안에서 따라갔지만 경로는 따라가지 않았습니다.

두 시각은 놓치기 쉬운 방식으로 어긋납니다. 따로 물어보면 둘 다 그럴듯해 보이기 때문입니다.

$ ip route get 10.44.0.1
10.44.0.1 via 192.168.30.4 dev eth0 src 192.168.30.20
$ dig +short vpn-gw.lan
192.168.30.11

패킷이 어디로 갈지는 첫 줄만 결정합니다. 둘째 줄은 커널이 한 번도 묻지 않은 질문에 답하고 있습니다. A 레코드가 여러 개인 레코드도 장애 조치 정책이 되지 않습니다. 각 주소는 여전히 그 세그먼트에서 쓸 수 있는 다음 홉이어야 하기 때문입니다.

명령이 끝난 뒤 테이블에 남는 것

Linux 경로는 여기서 중요한 두 가지를 기록합니다. 프로토콜 주소로서의 다음 홉, 그리고 인덱스 번호로서의 출구 인터페이스입니다. rtnetlink 경로 속성 은 그 첫 번째 필드를 RTA_GATEWAY라고 부르며, 여기에는 바이트가 들어갑니다. 항목이 자리를 잡으면 TTL이 붙지 않고 백그라운드 조회도 그것을 새로 고치지 않습니다.

그래서 ip route add 10.44.0.0/16 via vpn-gw.lan이 동작하는 것처럼 보일 수 있습니다. 도구는 명령이 실행되는 동안 이름을 해석하고, 그 결과 주소를 기록하고, 이름은 완전히 잊어버립니다. 그 뒤에 ip route show 10.44.0.0/16을 실행하면 문자 그대로의 주소가 돌아옵니다.

터널을 탓하기 전에 이 동작을 알아 둘 만합니다.

이름을 대신 해석해 주는 도구, 그리고 그 시점

일부 라우터와 방화벽은 경로나 게이트웨이 필드에 호스트 이름을 실제로 받아들입니다. 중요한 것은 해석이 언제 일어나는가입니다. 장치가 구성을 적용할 때만 이름을 해석한다면, 저장된 항목은 직접 입력한 주소만큼이나 정적이며, 나중에 주소가 바뀌면 한 번 더 적용해야 합니다. 필드가 이름을 받아들인다는 사실은 갱신에 대해 아무것도 알려 주지 않습니다.

관리형 설정은 보통 일을 나눕니다. DHCP 예약이나 정적 임대가 Pi를 한 주소에 붙잡아 두고, DNS 레코드는 그 임대를 그대로 따릅니다. 목표가 움직이지 않으므로 움직이는 목표를 추적할 필요가 없습니다.

모니터링되는 업데이터가 또 하나의 정당한 패턴이며, 여기에는 소유자가 필요합니다.

주소를 고정하거나 업데이터를 직접 실행하세요

작은 LAN이라면 DHCP 서버의 예약이 가장 저렴한 해결책입니다. 동적 풀 밖의 주소를 골라 Pi의 MAC 주소에 묶고, 다음 임대 갱신 뒤에 ip -4 addr show dev eth0로 확인하세요. 그다음 클라이언트의 다음 홉을 그 주소로 한 번 향하게 하세요. 이제 안정적인 게이트웨이와 그것을 설명하는 레코드가 생겼습니다. 관계가 실제로 작동하는 순서가 바로 이것입니다.

Pi가 정말로 옮겨야 한다면, 모든 클라이언트를 손으로 고치는 대신 경로 수리를 한곳에 모으세요. 해석하고 비교하고 교체하는 짧은 스크립트면 그 단계를 반복 가능하게 만들 수 있습니다.

new=$(dig +short vpn-gw.lan | head -n1)
cur=$(ip route get 10.44.0.1 | awk '{print $3}')
if [ "$new" != "$cur" ]; then
  ip route replace 10.44.0.0/16 via "$new"
fi
ip route get 10.44.0.1

마지막 명령이 인수 테스트입니다. 커널이 실제로 사용할 게이트웨이를 출력하기 때문입니다. 출력된 주소가 여전히 옛것이라면 스크립트가 잘못된 네트워크 네임스페이스에서 실행되었거나 권한이 없었던 것이고, DNS 쪽은 무관합니다.

돌아오는 경로도 확인하세요. Pi는 클라이언트 서브넷에 어떻게 도달할지 알아야 하고, 방화벽이 터널 트래픽을 허용해야 합니다. 불일치를 덮으려고 추가한 기본 경로는 보통 진짜 틈을 숨기고 일주일 뒤에 다른 무언가를 망가뜨립니다.

관련 글