본문 바로가기

DNS의 구조와 동작

오른쪽부터 읽는 도메인 이름의 계층과 영역의 위임을 정리하고, 스텁 리졸버, 재귀 리졸버, 루트, TLD, 권한 서버가 나누어 맡는 일을 봅니다. 리졸버가 위임을 따라가며 답을 찾는 과정과 TTL로 움직이는 여러 겹의 캐시를 모형으로 따라가고, 주소를 바꿀 때 TTL을 다루는 방법도 함께 다룹니다.

브라우저 주소창에 www.example.com을 입력하면 페이지가 열립니다. 하지만 패킷을 보내려면 이름이 아니라 IP 주소가 필요합니다. 사람이 쓰는 이름을 IP 주소를 비롯한 여러 정보로 바꿔 주는 것이 DNS(domain name system)입니다. DNS는 흔히 전화번호부에 비유되지만, 실제로는 한곳에 모여 있지 않고 전 세계 수많은 서버가 이름의 일부씩을 맡아 관리하는 계층형 분산 데이터베이스입니다. 이 구조는 RFC 1034와 RFC 1035에 정의되어 있습니다.

이름은 오른쪽부터 읽는다

도메인 이름은 점으로 나뉜 label들로 이루어지며, 오른쪽으로 갈수록 상위 계층입니다. www.example.com의 맨 오른쪽에는 보통 생략되는 점 하나가 더 있어서, 정확히 쓰면 www.example.com.입니다. 이 마지막 점이 모든 이름의 꼭대기인 루트(root)이고, 그 아래로 com이라는 최상위 도메인(top-level domain, TLD), example이라는 2단계 도메인, www라는 하위 도메인이 차례로 이어집니다. 마지막 점까지 쓴 이름을 FQDN(fully qualified domain name)이라고 합니다.

TLD의 종류예설명
일반 TLD(gTLD).com, .org, .net용도의 제한 없이 전 세계에서 쓰는 TLD
국가 코드 TLD(ccTLD).kr, .jp, .uk, .io국가나 지역의 두 글자 코드. .io도 영국령 인도양 지역의 코드다
새 gTLD.dev, .app, .blog2012년에 시작된 신청 절차로 크게 늘어난 TLD
후원 TLD(sTLD).edu, .gov특정 공동체나 기관을 위한 TLD
인프라 TLD.arpa주소로 이름을 찾는 역방향 조회 같은 인프라용

DNS 메시지 안에서 이름은 label마다 길이 바이트를 앞에 붙이고, 길이 0인 label로 끝을 표시합니다. 이 마지막 빈 label이 곧 루트입니다. RFC 1035는 label 하나를 63바이트, 이름 전체를 255바이트 이하로 제한합니다. 다음 코드는 이름을 계층의 위에서부터 나열하고, 메시지에 실리는 형태로 바꿉니다.

def encode_name(name):
    wire = b""
    for label in name.rstrip(".").split("."):
        raw = label.encode("ascii")
        if not 1 <= len(raw) <= 63:
            raise ValueError(f"label 길이 오류: {label!r}")
        wire += bytes([len(raw)]) + raw
    wire += b"\x00"                                  # 길이 0인 마지막 label이 루트다
    if len(wire) > 255:
        raise ValueError("이름이 255바이트를 넘는다")
    return wire

name = "www.example.com."
labels = name.rstrip(".").split(".")
print("위에서부터:", ["."] + [".".join(labels[i:]) + "." for i in range(len(labels) - 1, -1, -1)])
wire = encode_name(name)
print(f"{len(wire)}바이트: {wire}")
try:
    encode_name("www..example.com")
except ValueError as e:
    print(e)
위에서부터: ['.', 'com.', 'example.com.', 'www.example.com.']
17바이트: b'\x03www\x07example\x03com\x00'
label 길이 오류: ''

