DNS 누수의 판단 기준

DNS 누수는 도메인 조회가 의도한 경로를 벗어나 처리되는 현상입니다. 예를 들어 브라우저 트래픽은 프록시를 통하지만 도메인 조회 요청은 여전히 로컬 통신사의 DNS에서 처리될 수 있습니다. 웹페이지가 열리거나 외부 IP가 바뀌었다는 사실만으로 DNS도 의도한 경로를 거친다고 단정할 수 없습니다. 점검할 때는 애플리케이션 연결, DNS 업스트림, DNS 연결의 실제 출구를 각각 확인해야 합니다.

이 문서의 설정은 mihomo 커널을 사용하는 클라이언트를 대상으로 합니다. 구형 Clash 커널과 클라이언트 버전에 따라 지원하는 필드가 다를 수 있으므로, 수정 전에 클라이언트의 ‘정보’ 또는 커널 정보 화면에서 커널 이름과 버전, 현재 설정의 출처를 확인하세요. 메뉴 이름은 클라이언트마다 다릅니다. 특정 클라이언트의 메뉴 경로를 일반적인 방법으로 오해하지 않도록 아래에서는 설정 필드를 기준으로 설명합니다.

테스트 순서: 기준 결과를 기록하고 프록시 사용 전후를 비교하세요

1. 프록시를 사용하지 않을 때의 결과 기록

  1. 프록시 연결을 중지하고 현재 공인 IP, 시스템에 설정된 DNS 주소, 브라우저의 보안 DNS 설정을 기록합니다.
  2. https://www.dnsleaktest.com/에 접속해 Standard test와 Extended test를 각각 실행하고, 리졸버 IP와 조직명, 테스트 시간을 기록합니다.
  3. 현재 사용하는 시스템 프록시 또는 TUN을 켜고 캐시를 비운 다음, 같은 브라우저에서 두 가지 테스트를 다시 실행합니다.
  4. 노드와 브라우저, 네트워크는 그대로 유지하고 DNS 설정을 한 번에 하나씩만 변경한 뒤 테스트를 반복하세요. 노드, 리졸버, 트래픽 가로채기 방식을 동시에 바꾸지 마세요.

온라인 테스트는 보통 무작위 하위 도메인을 조회해 재귀 리졸버의 출처를 확인합니다. 결과에 표시되는 IP는 대개 리졸버의 재귀 질의 출구이며, 기기의 외부 IP가 아니고 설정에 지정한 1.1.1.1 같은 접속 주소와 일치하지 않을 수도 있습니다. 공용 DNS의 애니캐스트 라우팅과 위치 정보 데이터베이스의 오차도 표시 지역에 영향을 줍니다. 따라서 ‘리졸버 국가와 노드 국가가 다르다’는 사실은 단서일 뿐, 그 자체로 누수를 의미하지 않습니다.

2. 캐시를 비우고 테스트 조건 유지하기

Windows에서는 터미널에서 아래 명령을 실행할 수 있습니다. macOS의 두 번째 명령은 관리자 권한이 필요합니다. 캐시를 비운 다음 브라우저를 완전히 종료했다가 다시 열고, 필요하면 프록시에도 다시 연결하세요. 기존 연결이 이전 DNS 경로를 재사용하는 일을 방지할 수 있습니다.

# Windows
ipconfig /flushdns

# macOS
sudo dscacheutil -flushcache
sudo killall -HUP mDNSResponder

# systemd-resolved를 사용하는 Linux
resolvectl flush-caches

모든 Linux 배포판이 systemd-resolved를 사용하는 것은 아닙니다. 명령을 찾을 수 없다면 현재 DNS 리졸버 서비스를 확인하세요. 테스트 기록에는 시간, 트래픽 가로채기 방식, 브라우저 보안 DNS 상태, 리졸버 조직, 실제 연결 출구 등 다섯 가지 항목을 포함하는 것이 좋습니다. 임의의 실측 백분율은 제시하지 않으며, 수정 효과는 현재 기기에서 반복한 테스트 결과로 확인해야 합니다.

3. 주소 개수만 보지 말고 근거에 따라 결과 판단하기

