DNS の実装としては Internet Systems Consortium (ISC) の Berkeley Internet Name Domain (BIND) が有名です。本ページは公式サイトの Documentation からダウンロードできる v9.10.2 の PDF マニュアルおよび『DNSの仕組み完全解説』から基本事項を抽出してまとめたものです。より詳細な事項はドキュメントを直接ご参照ください。バックアップ目的でホスティングしました。なお動作検証には CentOS 6.6 を使用しました。BIND 本体 (bind) および dig などの付属ツール (bind-utils) は yum でインストールできます。
$ sudo yum install bind
$ sudo yum install bind-utils
$ sudo chkconfig named on
$ sudo service named start
BIND 9 はネームサーバ named およびクライアント resolver ライブラリ liblwres から成るサーバ・クライアント型のパッケージです。
クライアントである resolver は stub resolver ともよばれ、実質的な処理はしていないに等しい状況です。単にサーバ側に問い合わせるだけの機能しか有しておらず、賢さが要求される再帰処理などはすべてサーバ側で実行されます。
サーバ側は二種類に大別されます。名前解決時のイメージを先に示すと以下のようになります。
resolver → recursive/caching → authoritative
クライアント stub resolver からの要求を受けて再帰的に名前解決するものを recursive サーバとよびます。recursive サーバは結果を TTL の間キャッシュするため caching サーバともよばれます。recursive/caching サーバは分散キャッシュ構成をとることができ、自分のキャッシュになければ別の recursive/caching サーバにクライアントからの要求を転送 forward できます。
recursive/caching サーバは自分のキャッシュにない zone のリクエストを resolver から受けた場合にその zone の authoritative サーバを再帰的に検索して直接問い合わせます。DNS の名前空間はツリー構造になっており zone 単位で分割されています。ある root ノードから leaf ノードまでの部分木のうち別の zone の root ノード以下の部分木を除く領域が、その root ノードが代表する zone です。各 zone には少なくとも一つの authoritative サーバが存在しています。authoritative サーバはその zone に関するすべての情報を保有しています。resolver の要求は必ずいずれかの zone に対するものであるため recursive/caching サーバは再帰的に DNS ツリーを検索してその zone の authoritative サーバを見つけ、直接問い合わせます。キャッシュではなく Authoritative サーバからの直接の回答には Authoritative Answer (AA) フラグが立ちます。冗長化のため異なるネットワークにまたがって共通の zone に対する複数の authoritative サーバを用意することがあります。
Authoritative サーバには master/slave の二種類があります。DNS ツリーにおいて隠蔽された場合 stealth な master/slave とよばれます。
zone の情報はテキストファイルで管理されています。これをゾーンファイルとよびます。ゾーンファイルを直接参照する authoritative サーバを primary master または単に master とよびます。ゾーンファイルは手動編集することが多いですが設定によっては動的に更新することもできます。
その zone の master または別の slave からレプリケーションするサーバです。master → slave → slave →... という多段レプリケーションが可能ということになります。slave または secondary とよばれます。
DNS ツリーにおいて親 zone のゾーンファイルの NS レコードで登録されたサーバは、その NS レコードで指定した子 zone の権限を委譲された authoritative サーバとなります。親の NS レコードで指定された authoritative サーバの情報はすべて子 zone のゾーンファイルに記載する必要があります。ここで、権限を委譲されていないサーバの情報も子 zone のゾーンファイルに記載でき、このようなサーバは親 zone には存在が知られていないため stealth であるとよばれます。stealth な authoritative サーバは親 zone からは見えないため再帰的にツリーを下ってきた検索によって発見されることはなく、したがって recursive/caching サーバから問い合わせを受けることはありません。親 zone から見える authoritative サーバは外部インターネットに公開されており、stealth にすることで master へのアクセスを内部インターネットからのみに限定できます。あるいはバックアップ用途で slave を stealth にすることもあります。
BIND のネームサーバには「ある zone の masterサーバ」かつ「別の zone の slave サーバ」かつ「ある複数クライアントの recursive/caching サーバ」としての役割を兼任させることができます。しかしながら、様々な観点から兼任はしないほうがよいとされます。
名前解決時に使用される OS の DNS サーバ設定は以下の方法で確認できます。これらは手動で設定されたもの、あるいは DHCP で自動で取得されたものです。
例えば以下のコマンドで確認できます。
$ dig
;; SERVER: 10.0.2.3#53(10.0.2.3)
...
これは RedHat 系であれば /etc/resolv.conf で確認できます。
$ cat /etc/resolv.conf
options single-request-reopen
; generated by /sbin/dhclient-script
nameserver 10.0.2.3
コマンドプロンプトで以下のコマンドを実行します。
$ ipconfig /all
DNS サーバー. . . . . . . . . . . : 192.168.179.1
...
もちろん dig でも確認できます。
$ dig
;; SERVER: 192.168.179.1#53(192.168.179.1)
...
ちなみに Windows の DNS リゾルバはキャッシュ機能を有しており、その内容を確認するためには以下のようにします。
$ ipconfig /displaydns
www.qoosky.io
----------------------------------------
レコード名 . . . . . : www.qoosky.io
レコードの種類 . . . : 1
Time To Live . . . .: 1877
データの長さ . . . . : 4
セクション . . . . . . . : 回答
A (ホスト) レコード. . . : 49.212.166.76
...
動作確認を行うために OS の設定をこれから新規に立てる DNS サーバ用に変更してもよいのですが、それだと他の作業時にいろいろと不便です。dig は引数で問い合わせを行う対象となる DNS サーバを指定できます。OS で設定された既定の DNS サーバ設定を無視して動作確認ができるため便利です。
$ dig @localhost
example.com ゾーンの Authoritative ネームサーバを localhost に構築します。
/etc/named.conf
// グローバルな設定
options {
directory "/var/named";
};
// ルートゾーンの設定
zone "." {
type hint;
file "named.ca";
};
// ループバックアドレスの逆引き (正引きは /etc/hosts で対応)
zone "1.0.0.127.in-addr.arpa" {
type master;
file "named.loopback";
};
// example.com ゾーン (正引き)
zone "example.com" {
type master;
file "example.com.zone";
};
// example.com ゾーン (逆引き)
zone "33.168.192.in-addr.arpa" {
type master;
file "33.168.192.in-addr.arpa.zone";
};
/var/named/example.com.zone
$TTL 86400
;; 管理者 username@example.com
;; マスター ns1.example.com.
;; スレーブ ns2.example.com.
@ IN SOA ns1.example.com. username.example.com. (
2015031500 ; シリアル番号
28800 ; スレーブがゾーンファイルの更新を確認する秒間隔
7200 ; スレーブがゾーンファイルの更新確認に失敗した際に
; 再度確認するまでの秒間隔
604800 ; ゾーンファイルの有効秒
3600 ; ネガティブキャッシュの有効秒
)
IN NS ns1.example.com. ; マスター (プライマリ)
IN NS ns2.example.com. ; スレーブ (セカンダリ)
IN MX 10 mx1.example.com. ; プライマリメールサーバ
IN MX 20 mx2.example.com. ; セカンダリメールサーバ
IN A 192.168.33.105
ns1 IN A 192.168.33.101
ns2 IN A 192.168.33.102
mx1 IN A 192.168.33.103
mx2 IN A 192.168.33.104
www IN CNAME example.com.
/var/named/33.168.192.in-addr.arpa.zone
$TTL 86400
@ IN SOA ns1.example.com. username.example.com. (
2015031500
28800
7200
604800
3600
)
IN NS ns1.example.com.
IN NS ns2.example.com.
101 IN PTR ns1.example.com.
102 IN PTR ns2.example.com.
103 IN PTR mx1.example.com.
104 IN PTR mx2.example.com.
105 IN PTR example.com.
$ sudo chown named:named /etc/named.conf
$ sudo chmod 600 /etc/named.conf
$ sudo chown named:named /var/named/example.com.zone
$ sudo chmod 600 /var/named/example.com.zone
$ sudo chown named:named /var/named/33.168.192.in-addr.arpa.zone
$ sudo chmod 600 /var/named/33.168.192.in-addr.arpa.zone
$ sudo named-checkconf /etc/named.conf
$ sudo named-checkzone example.com. /var/named/example.com.zone
$ sudo named-checkzone 33.168.192.in-addr.arpa. /var/named/33.168.192.in-addr.arpa.zone
$ sudo service named reload
$ sudo grep named /var/log/messages | tail
A および PTR レコードを調査するためには
$ dig @localhost ns1.example.com
$ dig @localhost -x 192.168.33.101
あるいは
$ host ns1.example.com localhost
$ host 192.168.33.101 localhost
とします。他のレコードは明示的に引数で指定することで調査できます。
$ dig @localhost example.com MX
$ dig @localhost example.com NS
/etc/named.conf
// グローバルな設定
options {
directory "/var/named";
};
// ルートゾーンの設定
zone "." {
type hint;
file "named.ca";
};
// ループバックアドレスの逆引き (正引きは /etc/hosts で対応)
zone "1.0.0.127.in-addr.arpa" {
type master;
file "named.loopback";
};
// example.com ゾーン (正引き)
zone "example.com" {
type slave;
masters { 192.168.33.101; };
file "example.com.bak";
};
// example.com ゾーン (逆引き)
zone "33.168.192.in-addr.arpa" {
type slave;
masters { 192.168.33.101; };
file "33.168.192.in-addr.arpa.bak";
};
マスターから取得したゾーンファイルを named ユーザが書き込めるように、例えば以下のように権限設定します。
$ sudo chmod g+w /var/named
マスター設定の場合と同様に設定ファイルの設定も行います。
$ sudo chown named:named /etc/named.conf
$ sudo chmod 600 /etc/named.conf
$ sudo named-checkconf /etc/named.conf
$ sudo service named reload
$ sudo grep named /var/log/messages | tail
マスターからゾーンファイルを取得できていることを確認します。
$ sudo ls /var/named | grep bak
A および PTR レコードを調査するためには
$ dig @localhost ns1.example.com
$ dig @localhost -x 192.168.33.101
あるいは
$ host ns1.example.com localhost
$ host 192.168.33.101 localhost
とします。他のレコードは明示的に引数で指定することで調査できます。
$ dig @localhost example.com MX
$ dig @localhost example.com NS
先程構築したネームサーバは前述の recursive/caching 機能が有効になったままです。例えば
$ host yahoo.co.jp localhost
とすると再帰問い合わせを DNS ツリーに対して行って結果を返してくれます。recursive/caching 機能は DNS Cache Poisoning という攻撃の対象になります。Authoritative ネームサーバは DNS ツリーに属する必要性があり、内部インターネットからの問い合わせに対する名前解決だけを行う場合を除き、外部インターネットに公開せざるを得ません。Authoritative ネームサーバには recursive/caching 機能を持たせずに、内部インターネット用に非公開の recursive/caching 専用サーバを別途構築すべきです。
/etc/named.conf
// 攻撃者がアクセス元として使用する可能性のある IP リスト
acl "bogus" {
0.0.0.0/8; // 予約アドレス
1.0.0.0/8; // 予約アドレス
2.0.0.0/8; // 予約アドレス
169.254.0.0/16; // リンクローカルアドレス
192.0.2.0/24; // テストアドレス
224.0.0.0/3; // マルチキャストアドレス
10.0.0.0/8; // プライベートアドレス (グローバル IP からの問い合わせのみを受け付ける想定)
172.16.0.0/12; // プライベートアドレス (グローバル IP からの問い合わせのみを受け付ける想定)
192.168.0.0/16; // プライベートアドレス (グローバル IP からの問い合わせのみを受け付ける想定)
};
// 全体設定
options {
directory "/var/named";
recursion no; // Authoritative-only
allow-recursion { none; }; // Authoritative-only
blackhole { bogus; }; // パケットを処理せず破棄する (DoS対策)
// (グローバル IP からの問い合わせのみを受け付ける想定)
};
// example.com ゾーン (正引き)
zone "example.com" {
type master;
file "example.com.zone";
// すべてのクライアントから問い合わせを受け付ける (既定値)
// (グローバル IP からの問い合わせのみを受け付ける想定)
allow-query { any; };
// 指定したセカンダリ以外にはゾーン転送を許可しない (既定では許可)
// (すべての情報を漏洩させると攻撃されやすくなる)
allow-transfer { 192.168.33.102; };
// ダイナミックアップデートを受け付けない (既定値)
allow-update { none; };
// Slave にゾーンファイルの更新を通知する (既定値)
notify yes;
};
// example.com ゾーン (逆引き)
zone "33.168.192.in-addr.arpa" {
type master;
file "33.168.192.in-addr.arpa.zone";
allow-query { any; };
allow-transfer { 192.168.33.102; };
allow-update { none; };
notify yes;
};
allow-update はそもそも type slave に対しては許可されていないため明記しません。
/etc/named.conf
acl "bogus" {
0.0.0.0/8;
1.0.0.0/8;
2.0.0.0/8;
169.254.0.0/16;
192.0.2.0/24;
224.0.0.0/3;
10.0.0.0/8;
172.16.0.0/12;
192.168.0.0/16;
};
options {
directory "/var/named";
recursion no;
allow-recursion { none; };
blackhole { bogus; };
};
zone "example.com" {
type slave;
masters { 192.168.33.101; };
file "example.com.bak";
allow-query { any; };
allow-transfer { none; };
notify no;
};
zone "33.168.192.in-addr.arpa" {
type slave;
masters { 192.168.33.101; };
file "33.168.192.in-addr.arpa.bak";
allow-query { any; };
allow-transfer { none; };
notify no;
};