最小限の設定でDNSを使う

最小限の設定で“おうち用(もしくはSOHO用)”DNSサーバを立ててみた。

DNSサーバはPCが数台のネットワークでは余り使う機会はないと思う。それ程必要性が無いのに加えて設定がややこしい。しかし、仮想マシン環境を使い始めたため、実マシン、仮想マシンを合わせると、おうちの中にPCが10台近く存在することになった。(例えば、“Private Access Serverを作る”の様に幾つかの仮想マシンをサーバとして使ったりもしている。)

また台数の問題だけでなく、仮想マシン環境だと手軽に暫定的なマシンを作ることができ、他の仮想マシンや実マシンと通信するために、その度にhostsファイル等の設定が必要になってくる。

PCが数台であれば /etc/hsots や C:\WINDOWS\system32\drivers\etc\hosts を書き換えたりコピーしても大した手間ではなかったが、上のような状況になるとhostsの設定が煩雑になってしまう。そこでhostsファイルの一元管理が欲しくなった。LinuxでもWindowsでも使える名前解決となるとDNSしかない。DNSをインターネットへ向けた外向きのサーバとしてではなく、内向き限定のhostsファイルの代わりに使うことにした。

ということで、先ずはDNSの仕組みを知っておく必要があるが、それについては“DNSの仕組みの基本を理解しよう”等を参考にした。DNSは大企業やプロバイダなどでも使う仕組みなので、奥が深く真面目に設定すると結構大変だし、サーバも他の複数のDNSサーバに頻繁に問い合わせが発生するため(大したことはないが)負荷も発生する。しかし、やりたいのは外部に対してDNSの情報を提供することは一切せず、LAN内(おうち内)のマシンからの問い合わせにIPアドレスを教えるだけなので、基本的には数か所の変更と追加で済んでしまう。(このDNSサーバはNAT内にあるので、外部からアクセスされることはないという前提。)

どんなサーバにするのか、環境は?

DNSサーバの構成には幾つか種類があるが、今回は、おうち内のPCからの問い合わせに対して答えるだけで、自分の知らないマシン(つまりインターネットの世界のマシン)に関してはプロバイダのDNSサーバにそのまま丸投げする“フォーワーダー”設定すればいい。自分はおうちの中のPCのことだけ面倒を見る。

次に、ネットワークの名前。DNSではホスト名だけではなくドメイン名で問い合わせをするので、ネットワークに名前を付ける必要がある。今回は、192.168.0.0/24に対して“localnet”という名前にした。(“ネットワークの名前を考えてみた”を参照。127.0.0.0/8のネットワークのドメイン名は“loopback.”とした。)もし厳密にhostsやnetworksを記述すると次のようになる。
/etc/hosts:

127.0.0.1         localhost localhost.loopback
192.168.0.1       pc-server pc-server.localnet

/etc/networks:

127.0.0.1         loopback
192.168.0.0       localnet

また、今回はDNSサーバとしてUbuntu Server 8.04 LTSが動いているマシンを使った。(これはVMwareのホストマシンでもある。)

前準備

