公開日: 2012年8月10日 14:28:19
最終更新: 2016年7月7日 18:24:43

DDNS の更新スクリプト作成(bash)

DDNSを利用してホスト名でサーバを公開する

2016/06/02 いろいろ修正中

DDNS は、動的に変わるIPアドレスに対して、固定のホスト (or ドメイン) と関連付けてくれるサービスです。DDNS を利用すれば固定IPアドレスを取得しなくても、自宅サーバを「cro-pel.mydns.jp」 のようなドメイン名でインターネットへ公開することができます。

IP アドレスの登録・更新

自宅サーバに割り当てられている IP アドレスは、常時接続といえど PC 再起動や ISP のメンテナンスなど、インターネットに接続するたびに違ったアドレスが割り当てられます。IP アドレスの変更があった場合には速やかに更新作業を行う必要があります。
ここではシェルスクリプトの練習がてら、wget を使用して IP アドレス登録を更新するスクリプトを作成します。

更新スクリプトの作成

基本的なフローは次の通りとし、排他処理やら例外処理とか、他のOSでの汎用性などと小難しいことは一切考えないようにします。つーかそういうものが欲しい人はDiCEを使ってくらさい。

  1. ip コマンドで、自サーバの IP アドレスを取得する・・・(A)
  2. dig コマンドで、ドメイン名から IP アドレスを正引きする・・・(B)
  3. (A) と (B) の結果が異なる時だけ、DDNS 更新を実行する
  4. IP アドレスの更新が無い場合でも、7日おきに更新を行う (mydns の仕様)

まず、スクリプト本体の中にIDやパスワードが書かれているのは具合が悪いので、自称セキュリティ対策のため設定ファイルを別に作る。

LOG=ログファイル名
HOST=ドメイン名
URL=DDNS更新サイトのURL
USER=DDNSのユーザーID
PSWD=DDNSのパスワード
OPT="--http-user=$USER --http-password=$PSWD"

※ 「OPT」の部分は wgetで Basic認証を行う場合の wget のオプションどす。
設定情報は、更新スクリプトにコマンドラインの引数として渡す。

ipchk.sh の作成

IP 更新スクリプトの本体を作成します。標準入力から引数「$1」(設定ファイル名)を受け取って、最初に読み込んでおきます。また、WIF (WAN 側 NIC) とログファイルのパスを固定します。

#!/bin/sh
. /root/$1

WIF=ppp0
LOGFILE=/var/log/ddns_"$LOG"_log

# $LOGFILE が存在しないときは、touch で作っておきます。
if [ ! -e $LOGFILE ]; then
	touch $LOGFILE
fi

IPアドレスの取得

DDNSサービスに登録されているIPアドレスと、自機に割り当てられているグローバルアドレスが一致するかを確認します。自機の IP アドレス取得は、ip コマンドから得られる情報を awk で切り取って加工します。

# 現在のグローバルアドレスを取得
WIP=`ip addr show ppp0 | awk '/inet/ {print $2}' | cut -f1 -d "/"'

DDNS に登録されている IP アドレスは、dig コマンドで外部 DNS へ問い合わせます。
+short オプションで IP アドレスのみ取得。

# DDNSアドレスを取得
DDNS=`dig @8.8.8.8 cro-pel.com type=A +short`

IP アドレスの更新

DDNS サービスの提供者の中には、30日(1ヶ月)以上ログイン実績がないと、アカウントを停止する規則を設けているところがあります。IP アドレスが変わっていなくとも、前回の更新から30日が経過していたら、フラグを立てて IP アドレスの更新を行うようにします。

# ログファイルから最終更新日を参照します。
# ログがない場合は、「2001年7月1日」を最終更新日とします。
LUD=$(awk 'END{ print $1 }' $LOGFILE)
if [ "$LUD" == "" ] || [ "$((LUD + 1))" -le 20010701 ]; then
	LUD=20010701
fi

# 最終更新日から指定日数以上経過していたら、$DDNS に "LIMIT OF RELOAD" をセットします。文字列はわかりやすければ何でも良いです。
LUD=$(date --date "$LUD $RATE days" +%s)
if [ "$(date '+%s')" -ge "$LUD" ]; then
	DDNS='LIMIT OF RELOAD'
fi

## ログファイルの最後の行の日付(前回の更新日)を取得します
LUD=`awk 'END{ print $1 }' $LOGFILE`
LMT=$((`date '+%Y%m%d'`-$LUD))

## 30日以上更新していない場合は
## IPアドレスの更新を行う
if [ $LMT -ge 30 ]; then
        DDNS='LIMIT OF RELOAD'
fi

IP アドレスが変わっていたら更新を行います。下記は mydns.jp のログインページに、Basic認証でアクセスする方法です。wget を利用し、ID/PW を送信します。ID/PW は平分で送られてしまいますのであまりお薦めはできませんが。

# IPアドレスの更新を実行
if [ "$WIP" != "$DDNS" ]; then
	wget -q --timeout=60 $OPT $URL
	
	## ログファイルへ日時と変更前IPアドレス、更新後IPアドレスを記録
	echo `date '+%Y%m%d %H:%M:%S'` $DDNS to $WIP >> $LOGFILE
fi

cron サービスへの登録

/etc/crontab へ以下を記述します。15分おきにスクリプトが実行され、IPアドレスに変更があった場合は更新を行います。

## /etc/crontab
*/15	* * * *	root	/root/ipchk.sh cro-pel.conf

ログファイルのローテート

長期運用や回線断が長く続いた場合、ログファイルが肥大することがありますので、logrotate で世代管理し、古いログは削除します。

/var/log/ddns_*_log {
	missingok
	sharedscripts
	rotate 5
	postrotate
	endscript
}