EdgeRouterでのDDNS更新

EdgeRouterにはbuilt-inのDDNSクライアントであるddclientがあって、簡単にDDNSのアドレスの更新を行うことができます。しかしながら、EdgeRouterのDDNS機能、ひいてはddclientの使い方の解説があまり豊富でなく、自分では特にIPv6絡みで苦労しましたので、ここに纏めてみることとします。なお、EdgeRouterのfirmwareはv1.10.9でテストをしています。

Dyn(有料)のDDNS更新

Dyn(有料)のDDNS更新方法での調査結果をベースに、具体的な設定方法を書きます。

IPv4(Aレコード)の更新

IPv4の更新は公式の説明「EdgeRouter – Built-in Dynamic DNS」通りに設定すればOKです。PPPoEで取得したIPv4の更新の場合には以下となります。

set service dns dynamic interface pppoe0 service dyndns host-name xxx.xxx.xxx
set service dns dynamic interface pppoe0 service dyndns login xxxxx
set service dns dynamic interface pppoe0 service dyndns password xxxxx

IPv6(AAAAレコード)の更新

switch0にIPv6のグローバルアドレスを割り当てている場合には、取り合えず以下の設定をして強制更新をすることでIPv6(AAAAレコード)の更新は可能です。

set service dns dynamic interface switch0 service dyndns host-name xxx.xxx.xxx
set service dns dynamic interface switch0 service dyndns login xxxxx
set service dns dynamic interface switch0 service dyndns options ipv6=yes
set service dns dynamic interface switch0 service dyndns password xxxxx
set service dns dynamic interface switch0 web checkipv6.dyndns.com

$ update dns dynamic interface switch0

ただし、 別サイトの「EdgeRouter X の DDNS で Cloudflare DNS の IPv6 アドレスを更新させる」で詳しく解説されているように、perlのライブラリの追加インストールが必要になります。なお、上記設定では再起動時にIPv6アドレス変更があった場合に自動更新されない等、実用的に使い物になりませんので、オススメしません。後述するスクリプトを用いたDDNS更新方法がオススメです。

なお公式サイト上説明がありませんが、Firmwareのバージョンがv1.10.0やv1.10.3ではIPv6の更新の際には、ddclientで

usev6=if, if=eth0

といったパラメータ指定が可能でしたが、v1.10.9やv2.0.4ではusev6のオプションがなくなっており、ipv6オプションに変更されました。なので、最近のFirmwareではusev6の指定はエラーとなりますので、注意して下さい。

スクリプトを用いたDDNSの更新

ddclient自体の制約(IPv4とIPv6を同時に更新できない)、EdgeRouterの新機能開発が停滞していることを考えれば、IPv6のDDNS更新がCLIを通じて可能になる見込みは薄いです。こういう場合には、EdgeRouter自体がLinuxで動いていることを活かして、スクリプトを作って対処するのがEdgeRouter流でしょうか。

DynでIPv4(Aレコード)とIPv6(AAAAレコード)を同時更新するスクリプト

以下のようにDDNS更新スクリプトを作成します。/config以下のフォルダはファームアップデート時に消されないようなので、/config/user-dataに「ddns-update.sh」という名前でDDNSアップデートスクリプトを保存します。赤字部分はそれぞれの環境に応じて変更します。ここでは、IPv4はpppoe0、IPv6はswitch0で取得されていると仮定しています。

$ sudo vi /config/user-data/ddns-update.sh

#!/bin/bash

username='xxxxx'
updater_client_key='xxxxx'
hosts='xxx.xxx.xxx'
updateurl="https://${username}:${updater_client_key}@members.dyndns.org/v3/update?hostname=${hosts}&myip="

if_ipv4=pppoe0
if_ipv6=switch0

file_last_ipv4='/config/user-data/last_ipv4'
file_last_ipv6='/config/user-data/last_ipv6'

current_ipv4=$(ip -4 addr show dev $if_ipv4 scope global | grep inet | awk '{print $2}')
current_ipv6=$(ip -6 addr show dev $if_ipv6 scope global | grep inet6 | awk '{print $2}' | awk -F/ '{print $1}')
if [[ -z $current_ipv4 && -z $current_ipv6 ]]; then
    exit 1
fi

if [ -f $file_last_ipv4 ]; then
    last_ipv4=$(cat $file_last_ipv4)
fi
if [ -f $file_last_ipv6 ]; then
    last_ipv6=$(cat $file_last_ipv6)
fi
if [[ $last_ipv4 != $current_ipv4 || $last_ipv6 != $current_ipv6 || $(find $file_last_ipv4 -mmin +10080) || $1 = '-force' ]]; then
    curl "${updateurl}${current_ipv4},${current_ipv6}"
    logger "ddns-update.sh IPv4=$current_ipv4 IPv6=$current_ipv6"
    echo $current_ipv4 > $file_last_ipv4
    echo $current_ipv6 > $file_last_ipv6
fi

このスクリプトに実行権限を与えます。

$ sudo chmod 755 /config/user-data/ddns-update.sh

このスクリプトを、5分毎に自動実行するようにconfigを設定します。

$ configure
# set system task-scheduler task ddns-update executable path /config/user-data/ddns-update.sh
# set system task-scheduler task ddns-update interval 5m
# commit; save