www.example.com.은 길이 바이트 3과 www, 7과 example, 3과 com, 마지막 0으로 모두 17바이트가 됩니다. 점이 두 번 이어진 이름은 길이 0인 label이 중간에 끼어 루트로 끝나 버리는 셈이므로 올바른 이름이 아닙니다.

이름의 계층을 나누어 맡는 단위를 영역(zone)이라고 합니다. 루트 영역은 com 영역을 맡을 서버가 어디인지만 알려 주고, com 영역은 다시 example.com 영역을 맡을 서버를 알려 주는 식으로 관리를 아래로 넘기는데, 이것을 위임(delegation)이라고 합니다. label마다 영역이 나뉘는 것은 아닙니다. example.com을 관리하는 회사는 www.example.com과 api.example.com을 따로 위임하지 않고 한 영역 안에서 함께 관리할 수 있습니다.

DNS 서버의 역할

DNS에 관여하는 서버는 하는 일에 따라 나뉩니다.

스텁 리졸버(stub resolver)는 내 컴퓨터의 운영체제에 들어 있는 작은 클라이언트입니다. 애플리케이션은 DNS 메시지를 직접 만들지 않고 getaddrinfo(3) 같은 함수를 부르며, 운영체제는 설정에 따라 hosts 파일을 먼저 보거나 재귀 리졸버에 질문을 보냅니다. 스텁 리졸버는 "답을 끝까지 찾아 달라"고 부탁할 뿐, 스스로 여러 서버를 돌아다니지 않습니다.

재귀 리졸버(recursive resolver)는 그 부탁을 받아 답을 찾을 때까지 여러 서버에 차례로 묻고, 찾은 답을 캐시해 두는 서버입니다. 통신사가 운영하는 리졸버나 8.8.8.8(Google), 1.1.1.1(Cloudflare) 같은 공개 리졸버가 이 역할을 합니다.

루트 서버는 루트 영역을 맡아, TLD마다 어느 서버에게 물어야 하는지를 알려 줍니다. 루트 서버에는 a.root-servers.net부터 m.root-servers.net까지 13개의 이름이 있고, Verisign이 A와 J를 맡는 식으로 12개 기관이 나누어 운영합니다. 13이라는 수는 초기 DNS가 UDP 응답을 512바이트로 제한했을 때 모든 루트 서버의 이름과 주소를 한 응답에 담기 위해 정해졌습니다. 이름은 13개이지만 각 이름은 7장 3편의 애니캐스트로 전 세계 여러 곳에 설치되어 있으며, 설치된 곳의 목록은 root-servers.org에서 볼 수 있습니다.

TLD 서버는 com이나 kr 같은 TLD 영역을 맡아, 그 아래 도메인을 맡은 서버를 알려 줍니다. 권한 서버(authoritative name server)는 특정 영역의 레코드를 실제로 가지고 있어, www.example.com의 주소가 무엇인지 같은 질문에 최종 답을 내놓는 서버입니다. 루트 서버와 TLD 서버도 자기 영역에 대해서는 권한 서버입니다.

리졸버가 위임을 따라간다

캐시가 비어 있는 재귀 리졸버가 www.example.com의 주소를 찾는 과정을 따라가 보겠습니다.

리졸버가 각 서버에 보내는 질의

stub이 최종 이름 해석을 리졸버에 요청합니다. 권한 서버의 답을 받아 stub에 돌려줍니다. 각 단계의 값과 전환 이유를 비교합니다.

DNS · 캐시 없는 해석

질의는 리졸버가 각 권한 서버에 직접 보낸다

Stub은 재귀 리졸버에 www.example.com의 A 레코드를 요청합니다. 답과 위임 정보가 캐시에 없으면 리졸버는 루트·.com·example.com 권한 서버에 차례로 질의하며 받은 위임 정보를 따라갑니다.

