DiCEに代わるIP更新プログラム-改良版

投稿日: 2008年12月19日 | カテゴリ:『自宅サーバー』>自作プログラム

DiCEに代わるダイナミックIPアドレス更新プログラムについては、その導入の動機、改良点について既に紹介してあります。今回はこのプログラムをセキュリティ面で強化し、Bシェルスクリプトで書き直した改良版について紹介いたします。

プログラムの改良点
  1. DDOプロバイダーは、IPアドレス変更チェックを行った際に、IPアドレスが変更されていない場合には、パスワードの確認を行いません。したがって、定期確認(注1)の場合にはパスワードを付けてやる必要はないはずです。しかし、非常に僅かな確率ですが、定期確認の5分(IPアドレスの変更を確認するインターバルの時間)以内にIPアドレスが変更になった場合には、IPアドレスの変更に失敗して変更前のIPアドレスがそのまま残ってしまう危険があります。たとえ低い確率であるとしても、この不具合は重大な結果を生み出すので解決しておく必要があります。今回のプログラムではこの危険性を全面的に取り除いてあります。
  2. 定期確認実行のトリガーとして以前は現行のIPアドレスを保存してあるファイル(CRT_IP.dat)を削除することによって、新しいIPの保存ファイル(NEW_IP.dat)との相異を人為的に作り出す方法を採っていました。しかし、この方法では他のファイルを削除してしまう危険性があること、現行IP保存ファイルを残したプログラムの方がより安定性を発揮できることから、別に識別子ファイルを作りその識別子を変化させることによってトリガーを引くようにしました
  3. 本サイトでは、アクセス統計にAwstatsを使用していますが、自IPアドレスからのアクセスをカウントから除外する必要があります。この対処は、awstats.confファイル内の「SkipHosts」の項に自サイトのIPアドレスを書き込むことによって実現できます。しかし、ダイナミックIPアドレスは変更されることが前提ですので、IPの変更が起こった場合には、自サイトのIPアドレスがカウントされてしまうことになります。この不具合を解決するためのプログラムを追加しました。
  4. ログのHTMLタグを除去するPHPプログラムを改良してDDOから送られてくるログ内容を最大限生かす形にしました。
  5. (注1)DDOプロバイダーの場合、IPアドレスの変更通知が長時間(1ヶ月)行われないと登録を抹消されてしまう(freeのアカウントの場合)ので、これを防ぐために本サイトでは週1回定期確認をするようにしています。

プログラムの詳細説明

(1) プログラム ip_check.shの内容説明

#!/bin/sh 
CRT_IPF="/root/ddns/CRT_IP.dat"
NEW_IPF="/root/ddns/NEW_IP.dat"
TEMP_IPF="/root/ddns/store/TEMP_IPF.dat"
temp="/root/temp/ddns.tmp"
awstats="/etc/awstats/awstats.conf"
dummy="/root/temp/dummy.txt"

1行目:プログラムの宣言
2行目:現行IPアドレスの保存ファイルの指定
3行目:IPが変更された場合のIPアドレスを保存するファイルの指定
4行目:トリガー用の識別子を保存しておくファイルの指定
5行目:DDNSプロバイダーからの応答を保存しておく一時ファイルの指定
6行目:アクセス解析Awstatsのconfファイルのパスを指定。サイトの特殊性に応じて変更してください。
7行目:Awstatsのconfファイルを一時格納しておくファイルの指定

while true; do
wget -q -O $NEW_IPF http://info.ddo.jp/remote_addr.php
if [ $? = 0 ]; then
NEW_IP=`gawk -F : '/REMOTE_ADDR/{print $2}' $NEW_IPF`
else
NEW_IP=`grep '.' $CRT_IPF`
fi
if [ -e $CRT_IPF ]; then
CRT_IP=`grep '.' $CRT_IPF`
else
CRT_IP=$NEW_IP
echo $NEW_IP > $CRT_IPF
fi
if [ -e $TEMP_IPF ]; then
IP_CHECK=`grep ':' $TEMP_IPF`
else
IP_CHECK="NEW:IP"
echo "NEW:IP" > $TEMP_IPF
fi