これで5分毎にIPv4又はIPv6に変化があれば、DDNSの更新が行われるようになります。なお、スクリプトでは$(find $file_last_ipv4 -mmin +10080)の部分で最終更新から1週間以上経過しているかのチェックも行っており、1週間IPv4、IPv6に変化がなかったとしても念のため強制更新するようにしています。

スクリプトの解説

file_last_ipv4='/config/user-data/last_ipv4'
file_last_ipv6='/config/user-data/last_ipv6'

IPv4とIPv6のアドレスは、/config/user-data/の下にlast_ipv4、last_ipv6というファイル名で保存するようにしています。5分毎に現在のアドレスとこのファイルのアドレスを比較して、変化があれば更新する仕組みです。

current_ipv4=$(ip -4 addr show dev $if_ipv4 scope global | grep inet | awk '{print $2}')

現在のIPv4を取得し、変数current_ipv4にセットします。以下のようにipコマンドでIPv4のグローバルアドレスが取得可能です。

$ ip -4 addr show dev pppoe0 scope global
9: pppoe0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1492 qdisc pfifo_fast state UNKNOWN group default qlen 100
    inet 193.151.241.104 peer 118.23.38.243/32 scope global pppoe0
       valid_lft forever preferred_lft forever

よってこれから太字部分を抽出すればよいわけですが、該当行にはinetという文字列が含まれるのでそれでgrepをし絞り込みをかけます。

$ ip -4 addr show dev pppoe0 scope global | grep inet
    inet 193.151.241.104 peer 118.23.38.243/32 scope global pppoe0

これをスペース区切りで2番目の文字列がIPv4アドレスになるので、awkで2番目の要素を抽出します。

$ ip -4 addr show dev pppoe0 scope global | grep inet | awk '{print $2}'
193.151.241.104

最終的に、シェルでの実行結果に置換する処理(コマンド置換=command substitution)である$( )で変数current_ipv4にIPv4のグローバルアドレスがセットされることになります。

IPv6のグローバルアドレス取得もほぼ同じです。

current_ipv6=$(ip -6 addr show dev $if_ipv6 scope global | grep inet6 | awk '{print $2}' | awk -F/ '{print $1}')

現在のIPv6アドレスを取得し、変数current_ipv6にセットします。現在のIPv6アドレスは以下のipコマンドで取得可能です。

$ ip -6 addr show dev switch0 scope global
2: switch0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qlen 1000
    inet6 2408:21:b80:6e40::1/64 scope global 
       valid_lft forever preferred_lft forever

よってこれから太字部分を抽出すればよいわけですが、該当行にはinet6という文字列が含まれるのでそれでgrepをし絞り込みをかけます。

$ ip -6 addr show dev switch0 scope global | grep inet6
    inet6 2408:21:b80:6e40::1/64 scope global

これをスペース区切りで2番目の文字列がIPv6アドレスになるので、awkで2番目の要素を抽出します。

$ ip -6 addr show dev switch0 scope global | grep inet6 | awk '{print $2}'
2408:21:b80:6e40::1/64

「/64」が不要なので、/で区切ったとして1番目の要素をさらにawkで抽出します。

$ ip -6 addr show dev switch0 scope global | grep inet6 | awk '{print $2}' | awk -F/ '{print $1}'
2408:21:b80:6e40::1

これでIPv6のグローバルアドレスを取得できました。最終的に$( )で変数current_ipv6にIPv6のグローバルアドレスをセットします。

if [[ -z $current_ipv4 && -z $current_ipv6 ]]; then
    exit 1
fi

変数current_ipv4、変数current_ipv6の両方が空文字列であればスクリプトを終了します。両方が空というのは、IPv4とIPv6の現在のアドレスが両方とも取得できなかった時を意味します。この時はDDNS更新が出来ないので、終了することになります。

if [ -f $file_last_ipv4 ]; then
    last_ipv4=$(cat $file_last_ipv4)
fi
if [ -f $file_last_ipv6 ]; then
    last_ipv6=$(cat $file_last_ipv6)
fi

[-f $file_last_ipv4]は、ファイル/config/user-data/last_ipv4が存在するかを判定するものです。存在すればそのファイルから変数last_ipv4に前回更新時のIPv4アドレスを取得します。IPv6についても同様です。

if [[ $last_ipv4 != $current_ipv4 || $last_ipv6 != $current_ipv6 || $(find $file_last_ipv4 -mmin +10080) || $1 = '-force' ]]; then

これは「前回更新時のIPv4から変化がある」または「前回更新時のIPv6から変化がある」または「前回更新時から1週間(60分×24時間×7日=10080分)経過している」かを判定するもので、この条件の何れかに合致すればDDNSの更新処理を行います。

    curl "${updateurl}${current_ipv4},${current_ipv6}"

実際のDDNS更新処理です。DDNSの更新は特定のURLでHTTP or HTTPSアクセスするだけで行えますので、curlコマンドでIPv4やIPv6のアドレスを引数にして指定のページにHTTP(S)アクセスします。

    logger "ddns-update.sh IPv4=$current_ipv4 IPv6=$current_ipv6"
    echo $current_ipv4 > $file_last_ipv4
    echo $current_ipv6 > $file_last_ipv6

更新時にログに記録し、更新したアドレスをファイルに記録します。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です