테스트 결과가능한 원인다음 단계
로컬 통신사 리졸버가 표시됨시스템 DNS가 가로채지지 않았거나 정책에서 직접 연결하도록 설정됨TUN, 53번 포트 요청, DNS 정책 확인
공용 리졸버만 표시됨커널 또는 브라우저에서 공용 DNS 사용 중연결 출구를 추가로 확인하세요. 이 결과만으로 프록시를 통한다고 판단할 수 없습니다.
공용 리졸버가 여러 개 표시됨병렬 조회, fallback 또는 리졸버 클러스터설정된 업스트림과 하나씩 대조
브라우저와 명령줄의 결과가 다름브라우저의 독립 DoH, 캐시 또는 앱 프록시 설정 차이DNS 조회 경로를 하나로 정리한 뒤 다시 테스트

fake-ip와 nameserver: 확인 가능한 DNS 진입점부터 설정하기

enhanced-mode: fake-ip를 설정하면 커널이 해당 도메인에 가상 주소를 반환하고, 주소 매핑을 바탕으로 연결을 처리합니다. 일부 연결은 실제 주소를 미리 조회할 필요가 줄지만, 모든 업스트림 조회가 없어지는 것은 아닙니다. 직접 연결이나 IP 주소 기반 규칙 판정, 일부 앱에서는 여전히 실제 DNS 조회 결과가 필요할 수 있습니다.

아래는 DNS 연결 경로를 점검하기 위한 설정 예시이며, 완전한 구독 설정은 아닙니다. 기존 노드와 정책 그룹, 규칙은 유지하고 동일한 필드를 기존 설정에 합쳐 넣으세요. 같은 계층에 dns:를 두 번 작성하지 마세요. 예시의 7890은 혼합 프록시 포트이고 1053은 로컬 DNS 리스닝 포트입니다. 서로 바꿔 사용할 수 없습니다.

mixed-port: 7890
mode: rule

dns:
  enable: true
  listen: 127.0.0.1:1053
  enhanced-mode: fake-ip
  fake-ip-range: 198.18.0.1/16
  fake-ip-filter:
    - "localhost"
    - "*.lan"
  nameserver:
    - https://1.1.1.1/dns-query
    - https://8.8.8.8/dns-query
  • enable은 커널 DNS를 활성화합니다. 이 항목만 켜서는 모든 앱이 해당 리스닝 주소로 요청을 보내도록 자동 설정되지 않습니다.
  • listen은 로컬 테스트에 사용할 루프백 주소에 바인딩합니다. 점검을 위해 모든 네트워크 인터페이스에서 바로 수신하도록 설정하지 마세요. 로컬 네트워크에 DNS 서비스가 노출될 수 있습니다.
  • fake-ip-filter에 등록한 도메인은 실제 주소로 조회됩니다. 실제 호환성 문제가 있는 경우에만 추가하고, 특정 앱 하나를 해결하기 위해 모든 도메인을 제외하지 마세요.
  • nameserver는 업스트림을 지정합니다. 업스트림을 여러 개 설정해도 엄격한 주 서버·보조 서버 순서로 처리되는 것은 아닙니다. 첫 번째 주소가 완전히 실패한 뒤에야 두 번째 주소를 사용한다고 단정할 수 없습니다.

아래 명령으로 커널의 UDP DNS 리스너를 직접 확인할 수 있습니다. 필터링되지 않은 도메인을 조회하면 198.18.0.0/16 범위의 가상 주소가 표시되는 것이 정상입니다. 이 결과는 이번 조회가 커널에 도달했다는 것만 보여 주며, 브라우저도 같은 경로를 사용한다는 뜻은 아닙니다.

# Windows
nslookup -port=1053 example.com 127.0.0.1

# dig가 설치된 macOS / Linux
dig @127.0.0.1 -p 1053 example.com A

DoH 연결 출구: 암호화 전송과 프록시 전송은 다릅니다

