콘텐츠로 이동

EDNS0는 DNS 메시지 크기를 어떻게 넓혀줄까요?

DNS는 질문도 짧고 답도 짧을 것 같죠? 사실은 요즘 DNS 응답은 512바이트 안에 다 못 들어가는 일이 꽤 자연스러워요.

A, AAAA, CNAME... DNS 레코드는 왜 종류가 여러 갈래일까요?에서는 DNS 응답이 단순한 주소 하나가 아니라, A, AAAA, CNAME, TXT 같은 서로 다른 종류의 메모로 나뉜다는 걸 봤어요. 그리고 DNS 메시지는 왜 질문 하나에 칸이 이렇게 많을까요?에서는 그 메모들이 Answer, Authority, Additional 같은 구역에 담긴다는 것도 봤죠.

근데요, 여기서 이상한 질문이 하나 생겨요.

  • DNS는 원래 UDP로 가볍게 물어보고 답하는 느낌이었잖아요?
  • 그런데 TXT 레코드가 길거나, IPv6 주소가 여러 개 붙거나, DNSSEC 서명까지 들어오면 어떻게 될까요?
  • 512바이트 안에 못 들어가면 그냥 답을 포기할까요?
  • 아니면 처음부터 TCP로만 바꿔야 할까요?

사실은 둘 다 아니에요. DNS는 기존 메시지 모양을 크게 깨지 않으면서, "저는 더 큰 UDP 응답을 받을 수 있어요" 라는 확장 메모를 붙이는 쪽을 택했어요. 그 확장 방식이 바로 EDNS0예요.

오늘은 EDNS0가 한마디로 무엇인지, 왜 DNS 메시지 크기 문제에서 나왔는지, 기본 DNS 메시지의 Additional 구역과 어떻게 연결되는지, 그리고 그다음에야 OPT 의사 레코드, UDP payload size, TC 비트, TCP fallback 순서로 내려가볼게요. 큰 규칙은 RFC 6891의 EDNS(0) 정의를 기준으로 보고, TCP로 다시 묻는 운영 감각은 RFC 7766의 DNS over TCP 요구사항과 이어서 생각하면 돼요.

이 글의 범위

여기서는 EDNS0를 DNS 메시지 크기와 확장 메모 관점에서 볼게요. DNSSEC 검증, DoH/DoT, EDNS Client Subnet 같은 개별 옵션은 깊게 열지 않아요. 오늘은 OPT PSEUDOSECTION 이 왜 보이고, udp: 1232 같은 숫자를 어떻게 읽어야 하는지에 집중하면 충분해요.


왜 EDNS0를 알아야 할까요?

처음 DNS를 배울 때는 이런 장면이 편해요.

클라이언트가 example.com A? 라고 묻고, DNS 서버가 93.184.216.34 같은 주소 하나를 돌려주는 장면이죠. 이렇게만 보면 DNS 응답은 아주 작아 보여요. 실제로 예전의 단순한 A 레코드 하나라면 작은 UDP 메시지로 충분한 경우가 많았어요.

하지만 지금의 DNS는 주소 하나만 들고 다니지 않아요.

  • IPv4 주소와 IPv6 주소가 여러 개 붙을 수 있어요.
  • TXT 레코드가 도메인 검증, 메일 정책, 서비스 설정 때문에 길어질 수 있어요.
  • DNSSEC을 쓰면 서명과 키 정보가 응답에 같이 붙을 수 있어요.
  • 권한 서버 힌트와 추가 주소가 함께 들어올 수 있어요.

즉 DNS는 여전히 가볍게 보이지만, 안쪽에서는 짧은 쪽지에서 두꺼운 서류철로 커지는 장면이 생겨요. EDNS0는 바로 이 장면을 다루기 위해 필요해요.


작은 봉투로는 언제 부족할까요?

동네 안내 데스크에 질문지를 낸다고 상상해볼까요?

예전 규칙은 이랬어요.

"답장은 작은 봉투 하나에 들어갈 만큼만 보내주세요."

주소 하나만 물어보면 문제없어요. 작은 봉투면 충분하니까요.

근데 어느 날 질문이 이렇게 바뀌어요.

  • 이 가게의 예전 주소와 새 주소를 모두 알려주세요.
  • 별명으로 연결된 진짜 이름도 알려주세요.
  • 이 답이 진짜인지 확인할 서명도 붙여주세요.
  • 혹시 다음 담당 부서가 있으면 그쪽 연락처도 같이 넣어주세요.

작은 봉투에 다 안 들어가겠죠. 그렇다고 안내 데스크 시스템 전체를 새로 만들기는 부담스러워요. 그래서 질문지 맨 아래에 이런 메모를 붙이는 거예요.

