hana_shinのLinux技術ブログ

Linuxの技術情報を掲載しています。特にネットワークをメインに掲載していきます。

BINDの使い方(ゾーン転送)



1 はじめに

DNSの運用では、複数の権威DNSサーバを用意するのが一般的です。複数の権威DNSサーバを運用する場合、全ての権威DNSサーバでゾーンファイルを一致させる必要があります。管理者がこれを手作業で行うのは手間がかかり、ミスも発生します。このため、DNSでは複数の権威DNSサーバでゾーンファイルを同期するゾーン転送という仕組みがあります。ゾーンファイルを管理する権威DNSサーバをプライマリーサーバと呼び、ゾーン転送によってゾーンファイルのコピーを受け取り運用するサーバをセカンダリーサーバと呼びます。なお、検証に使うドメイン名は、RFC 2606 - Reserved Top Level DNS Namesで以下のように記述されているので、abc.testとします。

".test" is recommended for use in testing of current or new DNS related code.

DNSの名前解決の様子は、digコマンドの使い方 - hana_shinのLinux技術ブログを参照してください。

2 検証環境

2.1 ネットワーク構成

DNSサーバは、プライマリーサーバとセカンダリーサーバの2台構成です。

                       192.168.122.0/24
primary(eth0) ----------------------------------(eth0) secondary
             .16                             .213

2.2 版数

プライマリーサーバとセカンダリーサーバのAlmaLinux版数は以下のとおりです。

[root@primary ~]# cat /etc/redhat-release
AlmaLinux release 9.1 (Lime Lynx)

カーネル版数は以下のとおりです。

[root@primary ~]# uname -r
5.14.0-162.6.1.el9_1.x86_64

3 インストール方法

プライマリーサーバとセカンダリーサーバで bindパッケージ、bind-utilsパッケージをインストールします。なお、dnfコマンドの使い方は、dnfコマンドの使い方 - hana_shinのLinux技術ブログを参照してください。

[root@primary ~]# dnf -y install bind bind-utils

BINDの版数を確認します。

[root@primary ~]# named -v
BIND 9.16.23-RH (Extended Support Version) <id:fde3b1f>

4 ポート番号の開放

ゾーン転送に使うTCP/UDPのポート番号53を解放します。なお、firewall-cmdの使い方は、firewall-cmdの使い方 - hana_shinのLinux技術ブログを参照してください。

4.1 プライマリーサーバのポート番号開放

[root@primary ~]# firewall-cmd --add-port=53/tcp
success
[root@primary ~]# firewall-cmd --add-port=53/udp
success

開放したポート番号を確認します。

[root@primary ~]# firewall-cmd --list-ports
53/tcp 53/udp

4.2 セカンダリーサーバのポート番号開放

[root@secondary ~]# firewall-cmd --add-port=53/tcp
success
[root@secondary ~]# firewall-cmd --add-port=53/udp
success

開放したポート番号を確認します。

[root@secondary ~]# firewall-cmd --list-ports
53/tcp 53/udp

5 プライマリーサーバの設定

5.1 設定ファイルの編集

設定ファイル編集前後の差分を確認するため、バックアップファイルを作成します。

[root@primary ~]# cp /etc/named.conf /etc/named.conf.org

設定ファイルの差分を確認します。

