[Concept] 나는 DNS를 안다고 생각했는데
Source: Dev.to
번역을 진행하려면 번역이 필요한 텍스트를 제공해 주세요. 텍스트를 주시면 요청하신 대로 한국어로 번역해 드리겠습니다.
Introduction
우리는 모두 DNS가 어떻게 작동하는지 알고 있습니다 – 이를 설명하는 수많은 기사와 블로그가 있습니다.
좀 더 깊이 파고들면서 저에게는 새로운 여러 정보를 발견했으며, 이를 적어 보기로 했습니다.
Note: DNS에 관한 훌륭한 자료가 많이 있지만, 여기서 새로운 것을 찾으시길 바랍니다.
DNS가 왜 만들어졌나요?
DNS가 나오기 전에는 이름 기반 통신이 HOSTS.TXT 파일에 의존했으며, 이 파일은 컴퓨터마다 복사되었습니다.
각 사이트는 자체 파일을 유지하면서 호스트 이름을 네트워크 주소에 매핑했으며, 형식은 간단하고 사람이 읽을 수 있는 형태였습니다.
- 여러 사본의 hosts 파일을 유지하는 것은 비효율적이고 오류가 발생하기 쉬웠습니다.
- RFC 623과 RFC 625는 Stanford Research Institute Network Information Center (NIC) 를 마스터 hosts 파일의 공식 소스로 지정했습니다.
DNS의 탄생
Paul Mockapetris와 그의 팀은 사용자가 IP 주소를 기억하지 않아도 되는 보다 사용자 친화적인 네트워크를 만들라는 과제를 받았습니다.
그들은 호스트 이름이 다음과 같이 구성될 수 있다고 제안했습니다:
| 구성 요소 | 예시 |
|---|---|
| 이름 | IBM |
| 카테고리 / 목적 | .com (상업) |
1년 후, 최초의 일반 최상위 도메인(gTLD)이 도입되었습니다:
.com,.edu,.net,.org,.int,.gov,.mil
1985년 말까지 여섯 개의 새로운 .com 도메인이 존재했습니다. 최초로 등록된 도메인인 Symbolics.com은 오늘까지도 활성 상태입니다.
Trivia
DNS Interceptors
- Used for optimisation, censorship, captive portals, etc. → 최적화, 검열, 캡티브 포털 등에 사용됩니다.
- Since DNS is the gateway to the Internet, controlling it allows control over queries and requests. → DNS는 인터넷으로 가는 관문이므로, 이를 제어하면 질의와 요청을 제어할 수 있습니다.
Privacy
- RFC 7816 – QNAME Minimisation improves privacy. → RFC 7816 – QNAME 최소화는 프라이버시를 향상시킵니다.
- Instead of sending the full query to the authoritative name server, a resolver can send only the minimal required information. → 전체 질의를 권한 있는 이름 서버에 보내는 대신, 리졸버는 최소한의 필요한 정보만 보낼 수 있습니다.
한눈에 보는 DNS
DNS는 전역적이고 분산된 식별자 데이터베이스로, 정적인 /etc/hosts 파일을 대체했습니다.
그 분산 모델을 이해하려면 일반적인 조회 과정을 추적해 봅시다.
DNS 해석 과정
1. 브라우저 캐시
https://google.com을 요청하면 브라우저는 먼저 로컬 캐시를 확인합니다. 답변이 존재하면 즉시 반환됩니다.
2. 스텁 리졸버
캐시가 없을 경우, 운영 체제에 있는 스텁 리졸버(예: gethostbyname(), getaddrinfo())가 작동하여 재귀 리졸버에 쿼리를 보냅니다.
스텁 리졸버는 애플리케이션을 대신해 쿼리를 재귀 리졸버로 전달하는 얇은 클라이언트입니다.
3. 재귀 리졸버
재귀 리졸버가 실제 작업을 수행합니다:
- Cache Check – 캐시된 답변이 있으면(TTL이 아직 유효하면) 반환합니다.
- Root Hint File – 캐시가 없으면 루트 힌트 파일(13개의 루트 서버 IP 목록)부터 시작합니다.
- Priming Query – 루트 서버에 프라이밍 쿼리를 보내 루트 네임 서버 목록을 가져옵니다.
- Iterative Queries – DNS 계층 구조를 따라갑니다: 루트 → TLD → 해당 도메인의 권한 있는 네임 서버.
- Caching – 답변을 TTL (Time‑to‑Live) 값과 함께 캐시합니다.
TTL 세부 정보
- TTL은 레코드가 얼마나 오래 캐시될 수 있는지에 대한 제안입니다.
- 일부 리졸버는 최대 TTL을 강제하며, 이를 초과하는 값은 무시됩니다.
- TTL을 준수하기 위해, 리졸버는 다운스트림 클라이언트를 위해 결과를 캐시하기 전에 이미 소요된 해결 시간을 차감합니다.
4. 포워더 및 프록시 (선택 사항)
스텁과 재귀 리졸버 사이에 포워더 또는 프록시 서버가 있어 쿼리를 재귀 리졸버로 전달할 수 있습니다. 이는 보통 다음과 같은 이유로 수행됩니다:
- 보안 (내부 네트워크 세부 정보를 숨김)
- 중앙 집중식 캐싱
5. 리졸버 유형
| Type | Description |
|---|---|
| Stub | 애플리케이션에서 사용하는 얇은 클라이언트. |
| Recursive | 스텁을 대신해 전체 해석을 수행합니다. |
| Forwarder | 보안 또는 정책상의 이유로 다른 리졸버에 쿼리를 전달합니다. |
| Validating | DNSSEC 검증을 수행합니다. |
| Pay‑wall | 특정 도메인에 대한 접근을 제한합니다. |
대부분의 ISP는 자체 재귀 리졸버를 운영하며, 각각 자체 캐시를 유지합니다.
루트 영역
- ICANN, Verisign, 및 Root Server Operators가 루트 영역을 관리합니다.
- 루트 도메인(
.)에 대한 질의는 13개의 루트 네임 서버를 반환합니다.
글루 레코드
- Glue records는 순환 종속성을 없애는 하드코딩된 A (또는 AAAA) 레코드입니다.
- 순환 참조는 권한 있는 네임 서버의 이름이 해당 서버가 제공하는 영역 안에 존재할 때 발생합니다(예:
ns.example.com이example.com안에 있을 때). 글루가 없으면, 리졸버는 아직 IP를 알지 못하기 때문에 서버에 도달할 수 없습니다. - 글루 레코드는 영역을 위임할 때 도메인 레지스트라에 추가되며, 인터넷상의 각 네임 서버는 도메인 소유자가 만든 자체 글루 레코드를 가집니다.
요약
- DNS는 정적 hosts 파일을 분산형, 계층형 데이터베이스로 대체했습니다.
- 해석 흐름은 브라우저 캐시 → 스텁 리졸버 → 재귀 리졸버 → 루트 → TLD → 권한 서버 순으로 진행됩니다.
- 캐싱과 TTL은 각 단계에서 레코드가 저장되는 기간을 제어합니다.
- 루트 서버, 글루 레코드, 그리고 포워더가 시스템을 효율적이고 신뢰성 있게 유지합니다.
- **프라이버시(QNAME 최소화)**와 **가로채기(검열, 최적화)**와 같은 현대적인 문제는 확장 기능과 모범 사례를 통해 해결됩니다.
각 구성 요소를 자유롭게 탐구해 보세요 – DNS는 깊고 흥미로운 주제입니다!
이름 서버
이제 대부분의 작업을 담당하는 Recursive Resolver가 Authoritative Name Server를 찾아 쿼리의 답변(남은 TTL 포함)을 얻고 이를 Stub Resolver에 전달합니다. 이렇게 도메인 이름을 IP 주소로 해석합니다.
빠른 의사코드 요약
var cache = map[string]string{}
func stubResolver(domain string) string {
var (
ipAddress string
cacheHit bool
)
ipAddress, cacheHit = cache[domain]
if !cacheHit {
ipAddress = recursiveResolver(domain)
}
return ipAddress
}
func recursiveResolver(domain string) string {
// … recursively keep trying to identify the
// **Authoritative Name Server** by getting the
// **Name Servers** of each element.
// It may even go all the way to the root zone (".").
return ipAddress
}
Note: 실제 과정은 훨씬 복잡하며, 위 코드는 고수준의 예시일 뿐입니다.
DNS 쿼리란 무엇인가?
DNS 쿼리는 튜플( Query Tuple 라고도 함) 로 구성됩니다:
| 필드 | 설명 |
|---|---|
| 쿼리 이름 | 조회 중인 도메인 이름 |
| TTL | 응답의 TTL(생존 시간) |
| 클래스 | 보통 IN (Internet) |
| 쿼리 타입 | A, AAAA, MX 등 |
| RDATA | 리소스 레코드 데이터(응답에 포함) |
요청자는 전체 튜플을 요청합니다—단일 항목만 별도로 요청할 수 없습니다. 전송 시(RFC 1035) 쿼리는 ASCII와 유사한 레이블과 바이너리 데이터가 혼합된 형태이며, 역사적인 label‑compression 방식을 사용합니다.
퀴즈 세부 정보
| 주제 | 세부 내용 |
|---|---|
| Transport | DNS는 UDP를 선호합니다. 응답이 512 바이트보다 크거나 서버가 영역 전송을 수행하는 경우 TCP로 전환합니다. |
| In‑billiwick vs. Out‑of‑billiwick | In‑billiwick 서버는 위임된 영역 내부에 있으며 glue records에 의존합니다. Out‑of‑billiwick 서버는 영역 외부에 있습니다. |
| Packet Evolution | 초기 패킷은 RCODE 필드에 4비트만 사용했습니다. EDNS0(RFC 6891)에서는 OPT 의사 RR이 추가되어 RCODE가 12비트로 확장되고 새로운 플래그와 확장 기능이 도입되었습니다(예: 확장 오류 – RFC 8914, 클라이언트 서브넷 – RFC 7871). |
| Truncation | UDP 응답이 클라이언트 버퍼를 초과하면 TC (truncated) 비트가 설정됩니다. 클라이언트는 TCP로 재시도할 수 있고, 서버는 비필수 섹션을 삭제하여 맞출 수 있습니다. |
| Response Rate Limiting (RRL) | 쿼리 빈도에 따라 응답을 제한하는 DDoS 완화 기술입니다. |
| Reverse DNS (PTR) | IP 주소에서 이름을 찾으려면 옥텟 순서를 뒤집고 .in‑addr.arpa를 붙인 뒤 PTR 레코드를 조회합니다. 예: 142.250.72.196 → 196.72.250.142.in‑addr.arpa. |
| Apex, Terminal & Lame Delegations | Apex – 영역의 루트(예: example.com). Terminal – 영역의 마지막 노드. Lame delegation – 상위 NS 레코드가 더 이상 해당 영역을 제공하지 않는 하위로 가리킬 때. |
| Happy Eyeballs | 최신 클라이언트는 parallel A and AAAA queries(RFC 8305)를 전송합니다. 먼저 도착한 응답이 사용되어 사용자 경험이 향상됩니다. |
| Non‑existence Types | NXDOMAIN – 도메인 이름이 존재하지 않음. NOERROR와 빈 응답 – 존재하는 이름에 대해 요청한 레코드 타입이 존재하지 않음. |
| .com ↔ .net Dependency | 많은 .com 네임 서버가 자체적으로 .net 네임 서버에 위임되어 있습니다. |
| CNAME vs. DNAME | CNAME – 단일 이름에 대한 별칭(어떤 영역에도 지정 가능). DNAME – 전체 서브트리(영역)에 대한 별칭. |
| Wildcard Records | 와일드카드는 RFC 4592에 정의되어 있습니다. foo*.some-domain.com과 같은 쿼리는 유효하지 않으며, 별표는 가장 왼쪽 레이블(*.example.com)에만 사용할 수 있습니다. |
마무리 생각
이 “블로그 스타일” 메모가 DNS 내부 구조에 대한 더 명확한 그림과 흥미로운 잡다한 정보를 제공했기를 바랍니다.
학습 즐겁게!