"저는 큰 봉투도 받을 수 있어요. 이 정도 크기까지는 보내도 돼요."

EDNS0는 DNS에서 이 메모에 가까워요. 기존 DNS 메시지 형식을 유지하면서, Additional 구역에 확장 가능하다는 신호를 붙여요.

비유에서는 실제로는
작은 봉투 EDNS 없이 UDP DNS에서 흔히 말하는 512바이트 한계
큰 봉투도 받을 수 있다는 메모 EDNS0의 OPT 의사 레코드
받을 수 있는 봉투 크기 UDP payload size
봉투가 잘렸다는 표시 DNS 헤더의 TC 비트
다시 큰 택배로 보내기 TCP로 DNS 재시도

여기서 중요한 건 EDNS0가 새로운 DNS 서버 주소록이 아니라는 점이에요. 기존 DNS 메시지에 붙는 확장 약속이에요.


EDNS0는 한마디로 뭐예요?

짧게 잡으면 이래요.

EDNS0는 기존 DNS 메시지에 "나는 이런 확장을 이해하고, 이만큼 큰 UDP 응답을 받을 수 있어요"라고 알려주는 추가 메모예요.

이 메모는 보통 DNS 메시지의 Additional 구역에 OPT라는 특별한 항목으로 들어가요.

flowchart TD
    A[DNS Message]
    A --> B[Header<br/><small>ID, Flags, Counts</small>]
    A --> C[Question<br/><small>무엇을 물었는지</small>]
    A --> D[Answer<br/><small>직접 답</small>]
    A --> E[Authority<br/><small>권한 힌트</small>]
    A --> F[Additional<br/><small>추가 힌트와 확장 메모</small>]
    F --> G[OPT pseudo-RR<br/><small>EDNS0 신호</small>]

이 그림에서 EDNS0는 Answer에 들어가지 않아요. 사용자가 물어본 도메인의 주소도 아니고, AAAAA 같은 일반 레코드도 아니거든요. 그래서 OPT의사 레코드(pseudo-RR) 라고 불려요. 레코드처럼 보이지만, 주소록 데이터라기보다 메시지를 어떻게 주고받을지에 대한 협상 메모에 가까워요.


512바이트 한계는 어디서 문제가 될까요?

고전적인 DNS에서는 UDP 응답 크기를 512바이트 안쪽으로 보는 관성이 강했어요. 이 숫자는 작은 주소 조회에는 충분했지만, DNS가 더 많은 정보를 싣기 시작하면서 금방 좁아졌어요.

flowchart LR
    A[단순 A 응답<br/><small>작은 답</small>] --> B[512바이트 안에 충분]
    C[AAAA 여러 개<br/><small>주소가 길고 여러 개</small>] --> E[512바이트가 빡빡]
    D[DNSSEC 서명<br/><small>RRSIG, DNSKEY 등</small>] --> E
    F[긴 TXT 레코드<br/><small>검증, 정책, 설정</small>] --> E
    E --> G[EDNS0 필요<br/><small>큰 UDP 응답 가능 여부를 알림</small>]

512바이트를 넘는다고 해서 항상 장애가 나는 건 아니에요. 문제는 상대가 얼마나 큰 응답을 받을 수 있는지 서로 알 방법이 없으면, 서버가 조심스럽게 작게 보내거나 응답을 잘라야 한다는 점이에요.

그래서 EDNS0는 요청 쪽에서 먼저 말해요.

"저는 UDP로 이 정도 크기까지 받을 수 있어요."

그러면 응답 쪽은 그 범위 안에서 더 큰 DNS 응답을 UDP로 보낼 수 있어요.


OPT 의사 레코드는 어떻게 생겼을까요?

dig 출력에서 EDNS0가 보이면 보통 이런 줄을 만나요.

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232

처음 보면 레코드 같기도 하고, 설정값 같기도 하죠. 이 줄은 대략 이렇게 읽으면 돼요.

출력 조각 처음엔 이렇게 읽으면 돼요
OPT PSEUDOSECTION OPT 의사 레코드가 들어온 자리 일반 DNS 답이 아니라 EDNS0 메모
version: 0 EDNS 버전 지금 흔히 쓰는 EDNS0
flags: EDNS 확장 플래그 DNSSEC 요청 때 do 같은 표시가 붙을 수 있음
udp: 1232 광고한 UDP payload size 이 정도 크기의 UDP DNS 응답을 받을 수 있다는 신호

