Dynamic DNS

Table of Contents

ダイナミックDNSとは

固定IPを取得することなく、プロバイダから動的に割り振られているグローバルアドレスを使用して、あたかも固定IPの如く、全世界からDNS名前解決を受けることができる。

実現するには、第1に、ダイナミックDNSサービスを提供している団体との契約が必要。ダイナミックDNSサービスは、一種のレンタルDNSと言える。ドメイン、メールサーバ、WEBサーバやその他の各エイリアス名を登録しておき、自分のグローバルアドレスが変わる毎に、そのIPをダイナミックDNSサービスに通知する。通知は ddclient などのツールを使用して自動化できるので、使い心地は固定IPとほとんど変わりない。

※プロバイダから与えれれる動的IPは通常ひとつだけなので、複数のサーバを立てる場合には、自分でローカル用のキャッシュDNSサーバを設けるなど多少の工夫が必要だ。

※ モデムとサーバマシンとがブリッジ接続 (つまりサーバマシン自体が直接グローバル IP をもらっている) 場合には、BIND9 の Dynamic Update DNS 機能と dhcpd を組み合わせれば、ダイナミックDNS を自前で構築することも可能らしい。筆者はまだやってみたことはないが、Bind9設定 (Love Love BSD) で解説されている。

好みのダイナミックDNSサービスプロバイダを選ぶ

Dyn (旧DynDNS.org) は、ビジネスモデルが別の方向へ変質してしまった...。今ではあまりお勧めしない。コストパフォーマンス的にも、ごく小規模なドメインにはあまり適さない。Linux用のダイナミックDNSレコードアップデータを使うのであれば、海外の著名なダイナミックDNSプロバイダを選ぶのがいいだろう。昔からあってプライスも低めな no-ip あたりがいいのではなかろうか。こんな口コミページ (DNS Reviews) も参考になるかもしれない。

だいたいのダイナミックDNSサービスは、"<あなたのサブドメイン>.<幾つかから選べるお仕着せのドメイン>" というドメイン名も使えるが、ドメイン管理費も例えば ".com" なら2年で2000円くらい (お名前.com) なので、独自ドメインを取得することをお勧めする。

節度を持った運用を

ダイナミックDNSは、あくまでもプロバイダの帯域を拝借してのサーバ運営であり、巨大データが頻繁に往き来するような運用は遠慮すべきである。ダイナミックDNSによるサーバ公開の未来のために、心していただきたい。中にはサーバ運営禁止を明記しているプロバイダもあるので、確認してから実行すること。

ダイナミックDNSサービスの設定

ダイナミックDNSによる名前解決を有効にするには、まず、ふたつのことをしなくてはならない。ひとつは、ダイナミック DNS サービスプロバイダの ネームサーバに DNS レコードを登録すること。もうひとつは、ドメインを採ったレジストラのネームサーバ (こちらのほうが上位にあたる) に、取得ドメインの名前解決先としてダイナミック DNS サービスプロバイダのネームサーバを指定 (委譲) することだ。通常は、どちらも、ブラウザを通じて WEB インターフェース上で設定できる。

説明のための設定:
(独自ドメインを
取得済みと
仮定する)
自ドメイン:
ローカルIP:
ゲートウェイ:
実際のホスト名:
現グローバルIP:
WEBサーバの公開名:
メールサーバの公開名:
hoge.cxm
192.168.0.1
192.168.0.254
host1.hoge.cxm
61.x.x.x
www.hoge.cxm
mail.hoge.cxm
ネットにさらす前に!

さらすだけならサルでもできる。クラッキングの餌食や踏み台にされてからでは手遅れ。ファイヤーウォールを設定するまでは、絶対に公開してはいけない。現時点での RedHatセキュリティレベル (ファイヤーウォール) 設定ツールは、まったく使い物にならないので、iptables を手動で設定すべし。

ダイナミックDNS側の設定

ダイナミックDNSサービスプロバイダ側に登録する情報:

