【実験】DNSのゾーン情報はいかにして伝わるのか?
2024-03-08
azblob://2024/03/08/eyecatch/2024-03-08-dns-zoneinfo-propagation-experiment-000.jpg

1. はじめに

こんにちは!
最近docker-compose完全に理解した(してない)富田です!

突然ですが、DNSで俗に浸透と呼ばれる現象、ありますよね?
DNSサーバでゾーン情報を更新しても、その更新がユーザーの見える範囲に反映されるまで時間がかかるという、あの現象です。
今回はそれがどんなものなのかを直接見てみようと思い、手元で実験してみました!
(ちなみに、DNSの浸透という言葉を真面目に使うと、ネットワークつよつよの人からマサカリが飛んでくるらしいです。)

2. 実験環境の構成

2-1. 概要

ここで用いる実験環境はWSLのUbuntu上でdocker-composeを使って実験環境を構築しました。
(実験環境をコードで説明できるって便利ですよね!)

実験環境は以下の3つのサーバからなります。

  • 権威サーバ:ゾーン情報の大本を保持するサーバです。今回BINDを使用しています。
  • キャッシュサーバ:権威サーバの情報をキャッシュするサーバです。上に同じくBINDを使用しています。
  • 観測用サーバ:権威サーバとキャッシュサーバが保持している内容を問い合わせるサーバです。

これら3つのサーバは下の構成図のように一つのサブネット(exnet)につながっています。

2-2. フォルダー構成とファイル内容

このサブセクションは細かい構成の話なので、結果が見たい人はセクション3まで読み飛ばして大丈夫です。

フォルダー構成は以下の通りです。

DNSExperiment
├── docker-compose.yml
├── bind_auth
│   ├── named.conf
│   └── zonefiles
│       └── example.com.zone
├── bind_cache
│   └── named.conf
└── observer
    ├── Dockerfile
    └── observe.sh


ファイルの内容は、以下の通りです。

docker-compose.yml(全体の構成ファイル)
実験用のネットワークとして外界から隔離されたネットワークexnetを作成し、権威サーバとキャッシュサーバ、観測用サーバを接続します。
また、DNSの向き先は権威サーバとキャッシュサーバは権威サーバ、観測用サーバはキャッシュサーバを向くようにしています。
(結局、どのサーバもIPアドレス指定で参照するのであまり意味はないですが一応)

version: '3'

services:
  # DNS権威サーバ
  bind_auth:
    image: ubuntu/bind9:9.18-22.04_beta
    volumes:
      - ./bind_auth/named.conf:/etc/bind/named.conf
      - ./bind_auth/zonefiles:/var/lib/bind
    networks:
      exnet:
        ipv4_address: 192.168.11.11
    dns:  192.168.11.11

  # DNSキャッシュサーバ
  bind_cache:
    image: ubuntu/bind9:9.18-22.04_beta
    volumes:
      - ./bind_cache/named.conf:/etc/bind/named.conf
    networks:
      exnet:
        ipv4_address: 192.168.11.12
    dns:  192.168.11.11
    depends_on:
      - bind_auth

  # 観測用サーバ
  observer:
    build:
      context: ./observer
      dockerfile: Dockerfile
    networks:
      exnet:
        ipv4_address: 192.168.11.21
    dns:  192.168.11.12

networks:
  # 実験用ネットワーク(EXperimental NETwork)
  exnet:
    driver: bridge
    internal: true
    ipam:
      driver: default
      config:
        - subnet: 192.168.11.0/24

bind_auth/named.conf(権威サーバの設定ファイル)
ゾーン情報を持っているので、そのための項目をzoneで設定しています。
また、今回は実験を簡単にするため、dnssec-validationは切っています。

options {
  directory "/var/cache/bind";

  listen-on    { any; };
  listen-on-v6 { any; };

  recursion no;

  dnssec-validation no;
};

zone "example.com" IN {
  type master;
  file "/var/lib/bind/example.com.zone";
  allow-update { none; };
  notify no;
};

bind_auth/zonefiles/example.com.zone(実験対象のゾーン情報ファイル)
ゾーン情報本体です。
今回いじるのは1行目のTTLと、11行目のAレコードです。
普通はTTLは日単位のもう少し大きい数を指定すると思うのですが、今回は実験なので1分にしています。

$TTL 60
@     IN  SOA example.com. postmaster.example.com. (
        2024030211      ; Serial Number
        1800            ; Refresh
        900             ; Retry
        1209600         ; expire
        900             ; minimum
        )
;
      IN    NS  example.com.
      IN    A  192.168.10.100

bind_cache/named.conf(キャッシュサーバの設定ファイル)
権威サーバと違ってゾーン情報を持たないのでzoneの項目が無い代わりに、
forwardersに権威サーバを指定しています。

options {
  directory "/var/cache/bind";

  listen-on    { any; };
  listen-on-v6 { any; };

  forwarders {
    192.168.11.11;
  };

  recursion yes;

  dnssec-validation no;
};

observer/Dockerfile(観測用サーバの構成ファイル)
観測用サーバはdigコマンドを用いて権威サーバとキャッシュサーバのレコードを確認するので、
digコマンドを含むdnsutilsをインストールし、digコマンドを実行するスクリプトobserve.shをコピーしてきます。
コマンドがすぐに終了するとコンテナが止まってしまうので、sleep infinityを実行することで「何もしない」をしてもらいます。
(sleep infinityはこれで初めて知りました(笑))