리졸버가 각 서버에 보내는 질의캐시에 답과 위임 정보가 없는 예시입니다. Stub이 리졸버에 재귀 질의를 보내고, 리졸버가 루트, .com TLD, example.com 권한 서버에 직접 차례로 질의합니다. 노드 안에는 그 서버가 돌려주는 정보를 표시했습니다.Stub resolverwww.example.com A재귀 리졸버대리 조회 · 캐시루트 (.)반환: .com NS.com TLD반환: example.com NS권한 서버반환: 192.0.2.44① 질의② 루트 질의③ 질의④ 권한 질의리졸버가 각 서버에 보내는 질의캐시에 답과 위임 정보가 없는 예시입니다. Stub이 리졸버에 재귀 질의를 보내고, 리졸버가 루트, .com TLD, example.com 권한 서버에 직접 차례로 질의합니다. 노드 안에는 그 서버가 돌려주는 정보를 표시했습니다.Stub resolverwww.example.com A재귀 리졸버대리 조회 · 캐시루트 (.)반환: .comNS 위임.com TLDexample.comNS 위임권한 서버반환 주소192.0.2.44① 재귀 질의② 루트 질의③ TLD 질의④ 권한 질의

화살표는 질의 방향입니다. 각 서버의 반환 정보를 받은 리졸버가 다음 질의를 보내며, 최종 답 192.0.2.44를 stub에 돌려줍니다. 주소는 예시이며 캐시에 위임 정보가 있으면 앞 단계를 건너뛸 수 있습니다.

이 예의 조건

  • 본문과 전체 도표의 예를 따라 재귀 요청부터 권한 답변까지 진행합니다.
예의 값과 변화
관찰·상황값·보충 정보변화·이유
재귀 요청

stub이 최종 이름 해석을 리졸버에 요청합니다.

  • 리졸버·질의 1: www.example.com A
  • 리졸버·질의 2: 답/위임 캐시 없음
  • 응답·위임 캐시가 없는 예에서 재귀 요청 시작
루트 질의

리졸버가 루트 서버에 직접 질의합니다.

  • 리졸버·질의 1: .com NS 위임
  • .com NS 위임 확보; 최종 웹 주소는 아직 아님
TLD 질의

리졸버가 .com 서버에 직접 질의합니다.

  • 리졸버·질의 1: example.com NS 위임
  • example.com 권한 서버 위임 확보
권한 답변

권한 서버의 답을 받아 stub에 돌려줍니다.

  • 리졸버·질의 1: A192.0.2.44
  • 리졸버·질의 2: stub에 최종 답
  • 학습용 A 주소 반환; 위임 캐시가 있으면 앞 단계 생략 가능

리졸버가 각 서버에 보내는 질의

stub이 최종 이름 해석을 리졸버에 요청합니다. 권한 서버의 답을 받아 stub에 돌려줍니다. 각 단계의 값과 전환 이유를 비교합니다.

DNS · 캐시 없는 해석

질의는 리졸버가 각 권한 서버에 직접 보낸다

Stub은 재귀 리졸버에 www.example.com의 A 레코드를 요청합니다. 답과 위임 정보가 캐시에 없으면 리졸버는 루트·.com·example.com 권한 서버에 차례로 질의하며 받은 위임 정보를 따라갑니다.

리졸버가 각 서버에 보내는 질의캐시에 답과 위임 정보가 없는 예시입니다. Stub이 리졸버에 재귀 질의를 보내고, 리졸버가 루트, .com TLD, example.com 권한 서버에 직접 차례로 질의합니다. 노드 안에는 그 서버가 돌려주는 정보를 표시했습니다.Stub resolverwww.example.com A재귀 리졸버대리 조회 · 캐시루트 (.)반환: .com NS.com TLD반환: example.com NS권한 서버반환: 192.0.2.44① 질의② 루트 질의③ 질의④ 권한 질의리졸버가 각 서버에 보내는 질의캐시에 답과 위임 정보가 없는 예시입니다. Stub이 리졸버에 재귀 질의를 보내고, 리졸버가 루트, .com TLD, example.com 권한 서버에 직접 차례로 질의합니다. 노드 안에는 그 서버가 돌려주는 정보를 표시했습니다.Stub resolverwww.example.com A재귀 리졸버대리 조회 · 캐시루트 (.)반환: .comNS 위임.com TLDexample.comNS 위임권한 서버반환 주소192.0.2.44① 재귀 질의② 루트 질의③ TLD 질의④ 권한 질의