예시의 DoH는 일반적으로 TCP 443을 통해 HTTPS 연결을 맺으므로 조회 내용이 일반 UDP 53 패킷으로 전송되지는 않습니다. 하지만 이 연결이 직접 연결이면 리졸버는 로컬 네트워크의 공인 IP를 확인할 수 있고, 로컬 네트워크에서도 리졸버 연결의 목적지 주소를 관찰할 수 있습니다. 리졸버에 프록시 노드의 출구 IP가 표시되게 하려면 커널이 시작하는 DNS 연결에 적용되는 라우팅 규칙도 확인해야 합니다.

respect-rules 사용 전 노드 도메인의 DNS 조회부터 해결하기

해당 필드를 지원하는 mihomo에서는 dns.respect-rules: true를 설정해 DNS 연결이 라우팅 규칙을 따르게 할 수 있습니다. 이 설정은 ‘모든 DNS를 강제로 프록시 연결’하는 기능이 아닙니다. 리졸버 IP가 DIRECT 규칙에 매칭되면 직접 연결됩니다. 실제 규칙에서 선택한 리졸버 주소가 기존 프록시 정책을 따르게 설정하고, 앞선 직접 연결 규칙이 먼저 매칭되지 않도록 하세요.

이 기능을 켤 때는 proxy-server-nameserver도 설정해 프록시 노드 서버 도메인의 초기 조회를 별도로 처리해야 합니다. 그렇지 않으면 프록시에 연결하려면 먼저 노드 도메인을 조회해야 하고, 조회하려면 다시 프록시에 연결해야 하는 순환 의존성이 발생할 수 있습니다. 초기 조회용 리졸버도 네트워크 조건에 맞아야 합니다. 직접 연결되는 초기 조회를 사용하면 노드 도메인이 해당 리졸버에 노출된다는 점을 고려해야 합니다.

도메인 형식의 DoH 주소를 사용하면 리졸버 도메인을 처음 조회할 방법도 필요합니다. default-nameserver는 이런 초기 조회에 사용하며, 일반 DNS 조회의 기본 라우팅 정책은 아닙니다. 위 예시에서는 점검 범위를 줄이기 위해 IP 형식의 DoH 주소를 사용했지만, 업스트림 연결 가능 여부와 TLS 인증서 검증, 실제 연결 출구를 여전히 확인해야 합니다.

fallback과 nameserver-policy: 예상치 못한 DNS 경로 줄이기

fallback은 병렬 조회에 사용될 수 있습니다

fallback은 단순히 ‘주 DNS가 시간 초과된 뒤에만 실행되는 설정’이 아닙니다. 설정에 따라 커널이 주 리졸버와 보조 리졸버에 동시에 조회를 보내고, fallback-filter를 기준으로 어느 쪽 결과를 사용할지 결정할 수 있습니다. 따라서 테스트 페이지에 보조 DNS 서비스가 표시되더라도 주 리졸버가 고장 났거나 요청이 프록시를 우회했다고 단정할 수 없습니다.

초기 점검 단계에서는 fallback을 생략해 경로를 단순하게 유지하는 것이 좋습니다. 기본 연결 경로를 확인한 후 오염된 주소를 필터링해야 하는 경우 아래 필드를 기존 dns 블록에 합쳐 넣을 수 있습니다. 이 예시는 GeoIP 판정을 끄고 명시한 주소 범위에 해당할 때 보조 결과를 사용하도록 설정합니다. 모든 오염된 응답을 찾아내는 방법은 아닙니다.

  fallback:
    - https://9.9.9.9/dns-query
  fallback-filter:
    geoip: false
    ipcidr:
      - 0.0.0.0/32
      - 240.0.0.0/4

fallback-filter.geoip를 켜고 geoip-code: CN을 설정하면 주 DNS 응답이 지정 지역에 속하는지에 따라 결과 선택이 달라집니다. 이는 DNS 출구 제어가 아니라 응답 필터링입니다. 데이터베이스 만료, CDN 주소의 위치 정보 변경, 여러 지역에 걸친 서비스 구성에 따라 판단이 달라질 수 있으므로 GeoIP 판정을 범용 DNS 누수 방지 설정으로 사용하지 마세요.

nameserver-policy로 ‘조회할 리졸버’ 지정하기

