最新版はこちらの記事
あわせて読みたい
Python3でアドレス自動通知:ver2.1
ieServer はサービス終了したみたいだし、他にもいくつか自宅のグローバル IP アドレスを確認できるサイトがあるから、今まで自前チェック用に使用していた無料レンタル...
次の環境で動作確認済み。
- Ubuntu 18.04
- Python 3.6.9
- wget 1.19.4
- wc 8.28
クリックで展開
#!/usr/bin/python3
import codecs
import datetime
import ipaddress
import os
import re
import subprocess
import sys
from datetime import datetime
from datetime import timedelta
#####///// 編集箇所 /////#####
MYPATH = "/usr/local/sbin/mydns/" #このpythonスクリプトの配置場所
MASTER_ID = "mydns999999" #マスターID
PWD = "AAAaaa99999" #パスワード
C_CODE = "utf8" #通知サイトの文字コード(utf8,eucjp等)
LOG_FILE = "update.log" #MYPATH内に記録します。
SAVE_IP = "saveip.txt" #MYPATH内に記録します。
FORCE_UPDATE_TIME = 24 #強制通知間隔を時間単位で指定します。
LOG_FILE_SIZE = 20 #ログファイルの記録数を指定します。
#####///// ここまで /////#####
#####///// 環境に応じて1つ有効化して下さい /////#####
REMOTE_ADDR_CHK = "https://www.cman.jp/network/support/go_access.cgi"
#REMOTE_ADDR_CHK = "http://ieserver.net/ipcheck.shtml"
#####///// ここまで /////#####
### 定数を定義します。
PATTERN = "\d+\.\d+\.\d+\.\d+"
DDNS_UPDATE = "www.mydns.jp/login.html"
### 確認サイトから取得した受信データより、現在割り当てられているIPアドレスを抽出します。
current_IP = subprocess.run("wget -q -O - " + 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.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.today() - 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 = "wget -q -O - '"
cmd += "https://"
cmd += MASTER_ID
cmd += ":" + PWD
cmd += "@" + DDNS_UPDATE + "'"
ret = subprocess.run(cmd , stdout = subprocess.PIPE , shell=True)
### cmdの実行に成功した時の処理です。
if ("Login and IP address notify OK.") 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.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.now().strftime('%Y/%m/%d %H:%M:%S')
line += "\tIP Address の更新に失敗しました。\n"
f.write(line)
クリックで展開
#!/usr/bin/python3
import codecs
import datetime
import ipaddress
import os
import re
import subprocess
import sys
from datetime import datetime
from datetime import timedelta
#####///// 編集箇所 /////#####
MYPATH = "/usr/local/sbin/ieserver/" #このpythonスクリプトの配置場所
SUBDOMAIN_NAME = "subdomain" #サブドメイン名
DOMAIN_NAME = "dip.jp" #ドメイン名
PWD = "AAAAA99999" #パスワード
C_CODE = "eucjp" #通知サイトの文字コード(utf8,eucjp等)
LOG_FILE = "update.log" #MYPATH内に記録します。
SAVE_IP = "saveip.txt" #MYPATH内に記録します。
FORCE_UPDATE_TIME = 24 #強制通知間隔を時間単位で指定します。
LOG_FILE_SIZE = 20 #ログファイルの記録数を指定します。
#####///// ここまで /////#####
#####///// 環境に応じて1つ有効化して下さい /////#####
REMOTE_ADDR_CHK = "http://ieserver.net/ipcheck.shtml"
#REMOTE_ADDR_CHK = "https://www.cman.jp/network/support/go_access.cgi"
#####///// ここまで /////#####
### 定数を定義します。
PATTERN = "\d+\.\d+\.\d+\.\d+"
DDNS_UPDATE = "http://ieserver.net/cgi-bin/dip.cgi"
### 確認サイトから取得した受信データより、現在割り当てられているIPアドレスを抽出します。
current_IP = subprocess.run("wget -q -O - " + 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.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.today() - 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 = "wget -q -O - '"
cmd += DDNS_UPDATE + "?username=" + SUBDOMAIN_NAME
cmd += "&domain=" + DOMAIN_NAME
cmd += "&password=" + PWD
cmd += "&updatehost=1'"
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.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.now().strftime('%Y/%m/%d %H:%M:%S')
line += "\tIP Address の更新に失敗しました。\n"
f.write(line)
今のところieServerで登録しているドメインはテスト用非公開サーバーとMyDNSへのリダイレクトだけ。それでも更新だけはとりあえず定期的に実行している。
で、以前に作ったスクリプトを改良してみた。
ヘボいコードで本当はもっと効率的に書けるのは間違いないだろうけど、とりあえず思った通りに動作するから良しとしよう。
ということで、大したことではないけど次の3つを追加した。
目次
前回更新成功から一定時間を経過したら強制通知する。
これまでは、IPアドレスの状態を確認して変更があれば通知するスクリプトと、定時に強制的に通知するスクリプトの2つをcronで実行していた。
見直したのはタイトルのとおり、保存しているログをチェックして、前回更新に成功してから一定時間を経過していたら強制通知することにした。なので、cronの実行スクリプトは1つだけになった。
ログファイルの肥大化防止
ログに残すのは「更新成功」「更新失敗」「IPアドレス取得失敗」の3種類とした。スクリプトを実行して、このうちどれかをログに書き出すようなときは古いログを1行削除することにして、ログの記録数の上限を設定した。
数百行とかのログを残してもあまり意味が無いけど、例えば10分間隔でチェックしてて、IPアドレスチェックサイトの障害なんかで取得に毎回失敗するようなときは、1日で144回の「IPアドレス取得失敗」のログが残ることになる。
IPアドレスが頻繁に変更することもないし色々無駄なので10~20行程度でも十分かな。
IPアドレス更新チェック
自宅のグローバルIPアドレスを確認するサイトからの受信データにはIPアドレス以外の情報も混じっているから、IPアドレスだけを抽出することにした。これで、IPアドレス確認サイトでもチェックできるから、ieServerのIPアドレス確認画面だけに頼らなくても大丈夫。
どのサイトも長期間にわたってアクセスできなくなるような事態にはならないだろうと勝手に理解して、2つのサイトで照合するようなことはしていない。
ただ、あまりにも頻繁に更新チェックしていると不正アクセスとして締め出されるかもしれないのでご注意を。(この自鯖サイトは無料レンタルサーバーを使ってIPアドレスチェックを実施中。)
あわせて読みたい
アクセス情報【使用中のIPアドレス確認】
あなたのアクセスしているIPアドレス情報などをENVとJavaScriptで取得し表示します。あなたのIPアドレスからポート疎通・ping疎通・DNS索引・WHOIS情報も取得できます。
ファイルのオープン、読み込み、最初の1行削除、書き出し、ファイルのクローズと、一連の動作が4行で書けるのは少し感動。
IPアドレスを正規表現で抽出する方法が結局判らなかった。次のようなよく見かける表記だと、最後の3桁だけ、上位2桁しかマッチしてくれない・・・。
(([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]).){3}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])
WEB ARCH LABO
正規表現チェッカー | WEB ARCH LABO
正規表現チェッカーは、指定した正規表現がどのようにマッチするのかを検証・可視化するための開発補助ツールです。
コメント