DNS 조회, 규칙에 따른 트래픽 분기, 트래픽 가로채기를 구분하기

Clash에서 노드에 연결되는데 일부 웹사이트가 열리지 않는다면, 노드 장애가 원인이 아닐 수 있습니다. 웹사이트에 접속할 때는 도메인을 IP 주소로 조회하고, 규칙에 따라 연결 경로를 선택한 뒤, 앱의 연결을 프록시 코어로 전달하는 과정이 필요합니다. DNS 설정은 첫 번째 과정을 담당하고, TUN과 시스템 프록시는 세 번째 과정을 결정합니다. DNS 서버 주소만 바꾼다고 모든 앱의 트래픽이 자동으로 프록시를 통과하는 것은 아닙니다.

이 글에서는 mihomo, 즉 흔히 Clash Meta 코어라고 부르는 엔진을 기준으로 설명합니다. 기존 Clash나 다른 포크, 클라이언트 UI에서는 지원하는 설정 항목이 다를 수 있습니다. 먼저 클라이언트의 코어 정보나 시작 로그에서 실제로 사용하는 코어를 확인한 뒤 해당 설정을 적용하세요. 앱 버전과 코어 버전은 서로 다른 번호 체계를 사용합니다.

  1. 앱의 DNS 조회: 운영체제 DNS를 사용할 수도 있고, 브라우저 자체의 보안 DNS를 사용할 수도 있습니다.
  2. 코어의 쿼리 처리: DNS 쿼리를 받으면 설정에 따라 실제 IP 주소나 fake-ip을 반환합니다.
  3. 연결 규칙 확인: 도메인, 대상 IP, 프로세스 등의 정보를 규칙과 대조한 뒤 직접 연결 또는 프록시 정책을 선택합니다.

nameserver, default-nameserver, fallback의 역할

nameserver는 일반적인 도메인 조회에 사용하는 업스트림 DNS 목록입니다. default-nameserver는 주로 DNS 업스트림 자체의 도메인을 조회할 때 사용합니다. 예를 들어 업스트림을 https://dns.alidns.com/dns-query로 지정했다면, 암호화 연결을 시작하기 전에 dns.alidns.com의 IP 주소를 알아야 합니다. 이 과정을 부트스트랩 조회라고 합니다.

항목용도자주 하는 오해
enable코어의 DNS 기능을 활성화합니다.활성화한 뒤에도 시스템의 DNS 쿼리가 코어에 전달되도록 해야 합니다.
listenDNS 리스닝 주소와 포트를 지정합니다.HTTP 또는 SOCKS 프록시 포트가 아닙니다.
default-nameserver도메인으로 지정한 DNS 업스트림의 부트스트랩 조회를 담당합니다.모든 일반 DNS 쿼리에 우선 적용되는 기본 목록은 아닙니다.
nameserver일반 DNS 쿼리를 처리합니다.목록을 위에서부터 엄격하게 순서대로 시도하는 주 DNS·보조 DNS 구조로 보면 안 됩니다.
fallback별도의 조회 결과를 제공하고, 필터 조건에 따라 사용할 응답을 선택합니다.주 DNS가 시간 초과될 때만 사용하는 예비 목록이 아닙니다.
fallback-filter어떤 쿼리나 주 DNS 조회 결과에 fallback을 적용할지 결정합니다.광고 차단 기능이 아니며 웹 트래픽이 어느 노드로 이동할지도 결정하지 않습니다.

일반 DNS 업스트림은 223.5.5.5, DoT는 tls://1.1.1.1:853, DoH는 https://dns.google/dns-query와 같은 형식으로 지정할 수 있습니다. 일반 DNS는 보통 53번 포트, DoT는 853번 포트, DoH는 HTTPS의 443번 포트를 사용합니다. 포트에 접속할 수 있다고 해서 조회까지 정상적으로 처리되는 것은 아니므로 응답 결과와 로그도 확인해야 합니다.