1.DHCPサーバのドメイン名の情報を変更する
DHCPを使っている場合はDHCPサーバからクライアントに配る情報の内、DNSサーバのIPアドレスをこれから設定するサーバのアドレスになるように、またドメイン名が“localnet”になるように dhcp.conf を設定し直してDHCPサーバを再起動する。(私の場合、ブロードバンドルータDHCPサーバなので、dhcp.confではなくルータの設定画面から。)なお、DNSサーバとして、プライマリサーバはこれから設定しようとするLAN上のDNSサーバのIPアドレスセカンダリサーバはプロバイダのDNSサーバのIPアドレスを設定しておくといい。もし、おうちDNSサーバがダウンすると、LAN内の全てのマシンが名前解決が出来なくなってしまう。それではマズイので、おうちDNSサーバがダウンした時はプロバイダのDNSサーバへ直接問い合わせるようにする。そうすればLAN内のマシンに関しては名前解決が出来ないが、インターネット上のマシン(例えば、d.hatena.ne.jp等へは問題なくアクセスできる。

2.bindをインストールする
Ubuntu Serverをインストールするときに“利用するサーバ”にDNSサーバを指定していれば、既にbind9というDNSサーバが入っているはずである。もし未実装の場合は、次のコマンドでbind9をインストールする。

% sudo -s
# apt-get install bind9

BINDの設定

LinuxDNSソフトウェアであるbindを設定する。bind9をインストールした状態で/etc/bind/の下には次のようなファイルがある。

# ls /etc/bind
db.0    db.255    db.local  named.conf        named.conf.options  zones.rfc1918
db.127  db.empty  db.root   named.conf.local  rndc.key

この内、named.conf.options と named.conf.local にちょっと変更を加え、db.localnet、db.192.168.0というファイルを新たに作るだけ。

3./etc/bind/named.conf.optionsを変更する
named.conf.optionsの中の以下の部分を、

        // forwarders {
        //      0.0.0.0;
        // };

次のように修正する。

        forwarders {
             123.45.67.89;
             123.45.67.90;
        };

ただし、“123.45.67.89”、“123.45.67.90”は自分が使っているプロバイダのDNSサーバのIPアドレスとする。この例ではプライマリ・サーバとセカンダリ・サーバがある場合である。プロバイダからDNSサーバとして1つだけアドレスが通知されていれば、ここに記述するアドレスは1つでも良い。プロバイダからは明示的にDNSサーバのアドレスは配布されず、DHCPDNSIPアドレスも配布している場合は、プロバイダに直接接続しているルータの情報からDNSサーバのIPアドレスを確認する。

4./etc/bind/named.conf.localを修正する
named.conf.localはコメント行だけであり、実質、空である。そこで、次の内容を追加する。

zone "localnet"  {
        type master;
        file "/etc/bind/db.localnet";
};

zone "0.168.192.in-addr.arpa"  {
        type master;
        file "/etc/bind/db.192.168.0";
};

1つ目のブロックがlocalnetの正引き用ファイル(ホスト名⇒IPアドレス)へのポインタ、2つ目がその逆引き用ファイル(IPアドレス⇒ホスト名)へのポインタである。

5./etc/bind/db.localnetを作る
LANに接続している各マシンのホスト名とIPアドレスの対応表(正引き用)を作る。これが基本的にはhostsファイルと同じ内容となる。ここにLAN(おうちネットワーク)に接続されたマシンの名前とIPアドレスを列挙する。

;
; BIND data file for localnet
;
$TTL    86400
@       IN      SOA     ns.localnet. root.ns.localnet. (
                        2009010401      ; Serial
                        8H              ; Refresh 28800
                        4H              ; Retry 14400
                        3D              ; Expire 259200
                        1D )    ; Negative Cache TTL 86400
        IN      NS      ns.localnet.
        IN      A       192.168.0.1
ns      IN      A       192.168.0.1
pc-server       CNAME   ns.localnet.
localhost       IN      A       127.0.0.1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
firewall        IN      A       192.168.2.254

defaultgateway  IN      A       192.168.0.2

pc11            IN      A       192.168.0.11
pc12            IN      A       192.168.0.12
pc13            IN      A       192.168.0.13
pc14            IN      A       192.168.0.14
pc15            IN      A       192.168.0.15

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; VMware NAT network
vmhost          IN      A       192.168.1.1
vmgateway       IN      A       192.168.1.2
vpc11           IN      A       192.168.1.11

最初のブロックはDNSサーバへの設定や定義である。大体この通り入力すれば動くはずである。ただし“pc-server”はDNSサーバのホスト名に変更すること。

2つ目のブロックと3つ目のブロックはLAN内のマシンのホスト名とIPアドレスのデータベースとなる。使う環境にあわせて作る。(上の例では3つ目のブロックはVMwareの仮想環境内にある仮想マシンIPアドレスである。)

ここでのポイントは192.168.0の“localnet”に属していないマシンのIPアドレスも記述していることである(192.168.2にあるfirewallとか192.168.1VMwareのNAT環境のマシンとか)。クライアントからDNSサーバに通信したいマシンのIPアドレスを問い合わせる時、ホスト名だけでなく自動的に自分のドメイン名を付けて例えば“firewall.localnet”という形で問い合わせる。DNSサーバでそれらのマシンがlocalnetに存在しているとして処理しIPアドレスを返してやれば良い。従って、おうち内のマシンだけでなく、インターネット上のマシンのIPアドレスも自分独自のニックネームを使って同様にここで定義できる。

同様の理由でlocalhostをここでも定義している。DNSサーバへ“localhost.localnet”というドメイン名で問い合わせが来ても127.0.0.1を返答するようになっている。

6./etc/bind/db.192.168.0を作る
逆引き(IPアドレス⇒ホスト名)のデータを用意する。(逆引きの機能を使わないのであれば特に必要はないと思う。)

;
; BIND data file for localnet
;
$TTL    86400
@       IN      SOA     ns.localnet. root.ns.localnet. (
                        2009010401      ; Serial
                        8H              ; Refresh 28800
                        4H              ; Retry 14400
                        3D              ; Expire 259200
                        1D )    ; Negative Cache TTL 86400
        IN      NS      ns.localnet.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
01      IN      PTR     pc-server.
02      IN      PTR     defaultgateway.
11      IN      PTR     pc11.
12      IN      PTR     pc12.
13      IN      PTR     pc13.
14      IN      PTR     pc14.
15      IN      PTR     pc15.

正引き用ではドメイン外のマシンもあたかもドメイン内にあるとしてIPアドレスを返答したが、逆引きではそれは出来ないので、とりあえずlocalnet(192.168.0)にあるマシンの情報だけ記述しておく。

bindの再起動と動作確認

設定が終わったらbindを再起動する。

# /etc/init.d/bind9 restart

次にDNSクライアントソフト(リゾルバ)であるnslookup等で動作確認をするが、その前にDNSクライアントがDHCPクライアントであれば、DHCPサーバからDNSサーバのIPアドレスドメイン名が正しく伝達されているか確認する。DHCPクライアントでなければ、ネットワークのプロパティ(Windows系)や/etc/resolv.conf等(Linux/UNIX系)の設定が正しいか確認する。
DHCPクライアントの場合の確認(Windows系の場合)

C:\Documents and Settings\adsaria>ipconfig /all

Windows IP Configuration

        Host Name . . . . . . . . . . . . : pc11
        Primary Dns Suffix  . . . . . . . :
        Node Type . . . . . . . . . . . . : Unknown
        IP Routing Enabled. . . . . . . . : No
        WINS Proxy Enabled. . . . . . . . : No
        DNS Suffix Search List. . . . . . : localnet


Ethernet adapter ローカル エリア接続:

        Connection-specific DNS Suffix  . : localnet
        Description . . . . . . . . . . . : Intel(R) PRO/100 VE Network Connection
        Physical Address. . . . . . . . . : 01-23-45-67-89-AB
        Dhcp Enabled. . . . . . . . . . . : Yes
        Autoconfiguration Enabled . . . . : Yes
        IP Address. . . . . . . . . . . . : 192.168.0.11
        Subnet Mask . . . . . . . . . . . : 255.255.255.0
        Default Gateway . . . . . . . . . : 192.168.0.2
        DHCP Server . . . . . . . . . . . : 192.168.0.2
        DNS Servers . . . . . . . . . . . : 192.168.0.1
                                            123.45.67.89
        Lease Obtained. . . . . . . . . . : 2009年1月29日 22:56:30
        Lease Expires . . . . . . . . . . : 2009年1月30日 10:56:30

DHCPクライアントの場合の確認(Linux系の場合)

# cat /etc/resolv.conf
domain localnet
nameserver 192.168.0.1
nameserver 123.45.67.89

IP関連の設定を確認できたら、nslookupで名前解決が出来るか試してみる。(nslookupはWindowsでもLinuxでも使える。)

# nslookup
> pc-server
Server:         192.168.0.1
Address:        192.168.0.1#53

pc-server.localnet      canonical name = ns.localnet.
Name:   ns.localnet
Address: 192.168.0.1
>
>
> pc11
Server:         192.168.0.1
Address:        192.168.0.1#53

Name:   pc11.localnet
Address: 192.168.0.1
>
>
> localhost
Server:         192.168.0.1
Address:        192.168.0.1#53

Name:   localhost.localnet
Address: 127.0.0.1
>
>
> firewall
Server:         192.168.0.1
Address:        192.168.0.1#53

Name:   firewall.localnet
Address: 192.168.2.254
>

> www.hatena.ne.jp
Server:         192.168.0.1
Address:        192.168.0.1#53

Non-authoritative answer:
Name:   www.hatena.ne.jp
Address: 59.106.108.86
>

問題がなければ、おうちDNSサーバの出来上がり。後はマシンの追加・削除の時にdb.localnetとdb.192.168.0を変更しbind9を再起動すれ、全てのマシンで最新のデータが使える。

loopbackゾーンの設定

以上の設定だけで通常は問題なく使えるはずだ。しかし、更に完璧な設定にするのであればloopbackドメインの設定をしておく。
今回、127.0.0.0/8のアドレスには“loopback”という名前をつけた。従って127.0.0.1のマシンの正式名はlocalhost.loopbackとなる。DNSクライアントへ単に“localhost”と指定するとDNSサーバへは“localhost.localnet”として問い合わせをすることになる。しかし、ソフトウェアによっては“localhost.loopback”という正式名で問い合わせるものもあるかも知れない。その時に上記の設定だけで不十分となる。

# nslookup
> localhost.loopback
Server:         192.168.0.1
Address:        192.168.0.1#53

** server can't find localhost.loopback: NXDOMAIN
>

そこで次の4行をnamed.conf.localに追加し、

zone "loopback" {
        type master;
        file "/etc/bind/db.loopback";
};

次の内容のdb.loopbackというファイルを作成する。

;
; BIND data file for local loopback interface
;
$TTL    604800
@       IN      SOA     loopback. root.loopback. (
                              2         ; Serial
                         604800         ; Refresh
                          86400         ; Retry
                        2419200         ; Expire
                         604800 )       ; Negative Cache TTL
;
@       IN      NS      loopback.
@       IN      A       127.0.0.1
@       IN      AAAA    ::1
localhost       IN      A       127.0.0.1

これでbind9を再起動してnslookupで確認すると、今度はlocahost.loopbackでも名前解決できることが確認される。

# nslookup
> localhost.loopback
Server:         192.168.0.1
Address:        192.168.0.1#53

Name:   localhost.loopback
Address: 127.0.0.1
>

セキュリティに関して

今回のDNSサーバはNAT内で外部のネットワークからはアクセスされないという仮定でセキュリティに関しての設定は省いている。しかしDNSはセキュリティ上、もっとも脆弱な部分でもあるので、セキュリティを確保する設定も追加すべきであろう。
named.conf.optionsに次のようなオプションを追加する。

options {
		:
		:
		:
	allow-query {
		127.0.0.0/8;
		192.168.0.0/24;
		192.168.1.0/24;
	};

};

allow-queryはこのDNSサーバに対する問合せをDNSサーバ自身とLAN内のマシンからに限定する。

更にnamed.conf.localに次のような追加するなど。(本来はnamed.confに設定すべきだが、修正点をnamed.conf.localに集約した方が管理がやり易いと思う。)

include "/etc/bind/rndc.key";
controls {
        inet    127.0.0.1
        allow   { 127.0.0.1; }
        keys    { rndc-key; };
};

rndcというネットワークを経由してDNSサーバを制御するソフトがあるが、上記のcontrolsの例はリモートではなく自身のマシンからしか操作できないようにしている。

また、今回はプロバイダのDNSへforwardする設定になっているが、信頼できるプロバイダのDNSサーバ(というか信頼できるプロバイダ)を使おう。プロバイダのDNSサーバの管理がズサンだと“DNSキャッシュ・ポイゾニング”で偽サイトへ誘導されてしまう。

hostsファイルを削る!

セキュリティに関連して、また運用管理上のトラブルを避けるためにhostsファイル(Linux/UNIX系であれば /etc/hosts、Windows系であれば C:\WINDOWS\system32\drivers\etc\hosts の内容を必要最小限にする。特にDHCPクライアントでは例えば次の様に。

127.0.0.1       localhost

::1     ip6-localhost ip6-loopback

IPv6を使わないのであれば3行目は必要ない。)
DNSを使えるようにしてもhostsファイルがあるとそちらを優先して使うため。hostsの内容とDNSの情報が同じであれば良いが、違うと、幾らDNSを直しても古いhostsの内容を使ってしまう。

参考リンク

named.conf の設定 : bindの設定ファイルで使う項目が良くまとめられている。