FROM ubuntu:22.04

RUN apt update -y
RUN apt install dnsutils -y

COPY observe.sh /root/observe.sh
RUN chmod u+x /root/observe.sh

CMD ["sleep", "infinity"]

observer/observe.sh(観測スクリプト)
digコマンドを使用して権威サーバとキャッシュサーバにそれぞれ問い合わせます。

#!/usr/bin/bash

echo "================"
echo "bind_auth"
dig example.com @192.168.11.11 +noall +ans
echo "================"
echo "bind_cache"
dig example.com @192.168.11.12 +noall +ans
echo "================"

3. 実験1:権威サーバのIPアドレスを変えてみる

3-1. 環境を立ち上げる

早速やってみましょう! 
まず、環境を立ち上げます。

docker-compose up -d

観測用サーバで観測スクリプトを1秒おきに実行するようにします。

docker exec -t dnsexperiment_observer_1 watch -n 1 /root/observe.sh

観測スクリプトの結果がこんな感じに出てきます。

二段になってますが、上の段bind_authと書いてある方が権威サーバに問い合わせた結果で、
下の段bind_cacheと書いてある方がキャッシュサーバに問い合わせた結果です。

ゾーンファイルで設定した内容が出ていることが分かります。
この実験で注目する必要があるのは、2カラム目の数字と5カラム目のIPアドレスです。
2カラム目の数字はTTL(Time To Live)と言って、このゾーン情報の残りの有効時間(秒単位)を表します。
権威サーバはゾーンファイルに記されたTTLの値で固定で、キャッシュサーバは時間経過でカウントダウンしています。

3-2. 権威サーバのゾーン情報を書き換える

ここで、権威サーバに登録されているゾーン情報を変えてみようと思います。
ゾーンファイルを以下のように編集して

Diff$TTL 60
@     IN  SOA example.com. postmaster.example.com. (
        2024030211      ; Serial Number
        1800            ; Refresh
        900             ; Retry
        1209600         ; expire
        900             ; minimum
        )
;
      IN    NS  example.com.
-      IN    A  192.168.10.100
+      IN    A  192.168.10.123

以下のコマンドで権威サーバのゾーン情報を更新します。

docker exec dnsexperiment_bind_auth_1 rndc reload

このようになりました。

 権威サーバの方は確かにアドレスが変わりましたが、 キャッシュサーバの方は変わっていませんね。

キャッシュサーバ側のTTLが0になるまで待ってみます。(↓アニメーションGIFです)

TTLが切れると、キャッシュサーバの方も更新されました。

3-3. 実験1のまとめ

このことから、権威サーバが更新されてもキャッシュサーバはすぐには更新されず、TTLが0になるまでは古い情報を保持し続けることがわかりました。

4. 実験2:TTLを3秒にしてみる。

4-1. ゾーンファイルのTTLを3秒に変更

では、TTLを短くしたらすぐに更新されるのでは?と思ったので、今度は思い切ってTTLを3秒にしてみました。

Diff-$TTL 60
+$TTL 3
@     IN  SOA example.com. postmaster.example.com. (
        2024030211      ; Serial Number
        1800            ; Refresh
        900             ; Retry
        1209600         ; expire
        900             ; minimum
        )
;
      IN    NS  example.com.
      IN    A  192.168.10.123

先ほどと同じコマンドで権威サーバのゾーン情報を更新します。

IPアドレスと同じくすぐには変わりませんね。

また、TTLが切れるまで待つと、TTLが3秒になりました。

4-2. TTLが3秒の状態でIPアドレスを更新してみる。

ゾーンファイルを編集して更新すると

Diff$TTL 3
@     IN  SOA example.com. postmaster.example.com. (
        2024030211      ; Serial Number
        1800            ; Refresh
        900             ; Retry
        1209600         ; expire
        900             ; minimum
        )
;
      IN    NS  example.com.
-      IN    A  192.168.10.123
+      IN    A  192.168.10.234

すぐに更新されました。

4-3. 実験2のまとめ

このことから、TTLを短くするとすぐに更新されるようになるが、TTLの値が反映されるまでは旧TTLの時間分待つ必要があることがわかりました。

5. まとめ

以上の実験から、

  • キャッシュサーバの情報はIPアドレスもTTLも、キャッシュサーバに登録されている情報のTTLが切れるまでは更新されないこと
  • TTLを短くするとすぐに更新されるようになること。

がわかりました。

このTTLの値は権威サーバに登録されているゾーン情報に由来することを考えると、キャッシュの更新の頻度は権威サーバに主導権があることもわかります。
つまり、ゾーン情報の更新をすぐにキャッシュサーバに反映したい場合は、 あらかじめ権威サーバに登録されているゾーン情報のTTLを短くしておけばよいということですね!
流石に3秒は短すぎますが(笑)

ちなみに、冒頭でチラッと言った「浸透」というワード、何が問題なのか調べてみたところ、「『浸透』にはその過程がコントロールできないニュアンスがありますが、実際はこのまとめの通りコントロールできるものなので不適当である」ということでした。