화살표는 질의 방향입니다. 각 서버의 반환 정보를 받은 리졸버가 다음 질의를 보내며, 최종 답 192.0.2.44를 stub에 돌려줍니다. 주소는 예시이며 캐시에 위임 정보가 있으면 앞 단계를 건너뛸 수 있습니다.

이 예의 조건

  • 본문과 전체 도표의 예를 따라 재귀 요청부터 권한 답변까지 진행합니다.
예의 값과 변화
관찰·상황값·보충 정보변화·이유
재귀 요청

stub이 최종 이름 해석을 리졸버에 요청합니다.

  • 리졸버·질의 1: www.example.com A
  • 리졸버·질의 2: 답/위임 캐시 없음
  • 응답·위임 캐시가 없는 예에서 재귀 요청 시작
루트 질의

리졸버가 루트 서버에 직접 질의합니다.

  • 리졸버·질의 1: .com NS 위임
  • .com NS 위임 확보; 최종 웹 주소는 아직 아님
TLD 질의

리졸버가 .com 서버에 직접 질의합니다.

  • 리졸버·질의 1: example.com NS 위임
  • example.com 권한 서버 위임 확보
권한 답변

권한 서버의 답을 받아 stub에 돌려줍니다.

  • 리졸버·질의 1: A192.0.2.44
  • 리졸버·질의 2: stub에 최종 답
  • 학습용 A 주소 반환; 위임 캐시가 있으면 앞 단계 생략 가능

스텁 리졸버가 재귀 리졸버에 답을 끝까지 찾아 달라는 재귀 질의(recursive query)를 보냅니다. 재귀 리졸버는 루트 서버에 같은 질문을 하지만, 루트 서버는 답 대신 "com은 이 서버들이 맡고 있다"는 위임 정보를 돌려줍니다. 리졸버는 그 정보로 .com 서버에 다시 묻고, example.com을 맡은 권한 서버의 위치를 받은 뒤, 마지막으로 그 권한 서버에 물어 주소를 얻습니다. 이렇게 리졸버가 서버들을 차례로 직접 찾아가며 묻는 방식을 반복 질의(iterative query)라고 합니다. 루트 서버가 질문을 .com 서버에 대신 전달하는 것이 아니라, 모든 질문은 리졸버가 직접 보냅니다.

다음 코드는 이 과정을 모형으로 만든 것입니다. 각 서버는 자기가 아는 영역에 대해 답이나 위임을 돌려주고, 리졸버는 받은 위임을 기억해 두었다가 다음 질문에서 가장 가까운 위임부터 시작합니다.

def in_zone(name, zone):
    return name == zone or name.endswith("." + zone)

servers = {
    "루트 서버": {"com.": ("위임", ".com 서버")},
    ".com 서버": {"example.com.": ("위임", "example.com 서버")},
    "example.com 서버": {"www.example.com.": ("답", "192.0.2.44"), "api.example.com.": ("답", "192.0.2.80")},
}
delegations = {}                                     # 기억해 둔 위임: 영역 -> 그 영역을 맡은 서버

def resolve(name):
    known = [zone for zone in delegations if in_zone(name, zone)]
    server = delegations[max(known, key=len)] if known else "루트 서버"   # 가장 가까운 위임부터 묻는다
    asked = []
    while True:
        asked.append(server)
        zone, (kind, value) = next((z, r) for z, r in servers[server].items() if in_zone(name, z))
        if kind == "답":
            print(f"{name} -> {value}, 물어본 서버: {asked}")
            return
        delegations[zone] = value                    # 받은 위임을 기억해 둔다
        server = value