암호화 DNS는 클라이언트와 DNS 서비스 사이의 전송 구간을 보호합니다. 업스트림의 신뢰성을 보장하거나 모든 도메인 정보를 숨겨 주는 것은 아니며, DNS 요청이 프록시 노드를 거친다는 뜻도 아닙니다. 먼저 현재 네트워크에서 업스트림에 접속할 수 있는지 확인한 다음, 규칙에 따라 업스트림 연결을 프록시할지 판단하세요.

fake-ip과 redir-host: 호환성에 따라 선택하기

fake-ip은 코어가 관리하는 가상 IP 주소를 앱에 반환하고, 해당 주소와 도메인의 대응 관계를 저장합니다. 이후 앱이 이 주소에 연결하면 코어가 원래 도메인을 찾아 규칙을 적용할 수 있습니다. 일반적으로 사용하는 주소 대역은 198.18.0.1/16이며, 성능 테스트용 주소 범위에 속합니다. 웹사이트의 실제 서버 IP가 아닙니다.

redir-host는 조회한 실제 IP를 앱에 반환하고, 기록해 둔 조회 정보를 활용해 도메인을 판별합니다. 앱이 자체 암호화 DNS를 사용하거나 연결 정보에 IP 주소만 표시되면 코어가 원래 도메인을 정확히 알아내지 못할 수 있습니다. 도메인 스니핑으로 일부 정보를 보완할 수 있지만 모든 프로토콜에서 작동한다고 보장할 수는 없습니다.

  • 먼저 fake-ip 사용을 권장합니다: 도메인 기반 분기 정보를 안정적으로 유지하고 트래픽을 올바르게 가로채려는 데스크톱 환경에 적합합니다.
  • 특정 도메인만 예외 처리하기: 로컬 네트워크 기기 검색, 실제 IP가 필요한 프로그램 또는 연결 확인에 문제가 생기면 먼저 fake-ip-filter를 조정하세요.
  • 그다음 redir-host 검토하기: 업무용 프로그램이 가상 IP와 계속 호환되지 않는다면 모드를 바꿔 비교 테스트하세요. 모든 DNS 업스트림을 한꺼번에 변경할 필요는 없습니다.

문제를 진단할 때 fake-ip에 ping을 실행한 결과만으로 원격 웹사이트의 상태를 판단하지 마세요. 가상 IP는 도메인 매핑과 트래픽 가로채기에 사용됩니다. 앱이 연결을 설정할 수 있는지, 클라이언트의 연결 세부 정보에 표시된 도메인과 최종 정책이 올바른지를 확인하는 편이 유용합니다.

구조를 이해하기 쉬운 DNS 설정 예시

아래 예시는 로컬 DNS를 활성화하고 fake-ip과 두 그룹의 DNS 업스트림을 함께 사용하는 방법을 보여 줍니다. 127.0.0.1:1053에서 수신하므로 로컬 기기에서만 접속할 수 있어, 기기가 실수로 LAN DNS 서버로 노출되는 것을 방지합니다. 1053은 시스템 기본 DNS 포트가 아니므로 설정에 이 주소만 추가해도 운영체제가 자동으로 쿼리를 보내지는 않습니다.

dns:
  enable: true
  listen: 127.0.0.1:1053
  ipv6: false
  enhanced-mode: fake-ip
  fake-ip-range: 198.18.0.1/16
  fake-ip-filter:
    - localhost
    - "*.lan"
    - "*.local"
    - "+.msftconnecttest.com"
    - "+.msftncsi.com"
  default-nameserver:
    - 223.5.5.5
    - 119.29.29.29
  nameserver:
    - https://dns.alidns.com/dns-query
  fallback:
    - https://dns.google/dns-query
    - https://cloudflare-dns.com/dns-query
  fallback-filter:
    geoip: true
    geoip-code: CN
    ipcidr:
      - 0.0.0.0/32
      - 240.0.0.0/4