1行目:ループの開始
2行目:自サーバーのIPアドレスをDDNSのサーバーに問い合わせ、ファイル$NEW_IPFに取得
3~7行目:IPアドレスの取得が成功したか。成功ならば、NEW_IPFからIPを取得して変数NEW_IPに格納する。成功しなければ(サーバーがダウンしていて)、代わりにCRT_IPFからIPを取得する。
8~13行目:CRT_IPFファイルが存在するか。存在すれば、識別子(NEW:IPまたはOLD:IP)を取得する。存在しなければ、NEW:IPをIP_CHECKに代入すると共に、TEMP_IPFに保存する。
14~19行目:TEMP_IPFファイルが存在するか。存在すれば、識別子を変数IP_CHECKに代入する。存在しなければNEW:IPをTEMP_IPFに保存する(ファイルを作成)。

if [ $IP_CHECK = "OLD:IP" ] && [ $NEW_IP = $CRT_IP ]; then
 echo "*****定期確認*****" >$temp
 echo "開始(`date '+%Y年%m月%d日 %H時%M分%S秒'`)" >>$temp
 wget -q -O - 'http://free.ddo.jp/dnsupdate.php?dn=ID&pw=' |nkf -s >>$temp
# wget -q -O - 'http://ddo.jp/dnsupdate.php?dn=ID&pw=' |nkf -w >>$temp
 php /root/program/rm_htmltag.php
 echo "NEW:IP" >$TEMP_IPF
fi

1行目:定期確認時の設定=識別子がOLD:IPに変更されていて、かつ新IPと旧IPが同じ場合には定期確認を行う。
2~3行目:一次ファイルへのログの記述
4行目:IPアドレスの変更をDDNSに報告し、その結果をshift-jisに変換して一時ファイルに保存。IDにはユーザー名を記入。pwの記入は不要。
5行目:有料の場合のDNSサーバーのアドレスです。有料アカウントをもっている方はこちらに設定してください。
6行目:ログ整形プログラムを起動
7行目:NEW:IPをTEMP_IPFに保存

if [ $NEW_IP != $CRT_IP ]; then
 echo $NEW_IP > $CRT_IPF
 echo "*****IPアドレスの更新*****" >$temp
 echo "開始(`date '+%Y年%m月%d日 %H時%M分%S秒'`)" >>$temp
 wget -q -O - 'http://free.ddo.jp/dnsupdate.php?dn=ID&pw=PW' |nkf -s >>$temp
# wget -q -O - 'http://ddo.jp/dnsupdate.php?dn=ID&pw=PW' |nkf -w >>$temp
 /bin/bash /etc/cron.hourly/awstats
 cp $awstats $awstats.old
 sed -e "s/$CRT_IP/$NEW_IP/g" $awstats > $dummy
 cp $dummy $awstats
 php /root/program/rm_htmltag.php
fi

1行目:IP変更時の設定=取得した新IPアドレスが旧IPと異なっていたならばIP変更通知を実行。
2行目:新IPアドレスをCRT_IPFに保存
4行目:一次ファイルへのログの保存
5行目:新IPアドレスをDDNSに通知し、その結果をshift-jisに変換して一時ファイルに保存(IDにはユーザー名、PWにはパスワードを記入のこと)
6行目:有料の場合のDNSサーバーのアドレスです。有料アカウントをもっている方はこちらに設定してください。
7行目:ここからAwstatsのconfファイルの処理。まず、IPアドレスを変更する前に、前IPアドレスで解析を行っておく。すなわち、Awstatsは1時間ごとに情報収集を行うので、以前の更新時からIPアドレスが変更された時点の間に自IPアドレスからアクセスがあった場合にはそのログが残っているはずである。そこで、IP変更後の更新の際には以前のIPは自サイトのIPとは判断されないので記録にカウントされてしまうことになる。そのためにIP変更前に以前の記録を更新してログをクリアしておく。
8行目:Awstatsの既存confファイルを念のために退避させておく。
9行目:confファイル内の旧IPアドレスを検索して見付かったら、新IPアドレスに変換し、Dummyファイルに保存する
10行目:ダミーファイルの内容をconfファイルにコピーする
11行目:ログ整形プログラムを起動
(注):sedコマンドで保存先を直接$awstatsにすると制御ファイルが空になってしまうので、一旦ダミーファイルに保存して後にコピーするようにしてください。

