본문으로 건너뛰기
AZ Tools

DNS 메시지 디코더

DNS 패킷을 16진수나 DoH base64url로 붙여넣고 읽어 보세요. 헤더 플래그, opcode와 rcode, 모든 레코드, EDNS0 OPT 옵션까지 보여 줍니다.

메시지는 브라우저 안에서만 해석됩니다. 업로드되지 않고 DNS 질의도 보내지 않습니다.

사용법

  1. 메시지를 붙여넣습니다. 공백이나 콜론이 섞인 16진수, tcpdump -x 또는 hexdump -C 출력, base64, ?dns= 값이 들어 있는 DoH URL 전체 모두 인식합니다.
  2. 입력 상자 아래 줄에서 무엇으로 인식했는지, 그리고 앞 두 바이트를 헤더가 아니라 TCP 길이 접두사로 읽었는지 확인합니다.
  3. 헤더 줄을 읽습니다. opcode는 메시지의 종류를, rcode는 처리 결과를, 네 개의 개수는 각 섹션에 몇 개의 레코드가 있어야 하는지를 알려 줍니다.
  4. 섹션을 차례로 내려갑니다. 데이터 열은 존 파일과 같은 표기 형식의 rdata이고, 전용 디코더가 없는 타입은 \# 길이 16진수 형태로 나타납니다.
  5. EDNS0 패널에서 UDP 페이로드 크기와 DO 비트, 옵션을 봅니다. 확장 DNS 오류가 있다면 rcode가 암시만 하는 내용을 한 줄로 설명해 주는 경우가 많습니다.

자세한 설명

펼치기

리졸버가 하는 것과 같은 방식으로, 즉 첫 바이트부터 차례대로 DNS 메시지를 읽습니다. 패킷 어디에도 "이 레코드가 어디서 시작한다"는 표시가 없고, 앞선 모든 것의 길이만이 그 위치를 정하기 때문입니다. 12바이트 헤더에서 id와 opcode, 응답 코드, 네 섹션의 개수를 읽고 이어서 question, answer, authority, additional 섹션을 훑습니다. 압축 포인터는 따라가되, 앞쪽이나 자기 자신을 가리키는 포인터는 쫓아가지 않고 오류로 알립니다. 악의적인 패킷이 정확히 그런 모양이기 때문입니다. 레이블은 존 파일이 쓰는 방식 그대로, 레이블 안의 점은 \. 으로 쓰고 출력할 수 없는 바이트는 \DDD 형태로 적으므로, 임의의 옥텟이 든 이름도 원래대로 다시 읽힙니다. 가장 많은 사람이 걸려 넘어지는 곳은 응답 코드입니다. rcode는 4비트가 아니라 12비트이고 상위 8비트는 OPT 레코드의 TTL 안에 들어 있어서, 헤더의 4비트만 읽으면 BADVERS(16)가 NOERROR(0)로 보입니다. 이 도구는 둘을 합쳐서 보여 줍니다. EDNS0도 모두 해석합니다. 클래스 필드에 숨어 있는 요청자의 UDP 페이로드 크기, TTL에 담긴 버전과 DO 비트, 그리고 NSID·클라이언트 서브넷(소스와 스코프 프리픽스 길이 포함)·쿠키·패딩·확장 DNS 오류 같은 옵션들입니다. 확장 오류는 SERVFAIL의 이유를 한 줄로 알려 주는 경우가 많습니다. rdata는 A, AAAA, NS, CNAME, PTR, MX, TXT, SOA, SRV, CAA, NAPTR, DS, DNSKEY, RRSIG, NSEC, NSEC3, TLSA, SVCB, HTTPS에 대해 해석하고, 그 밖의 타입은 추측하지 않고 RFC 3597 일반 형식으로 보여 줍니다. 반대로 하지 않는 일도 분명합니다. 네임 서버에 질의하지 않고, 서명을 검증하지 않으며, 답이 참인지도 말해 주지 않습니다. TSIG나 RRSIG는 있다고 알려 줄 뿐입니다. 검증에 필요한 키는 패킷에 실려 오지 않기 때문입니다. 16진수, tcpdump나 hexdump 출력, base64, DoH의 ?dns= 값 모두 붙여넣을 수 있고, 2바이트 TCP 길이 접두사는 알아서 건너뜁니다.

자주 묻는 질문

헤더는 NOERROR인데 도구는 BADVERS라고 합니다. 어느 쪽이 맞나요?

둘 다 맞고, 바로 그 점이 핵심입니다. rcode는 원래 헤더 안의 4비트였는데 EDNS0가 OPT 레코드의 TTL 필드에 상위 8비트를 넣어 12비트로 넓혔습니다. 헤더의 4비트만 읽는 디코더는 16의 하위 4비트, 즉 0을 보고 NOERROR라고 말합니다. 그래서 리졸버가 EDNS 버전을 거부하고 있는 상황이 아무 문제 없는 빈 응답처럼 보입니다. OPT 레코드가 있는 메시지는 반드시 두 조각을 합쳐야 하며 이 도구는 그렇게 계산합니다. 확장 rcode 자체도 EDNS0 패널에 따로 표시해서 추가 비트가 어디서 왔는지 볼 수 있게 했습니다.

