사전 RFC 1035
표준

RFC 1035

gabury1고친 사람 github-actions[bot]

RFC 1035 는 도메인 이름 체계를 실제로 어떻게 만들지 적어 놓은 표준 문서입니다. 이름을 어떤 바이트로 적는지, 질문과 답을 어떤 모양으로 주고받는지, 받은 답을 얼마나 들고 있어도 되는지를 이 문서가 못박습니다. 1987년에 나온 문서이고 오늘 도는 이름 풀이도 이 규칙 위에 섭니다.

쉽고 빠른 이해

RFC 1035 는 이름을 주소로 바꾸는 절차를 바이트 단위까지 적어 둔 문서입니다. 브라우저가 example.com 을 열 때 오가는 질문과 답의 모양이 여기서 나옵니다.

규칙이 없으면 이름을 푸는 프로그램마다 메시지 모양이 갈립니다. 그러면 다른 회사가 만든 이름 서버와는 말이 안 통합니다.

돌아가는 방식은 이렇습니다.

  1. 묻는 쪽이 찾는 이름과 데이터 종류를 담은 질문 메시지를 만듭니다
  2. 이름 서버가 같은 메시지에 답을 채워 돌려줍니다
  3. 받은 쪽은 답에 붙어 온 시간만큼 그 답을 들고 있다가 버립니다

대가도 있습니다. 한 메시지를 512바이트로 묶어 둔 탓에 답이 길면 뒤가 잘립니다.

상세

이 문서의 제목과 짝 문서

RFC(Request for Comments)는 IETF(Internet Engineering Task Force, 인터넷 표준을 만드는 단체)가 번호를 붙여 내는 문서입니다. 1035번 문서의 제목은 「Domain Names - Implementation and Specification」입니다.

이 문서가 적는 것은 DNS(Domain Name System, 도메인 이름 체계)입니다. 사람이 쓰는 이름을 기계가 쓰는 IP 주소(IP 는 Internet Protocol, 인터넷에서 기계를 가리키는 번호를 정하는 규칙입니다) 같은 값으로 바꾸는 체계이고, 이름을 나눠 맡은 서버들이 서로 물어 답을 찾습니다.

짝 문서가 있습니다. RFC 1034 는 이 체계가 무엇이고 무엇을 해 주는지를 말로 풀고, 이 문서는 그것을 어떻게 만들지를 바이트까지 적습니다. 둘이 함께 인터넷 표준으로 올라가면서 STD(Standard, 표준) 13 이라는 번호를 같이 받았습니다.

나온 때는 1987년 11월입니다. 앞선 RFC 882 · 883 · 973 을 폐기했습니다. 그 뒤로 서른 편 가까운 문서가 이 문서의 일부를 고쳤지만 메시지 모양과 이름 규칙의 뼈대는 남아 있습니다.

도메인 이름을 적는 규칙

도메인 이름은 점으로 나뉜 조각의 줄입니다. 조각 하나를 레이블이라고 부릅니다. www.example.com 은 레이블 셋으로 이루어집니다.

메시지 안에서는 점을 쓰지 않습니다. 레이블마다 앞에 길이를 적은 한 바이트를 붙이고, 끝에 길이 0 인 바이트를 놓아 이름이 끝났다고 알립니다.

03 w w w              // 레이블 www
07 e x a m p l e      // 레이블 example
03 c o m              // 레이블 com
00                    // 이름 끝

길이 바이트는 여덟 비트지만 위 두 비트를 늘 0 으로 두기로 정했습니다. 그래서 레이블 하나는 63바이트를 넘지 못합니다. 이름 전체도 255바이트까지입니다. 남겨 둔 두 비트가 무엇을 하는지는 아래 「이름 압축」에서 드러납니다.

이름을 견줄 때는 대문자와 소문자를 같게 봅니다. Example.com 과 example.com 은 같은 이름입니다.

메시지의 다섯 부분

질문이든 답이든 같은 틀의 메시지 하나에 담깁니다. 틀은 다섯 부분으로 나뉘고 순서가 고정입니다.

block-beta
columns 1
  a["헤더 · 12바이트"]
  b["질문 · 무엇을 묻나"]
  c["답변 · 물은 것의 답"]
  d["권한 · 그 답을 아는 이름 서버"]
  e["추가 · 덤으로 붙이는 레코드"]

답하는 쪽은 받은 메시지의 질문 부분을 손대지 않고 두고, 뒤의 세 부분을 채워 돌려줍니다. 그래서 답만 받아도 무엇을 물었던 답인지 알 수 있습니다.

질문 부분에는 찾는 이름과 함께 「무슨 데이터를 원하는가」가 들어갑니다. 주소를 원하면 A, 메일 서버를 원하면 MX 를 적는 식입니다.