resolve("www.example.com.")
resolve("api.example.com.")
www.example.com. -> 192.0.2.44, 물어본 서버: ['루트 서버', '.com 서버', 'example.com 서버']
api.example.com. -> 192.0.2.80, 물어본 서버: ['example.com 서버']

첫 질문에서는 세 서버를 차례로 물었지만, 두 번째 질문은 example.com의 위임을 기억하고 있으므로 권한 서버에 바로 물었습니다. 실제 리졸버도 주소 레코드와 위임 정보를 따로 캐시하므로, 주소의 캐시가 만료되어도 위임 정보가 살아 있으면 루트부터 다시 묻지 않습니다. 실제 위임 응답에는 서버의 이름과 함께 그 주소가 실려 오기도 하는데, 이 주소를 글루 레코드(glue record)라고 합니다. 글루가 꼭 있어야 하는 것은 example.com의 권한 서버가 ns1.example.com처럼 자기 영역 안의 이름일 때입니다. 그 주소를 알려면 바로 그 서버에 물어야 하는 닭과 달걀의 문제가 생기기 때문입니다. 실제 위임의 사슬은 다음 글에서 dig +trace로 확인합니다.

더 깊이: 루트 서버에 이름 전체를 보내지 않는 QNAME 최소화

앞의 과정에서 리졸버는 루트 서버와 .com 서버에도 www.example.com이라는 이름 전체와 질문의 종류를 그대로 보냈습니다. 위임만 알려 주면 되는 서버들이 사용자가 어떤 이름을 찾는지까지 알게 되는 셈입니다. RFC 9156의 QNAME 최소화(QNAME minimisation)는 이를 줄이려고, 리졸버가 각 서버에 위임을 받는 데 필요한 만큼의 이름만 보내게 합니다. 루트 서버에는 com만, .com 서버에는 example.com만 묻고, 이름 전체와 원래의 질문 종류는 마지막 권한 서버에만 보냅니다.

중간 서버에 보내는 질문의 종류로는 A나 AAAA가 언제나 무난하다고 권합니다. 상위 영역의 서버는 어떤 종류의 질문에도 위임으로 답하기 때문입니다. 이름의 label이 많으면 그만큼 질문이 늘어나므로, RFC는 사용자 요청 하나에 나가는 질문의 수를 제한하는 장치를 반드시 두게 합니다. 그 방법의 하나로 최소화하며 묻는 횟수에 상한(MAX_MINIMISE_COUNT)을 둔다면 10을 권합니다. RFC 9156은 실험 단계의 문서였던 RFC 7816을 2021년에 표준으로 대체한 것입니다.

캐시는 여러 겹이다

실제로는 매번 루트 서버부터 묻지 않습니다. 브라우저는 자체 캐시를 갖고 있고, 운영체제의 스텁 리졸버도 답을 캐시하며, hosts 파일에 적힌 이름은 DNS를 거치지 않고 바로 쓰입니다. 그 뒤에 재귀 리졸버의 캐시가 있습니다. 어느 것을 먼저 보는지는 운영체제와 애플리케이션마다 다릅니다. Linux라면 /etc/nsswitch.conf의 hosts: 줄에 적힌 순서를 따릅니다.

각 레코드에는 캐시해 둘 수 있는 시간인 TTL(time to live)이 초 단위로 붙어 있습니다. 캐시는 TTL이 지나기 전까지 권한 서버에 다시 묻지 않고 저장한 답을 돌려주며, 이름이 없다는 응답(NXDOMAIN)도 영역이 정한 시간만큼 캐시합니다(RFC 2308). 다음 코드는 TTL이 60초인 주소를 캐시한 리졸버에서, 권한 서버가 20초에 주소를 바꾸고 TTL도 5초로 낮춘 상황을 따라갑니다.