sleep 300
done

1行目:300秒休止
2行目:ループの終了=先頭に戻る

次にip_check.shプログラムの全体像を掲載しておきます。View Codeをクリックすると別ウィンドウで内容が表示されますので、それをコピーしてファイルを作成してください。

#!/bin/sh 
#Dynamic DDS IP Address Checking Program
CRT_IPF="/root/ddns/CRT_IP.dat"
NEW_IPF="/root/ddns/NEW_IP.dat"
TEMP_IPF="/root/ddns/store/TEMP_IPF.dat"
temp="/root/temp/ddns.tmp"
#For Awstats
awstats="/etc/awstats/awstats.hsuzuki.ddo.jp.conf"
dummy="/root/temp/dummy.txt"

while true ; do
wget -q -O $NEW_IPF http://info.ddo.jp/remote_addr.php

#NEW_IPが取得できたか
if [ $? = 0 ]; then
NEW_IP=`gawk -F : '/REMOTE_ADDR/{print $2}' $NEW_IPF`
else
NEW_IP=`grep '.' $CRT_IPF`
fi

#旧IP保存ファイルがあるか
if [ -e $CRT_IPF ]; then
CRT_IP=`grep '.' $CRT_IPF`
else
CRT_IP=$NEW_IP
echo $NEW_IP > $CRT_IPF
fi
#識別子保存ファイルがあるか
if [ -e $TEMP_IPF ]; then
IP_CHECK=`grep ':' $TEMP_IPF`
else
IP_CHECK="NEW:IP"
echo "NEW:IP" > $TEMP_IPF
fi

#定期確認
if [ $IP_CHECK = "OLD:IP" ] && [ $NEW_IP = $CRT_IP ]; then
 echo "*****定期確認*****" >$temp
 echo "開始(`date '+%Y年%m月%d日 %H時%M分%S秒'`)" >>$temp
 wget -q -O - 'http://free.ddo.jp/dnsupdate.php?dn=ID&pw=' |nkf -s >>$temp
 php /root/program/rm_htmltag.php
 echo "NEW:IP" >$TEMP_IPF
fi
#IPの更新
if [ $NEW_IP != $CRT_IP ]; then
 echo $NEW_IP > $CRT_IPF
 echo "*****IPアドレスの更新*****" >$temp
 echo "開始(`date '+%Y年%m月%d日 %H時%M分%S秒'`)" >>$temp
 wget -q -O - 'http://free.ddo.jp/dnsupdate.php?dn=ID&pw=PW' |nkf -s >>$temp
 #Awstats IP converter
 /bin/bash /etc/cron.hourly/awstats
 cp $awstats $awstats.old
 sed -e "s/$CRT_IP/$NEW_IP/g" $awstats > $dummy
 cp $dummy $awstats
 #LOG整形
 php /root/program/rm_htmltag.php
fi
sleep 300
done

(2) 定期確認用のトリガー・プログラム

 #!/bin/sh
TEMP_IPF=/root/ddns/store/TEMP_IPF.dat
echo "OLD:IP" >$TEMP_IPF

識別子ファイルに保存されている識別子をOLD:IPに変更して定期確認を誘発するプログラムです。

(3) ログ整形プログラム
定期確認あるいはIP変更時に一時ファイルに保存したログを整形してログファイルに保存するプログラムです。簡単なPHPプログラムなので、コメントを読めば解かると思います。