HOST TTL TYPE DATA
hoge.cxm 600 A 61.x.x.x
mail.hoge.cxm 600 A 61.x.x.x
www.hoge.cxm 43200 CNAME hoge.cxm
hoge.cxm 43200 MX 5 mail.hoge.cxm
設定のポイント:

注意: Dyn の場合、Aレコードは、IPの変更が無いのにたびたび (10分間に 2 回以上) 変更をかけようとすると、 Abuse (失礼なヤツ) ロックがかけられてしまう。Abuse ロックがかかってしまったら、所定のWEBページにログインして解除を申請するまで、IPアドレスを更新することができない。

レジストラのネームサーバの設定

レジストラ側には、 利用するダイナミック DNS サービスプロバイダのDNSサーバの FQDN を登録するだけ。指定すべき DNSサーバ名は、利用するダイナミックDNSサービスプロバイダで情報が得られるはずだ。特に理由のない限り、あるだけ全て登録しておく。レコードがインターネット上に浸透するまでには或る程度時間が必要で、長い時には 48時間程度かかることもあった。

DNS設定のテスト

登録したレコードに問題がないか確かめておく。 dnsreport.com という診断ページがあり、 RFC などに照らした規則違反がないかチェックできる。

ルータの設定

ルータは通常の NAT 動作。簡易 DMZ (機種によってはバーチャルホストなどとも) で全ポートを晒すより、ポートマッピング (ポートフォワーディング) で必要なポートのパケットだけをサーバに送るよう指定したほうが、サーバ自体のセキュリティリスクは減る。

例でマッピングの必要なポートは以下の通り:

TCP 80 WWW
TCP 25 SMTP
TCP 110 POP3
TCP 443 HTTPS

※ HTTPS は、使わないなら開けないほうがいい。 Apache には過去に何度かセキュアHTTP接続関係の脆弱性がレポートされている。

ddclient

ルータのステータスページなどから現在の WAN 側 IP を読みとり、変化があれば自動的にダイナミック DNS サービスに通知してくれるプログラムを「Update Client」と呼ぶ。そのUNIX/Linux用として書かれたプログラムのひとつが ddclient だ。ルータのステータスページから IP アドレスを読む方法の他、インターネット上の公開 CGI を利用してグローバル IP を調べることもできる。

ddclientDyn のサポートページ から入手可能。ただし Dyn のサポートページは更新がやや遅れていることがあるので、最新版がほしければ sourceforge にある ddclient のメインページを訪ねた方がいい。GitHub にもレポジトリがある。 ddclient は Dyn の他、ZoneEdit, EasyDNS, Hammernode, dslreports.com, OrgDNS.org, dnspark.com, NameCheap などといったダイナミック DNS サービスプロバイダにも対応しているようだ (v.3.6.7時点)。

インストール

ddclient は Perl スクリプトなので、本体のインストールは ddclient/usr/sbin など PATH の通ったディレクトリにコピーするだけ。

root# cp ddclient /usr/sbin/
root# chmod 755 /usr/sbin/ddclient

そして、サンプルの設定ファイルをしかるべき場所にコピーする。バージョン 3.6.5 以降、設定ファイルの位置は /etc/ddclient/ddclient.conf になった (以前は /etc/ddclient.conf)。 ddclient.conf は幾つかのパスワードを生で書かなければならないファイルなので、パーミションは絞り上げておこう。オーナー (通常は root) 以外に読めるパーミションになっていると ddclient が、メッセージを表示しつつ自動的に 0600 に修正する。

root# mkdir /etc/ddclient
root# cp sample-etc_ddclient.conf /etc/ddclient/ddclient.conf
root# chmod 600 /etc/ddclient/ddclient.conf

前回の IPチェックや IP更新の結果はキャッシュファイルに記録される。 3.7 以降、デフォルトでは /var/cache/ddclinet/ddclient.cache というファイルに書こうとするので、ディレクトリがなければ作成しておく。キャッシュの位置は設定パラメータ cache= によって変更することも可能。

root# mkdir /var/cache/ddclient

加えて、RedHat や Fedora なら、 rc スクリプトを init ディレクトリにコピーし、各ランレベルに組み込む:

