zoneedit と ddclient

zoneedit の dynamic DNS の更新に ddclient (pkgsrc/net/ddcleint) を利用していたのだが、エラーが出て更新できなくなってしまった。

zoneedit のアナウンスとかは見当たらなかったが、どうやら HTTPS でのみ更新が可能なように仕様が変更されたっぽい。

pkgsrc-2014Q1 の ddclient-3.6.6 は SSL が使用できないが、最新版では使用できるらしいとの話を聞きつけて、ddclient-3.8.2 を本家から持ってきて試してみたのだがエラーが出てうまくいかない。

syswrite() on closed filehandle GEN1 at ./ddclient line 1902.
Use of uninitialized value $result in numeric ne (!=) at ./ddclient line 1904.
WARNING:  cannot send to dynamic.zoneedit.com:443 (Bad file descriptor).

デバッグ出力を埋め込んで調べてみると、zoneedit の SSL 証明書の検証ができなくて失敗していることがわかった。

WARNING:  cannot connect to dynamic.zoneedit.com:443 socket: SSL connect attempt failed with unknown error error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed SSL connect attempt failed with unknown error error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed

とはいえ、ブラウザはともかく、NetBSD で SSL ルート証明書の管理などしてない。どうしよう。

結局、検証は行わないように ddclient を修正して対処した。

@@ -1881,8 +1880,9 @@
             Proto => 'tcp',
             MultiHomed => 1,
             Timeout => opt('timeout'),
+            SSL_verify_mode => IO::Socket::SSL::SSL_VERIFY_NONE(),
         );
-           defined $sd or warning("cannot connect to $peer:$port socket: $@ " . IO::Socket::SSL::errstr());
+           fileno($sd) or warning("cannot connect to $peer:$port socket: $@ " . IO::Socket::SSL::errstr());
     } else {
            $sd = IO::Socket::INET->new(
             PeerAddr => $peer,

SSL_VERYFY_NONE は IO::Socket::SSL 内で定義されている定数だが、他所から明示的に参照したいときはサブルーチンのように記述すれば良いらしい。

あと、IPアドレス取得用の URL も https://dynamic.zoneedit.com/checkip.html のように HTTPS しか受け付けなくなってしまった。上記の修正だけでは HTTP で取得しようとしてしまうのだが、ddclient.conf の web の引数に https:// を付けて記述すればよい。

use=web, web=https://dynamic.zoneedit.com/checkip.html, web-skip='IP Address'