FreeDNSに登録しているDNSレコードを更新するDynamicDNSクライアントを作成
はじめに
DynamicDNSサービスに元々MyDNS.JPを使用していましたが、なぜか1レコード分以外のレコードがTXTレコードになってしまい、外部から自宅サーバへアクセスできなくなっていたので、FreeDNSに乗り換えてみました。
手順
前提
DynamicDNSクライアント環境
- sheevaplug(電源プラグ型LinuxPC: FlashROM)
- Ubuntu9.04
- python v2.6
XML API取得
下記のURLにアクセスすると、XML形式でレコード更新用URLが取得できます。
(shaの部分は、登録ユーザ名+パスワードを使用してSHA-1で暗号化した文字列が入ります。)
URL: http://freedns.afraid.org/api/?action=getdyndns&sha=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&style=xml
SHA-1暗号化
暗号化文字列は、username + pipe + passwordをSHA-1で暗号化すればよいようなので、
下記のような関数で暗号化文字列を作成します。
def gethashstr(username, password): import hashlib hashobj = hashlib.sha1() encstr = '|'.join([username, password]) hashobj.update(encstr) hashstring = hashobj.hexdigest() return hashstring
更新用URLの取得
下記のように必要なパラメータを用意して
HASH_ARGO = "sha" TARGET_PARAMS = {'action': "getdyndns", HASH_ARGO: None, 'style': "xml"} TARGET_API = "http://freedns.afraid.org/api/" TIMEOUT = 300
urllib2を使ってDNSレコード更新用URLが記述されているXMLを取得しました。
def request(url, timeout, **params): query = '' for k, v in params.items(): query += '?' if query == '' else '&' query += '{key}={value}'.format(key=k, value=v) url += query import urllib2 print 'Connecting URL: {url} ...'.format(url=url) res = urllib2.urlopen(url=url, timeout=timeout) print 'URL: {url} contents download finished.'.format(url=url) responsetext = res.read() return responsetext TARGET_PARAMS[HASH_ARGO] = gethashstr(hoge, hogepass) response = request(TARGET_API, TIMEOUT, TARGET_PARAMS)
XMLからレコード更新用URL抽出
responsetextに取得したXMLが格納されているとして、XMLから更新用URLを抽出します。
XMLの解析モジュールは、dom,saxとかいろいろあったのですが、xml.etree.ElementTreeが一番簡単でしたので、それを使用しました。
利点
欠点
- XML文字列をそのまま渡すと例外が発生する(ファイルオブジェクトを渡す必要あり)
- しかし、StringIOで渡せば問題なく対処できる。
- 通常のPCサーバであればXMLをtempfileにリダイレクトして渡せばよいと思います。
<root> <item> <host>www.hoge.com</host> <address>71.1.1.1</address> <url>http://freedns.afraid.org/dynamic/update.php?T3faGkljdax==</url> </item> <item> {...} <url>http://freedns.afraid.org/dynamic/update.php?jklIIUadaaa==</url> </item> </root>
def update(responsetext, timeout): from xml.etree.ElementTree import ElementTree from StringIO import StringIO try: # xml.etree.ElementTree requires FileObject output = StringIO(responsetext) tree = ElementTree() tree.parse(output) urls = tree.findall("item/url")