헤더의 비트 자리

헤더는 열두 바이트 고정입니다. 아래 그림은 그 안에 무엇이 어느 비트에 놓이는지 보입니다.

packet-beta
0-15: "ID"
16-16: "QR"
17-20: "Opcode"
21-21: "AA"
22-22: "TC"
23-23: "RD"
24-24: "RA"
25-27: "Z"
28-31: "RCODE"
32-47: "QDCOUNT"
48-63: "ANCOUNT"
64-79: "NSCOUNT"
80-95: "ARCOUNT"

그림의 이름들이 각각 무엇을 정하는지는 아래와 같습니다.

필드 하는 일
ID 질문마다 붙이는 16비트 번호. 답이 오면 이 번호로 짝을 맞춘다
QR 이 메시지가 질문인가 답인가
AA 답한 이름 서버가 그 이름을 직접 맡은 쪽인가
TC 크기 제한에 걸려 뒤가 잘렸나
RD 묻는 쪽이 끝까지 대신 찾아 달라고 부탁했나
RCODE 결과 번호. 0 은 정상이고 3 은 그런 이름이 없다는 뜻이다
뒤의 네 칸 뒤따르는 네 부분에 각각 몇 개가 들어 있나

ID 는 답이 뒤섞여 와도 짝을 맞추라고 둔 칸입니다. 질문을 UDP(User Datagram Protocol) 로 보내면 답이 보낸 순서대로 돌아온다는 보장이 없기 때문입니다.

리소스 레코드

답에 실려 오는 데이터 한 줄이 리소스 레코드입니다. 종류가 무엇이든 여섯 칸의 틀은 같습니다.

칸 담는 것
이름 이 레코드가 딸린 도메인 이름
종류 무슨 데이터인가
클래스 어느 망의 데이터인가. 인터넷이면 IN
TTL(Time to Live, 살아 있을 시간) 받은 답을 다시 써도 되는 초
길이 뒤따르는 데이터가 몇 바이트인가
데이터 종류마다 모양이 다른 값

종류 칸에 들어가는 값 가운데 지금도 자주 보는 것은 아래 일곱입니다.

종류 담는 값
A 호스트의 주소
NS 이 이름 아래를 맡은 이름 서버
CNAME 별명이 가리키는 본이름
SOA 이 도메인 묶음을 누가 맡고 사본을 얼마마다 새로 받나
PTR 주소에서 이름으로 거꾸로 가는 표시
MX 이 도메인의 메일을 받는 서버
TXT 아무 문자열

이 문서가 정한 종류는 열여섯 개입니다. 종류 칸이 16비트라 자리가 넉넉해서, 뒤에 나온 문서들이 AAAA 나 SRV 같은 종류를 계속 더했습니다.

이름 압축

한 메시지 안에 같은 이름이 여러 번 나옵니다. 질문에 example.com 이 있으면 답변에도, 권한 부분에도 같은 글자가 또 실립니다.

같은 글자를 되풀이하지 않으려고 앞에 나온 이름을 가리키는 두 바이트 포인터를 씁니다. 첫 두 비트를 11 로 두고 남은 열네 비트에 메시지 첫 바이트부터 떨어진 거리를 적습니다.

레이블 길이 바이트는 위 두 비트가 늘 0 이었습니다. 그래서 읽는 쪽은 바이트 하나만 보고 이것이 길이인지 포인터인지 가릅니다. 레이블을 63바이트로 묶은 상한은 이 구분을 얻으려고 치른 값입니다.

어느 길로 보내나

이름 서버는 포트 53번에서 기다립니다. 질문은 대개 UDP 로 보냅니다. 연결을 맺고 끊는 절차가 없어 한 왕복으로 끝나기 때문입니다.

다만 UDP 로 보내는 메시지는 512바이트까지입니다. 답이 그보다 길면 이름 서버는 들어가는 만큼만 채우고 TC 비트를 켭니다. 받은 쪽은 아래 순서로 다시 받아 옵니다.

flowchart TD
    A["UDP 로 질문한다"] --> B{"답이 512바이트에<br/>들어갔나"}
    B -->|들어갔다| C["답을 그대로 쓴다"]
    B -->|잘렸다| D["TC 비트가 켜져 온다"]
    D --> E["TCP 로 연결을 맺고<br/>같은 질문을 다시 한다"]
    E --> F["잘리지 않은 답을 받는다"]

TCP(Transmission Control Protocol) 로 보낼 때는 메시지 앞에 길이를 적은 두 바이트를 붙입니다. 바이트 흐름에는 경계가 없어서 이 길이가 없으면 어디까지가 한 메시지인지 읽는 쪽이 가릴 수 없습니다.

