だめ日記

kz のだめ日記 コンピュータ関係を中心に、備忘録のような日記

[Dynamic Do!.jp] IP アドレス自動更新スクリプト

2009-04-18 22:06:17 | FreeBSD
FreeBSD で動くサーバを Dynamic Do!.jp のダイナミックDNS で公開するとき作った IP アドレス自動更新 Perl スクリプト(Linx や *BSD でもちろん OK)

ちょっと事情があってサーバを預かっています。FreeBSD で構築し、アドレス解決は Dynamic Do!.jp の無料版ダイナミックDNS を使っています。
ADSL 回線だったんですが、これがしょっちゅう IP アドレスが変わるんで、ddo の更新スクリプトを直接 crontab に設定し1時間に3回、アドレス更新を行っていました。
先日、回線を FTTH に替えたのですが、こちらは今のところアドレスの変化がほとんどありません。となると、ddo の負荷を考えて変化があった時だけ更新するように変更しなきゃいかん、ということで wget を使った Perl5 のスクリプトを作成しました。
以下の内容のファイルを適当な名前で(ここでは ~/.ddns/ddo_update.pl )保存します。その際
  $previous_ip_file $domain $password  $wgetpath
を環境に合わせて変更します。有料版を使っている時は
  $ddns_update も  "http://ddo.jp/dnsupdate.php"
に変更します。
==================
#!/usr/bin/perl -w

##
## [Dynamic Do!.jp] IP アドレス更新スクリプト for Perl5
## by kzsugi, 2009.04.13
##    file name : ~/.ddns/ddo_update.pl
##
## 他に必要なもの:wget
##
## 前回更新時から IP アドレスが変化していたら更新する
## 変化していなくとも一週間に一回、強制的にアドレス更新を行う
##
## 更新した時は、ddo からのレスポンスが返る
## cron に登録した場合はその内容がメールされる
##
## 更新した結果(ddo からのレスポンス内容)についてはチェックしていない
## ddo 側でエラーになっていても、一週間毎に強制更新するから良しとする
##
# 要 設定確認
#  IPアドレス記録ファイル(保管するディレクトリは作成しておくこと)
$previous_ip_file = "/path/to/home/.ddns/previous_ip";
#
#  IPアドレス確認URL
$remote_addr_chk = "http://info.ddo.jp/remote_addr.php";
#  DDNS更新URL(無料版)
$ddns_update     = "http://free.ddo.jp/dnsupdate.php";
#
#  契約ドメイン情報
$domain          = "example.ddo.jp";  # ドメイン名
$password        = "password";        # パスワード
#
#  wget パス
$wgetpath        = "/usr/local/bin/wget";

$prev_ip = &get_prev_ip();
$now_ip = &get_now_ip();
if ($now_ip eq '9999') {
    print "Error : リモートアドレスを取得できない.n";
    exit;
}
if (&force_update() eq '1111') {
    exit;
}
if ($now_ip !~ /$prev_ip/m) {
    &update_ddns();
} else {
## 次行をアンコメントすると、アドレスに変化が無い時でも
## cron からメールが送られてくる
#    print "リモートアドレス変化無し[ $now_ip ].n";
}
exit;
#######
sub update_ddns() {
    my $ret;
   $ret = `$wgetpath -q -O - '$ddns_update?dn=$domain&pw=$password'`;
#    $ret = "テスト:更新必要.n";
    open (FILE, "> $previous_ip_file");
    print FILE $now_ip;
    close(FILE);
    print $ret;
}
sub force_update() {
    my @stat_inf;
    if ( -f $previous_ip_file) {
        @stat_inf = stat $previous_ip_file;
                    # 9 -> mtime  最終更新した時点のエポック時からの経過秒数
        if ((time() - $stat_inf[9]) > 60 * 60 * 24 * 7) { # 7日毎
#        if ((time() - $stat_inf[9]) > 60 * 60) { # 60分毎 test
            &update_ddns();
            return '1111';
        }
    }
}
sub get_now_ip() {
    my $nip;
    $nip = `$wgetpath -q -O - '$remote_addr_chk'`;
    if ($nip =~ /([0-9]{1,3}).([0-9]{1,3}).([0-9]{1,3}).([0-9]{1,3})/) {
        $nip = $1 . '.' . $2 . '.' . $3 . '.' . $4;
    } else {
        $nip = '9999';
    }
    return $nip;
}
sub get_prev_ip() {
    my ($pip, $tip);
    $pip = '0.0.0.0';
    if (open(FILE,"< $previous_ip_file")) {
        $tip = <FILE>;
        close(FILE);
        if ($tip =~ /([0-9]{1,3}).([0-9]{1,3}).([0-9]{1,3}).([0-9]{1,3})/) {
            $pip = $1 . '.' . $2 . '.' . $3 . '.' . $4;
        }
    }
    return $pip;
}
==================
保存したら、実行権を付与します。
> chmod 0700 .ddns/ddo_update.pl

まず、実行します。
> .ddns/ddo_update.pl

更新に対する ddo のレスポンスが表示されます。
IP アドレス記録ファイル($previous_ip_file に設定したファイル)が存在していて内容がリモートアドレスであることを確認してから、もう一度実行すると、今度は何も表示されません。(2回の実行の間にアドレスが変化していなければですが)
前回の IP アドレスから変化していなければ何もせずに戻ってくるので、これで正常です。
後は、このスクリプトを cron に登録しておきます。ADSL の時は 20分に1回強制更新をしていましたが、これからは1時間に1回チェックをするように設定します。
> crontab -e
 7 * * * * /path/to/home/.ddns/ddo_update.pl

cron からのメールがドンと減りました。
ソースは美しくないとこもあるけど、まあいいや。