社内や家庭内でローカルな名前解決をする際、(local.などのサブドメインをつけず)インターネット上に公開しているドメインと同じドメインを使いたいと思うことはないでしょうか。筆者はあります。とはいえ、インターネット上にある権威サーバーに、ローカルIPアドレスを返すレコードを登録するわけにもいきませんよね。そんな時はどうしたらよいでしょう?
ある一つのドメインの中で、ローカルな名前はローカル内だけで解決し、かつインターネット上に公開している名前は本来の権威サーバーにクエリーを投げて解決する、ということができればよさそうです。これが実現できると、グローバルIPとローカルIPを両方持つようなサーバー[1]は、家庭内で名前解決をした時のみはローカルIPを返す、というようなこともできそうです。
キャッシュリゾルバであるUnboundにはlocal-data(およびlocal-zoneのtransparent)という機能があり、この要求を実現することができます[2]。今回はUbuntu 14.04 LTSとUnboundを用いて、ご家庭内キャッシュサーバーを構築してみましょう。
Unboundのインストール
UnboundはUbuntu[3]のリポジトリにパッケージがありますので、apt-getでインストール簡単にインストールできます。パッケージ名はunboundです。
これだけで自動的にUnboundが動作します。ローカルホストの53番ポートをunboundがLISTENしているのを確認してみましょう[4]。
resolvconfとの連携
Ubuntuではresolvconfによって/etc/resolv.confが自動生成されます。そのためresolv.confを直接書き換えることはせず、使用するネームサーバーは/etc/network/interfaces内のdns-nameserversで指定する必要があるのは皆さんご存知の通りです。UbuntuのUnboundはresolvconfと連携し、Unbound(自分自身)で名前解決をするよう、サービスの起動時に/etc/resolv.confを書き換えます。また元々resolv.conf内で指定されていたnameserverを、Unboundのforwardに追加します。その仕組みを少し詳しく見てみましょう。
/etc/default/unboundを見てみてください。その中に以下の記述があります。
ここでRESOLVCONFとRESOLVCONF_FORWARDERSという2つの変数を設定しています。用途はコメントにある通りで、RESOLVCONFがtrueに設定されていると、/etc/resolv.confにUnboundが待ち受けているIPアドレスが設定されるようになります。またRESOLVCONF_FORWARDERSがtrueに設定されていると、元々dns-nameserversに指定されていたネームサーバーが、Unboundのforwardに追加されるようになります。これらはどちらもデフォルトでtrueに設定されているため、Unboundをインストールしただけで、サーバーは名前解決の際に自分自身のUnboundにクエリーを投げ、Unboundは元々設定されていたネームサーバーに再帰的にクエリーを投げる、という動作をします。つまりUbuntuデスクトップのDnsmasqと同じ挙動ですね。
resolv.confを書き換える処理は、/etc/init.d/unboundの中の
が行っています。この直前の条件分岐を見るとわかりますが、interfaceには0.0.0.0もしくは127.0.0.1が指定されていること[5]、もしくはinterfaceが明示的に指定されていないことを期待しています。(192.168.1.1のような)任意のIPアドレスが指定されていると、resolv.confが空になってしまうため注意してください。forwardの追加は/etc/resolvconf/update.d/unbound内で行われています。unbound-controlコマンド(後述)を利用して、forwardの追加もしくはoffを行っていることがわかります。
Unboundの設定
このように、Unboundはインストールしただけで、ローカルなキャッシュリゾルバとして動作します。これを家庭内LAN全体から使えるように、またローカルな名前解決のためのレコードを持てるように、いくつかの設定を行いましょう。Unboundの設定ファイルは/etc/unbound/unbound.confです。中身は以下のように、include文が一行書かれているだけです。
このことからもわかるように、設定ファイルは/etc/unbound/unbound.conf.d/*.confに分割して置くほうが管理しやすいでしょう。サーバーの基本的な設定は、以下の内容を/etc/unbound/unbound.conf.d/server.confに書くことにしました。0.0.0.0で待ち受け、ローカルホストと家庭内LANからはアクセスを許可するという意味です。
家庭内サーバーのDNSレコードも、メンテナンスしやすいように別ファイルにまとめましょう。/etc/unbound/unbound.conf.d/local-data.confというファイルを作成し、local-dataを列挙することにしました。local-dataに記述された名前に対するクエリーには、その結果をUnboundが返します。local-dataにない名前、たとえばこの例であれば「www.example.com」へのクエリーは、上位のDNSサーバーへ再帰問い合わせを行います。この挙動(local-dataにない名前は再帰問い合わせを行う=transparent)がUnboundのデフォルトですが、これを変更し、local-dataにない名前には即時NXDOMAINを返したり、エラーを返すことも可能です。詳しくはunbound.confのmanにあるlocal-zoneを参照してください。
/usr/share/doc/unbound/examples/unbound.confにコメントつきの完全な設定ファイルのサンプルが用意されているので、こちらをベースに設定ファイルを作成するのもよいでしょう。unbound.confの設定内容はこちらも参考になります。設定が完了したら、Unboundを再起動してください。
LAN内の別のPCから、digで名前解決ができるか試してみましょう。
ログの設定
サービスのログは設定の確認やトラブル時の問題解決に役立つのはもちろんのこと、DNSのクエリーログはセキュリティ的にも大きな意味を持ちます。ですので、可能であればログを出力する設定をしておきましょう。server.confのserver:ディレクティブに以下の内容を追記してください。ログの出力にはsyslogを利用し、またクエリーログを出力するということを意味します。
Unboundがsyslogに出力するログファシリティはdaemonです。Ubuntuのデフォルト設定では、daemon.*ログは個別のログファイルに書かれず/var/log/syslogにだけ書かれてしまいます。そこで/etc/rsyslog.d/50-default.confの以下の行のコメントアウトを解除して、rsyslogを再起動してください。/var/log/daemon.logにログが出力されるようになります。なお、Unboundのログの識別子はunboundです。
クエリーログはかなりの量になることが予想されるうえ、ある程度の期間保存しておきたいため、ログローテーションの設定を変更します。/etc/logrotate.d/rsyslogを見てみましょう。/var/log/daemon.logは、mail.logやauth.logと同様に、週次4世代ローテーションに設定されています。
上記の部分から/var/log/daemon.logの1行を削除したうえで、ファイルの末尾に以下を追加してください。日次で180世代ローテーション、つまり半年分のクエリーログを保存する設定です。もちろん世代数は、ログのサイズやディスクの容量と相談して決めてください。
unbound-controlを使う
unbound-controlは、Unboundをリモートから制御するためのCLIツールです。unbound-controlは設定をオンラインで変更できるため[6]「新しいサーバーを立てたのでlocal-dataを追加したい」というような場合も、いちいちUnboundを再起動しなくていいのです。
unbound-controlとUnboundが通信するためには、サーバー、クライアント双方にそれぞれ鍵ペアが必要になります。これを生成してくれるのがunbound-control-setupというシェルスクリプトなのですが、Ubuntuの場合、unboundパッケージのインストール後の処理で自動的に実行されるため、手動で行う必要はありません。/etc/unbound以下にunbound_control.key、unbound_control.pem、unbound_server.key、unbound_server.pemの4つのファイルがあるはずです。便利ですね。
次にリモートコントロールを有効にするため、/etc/unbound/unbound.conf.d/remote-control.confというファイルを作成し、以下の内容を記述してください。remote-control:ディレクティブでは、リモートコントロールの有効化とコントロールインターフェース、サーバー、クライアントそれぞれの鍵ファイルを指定しています。
……と言いはしたものの、実はUbuntuに限っては、この設定ファイルは作成しなくても動作します。その理由は以下の通りです。
unbound-controlからUnboundを操作するためには、設定のcontrol-enableを「yes」に設定しなくてはなりません。この値はデフォルトで「no」がセットされているため、設定ファイルにcontrol-enableの設定を明示的に書かない限り、unbound-controlは使えないはずです。しかしresolvconfの節で説明した通り、UbuntuではUnboundの起動時に、unbound-controlを使ってforwardを設定しなければならないという事情があります。そこで明示的な設定がなくてもこの機能が有効になるよう、パッケージ内でソースコードにパッチを当てているのです[7]。control-interfaceや各鍵ファイルは上記の設定値がデフォルト値そのままのため、この設定ファイルは(Ubuntuにおいては)不要、というわけです。
長々と説明しましたが、つまりUbuntuでは何もしなくてもunbound-controlコマンドが使えるということです。至れり尽くせりですね!
unbound-controlには様々なサブコマンドが用意されています。たとえばlocal-dataを追加するにはlocal_dataサブコマンドを利用します。詳しくはunbound-controlのmanを参照してください。
Muninでのモニタリング
Unboundには、MuninやCactiでクエリーの統計を取るためのプラグインが用意されています。せっかくですのでUnboundサーバーにMuninクライアントとプラグインをインストールして、Unboundを「見える化」してみましょう。 今回はApacheとMuninサーバーもUnboundと同じサーバー上に構築しました。Muninサーバー自体の構築方法は第359回を参照してください。
まずUnbound側の設定です。/etc/unbound/unbound.conf.d/statistics.confというファイルを作成し、統計のための設定を追加します。設定が完了したら、Unboundを一度再起動しておいてください。
次にUnboundのソース[8]を取得、展開してください。contribディレクトリの中にunbound_munin_というMuninプラグインがありますので、これを/usr/local/share以下にディレクトリを作成してコピーします。このプラグインはワイルドカードプラグインなので、名前を変えて複数のシンボリックリンクを/etc/munin/plugins以下に張ることで、それぞれ異なったグラフを生成することができます。
Muninプラグイン動作するために必要な設定を、/etc/munin/plugin-conf.d/munin-nodeの末尾に追記してください。具体的には以下のように、プラグインが使うテンポラリファイル、unbound.conf、unbound-controlのパスを記述します。
シンボリックリンクを張ってプラグインを有効にします。munin-nodeを再起動した後は、munin-runでプラグインの動作を確認しておきましょう。
5分ほど待てば、グラフが生成されます。
さいごに
家庭内でちょっとだけ名前解決したいんだけど、hostsをメンテするのは大変だし、BINDはサブドメインのゾーンを作らないといけないし、というような場合には、Unboundをご家庭キャッシュサーバーにすると便利かもしれませんね!