설정을 적용하기 전에 확인할 세 가지

  1. 기존 dns 섹션에 병합하기: 하나의 YAML 파일에 최상위 dns:를 두 번 작성하지 마세요. 같은 이름의 키가 덮어써지거나 파싱 오류가 발생할 수 있습니다. 들여쓰기에는 탭 대신 공백을 사용하세요.
  2. 업스트림 연결 확인하기: 현재 네트워크에서 Google이나 Cloudflare의 DoH에 연결할 수 없다면 이 fallback 설정만으로 네트워크 문제가 해결되지 않습니다. 먼저 실제로 접속할 수 있고 신뢰할 만한 업스트림으로 바꾸거나, DNS 업스트림의 프록시 경로를 추가로 설정하세요.
  3. IPv6 설정의 범위 이해하기: 여기서 dns.ipv6: false는 해당 DNS 서비스가 AAAA 레코드를 반환하지 않도록 합니다. 운영체제의 IPv6 기능을 끄는 설정이 아니며, 앱의 IPv6 트래픽이 우회하는 것을 단독으로 막을 수도 없습니다.

*.local을 필터링해도 기기 검색 트래픽을 가로채는 것은 아닙니다. 일반적인 mDNS는 UDP 5353과 멀티캐스트 주소를 사용하므로 일반 유니캐스트 DNS와 다릅니다. 프린터, 화면 공유 기기 또는 NAS를 찾지 못한다면 TUN의 LAN 라우팅, 시스템 방화벽, 멀티캐스트 처리도 확인하세요.

fallback-filter는 조회 결과를 어떻게 판별할까

위 설정의 geoip: true와 geoip-code: CN은 일반 DNS 조회 결과가 지정한 지역 조건에 맞지 않으면 fallback 결과를 사용한다는 뜻입니다. ipcidr에는 0.0.0.0/32처럼 제외할 주소 범위를 추가할 수 있습니다. 이 판별은 IP 지리 데이터베이스를 바탕으로 하므로 모든 CDN 주소를 정확하게 분류한다고 보장할 수는 없습니다.

중요한 점은 CN이 아닌 IP가 곧 오염된 IP는 아니라는 것입니다. 정상적인 웹사이트도 다른 지역에 서버를 둘 수 있습니다. 이 설정은 네트워크 환경에 맞춰 DNS 응답 선택 방식을 정하는 기능이지, 응답의 진위를 절대적으로 증명하지는 않습니다. 정상적인 IP를 받았는데 웹사이트 연결이 느리다면 필터 대역을 계속 늘리기보다 프록시 경로 규칙과 CDN 라우팅을 확인하세요.

특정 도메인에 별도 업스트림 지정하기

mihomo는 nameserver-policy도 지원합니다. 특정 도메인에 지정된 DNS를 항상 사용하려면 fallback 조건을 계속 추가하는 것보다 정책을 명시하는 편이 간단합니다. 아래 예시는 example.com과 모든 하위 도메인에 지정한 DoH를 사용하고, 나머지 쿼리는 기존 설정을 따르도록 하는 부분 설정입니다.

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

이 코드는 정책 문법만 보여 주므로 기존 dns 섹션에 병합해야 합니다. 사내 도메인을 사용하는 경우 회사에서 제공한 DNS 주소를 입력하고 VPN이나 전용 회선에서 접속할 수 있는지 확인하세요. 공용 DNS를 바꿔 가며 시도해도 사내 네트워크에서만 사용하는 비공개 레코드는 조회할 수 없습니다.

DNS 업스트림을 프록시할 때 순환 의존 방지하기

mihomo의 respect-rules를 사용하면 DNS 업스트림 연결에 라우팅 규칙을 적용할 수 있습니다. 이 옵션을 켤 때는 프록시 노드 서버의 도메인을 조회할 수 있도록 proxy-server-nameserver도 올바르게 설정해야 합니다. 그렇지 않으면 “DNS는 노드를 거쳐야 하는데, 노드 도메인은 DNS 조회가 필요하다”는 의존성 순환이 발생할 수 있습니다. 기본 설정이 정상적으로 작동하기 전에는 두 옵션을 함께 켜지 않는 편이 좋습니다.