root# cp sample-etc_rc.d_init.d_ddclient.redhat \
     /etc/rc.d/init.d/ddclient
root# chmod 755 /etc/rc.d/init.d/ddclient
root# chkconfig --add ddclient

ダイナミックDNSサービスプロバイダへの更新通知に SSL を使用する (設定パラメータ ssl=yes) 場合には、Perl モジュール IO::Socket::SSL のインストールが必要だ。RedHat/CentOS 5 及び 6 では、perl-IO-Socket-SSL パッケージ、debian では libio-socket-ssl-perl というパッケージに含まれるようだ。パッケージを使わずに CPANインターフェースでモジュールを直接インストールする場合は;

root# perl -MCPAN -e shell
cpan> i IO::Socket::SSL   <-- インストールされているかの確認。 INST_VERSION が not installed となった場合は未
cpan> o conf prerequisites_policy follow
cpan> install IO::Socket::SSL
cpan> quit

ddclient.conf の編集

設定ファイルの記述ルール

最も基本的には、1 行毎に;

var=value

という形で書くが、カンマで連ねて;

var1=value,var2=another_value,var3=more_value

のように 1 行中に複数のパラメータを並べることもできる。カンマと次のパラメータの間に半角スペースを入れても構わない。
また、パラメータは ddclient プログラムの中で、アップデートするDNSホスト毎の `ローカルな' 設定と、全てのDNSホストに共通の `グローバルな' 設定とに区別される。上記ふたつの例はグローバルな設定。これに対して、ローカルなパラメータを設定する場合には;

var1=value,var2=another_value,var3=more_value hoge.cxm,mail.hoge.cxm

といったように必ず 1行にまとめ、行端に、対象とするホストを <スペース> で結んで置く。対象ホストが複数の場合には上記のようにホスト同士をカンマで連ねる。こうした場合、読みやすくするために、 \ (バックスラッシュ) を使い;

var1=value,\
var2=another_value,\
var3=more_value \
hoge.cxm,mail.hoge.cxm 

のように書くこともできる。ただし \ の後ろにスペースが紛れ込むとパースエラーとなるので注意。その他の規則としては...

主な設定パラメータ

