VPN 클라이언트에서 사설 DNS 이름이 실패하는 이유와 확인할 지점
클라이언트가 여러분의 리졸버를 신뢰하고, 접미사가 한정되어 있고, 응답이 터널을 통해 돌아올 수 있을 때만 사설 이름이 확인됩니다.
호텔 방에서 노트북을 열고 클라이언트를 실행한 뒤 내부 파일 서버 이름을 입력했는데 아무것도 돌아오지 않습니다. 터널은 연결됨을 알리고 같은 서브넷 안의 주소로 보낸 ping에는 여전히 응답이 오므로 전송 자체는 정상입니다. 실패하는 것은 이름뿐이고, 그 간극은 문제를 두 곳으로 좁힙니다. 클라이언트가 어느 리졸버에 물었는지, 그리고 받은 응답이 터널을 통해 돌아올 수 있는지입니다. 한쪽을 고치고 다른 쪽을 건너뛰면 장애는 자리만 옮깁니다.
어떤 프로필이든 편집하기 전에 클라이언트가 이름을 어떻게 다루는지 확인하세요. Linux에서는 resolvectl query files.corp.example 이 어느 링크와 어느 리졸버가 응답을 만들었는지 보여 줍니다. Windows에서는 Resolve-DnsName files.corp.example 이 응답한 서버와 돌려준 주소를 보여 줍니다.
무엇이든 바꾸기 전에 응답을 읽으세요
이름이 몇 밀리초 만에 NXDOMAIN으로 돌아오면 질의가 여러분의 존에 도달한 적이 없고 공용 또는 호텔 리졸버가 대신 응답한 것입니다. 긴 멈춤 뒤에 돌아오면 경로 어딘가에서 UDP 53 포트를 버리고 있어 클라이언트가 결국 대안으로 내려간 것입니다. 올바른 주소로 응답하는데도 연결이 계속 멈춘다면 이름 확인은 정상이고 문제는 라우팅이나 서비스 자체에 있습니다.
이 삼분법은 한 시간의 추측을 아껴 줍니다. VPN을 건드려야 하는지도 알려 줍니다. 올바른 사설 주소로 확인되는 이름은 이미 리졸버 경로를 증명했으므로 남은 작업은 데이터 경로에 있습니다.
터널 안쪽에서 리졸버를 배포하세요
클라이언트는 두 부류로 나뉩니다. 한쪽은 연결을 설정할 때 서버가 리졸버를 지정할 수 있고, 다른 쪽은 설정을 로컬 파일에 두어 어떤 게이트웨이도 원격으로 바꿀 수 없습니다.
OpenVPN 은 첫 번째 부류입니다. 서버에서는 push "dhcp-option DNS 10.8.0.53" 과 push "dhcp-option DOMAIN corp.example" 이 제어 채널을 따라 내려가지만, 클라이언트 설정에 pull 이 여전히 켜져 있을 때만 그렇습니다. 손으로 고쳐 pull-filter ignore "dhcp-option" 을 담고 있는 클라이언트는 그것들을 결코 보지 못하며, 바로 이 한 줄이 «서버는 밀어 주는데 내 노트북은 동의하지 않는다»는 사례를 놀랄 만큼 많이 설명합니다.
WireGuard는 두 번째 부류이고, 이 프로토콜에는 옵션 협상이 아예 없습니다. 리졸버와 검색 도메인은 클라이언트 자신의 [Interface] 블록에 DNS = 10.8.0.53, corp.example 형태로 들어갑니다. wg-quick은 이를 resolvconf나 systemd-resolved를 통해 적용하고, Windows에서는 공식 클라이언트가 터널이 올라와 있는 동안에만 존재하는 NRPT 규칙을 설치합니다. Get-DnsClientNrptPolicy 이 그 규칙을 나열하므로 클라이언트가 여러분의 파일을 실제로 적용했는지 빠르게 확인할 수 있습니다.
IPsec/IKEv2는 중간입니다. strongSwan의 attr 플러그인은 풀에서 가져온 DNS 서버를 돌려줄 수 있고 Windows 클라이언트는 보통 이를 받아들이지만, 자기 이름 서버를 고정한 프로필은 게이트웨이가 제안하는 무엇이든 이깁니다. Linux 클라이언트에서 같은 역할을 하는 수동 단계는 resolvectl dns wg0 10.8.0.53 이고 그다음이 resolvectl domain wg0 '~corp.example' 입니다. 둘 다 인터페이스와 함께 사라지며, 이는 터널에 한정된 설정에 정확히 원하는 동작입니다.
모든 질의를 삼키는 대신 접미사를 한정하세요
클라이언트의 리졸버 목록 전체를 내부 서버로 돌리는 것은 쉽고 대개 틀렸습니다. 그러면 모든 공용 이름이 데이터 센터의 출구를 통해 확인되고, CDN은 먼 주소를 돌려주며, 리졸버 장애 한 번에 사용자의 브라우징이 함께 무너집니다.
안쪽으로는 사설 접미사만 보내세요. systemd-resolved에서 ~ 로 시작하는 도메인은 라우팅 전용이므로, ~corp.example 는 그 접미사 아래의 질의가 해당 링크의 서버로 간다는 뜻이고 나머지는 계속 물리 네트워크를 씁니다. Windows는 네임스페이스에 한정된 NRPT 규칙으로 같은 일을 하고, macOS는 /etc/resolver/ 아래의 보조 리졸버 파일로 합니다.
멀티캐스트 이름에는 별도의 답이 필요합니다. .local 이름은 설계상 링크 로컬(RFC 6762)이고 점대점 tun 인터페이스는 그 멀티캐스트 그룹을 나르지 않으므로, 공용 리졸버를 추가해도 그것들이 공개되지 않고 내부 유니캐스트 리졸버에 물어도 NXDOMAIN이 돌아옵니다. avahi 같은 리플렉터를 리플렉터 모드로 두면 두 세그먼트를 연결할 수 있지만, 그것은 어떤 클라이언트도 요구할 수 없는 서버 측 결정입니다. 프린터나 NAS에 이름으로 접근해야 한다면 대신 여러분의 존에 A 레코드를 두세요.
응답이 돌아올 수 있음을 증명하세요
도달할 수 없는 주소를 가리키는 올바른 응답은 경로를 확인하기 전까지 리졸버 문제와 똑같이 보입니다. 커널에 응답이 어디로 갈지 물어보세요. ip route get 10.20.5.20 은 인터페이스와, 더 유용하게는 사용할 원본 주소를 알려 줍니다.
리졸버 주소 자체를 지켜보세요. DNS = 10.8.0.53 옆에 AllowedIPs = 10.20.0.0/16 이 있는 클라이언트는 질의를 물리 NIC 밖으로 내보내고, 리졸버가 터널이 주장하는 어떤 프리픽스에도 들어 있지 않기 때문에 그 질의는 조용히 죽습니다. 이 불일치가 이 분야 전체에서 가장 흔한 단일 원인 장애이며, DNS 설정을 허용된 프리픽스와 줄 단위로 비교하지 않으면 보이지 않습니다.
겹치는 범위는 반대 방향의 장애를 만듭니다. 응답은 맞고 경로도 있지만 엉뚱한 호스트를 가리키는데, 집의 192.168.0.0/24 이 같은 범위로 가는 터널 경로보다 더 구체적이기 때문이므로 한쪽의 번호를 다시 매기거나 더 좁은 경로를 밀어 넣은 다음 서비스 호스트의 방화벽과 돌아오는 경로를 확인하세요. strongSwan의 포워딩 관련 설명이 그 경로의 sysctl 쪽을 다룹니다.
인증서는 사람들이 DNS 탓으로 돌리는 별개의 신원 확인입니다. 브라우저가 확인 오류 대신 이름 불일치를 보고한다면 이름 확인은 이미 성공한 것이고 고칠 것은 인증서의 SAN입니다. HTTPS는 이름으로 시험하고 맨 IP로는 절대 시험하지 마세요.
게이트웨이가 아니라 클라이언트에서 다시 시험하세요
사용자가 불평하는 그 응용 프로그램 안에서 시험하세요. 명령줄 조회는 브라우저가 같은 경로를 탄다는 증거가 아닙니다. Chrome의 보안 DNS와 Firefox의 network.trr.mode 은 시스템 리졸버를 완전히 우회할 수 있고, 그렇게 되면 사설 이름은 실패하거나 공용 리졸버로 새어 나갑니다. resolvectl query 과 손으로 실행한 dig @10.8.0.53 files.corp.example 을 비교하면 둘 중 무엇이 일어났는지 알 수 있습니다.
그다음 고쳤다고 말하기 전에 연결을 끊고 다시 연결하세요. 인터페이스에 손으로 넣은 설정은 인터페이스와 함께 사라지고, 잊고 남긴 로컬 편집 때문에 그저 맞아 보였던 프로필은 다음 부팅에서 실패합니다.
다음 기기를 위한 짧은 점검 목록은 이름이 터널의 리졸버로 확인되는지, 접미사가 전역이 아니라 한정되어 있는지, 리졸버 주소가 허용된 프리픽스 안에 있는지, 응답의 호스트가 서비스 포트에서 응답하는지, 인증서가 사용자가 입력한 이름을 포함하는지입니다.