シンプルなdjbdnsで作るDNSサーバー

以下のテキストは、執筆時当時の情報を元に書いたものであり、 現在の情勢にそぐわないことを含む場合があるので注意されたい。 また、テキストは最終提出原稿で校正を経る前のものなので、実際にUNIXUSER 本誌に記載されたものとは異なる。誤字脱字等そのままである。

致命的な誤り以外は加筆修正等は行なわないので情報の鮮度に気をつけつつ 利用して欲しい。

目次


【Part 3 djbdns】



■
■djbdns
■


●なぜdjbdnsか

ネームサーバとして利用されている実装で、圧倒的シェアを誇るのが
BIND(http://www.isc.org/products/BIND/)である。sendmail以上に「業界標準」
のイメージが高いBINDを使わず、djbdnsを選択するメリットはあるのだろうか。
DNSは、他の全てのサービスが依存している根幹となるサービスである。名前の
引けない所にメイルは送れないし、Webサーバも置けない。それほど重要な意味
を持つサービスを、これまで使用していたもの(たいていBINDだろう)からdjbdns 
に乗り換えることは相当の覚悟が必要と感じるのではないだろうか。しかし、大
事なサービスであればこそDJBツールに任せる意義があると感じている。

はじめに、djbdnsを利用する意味について説明したい。なお、以下で述べること
は筆者の個人的主観に基づくものである点をご了承頂きたい。

  ・安全性

  プログラムにバグは付き物である。人間は全知全能の神ではないのだから、作っ
  たものに間違いがあることはいたしかたない部分がある。最初から間違いがな
  いよう慎重にプログラムすることも大切だが、それ以上に大切なのは不具合を
  見付けたらすぐに対応することだろう。「オープンソース」なプログラムでは
  これまでそれがうまく機能してきた。BINDに目をむけよう。筆者がBINDを利用
  してネームサーバの管理をしていた範囲では3度の大きなセキュリティ勧告が
  あり、ほうぼうのnamedを入れ換えた記憶がある【註 い】。
---[註 い]------------------------------------------------------------
CA-2000-20, CA-1999-14, CA-1998-05 だと記憶している。
----------------------------------------------------------------------

  セキュリティホールというとクラッカーとプログラマのいたちごっこというイ
  メージでとても難しいレベルのプログラミングの問題という印象があるが、実
  際のところBINDに見つかったセキュリティホールのほとんどはバッファオーバー
  ランの危険性に起因するものである。詳しくは本誌2002年4月号 Part2 を見て
  頂きたいが、プログラムにバッファオーバーランの可能性があるかどうかはプ
  ログラマがそういう可能性を知ってプログラミングしているかどうかだけの非
  常に平易な問題である。にもかかわらず、この種のミスが多数見つかるという
  のは、

	・プログラムの設計がよほど古い(古き良き時代の)ものである
	・該当部分を書いたプログラマの受けた教育が不十分

  のいずれかと言えないだろうか。念のため強調しておきたいが、フリーソフト
  ウェアであるからもともと「無保証」で使うのが利用者の重要な心得である。
  すぐに修正版を出してもらえるなら実質的に商用ソフトウェアより安心して使
  えるだろう。問題なのは、「バッファオーバーラン」という(現代では)初歩的
  なミスが含まれていたものを今後も信頼し続けていく価値があるかどうかとい
  う点である。永年BINDにお世話になったので書きづらいが、筆者個人は、もう
  これ以上信頼できないと感じてdjbdnsを選んだ。

  ・使い勝手

  人間は「慣れる」動物なので、使い勝手というものは使い続けるうちにどんど
  ん向上していく。たとえば、現在BINDを利用している人が突然djbdnsを使い始
  めたら、やはり最初は使いづらいと感じるだろう。既にBINDの設定ファイルや
  ゾーンファイルは用意されていることが多いので、そのうち一部を修正するだ
  けならとても簡単だ。named.confがCに似た構文で人間が読んで分かりやすい
  のもありがたい。しかし。

  これまた筆者個人の経験談だが、最初にnamedの設定ファイルを見たときは(勉
  強不足で)さっぱり分からなかった。新米管理者だった時代に漠然と感じてい
  たことを思い出すと、

	* 「なんで逆引きは別ファイルに登録するんだろう。二度手間だなあ」
	* 「各種設定ファイルで丸括弧()だったり中括
	    弧{}だったり、セミコロンがあったり無かったり、どう違うんだ?」
	* 「スペルミスしたらnamedがエラー終了していた…怒られちゃった」
	* 「こら、ちゃんとホストをDNS登録しておけって言っただろう」
	  「え、先輩、しましたよ…」
	  「どらどら。ふーむ、シリアルナンバーを更新してないじゃないか!」
	  「す、すみません」

  などという、ちゃんと考えれば分かるだろうという、今思えば恥ずかしい疑問
  を感じたり失敗をくり返していた。ただ、もしそうした初心者的疑問が生じな
  いものがあったとしたらどうだろう。つまずきが少なくなるのではないだろう
  か。djbdnsはそのひとつであると考える。

●djbdnsの特徴

djbdnsはなんといっても、そのシンプルな構造が大きなアドバンテージとなって
いる。第一に、権限を持つゾーンのネームサーバとしての機能(tinydns)と、ク
ライアントからの名前解決依頼を受けて外部ネームサーバに問い合わせた結果を
返すキャッシュサーバの機能がプログラムとしても分離していること
が挙げられる。BINDでは両方ともnamedプログラムひとつで受け持つので、原理
を理解して意識して使わない限りそれらの差は実感せずに済んでしまうかもしれ
ないが、djbdnsはそれぞれが別プログラムになっているため、ちゃんと役割を考
えて設定することになる。

権限を持つゾーンのネームサーバとなる tinydns プログラムは、非常にシンプ
ルなゾーンファイルで管理できるのがたいへんありがたい。基本的に順引きレコー
ドを登録するだけで逆引きレコードも自動的に生成してくれる。具体例を示すと、
tinydnsのゾーンファイル中

	=www.ymzk.org:210.254.106.28:

のようなイコール記号(=)で始まる行はホスト名からIPアドレス(Aレコード)のエ
ントリと、IPアドレスからホスト名(PTRレコード)の両方を同時に生成してくれ
る。書式が単純なのでテキストエディタを使って管理することも容易だし、慣れ
ないうちはtinydnsの解釈できるゾーンレコードを自動的に足してくれるコマン
ド(add-* コマンド群)を利用することも可能である。この場合、新しいゾーンのネー
ムサーバを構築したければ、

	# ./add-ns newdomain.example.net 10.9.8.7
	# ./add-ns 8.9.10.in-addr.arpa 10.9.8.7
	# make

などとするだけで必要なゾーンファイルを作成してくれるので、「SOAレコードっ
てどうやって書くんだっけ?」といったことを思い出す必要が無いのは非常に心
強い。ちなみに上記のコマンドで生成されるエントリは

	.newdomain.example.net:10.9.8.7:a:259200
	.8.9.10.in-addr.arpa:10.9.8.7:a:259200

という短いものなので、もしコマンドに頼らず自ら明示的に作成したいと思う場
合でも困難は無かろう。これらの書式の詳細については後述する。

●djbdnsの導入

djbdnsを使ったネームサーバ/キャッシュサーバの運用は、二段階の手順を踏む
ことになる。一つはプログラム群のインストールで、もうひとつはサービスを受
け付けたいIPアドレスにたいするプログラムの割り当て作業である。djbdnsの導入に
はdaemontoolsの利用が前提となっている。daemontoolsを使わなくともdjbdnsを
利用することは可能だが、その場合ログを効果的に取ろうとするだけでもUNIX 
に関する広く深い知識が要求される、あれこれ悩むよりもdaemontoolsを利用す
るのが良いだろう。本特集ではPart2にてdaemontoolsのインストールが完了して
いるのでこれを前提としてdjbdnsインストールを行なう手順を解説する。


・djbdnsプログラムのインストール

  本稿執筆時のdjbdnsの最新版は djbdns 1.05 で、
  http://cr.yp.to/djbdns/djbdns-1.05.tar.gz から入手するか、付録CDROMか
  らコピーする。作業ディレクトリにソースアーカイブを置いたら以下の手順で
  インストールする。

	# gzip -dc djbdns-1.05.tar.gz | tar vxpf -
	# cd djbdns-1.05
	# make
	# make setup check

  以上でdjbdnsのプログラム群が /usr/local/bin にインストールされる。もし、
  インストール先を変更したい場合は make する前に、ソースディレクトリにあ
  る conf-home ファイルを修正すれば良いだろう。

  以下の説明ではdjbdnsの各プログラムが /usr/local/bin にインストールされ、
  作業時にそのディレクトリがPATH変数に登録されているものと仮定する。


・キャッシュサーバの導入

djbdnsでは、キャッシュサーバの設定によってふたつの起動形態を使いわけるこ
とになっている。

ひとつは「ローカルキャッシュ」で、これは図1のようにひとつのホストが名前
解決を行なうときに外部のネームサーバに問い合わせた結果を保持しておいて、
次回同じ問い合わせが来たときにそれを利用して効率化をはかるものである。こ
れは、一台のマシンだけが単体でDNSの問い合わせを必要とする場合に利用する。
ローカルキャッシュが最も有効に機能する例のひとつとしては、携帯可能なUNIX 
マシンを利用している場合が挙げられる。出先で、メイルやWebを利用するとき
に、遅いダイヤルアップ回線の先のネームサーバを参照するのではなく、ローカ
ルにキャッシュしてあるレコードを参照するとかなり快適になるだろう。

もうひとつは「外部キャッシュ」で、図2のようにキャッシュしてある名前を別
のマシンでも参照できるものである。
図1 ローカルキャッシュ----------------------+
|     Computer
|   +-----------+
|   |           |
|   |           |  (www.example.net という
|   |           |   名前の問い合わせが
|   +-+-------+-+   自己ループしている絵)
|     |↑  ↓   |
|  /~~~↑~~↓~~~~\
|   www.example.net
+-------------------------------------------+
図2 外部キャッシュ--------------------------+
|  キャッシュサーバ
|   +-----------+
|   |           |
|   |           |  (名前の問い合わせを
|   |           |   別ホストにさせている絵)
|   +-+-------+-+   +---+ +---+ +---+ +---+ 
|     |       |     |   | |   | |   | |   | 
|  /~~~~~~~~~~~~~\  +---+ +---+ +---+ +---+ 
|                   [...] [...] [...] [...] 
+-------------------------------------------+

この設定では、同一LANのコンピュータの、名前解決用ネームサーバとして利用
することができる。もちろんクライアント機はUNIXでなくても構わないし、参照
許可さえ出せば同一LANのものでなくても構わない。多くのオフィスでは自前の
ドメインを持つわけではなく、ネームサーバを単に外部ホストの名前解決のため
だけに利用していることから、「外部キャッシュ」がもっとも良く利用される形
態となるだろう。

・ローカルキャッシュの設定

単一マシンで外部DNS参照を行なう際に有効なローカルキャッシュを作成してみ
よう。次項で説明する「外部キャッシュ」もローカルキャッシュとほぼ同様の手
順になるので、外部キャッシュだけを導入したい場合でもまずはここにあること
がらを理解する必要がある。

ローカルキャッシュ設定前にサーバプログラムを動かすためのユーザと、ログを
取得するためのユーザを作成する必要がある。もともと信頼性の高いdjbdnsだが、
root以外のユーザで動かすことでよりいっそう安心できる。作成するアカウント
名は何でもよいが、http://cr.yp.to/djb.html にある設定例に従いここでは前
者のアカウント名を dnscache, 後者のものを dnslog とする。また、各アカウ
ントはどんなグループでも構わないが、分かりやすくするため両者を `dns' と
いうグループに入れることにしておく。

---[Solaris, NetBSD, OpenBSD, 各種Linuxの場合]------------------
	# groupadd dns
	# useradd -g dns -d /var/dns/dnscache dnscache
	# useradd -g dns -d /var/dns dnslog
---[FreeBSDの場合]------------------
	# pw groupadd dns
	# pw useradd dnscache -d /var/dns/dnscache -g dns
	# pw useradd dnslog -d /var/dns -g dns


これで、作成準備が整った。dnscache-conf プログラムでキャッシュサーバの動
作環境をセットアップする。dnscache-conf は

	# dnscache-conf キャッシュアカウント \
		ログ採取アカウント ディレクトリ [IPアドレス]

のように起動することで、指定した「ディレクトリ」にキャッシュサーバの環境
を構築してくれる。ここでは、上記で作成した二つのアカウントを利用し

	# dnscache-conf dnscache dnslog /var/dnscache

のように起動してみよう。最後の引数の /var/dnscache はキャッシュサーバの
動作環境を保持するディレクトリで、ここにchrootして動作することになる。も
ちろん読者の利用環境に応じて任意のディレクトリを指定して構わないが、このディ
レクトリの下にはログが出力されるので容量的にゆとりのあるパーティションに
配置する。もっとも、daemontools が自動的に古いログの破棄操作をしてくれる
ので(デフォルトは合計約1MB)それほど巨大なパーティションでなくても問題は
無いだろう。以後 /var/dnscache にセットアップしたものと仮定する。

上記のコマンドラインを実行したら、/var/dnscache ディレクトリとその中にあ
る run スクリプトを見てみよう。

--------------------------------------------------
# cd /var/dnscache
# ls -lF
total 5
drwxr-sr-x  2 root  wheel  512 Apr 24 13:42 env/
drwxr-sr-x  3 root  wheel  512 Apr 24 13:42 log/
drwxr-sr-x  4 root  wheel  512 Apr 24 13:42 root/
-rwxr-xr-x  1 root  wheel  148 Apr 24 13:42 run*
-rw-------  1 root  wheel  128 Apr 24 13:42 seed
# cat run
#!/bin/sh
exec 2>&1
exec <seed
exec envdir ./env sh -c '
  exec envuidgid dnscache softlimit -o250 -d "$DATALIMIT" /usr/local/bin/dnscache
'
--------------------------------------------------

djbdnsでは、各セットアップコマンドを利用するとdaemontoolsで管理するため
のrunスクリプトを自動生成してくれる。上記の例ではrunスクリプト中で、
daemontools 付属のコマンド envdir, envuidgid, softlimit を呼んでいるので、
runスクリプトが走るときに daemontools のコマンド群が含まれるディレクトリ
が$PATHに含まれることを再確認すること。

今作成した /var/dnscache ディレクトリは、daemontools の「サービスディレ
クトリ」としてふさわしい形式になっているので、ここを /service ディレクト
リ内のシンボリックリンクとしてsvscanに検知させよう。

  # ln -s /var/dnscache /service

5秒以内にdnscacheが起動するだろう。早速localhostをネームサーバとして動作
試験を行ってみよう。/etc/resolv.conf の nameserver の指定を書き換える。

--[/etc/resolv.conf]-----------------------------------------------
nameserver	127.0.0.1
-------------------------------------------------------------------

実際にWebブラウザなどを利用して任意のホスト名が引けるか確認してみる。
クライアントからの名前解決のリクエストがあると同時にキャッシュサーバの
/var/dnscache/log/main/current にログが書き込まれる。このログを観察する
ときは

	# tail -f /var/dnscache/log/main/current | tai64nlocal

などのように、tai64nlocal に渡し時刻を可読形式に変換すると読みやすい。

・外部キャッシュの設定

自ホスト以外のマシンからも利用できる外部キャッシュもローカルキャッシュと
ほぼ同じ手順で構築できる。dnscache-conf コマンドに、別のマシンから参照さ
せたいIPアドレスを与えて起動する。

	# dnscache-conf dnscache dnslog /var/dnscachex 10.9.8.7

これにより /var/dnscachex ディレクトリに必要なファイルがインストールされ
る。これも

  # ln -s /var/dnscachex /service

とすることでsvscanが5秒以内に検知して外部キャッシュサーバが立ち上がる。
ただし、このままではクライアントに対し名前解決の参照許可を与えていない状
態である。許可するホストのIPアドレスをファイル名とする空ファイルを 
/var/dnscachex/root/ip ディレクトリに作成する。たとえば

  # touch /var/dnscachex/root/ip/10.0.1.24

とすると IP アドレスが 10.0.1.24 であるホストからのDNS参照を許可し、

  # touch /var/dnscachex/root/ip/10.0.2

とすると、10.0.2.x (xは任意)のIPアドレスを持つホスト全てからのDNS参照を
許可することができる。これらのファイルはtouchした瞬間に許可が与えられ、
動作中のデーモンにシグナルを送ったりするなどの必要は無い。


・特定ドメインのネームサーバの明示的指定

dnscacheでは未知の名前の問い合わせがあった場合、デフォルトではルートサー
バに再問い合わせを行なう。しかしたとえば、自社のホスト名であれば自社のネー
ムサーバに直接問い合わせた方が効率が良いといったことが考えられるので、特
定のドメインに属する名前の問い合わせを指定したネームサーバに直接行なうよ
うに指示することができる。この指定は dnscache サービスディレクトリの中の 
"root/servers/<ドメイン名>" というファイルで行なう。もし、自社のドメイン
がexample.co.jp(10.1.0.0/16) で、そのネームサーバが 10.1.1.1 だとしたら
以下のようにする。

  # echo 10.1.1.1 > /var/dnscachex/root/servers/example.co.jp	   (順引き用)
  # echo 10.1.1.1 > /var/dnscachex/root/servers/1.10.in-addr.arpa  (逆引き用)

・キャッシュサーバのパラメータ設定

dnscache-conf で生成されるサービスディレクトリ内のファイルやディレクトリ
について簡単に説明しておこう。

  * envディレクトリ

  プログラム起動時に与える環境変数とその値を持つファイルを格納する。ここ
  に置くファイルで実際にプログラムに動作パラメータを渡すことになる。各コ
  マンドを特殊なディレクトリにインストールしている場合などはPATH変数の設
  定に "env/PATH" ファイルを利用すると効率的かもしれない。

  * logディレクトリ

  プログラムの出力するログを受け取るディレクトリ。このディレクトリも
  supervise が管理するので run スクリプトなどが含まれる。

  * superviseディレクトリ

  superviseがデーモンプロセスを監視する作業ディレクトリ。

  * runスクリプト

  実際にデーモンプロセスを動かすためのスクリプト。デーモンプログラムを呼
  ぶときに、envdirプログラムを経由させて、起動に必要な環境変数を渡してい
  る。

このうち、envディレクトリにあるファイルでキャッシュ用のパラメータを調整
することができる。変更できるパラメータは以下の通り。

  * env/CACHESIZE
  キャッシュするデータのバイトサイズを指定する。デフォルトは1000000。

  * env/DATALIMIT
  プロセス起動時のリソース datasize のリミット値を設定する。この値は
  softlimit コマンドに渡される。デフォルトは3000000で、もちろん
  env/CACHESIZEで指定したものより大きくなければ無意味である。

  * env/IP
  dnscacheがlistenするIPアドレスを設定する。キャッシュサーバのIPアドレス
  が変わった場合などはこのファイルを書き換えるだけで良い。

  * env/IPSEND
  パケット送出アドレスを指定。通常は0.0.0.0を指定。

  * env/ROOT
  キャッシュをコントロールするディレクトリを指定。

メモリに余裕があればキャッシュサイズは大きいほど効果的であるが、dnscache 
ではどんなレコードも(TTLにかかわらず)最長で一週間しか保存しない。
CACHESIZEを大きくする場合は利用状況を見てレコード寿命が平均で一週間を超
過しない範囲にとどめるように留意すると良い。平均寿命を知るにはログファイ
ル(log/main/current)の中の stats 行を参考にする。まず、ある時点での 
stats 行を見て、メモを取っておく。

 # grep -w stats /var/dnscachex/log/main/current \
     | tai64nlocal | tail -1

次に、およそ24時間後にもう一度 stats 行を見る。二つのstats行が以下の通り
だったとしよう。

   2002-04-24 14:03:53.744378500 stats 79081 105360 3 0
                                             ~~~~~~
   2002-04-25 14:15:34.542646500 stats 7153 326252 1 0
                                            ~~~~~~

statsに続く数字のうち2番目のものがキャッシュのデータ移動量に当たる。この
場合 326252-105360=220892 がこのキャッシュサーバでの一日のデータ移動量と
なる。したがって、一週間程度のレコード寿命を確保するにはこの値を7倍、余
裕を見て10倍程度にした2000000バイト程度のCACHESIZEがあれば十分ということ
になる。DATALIMITもこれに合わせて大きく取り直す必要があるので、

  # echo 2000000 > /var/dnscachex/env/CACHESIZE
  # echo 2097152 > /var/dnscachex/env/DATALIMIT
  # svc -t /service/dnscachex

のようにする。


●権限を持つゾーンのネームサーバの構築

権限を持つゾーンのネームサーバ(以下、単に「ネームサーバ」)はtinydnsによっ
て運用する。"tiny" なのはプログラムのバイトサイズだけで、大規模なドメイ
ンの管理を高速にこなせる "great" なプログラムである。

以下、ネームサーバ構築手順については、キャッシュサーバのときと同様 Part2
で解説した daemontools のインストールが完了しているものとみなすので注意
して欲しい。

・tinydnsによるネームサーバの設定

キャッシュサーバのときと同様、tinysdnsが動作するためのアカウントを作成し
よう。ここでは、ユーザ名として tinydns を作成する。

---[Solaris, NetBSD, OpenBSD, 各種Linuxの場合]------------------
	# groupadd dns
	# useradd -g dns -d /var/dns dnslog
	(↑以上キャッシュサーバ構築時に行なった場合は不要)
	# useradd -g dns -d /var/dns/tinydns tinydns
---[FreeBSDの場合]------------------
	# pw groupadd dns
	# pw useradd dnslog -d /var/dns -g dns 
	(↑以上キャッシュサーバ構築時に行なった場合は不要)
	# pw useradd tinydns -d /var/dns/tinydns -g dns

つづいてネームサーバのサービスディレクトリ生成を tinydns-conf コマンドで行う。

	# tinydns-conf tinydns dnslog /var/tinydns 172.16.1.53

この例では /var/tinydns ディレクトリに 172.16.1.53 というアドレスで公開
するネームサーバ環境を作成している。もし、公開したいドメイン名がLAN専用
のプライベートなものなら、プライベートIPアドレスを指定し、外部に公開する
ドメインであればグローバルIPアドレスを指定することになるだろう。

上記のコマンド起動により /var/tinydns/root にホスト情報を登録するために
必要なファイルがインストールされる。このディレクトリに作成されるdataとい
うファイルがゾーンファイルに該当する。BINDでいうところの named.conf のよ
うな設定ファイルは存在しない。たとえば、named.conf では、ネームサーバと
なるべきゾーンを記述する必要があるが、tinydnsの場合は対応するエントリを
dataファイルに書き込むだけで良い。

この "data" ファイルは人間が編集できる形式になっているが、同ディレクトリ
に用意されている専用コマンドを利用すると簡単にホストレコードの登録が行え
る。以下各コマンドとその役割とともに、実際にdataファイルに書き込まれるレ
コード行の書式に関して説明する。レコード行の書式の説明中に現れる
<timestamp>:<lo> という項目については後半で説明する。

  【add-ns】
  ドメインに対するネームサーバを追加する。
  
    ./add-ns <fqdn> <ip>
  
  と起動すると、ドメイン名 <fqdn> に対するAレコード、NSレコード、SOAを生
  成するエントリを追加する。実際にdataファイルに追加されるエントリは
  
  	.<fqdn>:<ip>:a:259200
  
  となる。dataファイルのピリオドで始まるエントリはネームサーバを表す。正式
  な書式は
  
  	.<fqdn>:<ip>:<x>:<ttl>:<timestamp>:<lo>
  
  で、<fqdn>ドメインのNSレコードとして <x>.<fqdn> を宣言する。ただし <x> 
  自身にピリオドが含まれる場合は <x> そのものをネームサーバ名とする。その
  ホストのAレコードが <ip> となる。また、ドメインのコンタクトアドレスと
  して、
	hostmaster@<fqdn>

  というメイルアドレスが自動的に設定される。これは良く覚えておく必要があ
  り、RFC2142 で推奨されているネームサーバ管理者に届くべきメイルボックス
  名なのでメイルサーバの方でも忘れずに "hostmaster" アドレスを有効化して
  おこう。
  
  【add-host】
  IPアドレスに対するホストの名前を追加する。
  
    ./add-host <fqdn> <ip>
  
  と起動すると、ホスト名 <fqdn> に対するAレコードとしてIPアドレス <ip>
  を生成し、逆に <ip> のPTRレコードとして <fqdn> を生成するエントリを追
  加する。実際に追加されるエントリは
  
  	=<fqdn>:<ip>:86400
  
  である。イコール(=)で始まるエントリは厳密には
  
  	=<fqdn>:<ip>:<ttl>:<timestamp>:<lo>
  
  という形式となる。
  
  【add-alias】
  IPアドレスに対するホストの別名を追加する。
  
    ./add-alias <fqdn> <ip>
  
  と起動すると、ホスト名 <fqdn> に対するAレコードとしてIPアドレス <ip>
  を生成するエントリを追加する。逆引きレコードは生成しない。
  実際に追加されるエントリは
  
  	+<fqdn>:<ip>:86400
  
  である。86400はデフォルトのttl値である。
  
  【add-mx】
  あるアドレスに対するメイルサーバ(MXレコード)を追加する。
  
    ./add-mx <fqdn> <ip>
  
  と起動すると、ホスト名またはドメイン名 <fqdn> に対するMXレコードとして
  IPアドレス <ip> を生成するエントリを追加する。
  実際に追加されるエントリは
  
  	@<fqdn>:<ip>:a::86400
  
  である。@記号で始まるエントリはMXレコードを表す。書式は、
  
  	@<fqdn>:<ip>:<x>:<dist>:<ttl>:<timestamp>:<lo>
  
  という形式で、<fqdn> のMXレコードのホスト名として <x>.<fqdn> が自動生成
  され、そのホストのAレコードが <ip> となる。もし <x> 自体にピリオドが含ま
  れたときは <x> 自身をMXレコードに対するホスト名とする。<dist> は
  preference値でadd-mx スクリプトで追加した場合は省略されて、既定値の0とな
  る。明示的にpreference値を指定したい場合はdataファイルを直接編集すればよ
  い。
  
  【add-childns】
  サブドメインに対して権限を委譲するエントリを追加する。
  
    ./add-childns <fqdn> <ip>
  
  と起動すると、サブドメイン名 <fqdn> に対する NS, A レコードを生成する
  エントリを追加する。実際に追加されるエントリは
  
  	&<fqdn>:<ip>:a:259200
  
  となる。&で始まるエントリは
  
  	&<fqdn>:<ip>:<x>:<ttl>
  
  という形式で、SOAレコードを自動生成しない点を除いて(add-nsによる)ピリオ
  ドで始まるエントリと同様である。


これらのコマンドを利用してdataファイルに何個かエントリを足してみればdata
ファイルのそのものの仕組みもすぐに理解できるだろう。dataファイル形式の詳
しい仕様の説明は
http://cr.yp.to/djbdns/tinydns-data.html にあるので、実際に管理を始める
ときに参考にするとよいだろう。

・tinydnsのその他のレコードフォーマット

サービスディレクトリにある ./add-* コマンド群で生成することのできない、
あまり使われることのないレコードフォーマットを紹介しよう。これらは、特殊
なDNSレコードを登録したいときに必要となるだろう。

	* TXTレコード

	  シングルクォートで始まる

	  '<fqdn>:<s>:<ttl>:<timestamp>:<lo>

	  という書式は、<fqdn>に対するTXTレコードを<s>に設定する。<s>の
	  部分には \xxx (xxxは8進数) という表記で任意の文字をいれること
	  ができる。たとえばコロン(:)自身を入れたいときは \072 と書ける。

	* PTRレコード

	  キャレット(^)で始まる

	  ^<fqdn>:<p>:<ttl>:<timestamp>:<lo>

	  という行は<fqdn>に対するPTRレコードとして<p>を登録する。たとえ
	  ば、ネットワーク型常時接続環境で、IPアドレス逆引きをCNAMEで委
	  譲されているような場合はこれを利用する。具体的には、x.y.z.a か
	  ら始まるいくつかのIPアドレスの逆引きレコードが、上位プロバイダ
	  側のネームサーバで

	  a.z.y.x.in-addr.arpa   CNAME  a.a.z.y.x.in-addr.arpa
	  b.z.y.x.in-addr.arpa   CNAME  b.a.z.y.x.in-addr.arpa
	  c.z.y.x.in-addr.arpa   CNAME  c.a.z.y.x.in-addr.arpa
		:
		:
	  のように登録されるケースがあるが、この場合自らのネームサーバで
	  はa〜cについて以下のようなレコードを作成しておけば良い。

	  (例)
	  # .a.z.y.x.in-addrのNSレコードとSOAを生成
	  .a.z.y.x.in-addr.arpa::ns.example.net:86400
	  #各ホストのPTRレコードを生成
	  ^a.a.z.y.x.in-addr.arpa:network.example.net::
	  ^b.a.z.y.x.in-addr.arpa:host-b.example.net::
	  ^c.a.z.y.x.in-addr.arpa:host-c.example.net::

	* SOA

	  大文字Zで始まる

Z<fqdn>:<mname>:<rname>:<ser>:<ref>:<ret>:<exp>:<min>:<ttl>:<timestamp>:<lo>

	  という書式は<fqdn>に対するSOAのみを生成する。djbdnsの場合ピリ
	  オドで始まるエントリでSOAの自動生成を行なってくれるのだが、こ
	  のデフォルト値ではないものを明示的に指定したい場合にZ行を利用
	  する。コロンで区切られた各エントリは<mname>から順に、プライマ
	  リネームサーバ、コンタクトメイルアドレス、シリアル番号、リフレッ
	  シュ時間(16384秒)、リトライ時間(2048秒)、expire時間(1048576秒)、
	  最小時間(2560秒)となっている(括弧内は省略したときのデフォルト
	  値)。


	* 汎用レコード

	  コロンで始まる

	  :<fqdn>:<n>:<rdata>:<ttl>:<timestamp>:<lo>

	  という書式は<fqdn>に対するタイプ<n>番のレコード値として<rdata>
	  を設定する。

・ロケーションセレクタ

特定の場所からの問い合わせに答える候補を異なるIPアドレス集合に定義するこ
ともできる。%記号で始まり、1文字または2文字のアルファベットとコロンが続
く行は、クライアントのIPアドレス集合を定義できる。

	%in:192.168
	%in:10.0.1
	%ex

とすると、クライアントアドレス、192.168.*.*, 10.0.1.* のものが "in" とい
うロケーショングループに登録される。どんなクライアントも必ず一つのロケー
ショングループに登録されるので、%ex の行は%inでマッチしなかったアドレス
のみが登録されることになる。この状態で

+www.xxxx.yyy:10.8.50.1:::in
+www.xxxx.yyy:192.168.1.1:::ex

とすると、ロケーショングループ in に属するクライアントには 10.8.50.1 を
返し、それ以外のクライアントには 192.168.1.1 を返す。これを利用するとプ
ライベートLANとそれ以外で違うIPアドレスを返すなどのことが可能となる。


・tinydnsのパラメータ設定

tinydnsも、dnscacheと同様サービスディレクトリ内の env ディレクトリに動作
環境を決定するファイルがあるのでこれを変更することでパラメータ設定が行え
る。

  * env/IP
  tinydnsがlistenするIPアドレスを設定する。

  * env/ROOT
  ドメインのdataファイルを置くディレクトリを指定する。

サーバのIPアドレスや、ファイルの置き場所を変えた場合などはこれらのファイ
ルを変更することですぐに対応することができる。


●複数ドメイン管理の実例

Unixの良さはいくつものツールを組み合わせることで、「梃の原理」のように少
ない労力で効果的な結果を得られるところにあるだろう。djbdnsを使うときも
ちょっとしたツールを使うことで飛躍的に管理が楽になる。もし、管理している
のが一つのDNSドメインならば単純に add-host コマンドなどを利用してホスト
登録をして行くのが最も楽な管理方法だろう。逆に、管理しているドメインがい
くつにも及ぶ場合は、makeユーティリティを使うことで効果的な運用が行なえる。

ここでは、筆者が管理しているドメインでdjbdnsを利用している事例をベースに
複数のドメインを管理する方法を紹介しよう。ここでは例題として、

	* 主ゾーンサーバとして2つのドメインを受け持っている
	  - foo.ymzk.org

	* レプリカサーバ(セカンダリ)として以下のドメインを受け持っている
	  - bar.captor.org

のような利用形態をシミュレートしてみよう。

・主ゾーンサーバとなるゾーンファイルの作成

  管理するゾーンが、複数に分かれていた場合、とくに各ゾーンの管理形態が違
  うような場合は、サービスディレクトリ内にある "data" ファイルを直接編集
  対象とするのではなく、ゾーンごとに分離したファイルから data ファイルを
  生成するのが良い。たとえば、上記の各ドメインを、同名のファイルで管理す
  るものとしよう。すると、次のような Makefile エントリを書けば良いことに
  なる。

  ---[ Makefile ]-------------------------------------------------------
  DOMAINS = foo.ymzk.org bar.captor.org

  data.cdb:	data
	/usr/local/bin/tinydns-data

  data:	${DOMAINS}
	cat ${DOMAINS} > data
  ----------------------------------------------------------------------

  そして、各ドメインのゾーンファイルは個別に編集・生成して行くことになる。
  それぞれの工夫点を紹介しよう。

  * foo.ymzk.org (自分で管理するドメイン)

  これは通常のdnbdnsゾーンファイルと全く同じ書式で手動で編集すれば良い。
  もしホストが増えたら

	# echo "=newhost.foo.ymzk.org:10.0.2.50" > foo.ymzk.org
	# make

  などとすれば良い。もし、tinydns-data 形式を書くことに不慣れなうちは

	# ./add-host newhost.foo.ymzk.org 10.0.2.50

  とすれば、./data ファイルの末尾に対応するエントリが追加されているので、
  これを手編集で foo.ymzk.org の末尾に追加するか

	# tail -1 data > foo.ymzk.org

  とすれば良いだろう。

  * bar.captor.org (レプリカサーバとなるドメイン)

  相手方のサーバがdjbdnsを利用している場合とBINDを利用している場合でやり
  方が異なって来る。先方もdjbdnsを利用している場合はゾーンファイルをscp
  やrsyncでコピーするのが良いだろう(この場合の工夫については後述)。先方
  がBINDの場合はゾーン転送を利用する。あらかじめ、先方のBINDの設定でゾー
  ン転送許可が出ているものと仮定する。

  djbdnsにはゾーン転送クライアントとしてaxfr-getコマンドが用意されている。
  これは、ucspi-tcp 付属の tcpclient コマンドと組み合わせて以下のように
  利用する。

	# tcpclient サーバ 53 axfr-get ゾーン ファイル テンポラリファイル

  たとえば、今回の例の bar.captor.org のネームサーバが ns.bar.captor.org 
  であるとすると、ゾーン転送は以下のコマンドで行なえることになる。

	# tcpclient ns.bar.captor.org 53 axfr-get bar.captor.org \
		    bar.captor.org tmpfile

  コマンドライン引数で2回登場している bar.captor.org のうち、前者が転送
  したいゾーン名、後者がそれを格納したいファイル名である。これをmakeで行
  なうための Makefile エントリは次のように書ける。

  ---[ Makefile 追加分 ]------------------------------------------------
  TCPC  = /usr/local/bin/tcpclient
  AXGET = /usr/local/bin/axfr-get

  bar.captor.org:
	${TCPC} ns.bar.captor.org 53 ${AXGET} $@ $@ tmpfile
  ----------------------------------------------------------------------

  以上の記述をまとめたものが【リスト ほ】である。

  ---[ リスト ほ Makefile ]---------------------------------------------
  DOMAINS = foo.ymzk.org bar.captor.org
  TCPC    = /usr/local/bin/tcpclient
  AXGET   = /usr/local/bin/axfr-get

  data.cdb:	data
	/usr/local/bin/tinydns-data

  data:	${DOMAINS}
	cat ${DOMAINS} > data
  bar.captor.org:
	${TCPC} ns.bar.captor.org 53 ${AXGET} $@ $@ tmpfile
  ----------------------------------------------------------------------

・djbdns同士の場合のファイルコピー

  セカンダリを受け持つ相手ドメインもdjbdnsを利用している場合、あるいは友
  人の手持ちのドメインを自分のところのdjbdnsでマスターサーバを代行してあ
  げたりしていて、友人にゾーンファイルの更新権限を与えたい場合などは、
  tinydns形式のファイルをリモートコピーすることになる。このような場合
  rsync と SSH を組み合わせて差分更新をするのがセキュアかつ効率的である。
  "rsync over ssh" は、djbdns利用のためだけでなく、Unix上でのリモートファ
  イル管理をする場合には極めて肝要なテクニックとなる。ここでは、少し一般
  的な話題となるが、安全にリモートファイルコピーを行なうときに重要となる、
  SSHの公開鍵の取り扱い方法を紹介しよう。

  以下で解説する例ではSSHの実装として OpenSSH 3.1p1 を利用することを前提
  とする。バージョンによってオペレーションや作成するファイルに若干の差異
  があるのでその場合はマニュアルを参照して適宜読みかえて欲しい。ここでは、
  リモートコピーするファイルとして、bar.captor.org ドメインのゾーンファ
  イルである bar.captor.org ファイル(同名)を扱うものとする。

  依頼者側と、受諾者側で必要な準備はそれぞれ次のようになる。

  依頼者側(相手):
	1. DNS更新用ユーザの作成
	2. SSH接続用認証鍵の作成
	3. 公開鍵をサーバ管理者に送る

  受諾者側(自分の管理するdjbdnsサーバ):
	1. DNS更新用ユーザの作成
	2. 受け取った公開鍵の authorized_keys への追加
	3. コピーしてもらうゾーンファイルの初期作成

  まず、依頼者側の処理を追って行こう。

  1. DNS更新用ユーザの作成
  -------------------------
  例として作成するユーザ名を bardomain としよう。ユーザアカウントとその
  ホームディレクトリを作成する。

	(Solaris, NetBSD, OpenBSD, 各種Linuxの場合)
	# useradd -m bardomain
	(FreeBSDの場合)
	# pw useradd bardomain -m

  このユーザはログインする必要がないので、パスワードは潰しておくと良いだ
  ろう。

  2. SSH接続用認証鍵の作成
  -------------------------
  bardomainユーザの権限で認証鍵を作成する。

  # su bardomain -c 'ssh-keygen -N "" -t rsa'
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  Enter file in which to save the key (/home/bardomain/.ssh/id_rsa): [RET]
								     ~~~~~
  Your identification has been saved in /home/bardomain/.ssh/id_rsa.
  Your public key has been saved in /home/bardomain/.ssh/id_rsa.pub.
  The key fingerprint is:
  41:2d:ca:8b:d6:e0:ae:43:5e:98:d6:01:f9:52:92:fd dns@venus.baz.captor.org

  この例では鍵のタイプとしてrsaを指定しているが、もちろんdsaなど別のタイ
  プでも構わない。

  3. 公開鍵をサーバ管理者に送る
  -----------------------------
  手順2で ~bardomain/.ssh/id_rsa.pub ができているので、これをネームサー
  バ管理者に送っておく。一行が長いファイルなので端末でcatしたものをコピー
  &ペーストすると余計な改行コードが入ってしまい、正しい鍵と判定できなく
  なるので、必ずファイルそのものを添付するように気をつける。

	-	-

  続いて受諾者側(ネームサーバ管理者側)の作業を追って行こう。

  1. DNS更新用ユーザの作成
  ------------------------

  まず、依頼者のドメインを管理するために利用するユーザアカウントを作成す
  る。ここでは依頼を受けた baz.captor.org ドメインのレコードファイルを保
  持するユーザとしてこちらでも bardomain を作成する。このユーザのホーム
  ディレクトリはtinydnsのデータディレクトリの配下にしておいた方が管理上
  分かりやすいだろう。

	(Solaris, NetBSD, OpenBSD, 各種Linuxの場合)
	# useradd -m -d /var/dns/tinydns/root/bardomain bardomain
	(FreeBSDの場合)
	# pw useradd bardomain -m -d /var/dns/tinydns/root/bardomain

  2. 受け取った公開鍵の authorized_keys への追加
  ----------------------------------------------
  ~bardomain に .ssh ディレクトリを作成し、依頼者から送ってもらった公開
  鍵を authorized_keys ファイルとして保存する。

	# mkdir ~bardomain/.ssh
	# cp 「受け取った公開鍵ファイル」 ~bardomain/.ssh/authorized_keys
	# chmod -R og-rx ~bardomain/.ssh

  3. コピーしてもらうゾーンファイルの初期作成
  -------------------------------------------
  あらかじめ、受け取るゾーンファイルを空(0バイト)で作り、tinydns/root ディ
  レクトリにシンボリックリンクを張っておく。

	# cd /var/dns/tinydns/root
	# touch bardomain/bar.captor.org
	# ln -s bardomain/bar.captor.org .
	# chown -R bardomain bardomain

  また、 /var/dns/tinydns/root/Makefile を編集し、makeを起動すれば 
  data.cdb ファイルが最新の bar.captor.org ファイルを含むようにしておく
  (リスト ほ であればそのようになっている)。

  以上、双方の準備作業が完了したら依頼者側のホストの bardomain ユーザが、
  パスフレーズなしでサーバ側にログインできることを確認しておこう。どうし
  てもパスフレーズを聞かれてしまう場合はSSHプロトコルバージョンが違う、
  あるいは .ssh ディレクトリやその中のファイルのパーミッションが違うな
  どの原因が典型的であるので、ssh -v などで問題解決に当たる。

  SSH鍵の準備が完了したら、あとは依頼者側がコピーするのみである。単一ファ
  イルであれば

	依頼者# su bardomain -c 'scp bar.captor.org ns.foo.ymzk.org:'

  とすれば良いし、rsyncを利用するのであれば

	依頼者# su bardomain -c 'rsync -e ssh -az ~ ns.foo.ymzk.org:'

  などとすれば良いだろう。

  こちら側(ネームサーバ)では、cronなどを利用して定期的に tinydns/root ディ
  レクトリで make コマンドを起動するのも良いし、あるいは dns ユーザに
  setuidして make を起動する wrapper コマンドを作成し、それを bardomain 
  ユーザ自らに起動してもらうのも良いだろう。「Unixで何ができるか」を知っ
  ていれば知っているだけの多様な方法が考えられるだろう。

●djbdnsの設定確認事項

djbdnsの導入時に陥りやすい点をまとめたので、何かうまく行かないことがあっ
たら以下の点を当たってみて欲しい。

* tinydns/dnscache が起動しない

  → 既に同じプログラムを起動していないかpsでみたり、同じソケットを別の
  プログラム(BIND等)が利用していないか netstat などで確認しよう。また、
  tinydns, dnscache はひとつのネットワークインタフェースのIPアドレスの
  UDPの53番を、axfrdns はTCPの53番を使用する。サービスディレクトリの 
  env/IP アドレスを確認して別のdjbdnsプログラムとかち合っていないか確認
  しよう。

  → runスクリプトで、コマンドサーチパス($PATH)の記述は十分か確認しよう。

* LAN内の1ホストにdnscacheをいれたのに名前が引けない

  → dnscache/root/ip/ ディレクトリにLANのIPアドレスのプリフィクスとなる
  ファイルが作成されているか確認しよう。

  → dnscache/env/IP がLANに向けられたネットワークインタフェースのIPアド
  レスとなっているか確認しよう。

* tinydnsを起動したのに外部から名前が引けない

  → tinydns/env/IP がWAN側ネットワークインタフェースのIPアドレスになっ
  ているか確認しよう。

* tinydns/dnscache が突然動かなくなった

  ログを取るパーティションが溢れてはいないか確認しよう。

いずれにしても肝腎な点は、起動するDNSサービスが利用する、「IPアドレス」
と「UDPの53番か、TCPの53番か」をきちんと把握しておき、ログファイルを確認
するように心掛ければけば問題解決が早いだろう。


●まとめ

Dynamic DNS風の運用など、近年の利用形態に即した例を紹介したがいかがだっ
ただろう。最初に必要な鍵の生成と交換など面倒に感じるかもしれないが、BIND
でセキュアにゾーン転送したいときにはほぼ同じ作業が必要になるので事前の手
間としては大差無いだろう。djbdns ではデータファイル構造が単純なのでプロ
グラムから自動的に修正するのも実にたやすい。ちょっとしたシェルスクリプト
を書くだけで飛躍的に使い勝手が向上する可能性を持っている。djbdnsでドメイ
ンマスターを目指そう。


yuuji@gentei.org
Fingerprint16 = FF F9 FF CC E0 FE 5C F7 19 97 28 24 EC 5D 39 BA
HIROSE Yuuji - ASTROLOGY / BIKE / EPO / GUEST BOOK / YaTeX [Tweet]