class TtlCache:
    def __init__(self):
        self.entries = {}                            # 이름 -> (주소, 만료 시각)

    def get(self, name, now, fetch):
        entry = self.entries.get(name)
        if entry and now < entry[1]:
            return entry[0], f"캐시, {entry[1] - now}초 남음"
        address, ttl = fetch(now)
        self.entries[name] = (address, now + ttl)
        return address, f"권한 서버에서 새로 받음, TTL {ttl}"

def authority(now):                                  # 20초에 주소를 바꾸고 TTL도 5로 낮췄다
    return ("192.0.2.44", 60) if now < 20 else ("192.0.2.45", 5)

cache = TtlCache()
for now in [0, 35, 59, 60, 63, 66]:
    address, how = cache.get("www.example.com.", now, authority)
    print(f"{now:>2}초: {address} ({how})")
 0초: 192.0.2.44 (권한 서버에서 새로 받음, TTL 60)
35초: 192.0.2.44 (캐시, 25초 남음)
59초: 192.0.2.44 (캐시, 1초 남음)
60초: 192.0.2.45 (권한 서버에서 새로 받음, TTL 5)
63초: 192.0.2.45 (캐시, 2초 남음)
66초: 192.0.2.45 (권한 서버에서 새로 받음, TTL 5)

권한 서버의 주소는 20초에 바뀌었지만, 이 리졸버는 0초에 받은 답이 만료되는 60초까지 예전 주소를 돌려줍니다. 새 TTL 5초도 60초에 새로 받은 답부터 적용됩니다. 권한 서버가 이미 퍼진 캐시에 변경을 알려 줄 방법은 없기 때문입니다. 그래서 서버를 옮길 때는 옮기기 전에 미리 TTL을 낮춰 두고, 예전 TTL이 모두 지난 뒤에 주소를 바꿉니다. TTL이 하루인 레코드라면 적어도 하루 전에 낮춰야 합니다. 리졸버마다 TTL의 최솟값이나 최댓값을 따로 두는 경우도 있으므로, 바꾼 뒤에도 한동안은 예전 주소로 오는 요청을 받을 수 있게 해 둡니다.

캐시를 확인하거나 비우는 명령은 운영체제마다 다릅니다. 내 컴퓨터의 캐시를 비워도 브라우저와 재귀 리졸버의 캐시는 그대로라는 점을 기억해 둡니다.

ipconfig /displaydns                                         # Windows: 운영체제의 DNS 캐시 보기
ipconfig /flushdns                                           # Windows: 비우기
resolvectl statistics                                        # Linux(systemd-resolved): 캐시 통계
sudo resolvectl flush-caches                                 # Linux(systemd-resolved): 비우기
sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder  # macOS: 비우기

hosts 파일은 Windows에서는 C:\Windows\System32\drivers\etc\hosts, Linux와 macOS에서는 /etc/hosts에 있습니다. 개발할 때 이름을 임시로 다른 주소로 돌리기에 편하지만, 지우는 것을 잊으면 DNS를 아무리 고쳐도 내 컴퓨터만 예전 주소로 가는 원인이 됩니다.

정리

  • 도메인 이름은 오른쪽으로 갈수록 상위 계층이며, 맨 끝의 생략된 점이 루트입니다. label은 63바이트, 이름 전체는 255바이트까지입니다.
  • 이름의 계층은 영역 단위로 나누어 관리되고, 상위 영역은 하위 영역을 맡을 서버를 알려 주는 위임으로 관리를 넘깁니다.
  • 스텁 리졸버는 재귀 리졸버에 답을 끝까지 찾아 달라고 하고, 재귀 리졸버는 루트, TLD, 권한 서버를 차례로 직접 물으며 위임을 따라갑니다.
  • 루트 서버는 13개의 이름을 12개 기관이 나누어 운영하며, 각 이름은 애니캐스트로 전 세계에 퍼져 있습니다.
  • 브라우저, 운영체제, hosts 파일, 재귀 리졸버에 캐시와 규칙이 여러 겹으로 있고, 캐시는 TTL 동안 권한 서버에 다시 묻지 않습니다.
  • 권한 서버의 변경은 이미 퍼진 캐시에 즉시 전해지지 않으므로, 주소를 바꾸기 전에 예전 TTL만큼 앞서 TTL을 낮춥니다.