여기서 udp: 1232항상 모든 서버가 그 크기로 답한다는 뜻이 아니에요. 요청자가 "저는 여기까지 받을 수 있어요" 라고 말하는 값에 가까워요. 실제 응답 크기는 서버가 가진 답, 경로의 MTU, 중간 장비, 구현 정책에 따라 더 작을 수도 있어요.

왜 1232가 자주 보일까요?

과거에는 4096 같은 큰 값을 자주 보기도 했어요. 하지만 UDP 조각화가 중간 경로에서 문제를 만들 수 있어서, 요즘 구현은 더 보수적인 값을 고르는 경우가 많아요. 1232는 IPv6의 최소 MTU 1280바이트에서 IP/UDP 헤더 여유를 뺀 감각과 잘 맞아서 자주 보이는 숫자예요.


EDNS0가 붙으면 메시지 흐름은 어떻게 바뀔까요?

EDNS0가 있을 때의 핵심 흐름은 이래요.

sequenceDiagram
    participant 앱 as 클라이언트 / 리졸버
    participant 서버 as DNS 서버

    앱->>서버: example.com DNS 질문<br/>+ OPT: udp payload size 1232
    서버-->>앱: 1232바이트 안에 담긴 응답

질문 자체가 완전히 다른 프로토콜로 바뀌는 게 아니에요. 여전히 DNS 메시지예요. 다만 Additional 구역에 OPT 메모가 붙어서, 양쪽이 조금 더 큰 봉투를 쓸 수 있게 돼요.

EDNS0가 없거나, 상대가 EDNS0를 이해하지 못하거나, 중간 장비가 큰 UDP 응답을 막으면 이야기가 달라져요.

sequenceDiagram
    participant 클라이언트 as 클라이언트
    participant 서버 as DNS 서버

    클라이언트->>서버: DNS 질문<br/>+ OPT 메모
    서버-->>클라이언트: 너무 커서 일부만 보냄<br/>TC=1
    클라이언트->>서버: TCP로 다시 질문
    서버-->>클라이언트: 잘리지 않은 전체 응답

여기서 TC=1Truncated, 즉 응답이 잘렸다는 신호예요. DNS 메시지 형식 글에서 봤던 헤더의 TC 비트가 바로 이 장면에서 중요해져요. TC=1을 보면 "답이 없다" 가 아니라 "UDP 응답 안에 다 못 실었으니 TCP로 다시 물어봐야 한다" 쪽으로 읽어야 해요.


왜 그냥 처음부터 TCP만 쓰지 않을까요?

그럼 이런 생각이 들 수 있어요.

"잘릴 수 있으면 DNS도 그냥 처음부터 TCP로 하면 안 돼요?"

물론 DNS도 TCP를 쓸 수 있어요. 특히 응답이 커졌거나, UDP 응답이 잘렸거나, 영역 전송 같은 장면에서는 TCP가 중요해요.

다만 일반 조회는 여전히 UDP가 잘 맞는 면이 있어요.

  • 연결을 여는 과정 없이 짧게 물어보고 답하기 좋아요.
  • 작은 조회가 매우 많이 오가는 DNS 특성과 잘 맞아요.
  • 캐시 리졸버와 권한 서버 사이에서도 짧은 질의응답이 많아요.

EDNS0는 이 둘 사이에서 현실적인 절충을 해요.

상황 주로 쓰기 좋은 방식 이유
작은 일반 조회 UDP 빠르고 가벼워요
조금 큰 응답 UDP + EDNS0 큰 UDP payload size를 광고할 수 있어요
너무 큰 응답, 잘린 응답 TCP fallback 전체 응답을 안정적으로 다시 받을 수 있어요
항상 암호화된 DNS 경로 DoT / DoH 같은 별도 흐름 전송 경로와 프라이버시 문제가 함께 들어와요

그러니까 EDNS0는 TCP를 없애는 기술이 아니에요. TCP로 넘어가기 전에 UDP가 감당할 수 있는 범위를 넓혀주는 기술에 가까워요.


실제 출력에서는 어디를 보면 될까요?

dig를 평소처럼 실행하면 OPT PSEUDOSECTION이 같이 보일 때가 많아요.

$ dig example.com A

;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 43120
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232

;; QUESTION SECTION:
;example.com.            IN  A

;; ANSWER SECTION:
example.com.        300 IN  A  93.184.216.34

여기서 읽을 순서는 이래요.

  1. ADDITIONAL: 1 — 추가 구역에 뭔가 하나 붙었구나
  2. OPT PSEUDOSECTION — 그게 일반 추가 주소가 아니라 EDNS0 메모구나
  3. udp: 1232 — 이 질의응답에서 광고한 UDP payload size가 1232구나
  4. flagstc가 없네 — 이번 응답은 잘리지 않았구나