<?php
//ログファイルのパス
$temp="/root/temp/ddns.tmp";
$log="/var/log/ddns.log";
//$log="/root/temp/ddns.log";
//tempファイルを開いてデータを読み込む
$save=array();
if (! $fp = @fopen("$temp", "r")){
			print "Could not open file<BR>";
			exit();
		}
while(! feof($fp)){
	$data=fgets($fp);
	if ($data != "\n"){
		if (preg_match("/^</",$data) && preg_match("/Dynamic/",$data)){
			$data="Dynamic DO!.jp"."\n";
			array_push($save,$data);
		 }elseif(!preg_match("/^</",$data) ){
			$data=str_replace("<br>","",$data);
			array_push($save,$data);
		 }else continue;
	}
}
fclose($fp);

//logファイルを開いてデータを書き込み
`echo "" >>$log`;
if (! $fp = @fopen("$log", "a")){
	print "Could not open file<BR>";
	exit();
}
foreach ($save as $data){
	fwrite($fp,$data);
}
fclose($fp);

?>
(注意)

旧プログラムのerg()関数(php7.0で使用不可になった)は、preg_match()関数に変更してあります(2017年8月14日)。

プログラムの実行方法
  1. まず、phpプログラムとnkfプログラムがインストールされているか確かめます。which php、及びwhich nkf。インストールされていない場合には、yum -y install php、及びyum -y install nkf としてインストールを行います。
  2. 上記の3つのプログラムをコピーし、ip_check.sh、chk_trigger.sh、rm_htmltag.phpを作成します。
  3. /root/ddns ディレクトリを作成しここに本体プログラム(ip_check.sh)と定期確認のトリガー・プログラム(chk_trigger.sh)をおきます。DDNSに登録したときに設定したユーザー名とパスワードを所定の部分に書き込みます。プログラムを実行可能にします。(注2)
  4. /root/ddns/store ディレクトリを作成します。
  5. /root/program ディレクトリを作成しここに整形プログラム(rm_htmltag.php)をおきます。プログラムを実行可能にします。
  6. /root/temp ディレクトリを作成しておきます。
  7. この段階で1回本体プログラムを実行させます。コマンド・ラインで、ip_check.sh & と打ってプログラムをバックグラウンドで走らせます(JOB番号を覚えておいて下さい)。更に定期確認のためのトリガープログラムを実行してみます。できればモデムの電源を切るなどしてIPアドレスを変更させてみます(変更が反映されるまで10分程度かかります)。バッググラウンドジョブを停止するには、セッションを終わらせるか、kill ジョブ番号 で停止させます。
    以上の操作を完了すれば、/root/ddns/ディレクトリにCR_IP.dat(「現行IPアドレス」を保存)とNEW_IP.datファイル(「REMOTE_ADDR:新IPアドレス」を保存、この段階では現行IPと新IPは同じはずです)、/root/ddns/storeにTEMP_IPF.datファイル(「NEW:IP」を保存)が自動的に作成されます。更に、/var/logディレクトリにddns.logファイルが作成され、次のようなログが残っているはずです(定期確認、IPアドレス変更の場合)。

    *****定期確認*****
    開始(2008年12月12日 03時05分16秒)
    Dynamic DO!.jp
    SUCCESS: hsuzuki.ddo.jp <= [ www.xxx.yyy.zzz ] IPアドレス更新完了.※IPアドレスに変更がありませんため、パスワードはチェックしておりません。 2008/12/12 03:05:16 *****IPアドレスの更新***** 開始(2008年12月14日 17時31分21秒) Dynamic DO!.jp SUCCESS: hsuzuki.ddo.jp <= [ aaa.bbb.ccc.ddd ] IPアドレス更新完了. 2008/12/14 17:31:22

関連記事



DiCEに代わるIP更新プログラム-改良版” への1件のコメント

コメントを残す




空欄に計算式を満たす数値を記入してください(必須)