PARAMETER 意味
プログラムの設定
daemon=300 300秒 (=5分) 毎にIPの変化をチェック。通常はデフォルトの 300 が最適。ddclient は前回の更新から 5分間 (下記 min-interval, min-error-interval パラメータ参照) は更新を拒否するようにできているので、それ以上短くすると、実質的には、チェックが行われる間隔は長くなってしまう。
mail=mail@address 更新結果をメールするメールアドレス
mail-failure=mail@address DNSのアップデートに失敗した場合に報告するメールアドレス
pid=/var/run/ddclient.pid PIDファイルの書き出し先ファイル名
cache=
/var/cache/ddclient/ddclient.cache
前回の IPチェック及び IP更新を記録するキャッシュファイル名。 3.7 以降でのデフォルトは左記例の通り
ssl=yes [ddclient-3.7以降] ダイナミックDNSサービスの更新インターフェースサイトへ接続する際に https で通信を行う。 ssl=yes を設定するには Perl モジュール IO::Socket::SSL が必須。ルータから IPを読み取る段階では https は使われない。なお、ホストローカルな設定ブロックにこれを書いても、ssl は常にグローバルパラメータとしてパースされ、個別に有効にすることは不可能なようだ
IP読み取り関係の設定
use=preset-router-name ddclient に仕様がコーディング済みのルータの場合。サポートされているのは Linksys など海外もののごく一部だけ。サポートされているルータを知るには ddclient 本体の序盤で定義されている %builtinfw 配列を覗けばいいが、基本的に、各定義は単なる name (ルータ機種名)、 url (WAN-IP ステータスページの URL)、 fw-skip パラメータの組み合わせに過ぎない
fw=192.168.0.254:port コーディング済みルータの場合、このようにルータのアドレスとポートを指定
use=fw コーディングされていないルータの場合
fw=192.168.0.254/status.html コーディングされていないルータの場合に、 WAN 側 IP が読めるルータのステータスページの URL を指定。フレームが利用されている場合にはダイレクトなページの URL を見つけて指定すること
fw-skip='phrase' ddclient はステータスページから得られたコンテンツを行を跨いで正規表現検索 (=~//is) し、最初に出現する IP 文字列 (Perl 式で表すと \b(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\b) を WAN 側アドレスとして認識する。しかしルータによっては LAN 側アドレスが先に書かれていたりするので、その回避策としてこのパラメータがある。通常は敢えて指定する必要はないが、読み取りがうまくいかない時に設定してみる。設定すると、 phrase が出現するまでの文字列は全てカットし、残りのコンテンツの中で最初の IP 文字列を探す。 phrasePerl 正規表現。日本語が使えるか少し試してはみたが、文字コードが絡んでくるので難しい
fw-login=user-name ルータのステータスを見るときに認証が必要な場合
fw-password=password その時のパスワード
use=web ルータからでなく、外部の CGI ページなどを見て自グローバル IP を見つける場合はこれを指定。下記の web= パラメータを省くと、デフォルトでは checkip.dyndns.org が使用される
web=checkip.dyndns.com/ 上記 use=web と併用し、ddclient デフォルトの checkip.dyndns.org 以外を参照して IP を探知したい場合に指定。Dyn のサイトの ddclient説明ページを見ると、スラッシュ付きの checkip.dyndns.com/ が指定されている。digってみると、checkip.dyndns.com は3台の実サーバでDNSラウンドロビンされていて、checkip.dyndns.org は 同.com の CNAME となっている。他のIP探知ページの類としては ipdetect.dnspark.com などがある。これと併せて、 checkip.dyndns.* の場合には web-skip='IP Address'、 ipdetect.dnspark.com の場合には web-skip='Current Address' も設定したほうが確実なようだ
use=cmd, \
cmd=/path/to/cmd
ddclient組込みの仕組みではどうしてもIPが探知できない場合は、自分でスクリプトなどを書き、それで検知したIPをddclientへ渡してやる方法も採れる。込み入ったステータスページを出すタチの悪いブロードバンドルータを使っている場合の奥の手だ。下にNTT光の腐ったルータ(PR-S300SE)で成功したスクリプトの例を示す
ダイナミックDNSサービスに関する設定
max-interval=20d IP アドレスに変化が無くてもアップデートサーバへ強制通知を行う間隔。左記設定例では、無変更期間が 20 日間に達すると強制更新を行う。 ddclient プログラムの内部的には秒数に展開されて使われる。特に指定しない場合のデフォルトは 25日 (=25d)。規定値でも問題ないので指定は必須ではない
min-interval=30s 前回正常に更新されてからこの期間 (左例では 30 秒) 経過するまでは、仮に IP が推移していてもアップデートを実行しない。 利用するダイナミック DNS サービスプロバイダ (下記 protocol パラメータ) に応じて最適な値がコーディングされているので滅多に設定しないほうがいい
min-error-interval=5m min-interval に似ているが、これは前回更新に失敗してからの最短時間。これも滅多に設定しないほうがいい
login=user-name ダイナミックDNS更新インターフェースへのアクセスに必要なユーザ名
password=password 同、パスワード
mx=mail.server MXレコードも随時更新の必要がある場合に指定。通常は要らない
backupmx=(yes|no) MXバックアップサービスを使っているなら、yes を指定してもよい。通常は不要
wildcard=(yes|no) 同、ワイルドカードサービスを使っている場合。通常は不要
custom=yes ここからは `ローカルな' パラメータ群なので 1 行で書くか \ でつなげる
Dyn の Standard DNS の場合は custom=yes を定義する。他に static=yes というパラメータもある
protocol=dyndns2 利用しているダイナミックDNSサービスの種別。 左記は Dyn の場合
server=members.dyndns.org 更新インターフェースの URL。左記は Dyn の場合

設定例 (Dyn の Standard DNS と仮定):

daemon=300
syslog=yes
mail=root@hoge.cxm
mail-failure=root@hoge.cxm
pid=/var/run/ddclient.pid
cache=/var/cache/ddclient/ddclient.cache
ssl=yes
 
use=fw
fw=192.168.0.254/status.html
fw-login=user
fw-password=password
 
max-interval=25d
custom=yes,                \
server=members.dyndns.org, \
protocol=dyndns2,          \
login=hoge,                \
password=hogepassword      \
hoge.cxm,mail.hoge.cxm

cmd=... 作戦で使ったPR-S300SE のIP探知スクリプトの例。wget に "--header='Accept-Language: en' を指定しようが何をしようが頑なに日本語 EUC-JP で出力しやがる(なんとご丁寧にコロンまで全角だ!) ので、ファイルの文字コードは iconv変換後のコードである UTF-8 にしておかなければならない。パスワードを含むためファイル属性は root:root 700 に絞り上げておく。

#!/bin/sh
URL='http://192.168.0.254/cgi-bin/main.cgi?mbg_webname=status&config_no=1'
FW_LOGIN=xxxxx
FW_PASSWORD=xxxxxxxxxx
FW_SKIP='WAN側IPアドレス'
echo $URL |
 wget -i - -O - -q --http-user=${FW_LOGIN} --http-passwd=${FW_PASSWORD} |
 iconv -f EUC-JP -t UTF-8 |grep -A1 ${FW_SKIP} |
 tail -n1 |sed -e 's/<[^>]*>:\([0-9.]*\)<[^>]*>/\1/'

うまくいかない時の対処法

IP 読み取り系のトラブル

ルータの仕様によって、ddclient がうまく動作しなかった経験がある。

NEC製ADSLモデム内蔵ルータの一部での経験
LAN 側 IP と WAN 側 IP が同じステータスページに書かれており、ADSL コネクションが一旦切断して再確立する合間に ddclient が LAN 側 のローカル IP を読み取ってダイナミックDNSサービスに通知してしまう。
メルコ (バッファロー) のルータの一部での経験
ステータスページでの IP アドレスを "061.020.001.010" のようにゼロでパディング表示するという、気の狂った仕様のブロードバンドルータが過去にあった。このまま通知してもダイナミックDNSサービス側ではゼロが取り除かれて通例通り "61.20.1.10" と更新されるが、それとステータスページ上のアドレスとは文字列として常に別物であるため、 ddclient はチェックの度に「変わった」と判断して更新をかけてしまう。結果、Dyn に Abuse ロックがかかってしまった。
まずはデバグテスト

まず初めに、何が起こっているか突き止めなければならない。そのためには ddclient をデバグモード且つ非デーモンモードで起動して出力を見よう。出力内容は長いかもしれないのでファイル debug.log に書き出すとした場合のコマンド例;

ddclient -daemon=0 -debug -verbose -noquiet >debug.log 2>&1
対処法 1. odd-fw パッチ

上記ふたつのトラブルを解決する パッチ を作った。加えたルーティンは、IPのゼロパディングの除去と、把握したIPが 192.168.0.0/16 か 10.0.0.0/8, 172.16.0.0/12 のネットワーク範囲だった場合に IP の探知を失敗と判断するルーティンだ。パッチ適用は;

root# cd ddclientの置いてあるdir
root# patch -p1 < ddclient-3.8.2-odd-fw.patchへのPATH

ルータから読み取ったローカルアドレスを無視する機能のほうは、ddclient.conf

fw-banlocal=yes

を書くかコマンドラインオプションに -fw-banlocal を付加しないと有効にならない点にご注意いただきたい。

対処法 2. use=web か use=cmd に作戦変更

ルータから WAN 側 IP を読み取るのはあきらめて use=web パラメータに切り替え、外部の CGI ページから自 IP を得る。これについては表 「主な設定パラメータ」 の 「IP読み取り関係の設定」 を参照いただきたい。あるいは、use=cmd に作戦変更して、紹介した例のように、ルータのIPを読み取るためのスクリプトを自力で書くかだ。