ひかり電話 HGW PR-600MI(PR-S300SEも同じ)は、NTT-GWのDHCPv6relayを介してDHCPv6サーバーより56ビット長のプレフィックスが委譲される。委譲されたプレフィックス「AAAA:BBBB:XXXX:YY00::/56」を16分割し、「AAAA:BBBB:XXXX:YY10::/60」から「AAAA:BBBB:XXXX:YYF0::/60」の15プレフィックスをDHCPv6-PDサーバーとして再委譲する。Prefix「AAAA:BBBB:XXXX:YY00::/64」をLAN側にRAし、インターフェースアドレスをSLAAC(StateLess Address Auto Configuration)設定する。またPrefix「AAAA:BBBB:XXXX:YY01::/64」のSLAACをLAN側インターフェースに設定し、DNSパケットのソースアドレスとしている。
PR-600MIのDHCPv6サーバーは、「Valid Life Time(14400秒)」を超えて「renew/rebind」がされないとリース情報がクリアされ、新たなクライアントのリース対象となる。また、PR-600MIの再起動で、全てのリース情報がクリアされる。再起動やプレフィックス変更時には、「reconfigure」が発行される。
現在「2409:10:XXXX:YY00::/56」のプレフィックスが委譲されており、NVR510に「2409:10:XXXX:YY10::/60」、OpenWrtに「2409:10:XXXX:YY20::/60」と「2409:10:XXXX:YY30::60」、NVR500に「2409:10:XXXX:YY40::/60」が委譲されている。PR-600MIの再起動が発生すると、DHCPv6サーバーからの「reconfigure」メッセージにより各ルータが再取得を行うが、早いもの順でprefixが取得されるため、設定が変更されてしまう(「ひかり電話 HGW PR-600MIのfirmware更新とIPv6パケットフィルターの不具合」)。UPSなどでシャットダウンからの起動でもprefix設定が変更されてしまう(「APC SMT500J にSynology DS216J (USB)とDebian10(Serial)から同時接続」)。
(1)PR-600MIのDHCPv6 サーバー機能
「IP通信網サービスのインターフェース 第三分冊」の「2.4.2.1.4 DHCPv6 における DUID 生成方式」で「DUID-LL」の使用が定義されている。リースデータの有効時間(取得値)は、下記の通り。仕様では、NTT-GWからRA(Router Advertisement)が発行されるように読めるが、PR-600MIがRS(Router Solicit)を発行してもNTT-GWは応答しない(ひかり電話契約)。
LAN側に接続されたルータからのRSに対して、Prefix=2409:10:XXXX:YY00::/64でOther Flag=1のRAが送出される。
(2)PR-600MIのDHCPv6サーバーの確認
「DUID-LL」の使用を指定されているが、「DUID-LLT」で接続する機器も存在するので両方確認してみた(RFC3315#section9)。
あ)確認方法
Debian10(ISC dhclient)は、クライアントIDを設定ファイルに記述、OpenWrt(odhcp6c)は、クライアントIDを引数指定で行う。LLTの時刻は、2000年1月1日0時0分UTC基準で秒数指定するがDebian10(Linux)のdateコマンドは、1970年1月1日0時0分UTCが基準のため下記変換スクリプトで算出した。LL及びLLTのクライアントID値は、下記の通り。DHCPv6クライアントは、Debian10のISC dhclientとOpenWrtのodhcp6cで行った。
dhclientの場合odhcp6cの場合
い)確認結果
PR-600MI(PR-S300SEを含む)は、DUIDにLLTを使用してもPrefixの委譲を受けられる。LLT時刻の異なる二つのクライアントIDを使い、一つのデバイスから二つのPrefix「2409:10:XXXX:YY30::/60」と「2409:10:XXXX:YY50::/60」を取得した時のPR-600MI「情報」「DHCPv6サーバ払い出し状況」
同一デバイス(MAC アドレスが同じ)だと最後のリース情報だけが表示される。リース数も表示されたリース数となる。「2409:10:XXXX:YY30::/60」のリース情報が表示されないが、リースされている。この状態でMACアドレスが異なるクライアントIDでPrefix Delagationを行うと、「2409:10:XXXX:YY30::/60」がリース中のため「2409:10:XXXX:YY60::/60」がリースされる。
LLTのクライアントIDで時刻を変えた12個のPrefix取得例
12個のPrefixの内、最後の「2409:10:XXXX:YYf0::/60」だけが表示され、リース個数も「4/15」と表示されるが、12個のPrefixがリースされた状態。
LLのクライアントIDでMACアドレスを変えた12個のPrefix取得例
12個のPrefixが全て表示され、リース個数も「15/15」と表示される。
PrivateネットワークなのでMACアドレスが重ならないように最終アドレスを変化させてPrefixを取得するのが良さそう。
う)リースされたPrefixの経路情報
PR-600MIがリースしたPrefixの経路情報は、指定したMACアドレス宛てと推定していたが、Prefix要求元のインターフェースアドレスとなる。(い)で取得したPrefixのアドレスをインターフェースに設定し、他端末からpingで確認した。「renew」「rebind」などは、クライアントIDが同じであれば、Prefix要求元のインターフェース以外からも更新が可能。NVR500/510のDHCPv6クライアントは、「release」指定が出来ない。他端末からNVR500/510のクライアントID(LL)で「release」が可能(LLTだと時刻の推定が難しい。パケットキャプチャで確認する必要がある)。経路情報をNVR500/510に向けるには、NVR500/510自身がPrefix取得を行う必要がある。
(3)任意のPrefixを取得する
ルータ機器が下記Prefixを取得できるよう制御する
PR-600MIの再起動後、NVR500, NVR510, OpenWrtの取得したPrefixを全て「release」させる。その後、NVR510, OpenWrt, NVR500の順にPrefixを再取得させる。
NVR500/510は、「ヤマハ NVR510 / NVR500 のDHCPv6-PDをCUSTOM-GUIで再取得させる」で再取得させる(「NVR510 / NVR500 のDHCPv6-PDをリモートで再取得させる」でも良い)。OpenWrtなどのLinux機は、「ssh」(公開鍵認証)によりコマンド実行で再取得させる。
PR-600MIのLAN側に接続されたDebian10クライアント端末からスクリプト実行によるDHCPv6-PDの再取得NVR510, OpenWrt, NVR500のリースをreleaseさせ、NVR510, OpenWrtで再取得を実行させる。NVR500の前に「2409:10:XXXX:YY30::/60」をスクリプト実行機でDumy取得し、その後にNVR500に再取得させる。Dummy取得したPrefixは、releaseしないでdhclientを終了させるので、Valid Lifetime後に解放される。dhclientを終了させなければ、定期的に「renew/rebind」がされ取得したPrefixを確保する事ができる。NVR510/500では難しいが、OpenWrtなどのLinux機であれば、取得するPrefix毎に異なるクライアントIDを使用すれば、1台のゲートウェイで複数のPrefix委譲を受ける事ができる。
PR-600MIのLAN側に接続したOpenWrtルータ上でDHCPv6-PDの再取得用スクリプトOpenWrtは、wget名のツールがインストールされているが「busybox」のwget相当ツールの為か、「--post-data=」の内容が正常に反映されなかった(OpenWrt 19.07.4)。「GNU Wget 1.20.3」をインストールして確認した。
(4)課題
PR-600MIが再起動した時にDHCPv6-PDの再取得用スクリプト実行の自動化。
現在は、手動実行なので、PR-600MIのDHCPv6から「reconfigure」メッセージを受信し、設計通りのPrefix設定が出来なかったら再取得のスクリプトを実行する。
PR-600MIのDHCPv6サーバーは、「Valid Life Time(14400秒)」を超えて「renew/rebind」がされないとリース情報がクリアされ、新たなクライアントのリース対象となる。また、PR-600MIの再起動で、全てのリース情報がクリアされる。再起動やプレフィックス変更時には、「reconfigure」が発行される。
現在「2409:10:XXXX:YY00::/56」のプレフィックスが委譲されており、NVR510に「2409:10:XXXX:YY10::/60」、OpenWrtに「2409:10:XXXX:YY20::/60」と「2409:10:XXXX:YY30::60」、NVR500に「2409:10:XXXX:YY40::/60」が委譲されている。PR-600MIの再起動が発生すると、DHCPv6サーバーからの「reconfigure」メッセージにより各ルータが再取得を行うが、早いもの順でprefixが取得されるため、設定が変更されてしまう(「ひかり電話 HGW PR-600MIのfirmware更新とIPv6パケットフィルターの不具合」)。UPSなどでシャットダウンからの起動でもprefix設定が変更されてしまう(「APC SMT500J にSynology DS216J (USB)とDebian10(Serial)から同時接続」)。
(1)PR-600MIのDHCPv6 サーバー機能
「IP通信網サービスのインターフェース 第三分冊」の「2.4.2.1.4 DHCPv6 における DUID 生成方式」で「DUID-LL」の使用が定義されている。リースデータの有効時間(取得値)は、下記の通り。
LAN側
T1 = 6300秒(renew)
T2 = 10800秒(rebind)
Preferred Life Time = 12600 秒
Valid Life Time = 14400 秒
LAN側に接続されたルータからのRSに対して、Prefix=2409:10:XXXX:YY00::/64でOther Flag=1のRAが送出される。
(2)PR-600MIのDHCPv6サーバーの確認
「DUID-LL」の使用を指定されているが、「DUID-LLT」で接続する機器も存在するので両方確認してみた(RFC3315#section9)。
あ)確認方法
Debian10(ISC dhclient)は、クライアントIDを設定ファイルに記述、OpenWrt(odhcp6c)は、クライアントIDを引数指定で行う。LLTの時刻は、2000年1月1日0時0分UTC基準で秒数指定するがDebian10(Linux)のdateコマンドは、1970年1月1日0時0分UTCが基準のため下記変換スクリプトで算出した。
date-d2s '2021/4/1 00:00:00 UTC'
#!/bin/sh
D70=`date --date="$1" +%s`
D2K=`date --date='2000/1/1' +%s`
printf '%x¥n' $(($D70-$D2K))
クライアントID
インターフェースのMAC address = 34:76:c5:57:0b:00
時刻(2021/4/1 00:00:00 UTC) = 27:f8:48:10
クライアントID(LLT) = 00:01:00:01:27:f8:48:10:34:76:c5:57:0b:00
クライアントID(LL) = 00:03:00:01:34:76:c5:57:0b:00
(OpenWrtのodhcp6cでは、「:」を記載せず指定)
dhclientの場合
ISC dhclient
#Prefix取得
dhclient -6 -P -cf vaio-00.conf -pf vaio-00.pid -lf vaio-00.enp3s0.leases enp3s0
#releaseしないで終了
dhclient -6 -x -P -cf vaio-00.conf -pf vaio-00.pid -lf vaio-00.enp3s0.leases enp3s0
#releaseして終了
dhclient -6 -r -P -cf vaio-00.conf -pf vaio-00.pid -lf vaio-00.enp3s0.leases enp3s0
---- vaio-00.conf ----
interfaces "enp3s0" {
also request dhcp6.sntp-servers, dhcp6.sip-servers-addresses;
send dhcp6.client-id 00:01:00:01:27:f8:48:10:34:76:c5:57:0b:00
}
OpenWrt
#Prefix取得
/usr/sbin/odhcp6c -k -P0 -c0001000127f848103476c5570b00 -s odhcp6c-script -d odhcp6c-pid eth1
kill `cat odhcp6c-pid`
#releaseして終了
/usr/sbin/odhcp6c -P0 -c0001000127f848103476c5570b00 -s odhcp6c-script -d odhcp6c-pid eth1
kill `cat odhcp6c-pid`
---- odhcp6c-script ---
#!/bin/sh
logger -t "odhcp6c-script" -s " Prefix=$PREFIXES Clinet-ID=$OPTION_1"
PR-600MI(PR-S300SEを含む)は、DUIDにLLTを使用してもPrefixの委譲を受けられる。LLT時刻の異なる二つのクライアントIDを使い、一つのデバイスから二つのPrefix「2409:10:XXXX:YY30::/60」と「2409:10:XXXX:YY50::/60」を取得した時のPR-600MI「情報」「DHCPv6サーバ払い出し状況」
同一デバイス(MAC アドレスが同じ)だと最後のリース情報だけが表示される。リース数も表示されたリース数となる。「2409:10:XXXX:YY30::/60」のリース情報が表示されないが、リースされている。この状態でMACアドレスが異なるクライアントIDでPrefix Delagationを行うと、「2409:10:XXXX:YY30::/60」がリース中のため「2409:10:XXXX:YY60::/60」がリースされる。
LLTのクライアントIDで時刻を変えた12個のPrefix取得例
12個のPrefixの内、最後の「2409:10:XXXX:YYf0::/60」だけが表示され、リース個数も「4/15」と表示されるが、12個のPrefixがリースされた状態。
LLのクライアントIDでMACアドレスを変えた12個のPrefix取得例
12個のPrefixが全て表示され、リース個数も「15/15」と表示される。
PrivateネットワークなのでMACアドレスが重ならないように最終アドレスを変化させてPrefixを取得するのが良さそう。
う)リースされたPrefixの経路情報
PR-600MIがリースしたPrefixの経路情報は、指定したMACアドレス宛てと推定していたが、Prefix要求元のインターフェースアドレスとなる。(い)で取得したPrefixのアドレスをインターフェースに設定し、他端末からpingで確認した。
ip address add 2409:10:XXXX:YYf0::1 dev enp3s0
ping -6 2409:10:XXXX:YYf0::1
(3)任意のPrefixを取得する
ルータ機器が下記Prefixを取得できるよう制御する
NVR510 「2409:10:XXXX:YY10::/60」
OpenWrt 「2409:10:XXXX:YY20::/60」
NVR500 「2409:10:XXXX:YY40::/60」
NVR500/510は、「ヤマハ NVR510 / NVR500 のDHCPv6-PDをCUSTOM-GUIで再取得させる」で再取得させる(「NVR510 / NVR500 のDHCPv6-PDをリモートで再取得させる」でも良い)。OpenWrtなどのLinux機は、「ssh」(公開鍵認証)によりコマンド実行で再取得させる。
PR-600MIのLAN側に接続されたDebian10クライアント端末からスクリプト実行によるDHCPv6-PDの再取得
Debian10
---- RebindAllISC ----
#!/bin/shbash
# for ISC DHCP
ID1="NVR510"
ID2="OpenWrt"
ID3="Dummy"
ID4="NVR500"
PTH="/home/dhcp"
DHCPV6CL="/usr/sbin/dhclient -6 -P "
#----
CID="$ID1 $ID2 $ID3 $ID4"
IF="enp3s0"
CUSTOMAPI="custom/api?password=JYUMON"
# release all prefix
for CL in $CID; do
$DHCPV6CL -cf "$PTH/$CL.conf" -pf "$PTH/$CL.pid" -lf "$PTH/$CL.$IF.leases" $IF
$DHCPV6CL -r -cf "$PTH/$CL.conf" -pf "$PTH/$CL.pid" -lf "$PTH/$CL.$IF.leases" $IF
done
echo "Released all"
# rebind NVR510 for #1
if echo -n $CID | grep "$ID1" >/dev/null; then
wget -q -O- --post-data=$'syslog debug on\r\nipv6 lan2 dhcp service client' http://nvr510-lan2.familynae/$CUSTOMAPI
while [ "$pf" = "" ]; do
sleep 1
pf=`wget -q -O- --post-data="show status ipv6 dhcp" http://nvr510-lan2.familyname/$CUSTOMAPI | grep prefix | sed 's/ *prefix: //'`
done
wget -q -O- --post-data="syslog debug off" http://nvr510-lan2.familyname/$CUSTOMAPI >/dev/null
echo "Bind #1"
fi
# rebind OpenWrt for #2
if echo -n $CID | grep "$ID2" >/dev/null; then
ssh root@openwrt.familyname ubus call network.interface.wan6 renew
echo "Bind #2"
fi
# rebind Dummy for #3
if echo -n $CID | grep "$ID3" >/dev/null; then
$DHCPV6CL -cf "$PTH/$ID3.conf" -pf "$PTH/$ID3.pid" -lf "$PTH/$ID3.$IF.leases" $IF
$DHCPV6CL -x -cf "$PTH/$ID3.conf" -pf "$PTH/$ID3.pid" -lf "$PTH/$ID3.$IF.leases" $IF
echo "Bind #3"
fi
# rebind NVR500 for #4
if echo -n $CID | grep "$ID4" >/dev/null; then
wget -q -O- --post-data=$'syslog debug on\r\nipv6 lan2 dhcp service client' http://nvr500-lan2.familyname/$CUSTOMAPI >/dev/null
while [ "$pf" = "" ]; do
sleep 1
pf=`wget -q -O- --post-data="show status ipv6 dhcp" http://nvr500-lan2.familyname/$CUSTOMAPI 2>/dev/null | grep prefix | sed 's/ *prefix: //'`
done
wget -q -O- --post-data="syslog debug off" http://nvr500-lan2.familyname/$CUSTOMAPI >/dev/null
echo "Bind #4"
fi
-------- dhclient用設定ファイル --------
---- nvr510.conf ----
interface "enp3s0" {
also request dhcp6.sntp-servers, dhcp6.sip-servers-addresses;
send dhcp6.client-id 00:03:00:01:ac:44:f2:AA:BB:CC; #nvr510 WAN
}
---- OpenWrt.conf ----
interface "enp3s0" {
also request dhcp6.sntp-servers, dhcp6.sip-servers-addresses;
send dhcp6.client-id 00:03:00:01:00:1d:73:34:45:56; #openwrt WAN
}
---- Dummy.conf ----
interface "enp3s0" {
also request dhcp6.sntp-servers, dhcp6.sip-servers-addresses;
send dhcp6.client-id 00:03:00:01:00:1d:73:34:45:57; #Dummy
}
---- nvr500.conf ----
interface "enp3s0" {
also request dhcp6.sntp-servers, dhcp6.sip-servers-addresses;
send dhcp6.client-id 00:03:00:01:00:a0:de:AA:BB:DD; #nvr500 WAN
}
2021/10/7 修正: /bin/sh -> /bin/bashに変更。debian10の/bin/sh は、/usr/bin/dashへのリンク。wgetが誤動作するため/usr/bin/bashに変更。
PR-600MIのLAN側に接続したOpenWrtルータ上でDHCPv6-PDの再取得用スクリプト
OpenWrt
---- RebindAll ----
#!/bin/sh
# for OpenWrt odhcp6c
NVR510="ac44f2AABBCC"
OpenWrt="001d73344556"
Dummy="001d73344557"
NVR500="00a0deAABBDD"
ID1="00030001$NVR510"
ID2="00030001$OpenWrt"
ID3="00030001$Dummy"
ID4="00030001$NVR500"
CID="$ID1 $ID2 $ID3 $ID4"
IF="eth1"
PID="/var/run/odhcp6c-sh.pid"
SCRIPT="/root/odhcp6c-sh"
DHCPV6CL="/usr/sbin/odhcp6c -P0" #release
#DHCPV6CL="/usr/sbin/odhcp6c -k -P0" #keeping
CUSTOMAPI="custom/api?password=JYUGEM"
# release all prefix
for CL in $CID; do
$DHCPV6CL -c$CL -s$SCRIPT -d -p$PID $IF
while [ ! -e "$PID" ]; do sleep 1; done
kill `cat $PID`
while [ -e "$PID" ]; do sleep 1; done
done
echo "Released all"
# rebind NVR510 for #1
if echo -n $CID | grep "$ID1" >/dev/null; then
wget -q -O- --post-data=$'syslog debug on\r\nipv6 lan2 dhcp service client' http://nvr510-lan2.familyname/$CUSTOMAPI
while [ "$pf" = "" ]; do
sleep 1
pf=`wget -q -O- --post-data="show status ipv6 dhcp" http://nvr510-lan2.familyname/$CUSTOMAPI | grep prefix | sed 's/ *prefix: //'`
done
wget -q -O- --post-data="syslog debug off" http://nvr510-lan2.familyname/$CUSTOMAPI >/dev/null
echo "Bind #1"
fi
# rebind OpenWrt for #2
if echo -n $CID | grep "$ID2" >/dev/null; then
ubus call network.interface.wan6 renew
echo "Bind #2"
fi
# rebind Dumy for #3
if echo -n $CID | grep "$ID3" >/dev/null; then
$DHCPV6CL -k -c$ID3 -s$SCRIPT -d -p$PID $IF
while [ ! -e "$PID" ]; do sleep 1; done
kill `cat $PID`
while [ -e "$PID" ]; do sleep 1; done
echo "Bind #3"
fi
# rebind NVR500 for #4
if echo -n $CID | grep "$ID4" >/dev/null; then
wget -q -O- --post-data=$'syslog debug on\r\nipv6 lan2 dhcp service client' http://nvr500-lan2.familyname/$CUSTOMAPI >/dev/null
while [ "$pf" = "" ]; do
sleep 1
pf=`wget -q -O- --post-data="show status ipv6 dhcp" http://nvr500-lan2.familyname/$CUSTOMAPI 2>/dev/null | grep prefix | sed 's/ *prefix: //'`
done
wget -q -O- --post-data="syslog debug off" http://nvr500-lan2.familyname/$CUSTOMAPI >/dev/null
echo "Bind #4"
fi
--------
---- odhcp6c-sh ----
#!/bin/sh
logger -t "odhcp6c-script" -s " Prefix=$PREFIXES Clinet-ID=$OPTION_1"
----
(4)課題
PR-600MIが再起動した時にDHCPv6-PDの再取得用スクリプト実行の自動化。
現在は、手動実行なので、PR-600MIのDHCPv6から「reconfigure」メッセージを受信し、設計通りのPrefix設定が出来なかったら再取得のスクリプトを実行する。