연습 문제

1. 루트 서버는 무엇을 돌려주나

캐시가 빈 재귀 리졸버가 루트 서버에 www.example.com의 주소를 물었습니다. 루트 서버는 무엇을 돌려주나요? "루트 서버가 질문을 .com 서버에 넘겨 준다"는 설명은 맞나요?

해설 보기

루트 서버는 www.example.com의 주소를 모르므로, com 영역을 맡은 서버들의 이름과 주소를 담은 위임 정보를 돌려줍니다. 질문을 .com 서버에 넘겨 주지는 않습니다. 리졸버가 그 위임 정보를 보고 .com 서버에 직접 다시 묻고, 같은 방식으로 example.com의 권한 서버까지 찾아갑니다. 루트 서버가 질문을 전달하는 방식이었다면 루트 서버가 세상의 모든 질문을 끝까지 처리해야 했을 것입니다. 루트는 위임만 알려 주므로 훨씬 적은 일로 버틸 수 있습니다.

2. TTL을 늦게 낮추면

www.example.com의 TTL이 3600초입니다. 운영자가 서버를 옮기면서 오후 2시에 주소를 바꾸고 동시에 TTL을 60초로 낮췄습니다. 오후 1시 50분에 이 이름을 캐시한 리졸버를 쓰는 사용자는 언제까지 예전 주소로 접속하나요? 처음부터 어떻게 했어야 하나요?

해설 보기

오후 1시 50분에 캐시한 답은 TTL 3600초, 곧 1시간 동안 유효하므로 그 리졸버를 쓰는 사용자는 오후 2시 50분까지 예전 주소로 접속합니다. 2시에 낮춘 TTL 60초는 2시 50분 이후에 새로 받은 답부터 적용됩니다. 처음부터 주소를 바꾸기 적어도 1시간 전에 TTL을 60초로 낮춰 두었다면, 바꾸는 시점에는 모든 캐시가 60초짜리 답을 갖고 있어 1분 안에 새 주소로 옮겨 갔을 것입니다. 옮긴 뒤 안정되면 TTL을 다시 올려 권한 서버의 부담을 줄입니다.

3. 메시지 안의 이름 길이

mail.corp.example.co.kr.을 본문의 encode_name으로 바꾸면 몇 바이트가 되나요? label 하나가 63바이트를 넘지 못하는 이유도 생각해 보세요. 길이 바이트 하나는 0부터 255까지 적을 수 있는데도 말입니다.

해설 보기

label마다 길이 바이트 하나가 붙으므로 mail은 5, corp는 5, example은 8, co는 3, kr은 3바이트이고, 마지막 루트의 0이 1바이트이므로 모두 25바이트입니다. 63이라는 한도는 길이 바이트의 위쪽 두 비트를 다른 용도로 남겨 두었기 때문입니다. RFC 1035 §4.1.4는 위쪽 두 비트가 모두 1인 바이트를 "이 이름의 나머지는 메시지의 앞쪽 어디에 이미 있다"는 압축 포인터로 쓰므로, label의 길이에는 남은 6비트, 곧 0부터 63까지만 쓸 수 있습니다.

다음 글 DNS 레코드와 실습에서는 A, AAAA, CNAME, MX 같은 레코드의 종류와 제약을 정리하고, dig와 nslookup으로 실제 응답과 TTL을 읽는 방법을 살펴봅니다.