TUN DNS 가로채기: 시스템 쿼리를 코어로 전달하기

시스템 프록시만 켜면 일반적으로 프록시 설정을 지원하는 앱이 HTTP 또는 SOCKS 연결을 코어에 전달합니다. 하지만 운영체제의 DNS 쿼리는 여전히 라우터나 통신사 DNS 서버로 전송될 수 있습니다. TUN은 가상 네트워크 어댑터로 더 많은 IP 트래픽을 가로채며, 포착한 DNS 요청을 코어의 DNS 서비스로 전달할 수도 있습니다.

클라이언트 서비스 모드나 필요한 권한을 준비한 뒤 아래 mihomo 부분 설정을 참고하세요. 데스크톱 클라이언트가 TUN 설정을 직접 관리하는 경우가 많습니다. UI에서 같은 설정을 이미 생성했다면 최종 적용 설정을 확인해 UI 옵션과 수동 오버라이드가 서로 덮어쓰지 않도록 하세요.

tun:
  enable: true
  stack: mixed
  auto-route: true
  auto-detect-interface: true
  dns-hijack:
    - any:53
    - tcp://any:53
  • any:53은 해당 조건에 맞는 UDP DNS 요청을 가로채며, tcp://any:53은 TCP DNS 요청을 추가로 처리합니다. 두 설정 모두 트래픽 가로채기 경로로 들어오는 요청에 적용됩니다.
  • auto-route는 관련 라우트를 자동으로 설정합니다. 다른 VPN, 가상 머신 네트워크 또는 기업 보안 소프트웨어에 영향을 줄 수 있으므로 하나씩 테스트하세요.
  • auto-detect-interface는 나가는 네트워크 인터페이스를 자동으로 찾습니다. 여러 네트워크 어댑터를 사용하거나 핫스팟을 공유하는 환경, 복잡한 VPN 환경에서는 나갈 인터페이스를 직접 지정해야 할 수 있습니다.

TUN을 사용하지 않고 시스템이 로컬 DNS를 직접 사용하게 하려면 보통 로컬 53번 포트에서 DNS 서비스를 실행하고 시스템 DNS 주소를 해당 서비스로 지정해야 합니다. 이 경우 포트 충돌, 관리자 권한, 시스템 DNS 서비스와의 충돌을 고려해야 합니다. 예시의 1053을 IP 주소만 입력할 수 있는 시스템 DNS 설정란에 그대로 넣어서는 안 됩니다.

순서대로 점검하기: DNS 조회 실패, fake-ip 미작동, DNS 유출

1단계: 코어의 리스닝 포트에 직접 쿼리하기

dig가 설치된 Linux 또는 macOS에서 먼저 아래 명령을 실행하세요. Windows에서도 해당 도구를 사용할 수 있는 터미널 환경이라면 같은 방법으로 테스트할 수 있습니다. 일반 nslookup은 기본적으로 53번 포트를 사용하므로, 그 결과를 1053번 포트 테스트로 착각하지 마세요.

dig @127.0.0.1 -p 1053 example.com A
dig @127.0.0.1 -p 1053 example.com A +tcp

fake-ip 모드에서 필터 목록에 없는 도메인을 조회하면 일반적으로 198.18.0.0/16 범위의 매핑 주소가 반환됩니다. 요청 시간이 초과되면 먼저 DNS 기능 활성화 여부, 포트 사용 여부, 설정 로드 성공 여부를 확인하세요. fake-ip을 받았다는 사실은 로컬 매핑 조회가 정상이라는 뜻일 뿐, 원격 DNS 조회와 웹사이트 접속까지 정상이라는 의미는 아닙니다.

