CentOS 5.4でDNSサーバーの構築
CentOS 5.4にBINDを導入し、DNSサーバーとして動作させる。
1. 要件と仮定
今回の要件は以下の通り。
- 保有している独自ドメイン用のゾーンサーバーとして動作させる。
- 同時に、内部ネットワーク用のキャッシュサーバーとしても動作させる。
便宜上、設定等について以下の通り仮定する。
- 固定IPネットワーク 123.45.67.0/29 を取得済みであるとする。
- 内部ネットワークは 192.168.0.0/24 であるとする。
- 保有する独自ドメインは example.com であるとする。
2. インストール
yumからインストールを行う。セキュリティを考慮してchroot環境で動作させたいので、bind-chroot も同時に導入しておく。
[root@localhost ~]# yum -y install bind bind-chroot
2009年12月24現在、yumでインストールした場合のバージョンは 9.3.6 だった。以降の手順の確認は本バージョンで行っており、以前・以降のバージョンでは異なる場合があるので注意してほしい。
3. 設定
まず、bindの設定ファイルである named.conf を作成する。bind-chrootを導入した場合のパスは /var/named/chroot/etc/named.conf だ。設定方法が複雑なため、細かくコメントを入れているが、実際のファイルにコメントを記述する必要はない。
BIND9から実装された view ステートメントにより、リクエスト元のアドレスや受信インターフェースのアドレスなどにより、namedの挙動や返答内容を変えることができる。
view 定義は先頭から順に評価され、最初に全条件にマッチした view が使用される。ここではLAN向けの view と WAN向けの view を定義し、LAN向けには再帰問い合わせを許可するようにしている。また、LANへはローカルIP、WANへはグローバルIPを返すよう、ゾーンファイルをLAN用とWAN用で分けている。
# ネットワーク定義。ローカルネットワークを定義している。 acl "lan" { 127.0.0.1; 192.168.0.0/24; }; # ネットワーク定義。ゾーン転送を許可するホストを定義している。 # 有効なスレーブサーバーのIPを全て指定すればOK。 acl "slaves" { 192.168.0.3; }; # デフォルトオプション設定 options { # ゾーン情報が更新された場合にスレーブサーバーへ通知する。 notify yes; # バージョン情報を非公開とする。 version "unknown"; # ゾーン情報が格納されているディレクトリ。 # chroot環境の場合、以下の設定で /var/named/chroot/var/named となる。 directory "/var/named"; # ゾーン情報が更新された場合に通知するホストのリスト。 also-notify { slaves; }; # ゾーン情報のコピー(ゾーン転送)を許可するホストのリスト。 allow-transfer { slaves; }; }; # ログ設定 logging { # 通常のログチャンネル channel "log_default" { # ログファイルの指定とログの最大サイズ、保管世代数の指定。 file "/var/log/default.log" versions 7 size 10m; # ログのレベルの指定。 severity info; # ログの各行に日時を記録する。 print-time yes; # ログの各行にカテゴリ名を記録する。 print-category yes; }; # セキュリティ関連ログチャンネル channel "log_security" { file "/var/log/security.log" versions 7 size 10m; severity info; print-time yes; print-category yes; }; # 通常のログはログチャンネル log_default に記録。 category "default" { log_default; }; # セキュリティ/クライアント関連のログはログチャンネル log_security に記録。 category "security" { log_security; }; category "client" { log_security; }; }; # LAN用VIEW view "internal" { # 条件:ローカルネットワーク内からのリクエストである事。 match-clients { lan; }; # 条件:ローカルIPへ送られてきたリクエストである事。 match-destinations { lan; }; # 再帰問い合わせに応答する。 recursion yes; # ルートヒントファイルを読み込む。 include "/etc/named.root.hints"; # RFC1912に定義されているローカルエリア等のゾーン情報を読み込む。 include "/etc/named.rfc1912.zones"; # LAN向け example.com 正引きゾーン定義 zone "example.com" { type master; file "example.com.lan.zone"; }; # IPネットワーク 192.168.0.0/24 逆引きゾーン定義 zone "0.168.192.in-addr.arpa" { type master; file "lan.rev"; }; }; # WAN用VIEW view "external" { # 条件:LAN用VIEWにマッチしなかった全ての接続が対象となる。 match-clients { any; }; match-destinations { any; }; # 再帰問い合わせに応答しない。 recursion no; # WAN向け example.com 正引きゾーン定義 zone "example.com" { type master; file "example.com.wan.zone"; }; # IPネットワーク 123.123.123.0/29 逆引きゾーン定義 # ゾーン名はISPから指定された名前を設定すること。 # また、ISPから逆引き権限が委譲されない場合、設定は不要。 zone "sub-a.67.45.123.in-addr.arpa" { type master; file "wan.rev" } };
次に /var/named/chroot/etc/named.root.hints を以下の様に作成する。
zone "." { type hint; file "named.root"; };
続いて /var/named/chroot/etc/named.rfc1912.zones を作成する。/usr/share/doc/bind-9.3.6/sample/etc/named.rfc1912.zones にあるサンプルをそのままコピーすればOK。
[root@localhost ~]# cd /usr/share/doc/bind-9.3.6/sample/etc [root@localhost etc]# cp named.rfc1912.zones /var/named/chroot/etc/
/var/named/chroot/var/named 以下に必要なファイルをコピー(または作成)する。
[root@localhost ~]# cd /usr/share/doc/bind-9.3.6/sample/var/named [root@localhost named]# cp local*.zone /var/named/chroot/var/named/ [root@localhost named]# cp named.* /var/named/chroot/var/named/ [root@localhost named]# chown root:named *.* [root@localhost named]# chmod 644 *.*
ログファイルが存在しないとログの記録が開始されないため、あらかじめ用意しておく。
[root@localhost ~]# mkdir /var/named/chroot/var/log [root@localhost ~]# touch /var/named/chroot/var/log/default.log [root@localhost ~]# touch /var/named/chroot/var/log/secuirty.log [root@localhost ~]# chgrp named /var/named/chroot/var/log/*.log [root@localhost ~]# chmod 664 /var/named/chroot/var/log/*.log [root@localhost ~]# ln -s /var/named/chroot/var/log /var/log/named
4. 正引きゾーンファイルの作成
いよいよ自ドメイン用の設定に入る。ドメインからIPを割り出すためのデータファイルは「ゾーンファイル」と呼ばれ、ドメインごとに作る必要がある。ゾーンファイルは「レコード」と呼ばれる情報を列挙する形で記述する。レコードの形式は次のようになっている。
ホスト[ TTL] クラス タイプ データ[ データ[ データ]*]
「ホスト」はその名の通りホスト名を指定する。省略に関するルールが絡むので混乱しやすい。省略しない場合は「hostname.example.com.」の様に ホスト名.ドメイン名. の形となるが、ドメイン部は省略可能なので「hostname」とだけ書いても同じ意味になる。また、「@」とだけ書いた場合は「example.com.」と解釈される。また、レコードの先頭が空白文字で始まる=ホストを省略した場合、直前のレコードと同じホストが指定されたと見なされる。
「TTL」はそのレコードがキャッシュされた場合の有効期限だが、レコード毎にTTLを変える事は稀であり、たいてい省略される。省略した場合、$TTL で設定した数値が指定されたと見なされる。
「クラス」は本来ネットワークの種別などを指定するために存在するが、現在ではインターネットを表す "IN" 以外の設定はまず行われない。省略しないこと。
「タイプ」はレコードの種別を表す。使用可能なタイプと簡単な説明は下記の通り。
タイプ | 用途 |
---|---|
SOA | ゾーンファイルに必ず必要となるレコード。ゾーンに関する情報などを指定する。 |
NS | ネームサーバーの指定。 |
MX | メールサーバーの指定。 |
A | ホスト名に対応するIPv4アドレスの指定。 |
AAAA | ホスト名に対応するIPv6アドレスの指定。 |
CNAME | ホストの別名(Canonical Name)の指定。 |
PTR | PoinTeRレコード。主に逆引き設定に使用される。 |
「データ」はタイプ毎に必要なパラメータを指定する。必要なパラメータの内容や数はタイプによって異なる。データ部にホスト名を指定する場合、ホスト部と同様のルールで省略が可能。
各パラメータは任意の数の空白(半角スペースまたはTab文字)で区切られ、レコードとレコードの間は改行で区切られる。ただし、SOAレコードなどは1行に記述すると見づらいため、括弧でくくる事で複数行の記述も可能だ。
LAN向け正引きデータである /var/named/chroot/var/named/example.com.lan.zone を例に記述方法を解説する。
; デフォルトのTTL(キャッシュ有効期限)。以下の場合1日に設定。 $TTL 86400 ; SOAレコード(詳細は後述) @ IN SOA ns1 root ( 2009122401 ; Serial 3H ; Refresh 1H ; Retry 1W ; Expire 1H ; Min-TTL ) ; NSレコード ; データ部にはネームサーバーのホスト名を指定する。 IN NS ns1 IN NS ns2 ; MXレコード ; データ部には優先度とホスト名を指定する。 ; 優先度が低いサーバーから使用される。 IN MX 10 mail ; Aレコード ; ホスト名に対応するIPアドレスを指定する。 IN A 192.168.0.2 mail IN A 192.168.0.2 router IN A 192.168.0.1 host01 IN A 192.168.0.2 host02 IN A 192.168.0.3 host03 IN A 192.168.0.4 ; CNAMEレコード ; ホスト名に対応するホスト名を指定する。 ns1 IN CNAME host01 ns2 IN CNAME host02 www IN CNAME host01
SOAレコードに記述するデータは
- NameServer
- MailAddress
- Serial
- Refresh
- Retry
- Expire
- Minimum
と7つもあるため、上記のように括弧を使って複数行に分けるのが通例。それぞれ次の通り設定する。
項目 | 例 | 設定内容 |
---|---|---|
NameServer | ns1 | ドメインのプライマリネームサーバー、つまりBINDをセットアップ中のサーバーのホスト名を指定する。例の場合 "ns1.example.com" となる。 |
MailAddress | root | ゾーンファイルに記述されているドメインについての連絡先。例の場合 "root@example.com" となる。 |
Serial | 2009122401 | ゾーン情報の改訂番号。ゾーンファイルを更新した場合に以前より大きい数値を指定する必要がある。YYYYMMDD+2桁の連番とするのが通例。 |
Refresh | 3H | スレーブサーバーによる更新確認頻度の指定。例の場合3時間。 |
Retry | 1H | スレーブサーバーが更新確認に失敗した場合のリトライ間隔。例の場合1時間。 |
Expire | 1W | スレーブサーバーが更新を行わなかった場合のゾーン情報有効期限。指定期間以内に再び更新を行わなかったスレーブサーバーはクライアントからのリクエストに応答できなくなる。 |
Min-TTL | 1D | ネガティブキャッシュの有効期限。ネガティブキャッシュについては後述する。 |
ネガティブキャッシュについて説明するためには、まずDNSサーバーの役割について解説する必要がある。要件でもさらりと書いたが、DNSには大きく分けて2つの機能がある。
- ゾーンサーバー
- ドメインからIP、IPからドメインへの名前解決を実際に行うサーバー。ゾーン情報を保有する。
- キャッシュサーバー
- クライアントからの問い合わせに応じて外部のゾーンサーバーに問い合わせを行い、その結果をクライアントに返すと共に、一定期間結果をキャッシュする。
このキャッシュサーバーによる「キャッシュ」は正常な応答をキャッシュするのはもちろん、名前解決に失敗した事も記憶する。この失敗についての記憶が「ネガティブキャッシュ」だ。SOAレコードの「Min-TTL」はこのネガティブキャッシュの有効期限を指定するパラメータとなる。
ゾーンファイルを作成したら、named-checkzone コマンドで間違いがないか確認する。以下のように「OK」とでれば問題なし。
[root@localhost ~]# named-checkzone example.com /var/named/chroot/var/named/example.com.lan.zone zone example.com/IN: loaded serial 2009122401 OK
同様に、WAN向けのゾーンファイル example.com.wan.zone も作成し、チェックしておく。
5. 逆引きゾーンファイルの作成
次にLAN向け逆引きデータ /var/named/chroot/var/named/lan.rev を作成する。SOAレコードとNSレコードについては正引きの場合とほぼ一緒でOK。PTRレコードは同じIPについて1レコードしか記述できないので注意。
$TTL 86400 @ IN SOA ns1 root ( 2009122401 ; Serial 10800 ; Refresh 3600 ; Retry 604800 ; Expire 86400 ; Minimum ) ; NSレコード IN NS ns1.example.com. IN NS ns2.example.com. ; PTRレコード ; IPからドメイン名に変換する逆引き設定。 1 IN PTR router.example.com. 2 IN PTR host01.example.com. 3 IN PTR host02.example.com. 4 IN PTR host03.example.com.
こちらも named-checkzone コマンドで確認する。
[root@athena named]# named-checkzone 0.168.192.in-addr.arpa /var/named/chroot/var/named/lan.rev zone 0.168.192.in-addr.arpa/IN: loaded serial 2009122401 OK
6. namedの起動と確認
namedを起動し、次回から自動的に実行されるように設定する。
[root@localhost ~]# service named start [root@localhost ~]# chkconfig named on
起動したら、dig コマンドで応答を確認する。
[root@localhost ~]# dig @127.0.0.1 www.example.com ; <<>> DiG 9.3.6-P1-RedHat-9.3.6-4.P1.el5_4.1 <<>> @127.0.0.1 www.example.com ; (1 server found) ;; global options: printcmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 43734 ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 2, ADDITIONAL: 0 ;; QUESTION SECTION: ;www.example.com. IN A ;; ANSWER SECTION: www.example.com. 86400 IN CNAME host01.example.com. host01.example.com. 86400 IN A 192.168.0.2 ;; AUTHORITY SECTION: example.com. 86400 IN NS ns2.example.com. example.com. 86400 IN NS ns1.example.com. ;; Query time: 1 msec ;; SERVER: 127.0.0.1#53(127.0.0.1) ;; WHEN: Thu Dec 24 18:38:41 2009 ;; MSG SIZE rcvd: 106
こんなカンジに返答が帰ってくればOK。