DNS-over-HTTPS 요청의 ?dns= 값은 정확히 무엇인가요?

UDP 패킷에 담겼을 바로 그 와이어 포맷 메시지 전체를 base64url로 인코딩하고, RFC 8484에 따라 패딩을 없앤 것입니다. URL 질의 문자열에서 살아남아야 하므로 + 와 / 대신 - 와 _ 를 씁니다. 두 가지가 자주 혼동을 부릅니다. GET 요청에서는 같은 질의가 같은 URL이 되어 HTTP 캐시에 올라갈 수 있도록 메시지 id를 0으로 두는 것이 관례이고, 응답은 JSON이 아니라 application/dns-message 원본 바이트로 돌아옵니다. 그래서 네트워크 패널에서 복사한 것은 16진수로 바꿔야 읽을 수 있습니다. 여기서는 두 형태 모두 붙여넣을 수 있습니다.

앞쪽을 가리키는 압축 포인터를 왜 거부하나요?

포인터는 이름의 나머지를 찾을 수 있는 메시지 내 오프셋을 가리키며, RFC 1035는 반드시 앞서 나온 위치를 가리키라고 규정합니다. 뒤쪽만 가리키게 한 것은 취향의 문제가 아니라 포인터 추적이 반드시 끝나도록 보장하는 장치입니다. 자기 자신이나 더 뒤의 오프셋을 가리키면 단 두 바이트로 순진한 디코더를 영원히 돌게 만들 수 있고, 실제로 그런 모양의 패킷이 서비스 거부 시험용으로 돌아다닙니다. 그래서 앞쪽이나 자기 자신을 가리키는 포인터는 따라가지 않고 결함으로 보고하며, 뒤쪽 연쇄에도 점프 횟수 상한을 둡니다.

TXT 레코드에 따옴표 문자열이 여러 개 보입니다. 어느 것이 값인가요?

전부입니다. 사이에 아무것도 넣지 않고 이어 붙인 것이 값입니다. TXT의 rdata는 1바이트 길이가 앞에 붙는 문자열들의 나열이라 문자열 하나가 255바이트를 넘을 수 없습니다. DKIM 공개키나 긴 SPF 정책처럼 그보다 긴 값은 반드시 쪼개야 하고 받는 쪽이 이어 붙입니다. DKIM 레코드가 base64 중간에서 끊긴 두 조각처럼 보이는 이유입니다. 이 도구가 조각을 따로 보여 주는 것은 그 분할이 실제로 패킷에 존재하기 때문이고, 작성자가 별개의 값으로 의도한 실수는 이어 붙이지 않아야만 눈에 띄기 때문입니다.

SVCB와 HTTPS 레코드는 무엇을 보여 주며 순서는 왜 중요한가요?

HTTPS나 SVCB 레코드는 우선순위와 대상 이름, 그리고 키/값 SvcParams의 목록입니다. 서버가 말하는 프로토콜을 담은 alpn, port, A와 AAAA 조회를 기다리는 동안 먼저 시도할 주소인 ipv4hint와 ipv6hint, 암호화된 클라이언트 헬로 설정인 ech 등이 있습니다. 와이어 포맷은 파라미터가 키 번호의 오름차순이고 중복이 없어야 한다고 요구합니다. 덕분에 파싱이 값싸지지만, 손으로 만든 레코드가 가장 자주 어기는 규칙이기도 합니다. 키 순서가 어긋난 레코드는 잘못된 레코드이므로, 그럴듯해 보이도록 몰래 재정렬하지 않고 원본 16진수로 보여 줍니다.

DNSSEC 검증이나 TSIG 서명 확인도 되나요?

되지 않고, 패킷 하나만 읽는 도구라면 무엇도 할 수 없습니다. RRSIG는 해당 존의 DNSKEY로 검증해야 하는데 그 키를 따로 가져와 DS 레코드를 타고 신뢰 기준점까지 연결해야 하고, TSIG는 정의상 메시지에 실리지 않는 공유 비밀로 검증합니다. 대신 바이트 자체가 말해 주는 것은 모두 얻을 수 있습니다. 어떤 RRSIG가 어떤 타입을 덮는지, 시작과 만료 시각은 언제인지, DNSKEY 집합과 대조할 키 태그와 서명자 이름은 무엇인지, 그리고 AD 비트가 켜져 있는지입니다. AD 비트는 상위의 어떤 리졸버가 검증했다고 주장한다는 사실만 기록할 뿐 검증이 실제로 이루어졌음을 뜻하지는 않습니다.

관련 도구