2단계: 시스템과 앱이 같은 경로를 사용하는지 확인하기

  1. 설정을 다시 불러온 뒤 로그에 알 수 없는 항목, YAML 들여쓰기 오류 또는 포트 바인딩 오류가 없는지 확인하세요.
  2. TUN을 켜고 브라우저에서 테스트 도메인에 접속한 다음, 클라이언트의 연결 세부 정보에서 도메인, 일치한 규칙, 나가는 경로를 확인하세요.
  3. 브라우저의 보안 DNS를 잠시 끄고 증상을 비교하세요. 끈 뒤 문제가 해결된다면 fallback만 바꾸지 말고 브라우저의 DoH 경로를 확인하세요.
  4. 다른 VPN, 수동 DNS 설정, 앱 자체 프록시를 하나씩 끄고 확인해 여러 트래픽 가로채기 경로가 동시에 작동하지 않도록 하세요.

3단계: 캐시를 비운 뒤 다시 테스트하기

Windows에서는 ipconfig /flushdns를 실행하고, systemd-resolved를 사용하는 Linux에서는 sudo resolvectl flush-caches를 실행하세요. macOS에서는 다음 명령을 주로 사용합니다. 시스템 캐시, 브라우저 캐시, 코어의 fake-ip 매핑은 서로 다른 계층입니다. 필요하면 테스트 앱을 다시 시작하거나 클라이언트의 DNS 캐시 삭제 기능을 사용하세요.

sudo dscacheutil -flushcache
sudo killall -HUP mDNSResponder

fake-ip에서 redir-host로 전환한 뒤에는 앱에 이전 가상 IP가 남아 있지 않은지 확인하세요. 코어의 매핑을 지웠는데 브라우저가 이전 fake-ip을 캐시하고 있다면 연결이 일시적으로 실패할 수 있습니다. 규칙을 계속 바꾸기보다 브라우저를 다시 시작해 보세요.

4단계: ‘DNS 누출 테스트’ 결과는 단서로만 보기

DNS 테스트 사이트에 표시되는 주소는 보통 재귀 DNS 서버의 출구 IP이며, 로컬 기기나 프록시 노드의 IP가 아닐 수 있습니다. DNS 서버와 노드의 위치가 다르다고 해서 요청이 프록시를 우회했다고 단정할 수도 없습니다. 통신사에 평문 DNS 쿼리가 노출되지 않게 하려는지, 앱의 DNS 경로를 통일하려는지, 특정 업스트림을 프록시하려는지 먼저 정하세요. 그런 다음 로그와 연결 기록, 필요한 경우 패킷 캡처를 함께 확인하세요.

DNS 설정 마무리: 먼저 정상 작동을 확인한 뒤 정책을 하나씩 추가하기

안정적으로 시작하려면 접속 가능한 DNS 업스트림, 명확한 조회 모드, 실제로 작동하는 트래픽 가로채기가 필요합니다. 먼저 로컬 포트에 직접 쿼리해 DNS 서비스가 작동하는지 확인한 다음, 앱으로 접속해 규칙과 나가는 경로를 점검하세요. 구체적인 문제가 확인된 경우에만 fake-ip-filter, nameserver-policy 또는 DNS 업스트림 프록시 정책을 추가하세요.

  • 로컬 네트워크 도메인 조회 실패: 공용 업스트림을 바꾸기 전에 사내 DNS, mDNS, 라우팅을 확인하세요.
  • 특정 앱에서만 실패: 앱 자체 DoH, 프록시 설정, fake-ip 호환성을 먼저 확인하세요.
  • 모든 도메인의 조회 시간 초과: 서비스 리스닝 상태, 업스트림 연결 가능 여부, DNS 순환 의존을 먼저 확인하세요.
  • DNS 조회는 정상인데 웹사이트가 열리지 않음: 노드 연결, 규칙 일치, 대상 포트를 확인하세요. 모든 문제를 DNS 탓으로 돌리지 마세요.

한 번에 한 항목만 바꾸고 수정 전후의 설정과 오류 로그를 저장하세요. 그래야 실제로 효과가 있는 변경 사항을 찾고, 구독 업데이트나 코어 업그레이드, 네트워크 변경 후에도 빠르게 이전 상태로 복구할 수 있습니다.