Hurricane Electric Free IPv6 Tunnel Broker 自動アップデートスクリプト
2024年5月5日(日曜日) - 15:16
Client IPv4 Address(自鯖の WAN 側)が変更されたときに、Tunnel Broker をアップデートするためのスクリプト。MyDNS.jp 用に使っている Python スクリプトをちょこっと修正してみた。
アドレスが変わったときの手動アップデートは、Tunnel Broker にログインして自分のトンネルを選択、Advanced タブのところにサンプル URL が表示されているから、これをコピーしてブラウザで表示させればよい。
今回は、この情報をもとに次のスクリプトを cron で定期的に実行し、アドレスに変更があれば更新することにした。元のコードが MyDNS.jp 用だから、定数とかは内容と合致していない。
#!/usr/bin/python3
import codecs
import datetime
import ipaddress
import os
import re
import subprocess
import sys
from datetime import timedelta
#####///// 編集箇所 /////#####
MYPATH = "/usr/local/sbin/mydns/jisaba/" #このpythonスクリプトの配置場所
MASTER_ID = "Login ID" #ログインID
PWD = "Update Key" #アップデートキー
HOSTID = "Tunnel ID" #トンネルID
C_CODE = "utf8" #通知サイトの文字コード(utf8,eucjp等)
LOG_FILE = "update.log" #MYPATH内に記録します。
SAVE_IP = "saveip.txt" #MYPATH内に記録します。
FORCE_UPDATE_TIME = 24 #強制通知間隔を時間単位で指定します。
LOG_FILE_SIZE = 10 #ログファイルの記録数を指定します。
REMOTE_ADDR_CHK = "https://checkip.amazonaws.com" #IPアドレス確認サイト
#####///// ここまで /////#####
### 定数を定義します。
PATTERN = "\d+\.\d+\.\d+\.\d+"
DDNS_UPDATE = "ipv4.tunnelbroker.net/nic/update?hostname="
### 確認サイトから取得した受信データより、現在割り当てられているIPアドレスを抽出します。
current_IP = subprocess.run("curl " + REMOTE_ADDR_CHK , stdout = subprocess.PIPE , shell=True)
currIp = re.search(PATTERN,current_IP.stdout.decode("utf8"))
### ログファイルが"LOG_FILE_SIZE"行を超えていたら1行目を削除します。
if os.path.isfile(MYPATH + LOG_FILE) == True:
line_count = int(subprocess.check_output(["wc", "-l", MYPATH + LOG_FILE]).decode().split(" ")[0])
if (line_count >= LOG_FILE_SIZE):
with open(MYPATH + LOG_FILE,"r") as f:
mylist = f.readlines()
with open(MYPATH + LOG_FILE,"w") as f:
f.writelines(mylist[1:])
### IPアドレスの取得に失敗したときはログを残してプログラムを終了します。
if (currIp and ipaddress.ip_address(currIp.group()).version == 4):
addr4 = currIp.group()
else:
with open(MYPATH + LOG_FILE,"a") as f:
line = datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S")
line += "\tIP Address を取得できませんでした。\n"
f.write(line)
### 強制終了します。
sys.exit()
### 直近で確認したIPアドレスを読み込みます。
line_ip = ("none")
if os.path.exists(MYPATH + SAVE_IP) == True:
with open(MYPATH + SAVE_IP,"r") as f:
for line_ip in f:
dummy = line_ip
### IPアドレス更新ログが無かったら強制通知します。
force_update = False
if os.path.isfile(MYPATH + LOG_FILE) == True:
line_count = int(subprocess.check_output(["wc", "-l", MYPATH + LOG_FILE]).decode().split(" ")[0])
with open(MYPATH + LOG_FILE,"r") as f:
lines = f.readlines()
c = 1
while c <= line_count:
if ("IP Address を通知しました。") in lines[line_count - c]:
log_date = re.match("\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}",lines[line_count -c]).group()
break
c += 1
else:
### 更新成功ログが残っていなかった場合は強制通知フラグが立ちます。
log_date = "2000/01/01 00:00:00"
### LOG_FILEそのものが無かったら"2000/01/01 00:00:00"を書き込んでファイルを作成します。
else:
with open(MYPATH + LOG_FILE,"w") as f:
log_date = "2000/01/01 00:00:00"
f.write(log_date + "\n")
### 強制通知間隔を経過したら強制通知フラグを立てます。
td = datetime.datetime.today() - datetime.datetime.strptime(log_date, "%Y/%m/%d %H:%M:%S")
time_delta = td.total_seconds() / 3600
if (time_delta >= FORCE_UPDATE_TIME):
force_update = True
### IPアドレスの更新通知処理です。
if (addr4 != line_ip or force_update == True):
cmd = "curl '"
cmd += "https://"
cmd += MASTER_ID
cmd += ":" + PWD
cmd += "@" + DDNS_UPDATE + HOSTID + "'"
ret = subprocess.run(cmd , stdout = subprocess.PIPE , shell=True)
### cmdの実行に成功した時の処理です。
if (addr4) in ret.stdout.decode(C_CODE):
with open(MYPATH + SAVE_IP,"w") as f:
f.write(addr4)
with open(MYPATH + LOG_FILE,"a") as f:
line = datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S')
line += "\tIP Address を通知しました。[" + addr4 + "]\n"
f.write(line)
### cmdの実行に失敗した時の処理です。
else:
with open(MYPATH + LOG_FILE,"a") as f:
line = datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S')
line += "\tIP Address の通知に失敗しました。\n"
f.write(line)
コードを ChatGPT でチェックすると幾つか改善点を提案してくれた。が、自分専用ということもあるし、このまま使用する。
/etc/cron.d/ に保存したファイルはこちら。15 分間隔で WAN 側アドレスをチェックして、変更があったら通知する。
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=""
*/15 * * * * root /usr/local/sbin/mydns/jisaba/tunnel_broker /dev/null 2>&1