반대로 응답이 잘렸다면 헤더 쪽에 tc가 보일 수 있어요.

;; flags: qr rd ra tc; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

이때는 "서버가 답을 모른다" 라고 읽으면 안 돼요. 응답이 너무 커서 UDP로 일부만 왔을 수 있다고 봐야 해요.


잘못 읽기 쉬운 함정

EDNS0는 출력에 자주 보이지만, 의미를 잘못 붙이기 쉬워요.

헷갈리는 읽기 더 정확한 읽기
OPT는 새 DNS 레코드 종류다 일반 주소록 레코드가 아니라 EDNS0용 의사 레코드예요
udp: 1232면 응답이 반드시 1232바이트다 받을 수 있다고 광고한 크기예요. 실제 응답 크기는 더 작을 수 있어요
EDNS0가 있으면 TCP는 필요 없다 응답이 더 크거나 잘리면 TCP fallback이 여전히 필요해요
TC=1은 DNS 실패다 실패라기보다 UDP 응답이 잘렸다는 신호예요
EDNS0는 DNSSEC 그 자체다 DNSSEC이 EDNS0를 활용할 수 있지만, EDNS0와 DNSSEC은 같은 개념이 아니에요

특히 마지막 줄이 중요해요. DNSSEC은 응답을 검증 가능하게 만들기 위해 서명과 키 정보를 붙여요. 그 결과 응답이 커지니까 EDNS0가 도움이 되는 거예요. EDNS0는 공간과 확장 신호의 문제, DNSSEC은 신뢰와 검증의 문제라고 나눠 읽으면 덜 헷갈려요.


그럼 진짜 운영 장면에서는 무엇을 의심해야 할까요?

EDNS0는 평소에는 조용히 지나가요. 하지만 DNS가 간헐적으로 느리거나, 특정 네트워크에서만 실패하거나, DNSSEC 도메인만 이상하게 보이면 이쪽을 의심할 때가 있어요.

예를 들어 이런 장면이에요.

  • 작은 A 조회는 되는데 DNSSEC 관련 조회가 자주 실패해요.
  • 어떤 네트워크에서는 dig가 바로 답하지만, 다른 네트워크에서는 타임아웃이 나요.
  • UDP 응답이 잘려서 TCP로 재시도해야 하는데, 방화벽이 TCP 53번을 막고 있어요.
  • 큰 UDP 응답이 IP 조각으로 나뉘었는데, 중간 장비가 조각을 버려요.

이럴 때는 단순히 "DNS 서버가 죽었나?" 만 보면 부족해요. 질문을 이렇게 나눠야 해요.

확인할 것 왜 보는 걸까요?
OPT PSEUDOSECTION이 있는지 EDNS0를 쓰고 있는지 보기 위해서예요
udp: 값이 얼마인지 어느 정도 큰 응답을 기대하는지 보기 위해서예요
헤더에 tc가 있는지 UDP 응답이 잘렸는지 보기 위해서예요
TCP 53번 재시도가 되는지 잘린 응답을 다시 받을 길이 있는지 보기 위해서예요
작은 조회와 큰 조회가 다르게 실패하는지 크기 문제인지, 이름 문제인지 나누기 위해서예요

이 지점부터는 DNS가 단순 주소록이 아니라 경로와 크기와 중간 장비까지 함께 보는 운영 장면으로 바뀌어요.


자, 정리해볼까요?

오늘 우리가 배운 것

  • EDNS0는 기존 DNS 메시지에 붙는 확장 메모예요.
  • EDNS0는 보통 Additional 구역의 OPT 의사 레코드로 보여요.
  • udp: 1232 같은 값은 이 정도 크기의 UDP DNS 응답을 받을 수 있다는 광고에 가까워요.
  • DNS 응답이 너무 크면 헤더의 TC 비트가 켜질 수 있고, 이때는 TCP로 다시 물어봐야 해요.
  • EDNS0는 DNSSEC이 아니에요. 다만 DNSSEC처럼 큰 응답을 만드는 기능이 EDNS0의 도움을 받을 수 있어요.

이제 dig 출력에서 OPT PSEUDOSECTION이 보여도 낯설지 않죠. 그 줄은 이상한 덤이 아니라, DNS가 작은 봉투의 한계를 넘기 위해 붙인 확장 가능성 표시예요.

이어서 보면 좋은 글

이어서 볼 질문

"크기를 키우는 건 알겠어요. 그럼 DNS 응답이 진짜인지 아닌지는 어떻게 확인할까요?"

다음에는 DNSSEC이 DNS 응답을 어떻게 검증 가능한 답으로 만드는지 이어서 열어볼게요.

댓글