한 이름 서버가 통째로 맡은 도메인 묶음을 존이라고 합니다. 존을 그대로 복사해 가는 존 전송은 UDP 로 하면 안 됩니다. 중간이 빠져도 받는 쪽이 빠진 줄 모르기 때문입니다.

잃어버린 질문은 다시 묻는다

UDP 는 잃어버린 패킷(망으로 오가는 데이터 한 덩이)을 대신 채워 주지 않습니다. 그래서 묻는 쪽이 답을 기다리다 안 오면 스스로 다시 물어야 합니다. 이 되물음이 재전송입니다.

이 문서는 다시 묻는 방법을 권고로 적습니다. 같은 주소에 되풀이해 묻기 전에 그 도메인을 맡은 다른 이름 서버를 먼저 찔러 보라고 합니다. 다시 묻는 간격은 앞서 재 둔 응답 시간에서 뽑되 최소 2~5초는 두라고 적습니다.

간격을 짧게 잡으면 아직 답을 못 준 서버에 같은 질문이 계속 쌓입니다. 그러면 그 서버가 처리할 것이 늘어 모두가 더 오래 기다리게 됩니다. 최소 간격은 그 쏠림을 막으려고 둔 선입니다.

답을 얼마나 들고 있나

답에 실린 레코드마다 TTL 이 붙어 옵니다. 값은 32비트 정수이고 단위는 초입니다.

받은 쪽은 그 초 동안 답을 손안에 저장해 두었다가, 같은 질문이 또 오면 이름 서버에 묻지 않고 꺼내 씁니다. 이렇게 받은 답을 들고 있다 다시 쓰는 것이 캐싱이고, 답을 모아 둔 곳을 캐시라고 부릅니다.

TTL 이 0 이면 캐시하면 안 됩니다. 지금 하고 있는 질문에만 쓰고 버리라는 뜻입니다.

이 값이 부호 있는 수인지 없는 수인지는 이 문서 안에서도 절마다 달리 적혀 있습니다. 뒤에 나온 RFC 2181 이 어긋남을 정리했습니다.

캐시가 있어서 이름 서버 몇 대가 세상의 질문을 감당합니다. 대신 값을 바꿔도 먼저 나간 답의 TTL 이 지나기 전에는 옛 값을 보는 쪽이 남습니다. 웹 캐시가 신선도를 재면서 치르는 것과 같은 대가입니다.

나중에 고쳐진 대목

512바이트 상한은 답이 길어지면서 짐이 됐습니다. 뒤에 나온 EDNS0(Extension Mechanisms for DNS, DNS 확장 방식)이 묻는 쪽이 받을 수 있는 크기를 미리 알리게 해서 이 상한을 넓혔습니다.

받은 답이 진짜 그 도메인의 주인에게서 온 것인지 가리는 방법은 이 문서에 없습니다. 중간에서 답을 가로채 가짜를 돌려주면 묻는 쪽은 알아챌 수 없습니다. 그 몫은 뒤에 나온 DNSSEC(DNS Security Extensions, DNS 보안 확장)이 서명으로 맡았습니다.

관련 항목

이 문서와 함께 DNS 를 정의하는 표준 문서

RFC 1034 · RFC 1123 · RFC 2181 · RFC 2308 · RFC 6891 · RFC 4033 · RFC 7766

이 문서가 정의하는 메시지 구성 요소

DNS 메시지 · DNS 헤더 · 리소스 레코드 · 레이블 · 이름 압축 · 존 파일 · RDATA

이 문서가 정한 리소스 레코드 종류

A 레코드 · NS 레코드 · CNAME · SOA 레코드 · PTR 레코드 · MX 레코드 · TXT 레코드 · HINFO 레코드

DNS 메시지를 나르는 하위 프로토콜

UDP · TCP · IP 주소 · 포트 · 데이터그램 · 패킷

DNS 질의에 관여하는 역할

리졸버 · 스텁 리졸버 · 재귀 이름 서버 · 권한 있는 이름 서버 · 루트 이름 서버 · 존

답을 다시 쓸지 가리는 개념

TTL · 신선도 · 캐싱 · 낡은 데이터 · 네거티브 캐싱 · 재전송

이 문서를 넓히거나 대체한 확장

EDNS0 · DNSSEC · DNS over HTTPS · DNS over TLS · 존 전송 · 동적 갱신

이 규칙을 구현한 이름 서버와 조회 도구

BIND · Unbound · dnsmasq · PowerDNS · dig · nslookup

DNS 에서 나는 보안 문제

DNS 캐시 포이즈닝 · DNS 증폭 공격 · 도메인 하이재킹 · 서비스 거부 공격

이것이 속하는 상위 분류

DNS · RFC · IETF · IANA · 인터넷 표준 · 프로토콜

다른 이름: Domain Names - Implementation and Specification