[root@primary ~]# vi /etc/named.conf
[root@primary ~]# diff -Nur /etc/named.conf.org /etc/named.conf
--- /etc/named.conf.org 2023-05-21 20:12:04.638427807 +0900
+++ /etc/named.conf     2023-05-27 19:59:22.375933433 +0900
@@ -8,7 +8,7 @@
 //

 options {
-       listen-on port 53 { 127.0.0.1; };
+       listen-on port 53 { 192.168.122.16; };
        listen-on-v6 port 53 { ::1; };
        directory       "/var/named";
        dump-file       "/var/named/data/cache_dump.db";
@@ -16,7 +16,7 @@
        memstatistics-file "/var/named/data/named_mem_stats.txt";
        secroots-file   "/var/named/data/named.secroots";
        recursing-file  "/var/named/data/named.recursing";
-       allow-query     { localhost; };
+       allow-query     { any; };

        /*
         - If you are building an AUTHORITATIVE DNS server, do NOT enable recursion.
@@ -28,7 +28,7 @@
           attacks. Implementing BCP38 within your network would greatly
           reduce such attack surface
        */
-       recursion yes;
+       recursion no;

        dnssec-validation yes;

@@ -57,3 +57,9 @@
 include "/etc/named.rfc1912.zones";
 include "/etc/named.root.key";

+zone "abc.test" IN {
+       type master;
+       file "abc.test.db";
+       allow-transfer { 192.168.122.213; };
+       notify yes;
+};

設定変更したステートメントの意味を以下に示します。

ステートメント 意味
listen-on DNSサーバが問い合わせを受け付けるIPアドレスを設定します。
allow-query DNSクエリーを受け付けるDNSクライアントのIPアドレスを設定します。ここでは、全てのDNSクライアントからのDNSクエリを受け付けるanyを設定します。
recursion 再帰問い合わせを受け付けるかどうかを設定します。DNS権威サーバは再帰クエリは受け付けないのでnoを設定します
type DNSサーバがプライマリーサーバか、セカンダリーサーバなのかを設定します。プライマリーサーバはmaster、セカンダリーサーバはslave、DNSキャッシュサーバはhintを設定します。
file ゾーンファイル名を設定します。ゾーンファイルは、directoryステートメントで指定したディレクトリ以下に格納されます
allow-transfer ゾーンファイルの転送を許可するセカンダリーサーバのIPアドレスを設定します。
notify プライマリーサーバのゾーンファイルが更新された時、セカンダリーサーバに更新があったことを通知するかどうかを設定します。通知する場合はyes、通知しない場合はnoを設定します。

5.2 ゾーンファイルの作成

ゾーン転送の動作確認をするため、正引きのゾーンファイルのみを作成します。ゾーン転送はゾーンファイルのSOAレコードで制御されます。なお、SOAレコードのパラメータの意味は、digコマンドの使い方 - hana_shinのLinux技術ブログを参照してください。

[root@primary ~]# vi /var/named/abc.test.db
[root@primary ~]# cat /var/named/abc.test.db
$ORIGIN abc.test.
$TTL 3600
@    IN SOA     primary.abc.test. root.abc.test. (
                                        2023052801 ; serial
                                        300        ; refresh
                                        900        ; retry
                                        3600       ; expire
                                        3600 )     ; minimum
           NS      primary.abc.test.
primary    A       192.168.122.16

6 セカンダリーサーバの設定

6.1 設定ファイルの編集

設定ファイル編集前後の差分を確認するため、バックアップファイルを作成します。

[root@secondary ~]# cp /etc/named.conf /etc/named.conf.org

設定ファイルの差分を確認します。

[root@secondary ~]# vi /etc/named.conf
[root@secondary ~]# diff -Nur /etc/named.conf.org /etc/named.conf
--- /etc/named.conf.org 2023-05-21 20:16:02.611164689 +0900
+++ /etc/named.conf     2023-05-21 20:18:38.335385768 +0900
@@ -8,7 +8,7 @@
 //

 options {
-       listen-on port 53 { 127.0.0.1; };
+       listen-on port 53 { 192.168.122.213; };
        listen-on-v6 port 53 { ::1; };
        directory       "/var/named";
        dump-file       "/var/named/data/cache_dump.db";
@@ -16,7 +16,7 @@
        memstatistics-file "/var/named/data/named_mem_stats.txt";
        secroots-file   "/var/named/data/named.secroots";
        recursing-file  "/var/named/data/named.recursing";
-       allow-query     { localhost; };
+       allow-query     { any; };

        /*
         - If you are building an AUTHORITATIVE DNS server, do NOT enable recursion.
@@ -28,7 +28,7 @@
           attacks. Implementing BCP38 within your network would greatly
           reduce such attack surface
        */
-       recursion yes;
+       recursion no;

        dnssec-validation yes;

@@ -57,3 +57,8 @@
 include "/etc/named.rfc1912.zones";
 include "/etc/named.root.key";

+zone "abc.test" IN {
+       type slave;
+       file "slaves/abc.test.db";
+       masters { 192.168.122.16; };
+};

7 設定ファイル、ゾーンファイルの構文チェック

設定ファイル、およびゾーンファイルの構文が正しいかどうかをチェックします。それぞれ、以下のコマンドでチェックすることができます。
・named-checkconf:設定ファイル(named.conf)の構文チェック
・named-checkzone:ゾーンファイルの構文チェック

7.1 プライマリーサーバ

named-checkconfコマンドを使って、プライマリーサーバの設定ファイルの構文をチェックします。named-checkconfコマンドが正常終了しているので、設定ファイルに誤りがないことがわかります。

[root@primary ~]# named-checkconf /etc/named.conf
[root@primary ~]#

named-checkzoneコマンドを使って、プライマリーサーバのゾーンファイルの構文をチェックします。named-checkzoneコマンドが正常終了しているので、ゾーンファイルに誤りがないことがわかります。

[root@primary ~]# named-checkzone abc.test /var/named/abc.test.db
zone abc.test/IN: loaded serial 2023052801
OK

7.2 セカンダリーサーバ

named-checkconfコマンドを使って、セカンダリーサーバの設定ファイルの構文をチェックします。named-checkconfコマンドが正常終了しているので、設定ファイルに誤りがないことがわかります。

[root@secondary ~]# named-checkconf /etc/named.conf
[root@secondary ~]#

8 セカンダリサーバ起動時のシーケンス

セカンダリサーバ起動時、プライマリサーバからセカンダリサーバにゾーンファイルが転送されます。その時の状況を確認してみます。

プライマリーサーバでnamedサービスを起動します。

[root@primary ~]# systemctl start named

セカンダリーサーバのゾーンファイルを確認すると、まだゾーンファイルが存在しないことがわかります。

[root@secondary ~]# ls -l /var/named/slaves
合計 0

セカンダリーサーバでnamedサービスを起動します。

[root@secondary ~]# systemctl start named

セカンダリーサーバでnamedサービスを起動すると、プライマリーサーバからセカンダリサーバにゾーンファイルが転送されたことがわかります。

[root@secondary ~]# ls -l /var/named/slaves/abc.test.db
-rw-r--r--. 1 named named 203  5月 31 20:03 /var/named/slaves/abc.test.db

ゾーンファイルはバイナリファイルなので、named-compilezoneコマンドを使ってテキストファイルに変換します。

[root@secondary ~]# named-compilezone -f raw -F text -o /tmp/abc.test.db abc.test. /var/named/slaves/abc.test.db
zone abc.test/IN: loaded serial 2023052801
dump zone to /tmp/abc.test.db...done
OK

ゾーンファイルを確認すると、プライマリサーバのゾーンファイルが転送されたことがわかります。

[root@secondary ~]# cat /tmp/abc.test.db
abc.test.                                     3600 IN SOA       primary.abc.test. root.abc.test. 2023052801 300 900 3600 3600
abc.test.                                     3600 IN NS        primary.abc.test.
primary.abc.test.                             3600 IN A         192.168.122.16

tcpdumpコマンドで採取したゾーン転送時のキャプチャファイルを以下に示します。

キャプチャファイルのシーケンスを以下に示します。まず、セカンダリサーバはUDPを使用してゾーンファイルの転送を要求します。そして、ゾーンファイルが存在する場合は、TCPコネクションを確立し、ゾーンファイルの転送を行います。ゾーンファイルの転送が完了すると、セカンダリサーバはTCPコネクションをクローズします。

プライマリーサーバ                      セカンダリーサーバ

TCP/53    UDP/53                         UDP/53    TCP/53
  |          |                             |          |
  |          |<----- DNS query ------------|          | ---
  |          |                             |          |  | <= ゾーンファイルの確認
  |          |------ DNS query response -->|          | ---
  |          |                             |          |
  |<---------|------ TCP SYN --------------|----------| ---
  |----------|------ TCP SYN+ACK ----------|--------->|  | <= TCPコネクションの確立
  |<---------|------ TCP ACK --------------|----------| ---
  |          |                             |          |
  |<---------|------ DNS query ------------|----------| ---
  |          |                             |          |  | <= ゾーンファイルの転送
  |----------|------ DNS query response ---|--------->| ---
  |          |                             |          |
  |<---------|------ TCP FIN --------------|----------| ---
  |----------|------ TCP FIN+ACK ----------|--------->|  | <= TCPコネクションのクローズ
  |<---------|------ TCP ACK --------------|----------| ---
  |          |                             |          |

9 セカンダリサーバ起動後のシーケンス

セカンダリサーバが起動した後、プライマリサーバとのパケットのやりとりを確認してみます。セカンダリサーバは定期的にプライマリサーバに対してゾーンファイルの更新があるかどうかをチェックします。このチェックはおおよそ4分の間隔で行われています。私はSOAレコードのrefreshで指定した間隔で行われると思っていたため、5分間隔で行われると考えていました。しかし、実際は違っていました。なぜ5分間隔でチェックが行われないのかについて、ご存じの方がいらっしゃいましたら、教えていただけませんか。

[root@secondary ~]# tcpdump -i eth0 host 192.168.122.16 and port 53 -v -nn
dropped privs to tcpdump
tcpdump: listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
21:46:00.719188 IP (tos 0x0, ttl 64, id 12655, offset 0, flags [none], proto UDP (17), length 69)
    192.168.122.213.42212 > 192.168.122.16.53: 34635 [1au] SOA? abc.test. (41)
21:46:00.724449 IP (tos 0x0, ttl 64, id 27651, offset 0, flags [none], proto UDP (17), length 152)
    192.168.122.16.53 > 192.168.122.213.42212: 34635*- 1/1/2 abc.test. SOA primary.abc.test. root.abc.test. 2023052801 300 900 3600 3600 (124)
21:49:53.730645 IP (tos 0x0, ttl 64, id 63337, offset 0, flags [none], proto UDP (17), length 69)
    192.168.122.213.32943 > 192.168.122.16.53: 17190 [1au] SOA? abc.test. (41)
21:49:53.738170 IP (tos 0x0, ttl 64, id 14792, offset 0, flags [none], proto UDP (17), length 152)
    192.168.122.16.53 > 192.168.122.213.32943: 17190*- 1/1/2 abc.test. SOA primary.abc.test. root.abc.test. 2023052801 300 900 3600 3600 (124)
21:54:36.741113 IP (tos 0x0, ttl 64, id 58342, offset 0, flags [none], proto UDP (17), length 69)
    192.168.122.213.48592 > 192.168.122.16.53: 27517 [1au] SOA? abc.test. (41)
21:54:36.747100 IP (tos 0x0, ttl 64, id 32930, offset 0, flags [none], proto UDP (17), length 152)
    192.168.122.16.53 > 192.168.122.213.48592: 27517*- 1/1/2 abc.test. SOA primary.abc.test. root.abc.test. 2023052801 300 900 3600 3600 (124)
-snip-

10 ゾーンファイル編集後のシーケンス

ゾーンファイルを編集します。シリアル番号を1増やして、wwwサーバのリソースレコードを1つ追加します。

[root@primary ~]# vi /var/named/abc.test.db
[root@primary ~]# diff -Nur /var/named/abc.test.db.org /var/named/abc.test.db
--- /var/named/abc.test.db.org  2023-06-01 19:58:07.222806548 +0900
+++ /var/named/abc.test.db      2023-06-01 19:50:41.223070363 +0900
@@ -1,10 +1,11 @@
 $ORIGIN abc.test.
 $TTL 3600
 @    IN SOA     primary.abc.test. root.abc.test. (
-                                        2023052801 ; serial
+                                        2023052802 ; serial
                                         300        ; refresh
                                         900        ; retry
                                         3600       ; expire
                                         3600 )     ; minimum
            NS      primary.abc.test.
 primary    A       192.168.122.16
+www        A       192.168.122.20

ゾーンファイルを編集したら、namedを再起動します。

[root@primary ~]# rndc reload
server reload successful

tcpdumpコマンドを使って、ゾーン転送時のパケットをキャプチャします。

[root@secondary ~]# tcpdump -i eth0 host 192.168.122.16 and port 53 -v -nn
dropped privs to tcpdump
tcpdump: listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
-snip-
19:54:33.608079 IP (tos 0x0, ttl 64, id 14416, offset 0, flags [none], proto UDP (17), length 69)
    192.168.122.213.36158 > 192.168.122.16.53: 52391 [1au] SOA? abc.test. (41)
19:54:33.612003 IP (tos 0x0, ttl 64, id 34989, offset 0, flags [none], proto UDP (17), length 152)
    192.168.122.16.53 > 192.168.122.213.36158: 52391*- 1/1/2 abc.test. SOA primary.abc.test. root.abc.test. 2023052802 300 900 3600 3600 (124)
19:54:33.613313 IP (tos 0x0, ttl 64, id 59507, offset 0, flags [none], proto TCP (6), length 60)
    192.168.122.213.34845 > 192.168.122.16.53: Flags [S], cksum 0x7665 (incorrect -> 0x89b9), seq 256144245, win 64240, options [mss 1460,sackOK,TS val 2617157140 ecr 0,nop,wscale 7], length 0
19:54:33.615881 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 60)
    192.168.122.16.53 > 192.168.122.213.34845: Flags [S.], cksum 0x5884 (correct), seq 62942961, ack 256144246, win 65160, options [mss 1460,sackOK,TS val 75478619 ecr 2617157140,nop,wscale 7], length 0
19:54:33.616054 IP (tos 0x0, ttl 64, id 59508, offset 0, flags [none], proto TCP (6), length 52)
    192.168.122.213.34845 > 192.168.122.16.53: Flags [.], cksum 0x765d (incorrect -> 0x83e0), ack 1, win 502, options [nop,nop,TS val 2617157143 ecr 75478619], length 0
19:54:33.616912 IP (tos 0x0, ttl 64, id 59509, offset 0, flags [none], proto TCP (6), length 129)
    192.168.122.213.34845 > 192.168.122.16.53: Flags [P.], cksum 0x76aa (incorrect -> 0xd6cf), seq 1:78, ack 1, win 502, options [nop,nop,TS val 2617157144 ecr 75478619], length 77 9258 [1n] IXFR? abc.test. (75)
19:54:33.619731 IP (tos 0x0, ttl 64, id 65243, offset 0, flags [DF], proto TCP (6), length 52)
    192.168.122.16.53 > 192.168.122.213.34845: Flags [.], cksum 0x8388 (correct), ack 78, win 509, options [nop,nop,TS val 75478622 ecr 2617157144], length 0
19:54:33.621098 IP (tos 0x0, ttl 64, id 65244, offset 0, flags [DF], proto TCP (6), length 215)
    192.168.122.16.53 > 192.168.122.213.34845: Flags [P.], cksum 0x486d (correct), seq 1:164, ack 78, win 509, options [nop,nop,TS val 75478624 ecr 2617157144], length 163 9258*- 5/0/0 abc.test. SOA primary.abc.test. root.abc.test. 2023052802 300 900 3600 3600, abc.test. NS primary.abc.test., primary.abc.test. A 192.168.122.16, www.abc.test. A 192.168.122.20, abc.test. SOA primary.abc.test. root.abc.test. 2023052802 300 900 3600 3600 (161)
19:54:33.621139 IP (tos 0x0, ttl 64, id 59510, offset 0, flags [none], proto TCP (6), length 52)
    192.168.122.213.34845 > 192.168.122.16.53: Flags [.], cksum 0x765d (incorrect -> 0x82e7), ack 164, win 501, options [nop,nop,TS val 2617157148 ecr 75478624], length 0
19:54:33.623264 IP (tos 0x0, ttl 64, id 59511, offset 0, flags [none], proto TCP (6), length 52)
    192.168.122.213.34845 > 192.168.122.16.53: Flags [F.], cksum 0x765d (incorrect -> 0x82e4), seq 78, ack 164, win 501, options [nop,nop,TS val 2617157150 ecr 75478624], length 0
19:54:33.625855 IP (tos 0x0, ttl 64, id 65245, offset 0, flags [DF], proto TCP (6), length 52)
    192.168.122.16.53 > 192.168.122.213.34845: Flags [F.], cksum 0x82d6 (correct), seq 164, ack 79, win 509, options [nop,nop,TS val 75478629 ecr 2617157150], length 0
19:54:33.625906 IP (tos 0x0, ttl 64, id 59512, offset 0, flags [none], proto TCP (6), length 52)
    192.168.122.213.34845 > 192.168.122.16.53: Flags [.], cksum 0x765d (incorrect -> 0x82db), ack 165, win 501, options [nop,nop,TS val 2617157153 ecr 75478629], length 0

named-compilezoneコマンドを使って、ゾーンファイルをテキストファイルに変換します。

[root@secondary ~]# named-compilezone -f raw -F text -o /tmp/abc.test.db abc.test. /var/named/slaves/abc.test.db
zone abc.test/IN: loaded serial 2023052802
dump zone to /tmp/abc.test.db...done
OK

ゾーンファイルを確認すると、シリアル番号が1つ増加したことと、wwwサーバのリソースレコードが追加されたことがわかります。

[root@secondary ~]# cat /tmp/abc.test.db
abc.test.                                     3600 IN SOA       primary.abc.test. root.abc.test. 2023052802 300 900 3600 3600
abc.test.                                     3600 IN NS        primary.abc.test.
primary.abc.test.                             3600 IN A         192.168.122.16
www.abc.test.                                 3600 IN A         192.168.122.20

11 ゾーンファイルの転送確認

ゾーンファイルを転送したセカンダリーサーバに対して名前解決を要求してみます。まず、primary.abc.testのIPアドレスの解決を要求してみます。primary.abc.testのIPアドレスが192.168.122.16であることがわかります。

[root@primary ~]# dig @192.168.122.213 primary.abc.test +short
192.168.122.16

次に、www.abc.testのIPアドレスの解決を要求してみます。www.abc.testのIPアドレスが192.168.122.20であることがわかります。

[root@primary ~]# dig @192.168.122.213 www.abc.test +short
192.168.122.20

Z 参考情報

私が業務や記事執筆で参考にした書籍を以下のページに記載します。
Linux技術のスキルアップをしよう! - hana_shinのLinux技術ブログ

BIND 9 Administrator Reference Manual — BIND 9 9.19.18-dev documentation