nameserver-policy를 사용하면 도메인별로 리졸버를 지정할 수 있습니다. 예를 들어 아래 설정은 example.com과 하위 도메인의 조회에 지정한 DoH를 사용하도록 합니다. 이 도메인은 문법 설명을 위한 예시입니다. 실제로는 전용 리졸버가 필요한 도메인을 입력하고 설정을 합친 뒤 동작을 확인하세요.

  nameserver-policy:
    "+.example.com":
      - https://1.1.1.1/dns-query

도메인 조회 정책과 연결 라우팅 규칙은 별개의 판단 기준입니다. 리졸버를 지정해도 해당 웹사이트 트래픽이 프록시로 바뀌는 것은 아닙니다. 반대로 웹사이트 규칙을 프록시로 설정해도 리졸버 연결까지 반드시 프록시를 통하는 것은 아닙니다. 사내 네트워크나 가정용 기기의 도메인에는 로컬 리졸버가 필요할 수 있습니다. 이런 도메인만 직접 연결되는 리졸버를 지정했다면, 의도적으로 남겨 둔 예외로 기록하고 공용 도메인 테스트와 구분하세요.

TUN DNS 가로채기: 시스템의 53번 포트 조회 처리하기

시스템 프록시는 프록시 설정을 따르는 앱에 주로 영향을 주며 시스템 DNS 경로까지 자동으로 바꾸지는 않습니다. TUN은 더 많은 IP 트래픽을 커널로 전달하고, DNS 가로채기를 함께 설정하면 일반 DNS 요청을 받아 처리할 수 있습니다. 아래 역시 기존 설정에 합쳐 넣는 예시입니다. TUN을 지원하는 mihomo 클라이언트가 필요하며, 플랫폼별 요구 사항에 따라 가상 네트워크 인터페이스 생성과 라우팅 변경을 허용해야 합니다.

tun:
  enable: true
  stack: mixed
  auto-route: true
  auto-detect-interface: true
  dns-hijack:
    - any:53
    - tcp://any:53
  • auto-route는 라우팅을 자동으로 설정합니다. 활성화한 뒤에는 스위치가 켜져 있는지만 보지 말고 클라이언트에 TUN이 실제로 실행 중이라고 표시되는지 확인하세요.
  • any:53과 tcp://any:53은 가로채기 경로로 들어오는 일반 UDP 및 TCP DNS 요청을 각각 처리합니다.
  • auto-detect-interface는 트래픽이 나갈 네트워크 인터페이스를 찾는 데 도움이 됩니다. VPN이나 가상 인터페이스가 여러 개 있거나 특수 라우팅을 사용하는 경우에는 실제로 선택된 인터페이스를 확인해야 합니다.

DNS 가로채기가 모든 암호화된 DNS를 차단하는 것은 아닙니다. 앱에 내장된 DoH는 HTTPS를 사용하고 DoT는 보통 TCP 853을 사용하므로 53번 포트 규칙에 포함해도 커널 DNS로 바뀌지 않습니다. 다른 VPN이 이미 가로챈 요청이나 제외 경로를 통해 우회하는 요청, 특수한 시스템 DNS 경로에서 처리되는 요청도 이 가로채기 규칙에 들어오지 않을 수 있습니다.

브라우저 보안 DNS와 IPv6도 따로 확인하기

테스트 중에는 브라우저의 독립 보안 DNS를 일시적으로 꺼서 브라우저와 시스템이 같은 DNS 경로를 사용하게 할 수 있습니다. Chrome에서는 ‘설정’ → ‘개인 정보 보호 및 보안’ → ‘보안’에서 ‘보안 DNS 사용’을 확인하세요. 메뉴 문구는 버전에 따라 달라질 수 있습니다. 브라우저 DoH를 계속 사용하려면 리졸버, 연결 출구, 실패 시 대체 동작을 포함해 별도 경로로 점검해야 합니다.

IPv6도 함께 확인하세요. DNS에서 AAAA 레코드를 반환하는 것과 IPv6 트래픽이 올바르게 가로채지는 것은 별개의 문제입니다. dns.ipv6: false는 커널의 AAAA 응답 처리에 영향을 주지만 시스템 IPv6 라우팅 제어를 대신하지 않습니다. 앱 자체 DNS 조회에서는 여전히 IPv6 주소를 받을 수 있습니다. IPv4 출구만 확인하고 테스트를 끝내지 마세요.

수정 후 검증과 자주 발생하는 문제

세 단계의 근거로 결과 확인하기

  1. 진입점 확인: 로컬 1053 포트로 DNS 조회가 정상 동작하고 fake-ip 매핑이 예상대로 처리되는지 확인합니다. TUN을 켠 뒤에는 시스템의 일반 DNS 요청이 커널에 전달되는지도 확인하세요.
  2. 라우팅 확인: 클라이언트의 연결 패널이나 디버그 로그에서 리졸버 주소와 적용된 정책, 연결 출구를 확인합니다. 디버그 로그를 켰다면 확인 후 평소 로그 수준으로 되돌리고, 공유하기 전에는 도메인과 노드, 구독 정보를 삭제하세요.
  3. 외부 확인: 기본 테스트와 확장 테스트를 다시 실행해 표시된 모든 리졸버를 현재 설정으로 설명할 수 있는지 확인합니다. 브라우저와 명령줄, 보호 대상인 다른 앱에서도 검증하세요.

실제 외부 연결에 사용하는 네트워크 인터페이스에서 패킷을 캡처하고 Wireshark 표시 필터 udp.port == 53 || tcp.port == 53 || tcp.port == 853를 사용해 일반 DNS와 흔히 쓰이는 DoT 연결을 찾을 수도 있습니다. 캡처 인터페이스를 올바르게 선택해야 합니다. 가상 인터페이스의 평문 요청은 이후 커널이 가로챌 수 있으므로 이를 물리 네트워크의 누수로 바로 판단하면 안 됩니다. DoH는 HTTPS 트래픽에 섞이므로 이 필터만으로 조회 내용을 확인할 수 없습니다.

fake-ip를 켰는데도 테스트에 통신사 DNS가 표시됩니다. 어디부터 확인해야 하나요?

먼저 로컬 1053 포트로 DNS 설정이 적용됐는지 확인한 다음, 시스템 조회가 TUN으로 들어오는지 확인하세요. 이어서 브라우저의 독립 DNS 조회, 다른 VPN, 정책에 지정된 로컬 리졸버, 구독 업데이트가 수정을 덮어썼는지 점검합니다. fake-ip 자체가 시스템의 DNS 진입점을 선택해 주지는 않습니다.

DoH를 설정한 뒤 모든 웹사이트가 열리지 않습니다. 어떻게 복구하나요?

수정 전 설정으로 되돌리고 노드와 기본 네트워크가 정상인지 먼저 확인하세요. 그런 다음 연결할 수 있다고 확인된 DoH 하나만 활성화하고 시간 초과, TLS 오류, 노드 도메인 조회의 순환 의존성이 있는지 살펴보세요. 이 단계에서는 fallback과 정책별 조회, 규칙 적용 설정을 동시에 추가하지 마세요.

구독을 업데이트한 뒤 수정 사항이 사라졌습니다. 설정을 유지하려면 어떻게 해야 하나요?

다운로드한 구독 파일을 한 번 수정하는 대신 클라이언트에서 지원하는 오버라이드, 설정 병합 또는 설정 확장 기능을 사용하세요. 저장 후 최종 적용 설정에서 dns와 tun 필드가 후속 병합으로 덮어쓰이지 않았는지 확인합니다. 기능 이름과 지원 범위는 사용하는 클라이언트에 따라 다릅니다.

검증 목표는 테스트 페이지에 주소 하나만 표시되게 하는 것이 아니라 모든 DNS 경로의 출처와 연결 출구를 명확히 파악하는 것입니다. 완료 후 브라우저 보안 DNS, 로컬 네트워크 DNS 예외, 기타 네트워크 도구를 하나씩 다시 활성화하고 매번 테스트를 반복하세요. 이렇게 하면 새로 추가된 경로를 찾아낼 수 있어 다음 문제가 생겼을 때 원인을 처음부터 다시 추측할 필요가 없습니다.