IPv6アドレス変更時のVPNトンネル自動復帰

図 IPv6リナンバリング対応 下矢印:回線変更 図 IPv6リナンバリング対応

IPv6のインターネット回線の繋ぎ替えによってルーターに割り振られるIPv6アドレスの変更を監視し、設定を変更する設定例です。
対向ルーターのIPv6アドレスは、生存通知2パケットを受信した際に出力されるログから取得し、IPv6アドレスに変更があった場合、設定に反映します。

RTX1200(1)の設定例

経路の設定 ip route default gateway pp 1
LANの
インタフェースの設定
(LAN1ポートを使用)
ip lan1 address 192.168.100.1/24
WANの
インタフェースの設定
(LAN2ポートを使用)
ipv6 lan2 address ra-prefix@lan2::10/64
ipv6 lan2 prefix change log on
WANの
インタフェースの設定
(LAN3ポートを使用)
pp select 1
pp always-on on
pppoe use lan3
pppoe auto connect on
pppoe auto disconnect off
pp auth accept pap chap
pp auth myname (ISPへ接続するID) (ISPへ接続するパスワード)
ppp lcp mru on 1454
ppp ipcp ipaddress on
ppp ipcp msext on
ip pp mtu 1454
ip pp nat descriptor 1
netvolante-dns hostname host pp server=1 (NetvolanteDNSに設定された名前) # 注釈1
pp enable 1
VPN(IPsec)の設定 tunnel select 1
ipsec tunnel 1
ipsec sa policy 1 1 esp aes256-cbc sha256-hmac
ipsec ike local address 1 (RTX1200(1)に割り振られたIPv6アドレス)
ipsec ike pre-shared-key 1 text himitsu
ipsec ike remote address 1 (RTX1200(2)に割り振られたIPv6アドレス)
tunnel enable 1
ipsec auto refresh on
NATの設定 nat descriptor type 1 masquerade
nat descriptor masquerade static 1 1 192.168.100.1 udp 8512
DNSの設定 dns server pp 1
DHCPの設定 dhcp service server
dhcp server rfc2131 compliant except remain-silent
dhcp scope 1 192.168.100.2-192.168.100.191/24
Luaスクリプトの
スケジュール設定
schedule at 1 startup * lua (Luaスクリプト(1)ファイル名)
schedule at 2 startup * lua (Luaスクリプト(2)ファイル名)
生存通知2の設定 heartbeat2 myname (RTX1200(1)に割り振られたIPv6アドレス)
heartbeat2 transmit 1 crypto CRPT_KEY_a auth AYTH_KEY_a (RTX1200(2)のNetvolanteDNSに設定された名前)
heartbeat2 transmit interval 1 30
heartbeat2 transmit log 1 on
heartbeat2 transmit enable 1
heartbeat2 receive 1 crypto CRPT_KEY_b auth AYTH_KEY_b
heartbeat2 receive monitor 1 300
heartbeat2 receive log on
heartbeat2 receive enable 1
heartbeat2 receive record limit 128

RTX1200(2)の設定例

経路の設定 ip route default gateway pp 1
LANの
インタフェースの設定
(LAN1ポートを使用)
ip lan1 address 192.168.200.1/24
WANの
インタフェースの設定
(LAN2ポートを使用)
ipv6 lan2 address ra-prefix@lan2::11/64
ipv6 lan2 prefix change log on
WANの
インタフェースの設定
(LAN3ポートを使用)
pp select 1
pp always-on on
pppoe use lan3
pppoe auto connect on
pppoe auto disconnect off
pp auth accept pap chap
pp auth myname (ISPへ接続するID) (ISPへ接続するパスワード)
ppp lcp mru on 1454
ppp ipcp ipaddress on
ppp ipcp msext on
ip pp mtu 1454
ip pp nat descriptor 1
netvolante-dns hostname host pp server=1 (NetvolanteDNSに設定された名前) # 注釈1
pp enable 1
VPN(IPsec)の設定 tunnel select 1
ipsec tunnel 1
ipsec sa policy 1 1 esp aes256-cbc sha256-hmac
ipsec ike local address 1 (RTX1200(2)に割り振られたIPv6アドレス)
ipsec ike pre-shared-key 1 text himitsu
ipsec ike remote address 1 (RTX1200(1)に割り振られたIPv6アドレス)
tunnel enable 1
ipsec auto refresh on
NATの設定 nat descriptor type 1 masquerade
nat descriptor masquerade static 1 1 192.168.200.1 udp 8512
DNSの設定 dns server pp 1
DHCPの設定 dhcp service server
dhcp server rfc2131 compliant except remain-silent
dhcp scope 1 192.168.200.2-192.168.200.191/24
Luaスクリプトの
スケジュール設定
schedule at 1 startup * lua (Luaスクリプト(1)ファイル名)
schedule at 2 startup * lua (Luaスクリプト(2)ファイル名)
生存通知2の設定 heartbeat2 myname (RTX1200(2)に割り振られたIPv6アドレス)
heartbeat2 transmit 1 crypto CRPT_KEY_b auth AYTH_KEY_b (RTX1200(1)のNetvolanteDNSに設定された名前)
heartbeat2 transmit interval 1 30
heartbeat2 transmit log 1 on
heartbeat2 transmit enable 1
heartbeat2 receive 1 crypto CRPT_KEY_a auth AYTH_KEY_a
heartbeat2 receive monitor 1 300
heartbeat2 receive log on
heartbeat2 receive enable 1
heartbeat2 receive record limit 128

Luaスクリプト例(1)

設定値 -- 出力する SYSLOG のレベル(info, debug, notice)
log_level = "(SYSLOGレベル)"
show ipv6 address の結果から
現在のIPv6アドレスを返す関数

function get_ipv6_address(lan)
 local rtn, str, s1, s2, e, adr, time, i, a, max, max_n
 local p_time, v
 local ptn_g = "バル%s+"
 local t = {}
 local ret
 local err

 -- コマンド実行 --
 rtn, str = rt.command("show ipv6 address " .. lan)
 
 -- 現在のIPv6アドレスと寿命時間の検出 --
 i = 1
 if rtn and str then
  s1 = str:find(ptn_g, 0)
  if s1 then
   while true do
    s2 = str:find("%x+", s1)
    e = str:find("%/", s2)
    adr = str:sub(s2, e-1)
    p_time = tonumber(str:match("lifetime: (%d+)%/", e))

    t[i] = {a = adr, time = p_time}
    
    next = str:find(ptn_g, e)
    if next then
     s1 = next
     i = i + 1
    else
     break
    end
   end

   -- 最大寿命のIPv6アドレスの検出 --
   max = 0
   max_n = 1
   for i, v in ipairs(t) do
    if v.time > max then
     max_n = i
     max = v.time
    end
   end
   ret = t[max_n].a
  else
   err = "グローバルアドレスがありません。"
  end
 end
 return ret, err
end

show ipv6 addressの結果と
prefixからIPv6アドレスを返す関数

function get_address(lan, prefix)
 local rtn, str, a, b, c, pfx, adr, err

 rtn, str = rt.command("show ipv6 address " .. lan)
 if rtn and str then
  a = str:find(prefix)
  b, c = str:find("%/%d+", a)
  pfx = prefix .. str:sub(b, c)
  adr = str:sub(a, b-1)
 else
  err = "コマンド実行に失敗"
 end
 return pfx, adr, err
end

監視しているlogからprefixを
検出する関数

function get_prefix(str)
 local s1, s, e, pfx
 local ptn_s = "IPv6 prefix%s+"
 local ptn_e = "%/%d+%s+%b()"

 s1, s = str:find(ptn_s)
 e = str:find(ptn_e)
 pfx = str:sub(s+1, e-2)
 return pfx
end

メインルーチン

local adr1, adr2, prefix, pfx, err, rtn, str

-- 検出するパターン
local ptn = "Add IPv6 prefix%s+"

-- 現在のIPv6アドレスを取得
adr1, err = get_ipv6_address("lan2")
assert(adr1, err)

rt.command("ipsec ike local address 1 " .. adr1)
rt.command("heartbeat2 myname " .. adr1)

while true do
 rtn, str = rt.syslogwatch(ptn)

 if rtn and str then
  prefix = get_prefix(str[1])
  pfx, adr2, err = get_address("lan2", prefix)
  if adr2 then

   -- 今までのIPv6アドレスと現在のIPv6アドレスが異なる場合、設定の変更
   if string.match(adr1, adr2) == nil then
    rt.command("tunnel select 1")
    rt.command("ipsec ike local address 1 " .. adr2)
    rt.command("tunnel select none")
    rt.command("heartbeat2 myname " .. adr2)
    rt.syslog(log_level, "アドレスを変更し、設定を変更しました。")

    adr1 = adr2

   else
    print("アドレスに変更はありません。")
   end

  else
   rt.syslog(log_level, err)
  end
 end
end

Luaスクリプト例(2)

設定値

-- 検出するパターン
ptn_hbt = "Received from "

-- トンネル番号
tunnel_num = 1

-- 出力する SYSLOG のレベル(info, debug, notice)
log_level = "(SYSLOGレベル)"

設定されているIPv6アドレスを
取得する関数

function get_address_config(tunnel_num)
 local rtn, str, a, b, c, adr
 local ptn = "ipsec ike remote address " .. tostring(tunnel_num) .. " "

 rtn, str = rt.command("show config")
 if rtn and str then
  a, b = str:find(ptn)
  if a and b then
   c = str:find("%s", b+1)
   adr = str:sub(b+1, c-1)
  end
 end
 return adr
end

hertbeat2ログからIPv6アドレスを
取得する関数

function get_remote_address(str)
 local s, e, adr
 local ptn = "Received from ([%x:]+) "

 s, e, adr = str:find(ptn)
 return adr

end

対向ルーターのIPv6アドレスが
変更されていた場合、
IPsec のリモートアドレスの
設定を変更する関数
function change_config(tunnel_num, chg_adr)
 rt.command("tunnel select " .. tunnel_num)
 rt.command("ipsec ike remote address " .. tunnel_num .. " " .. chg_adr)
 rt.command("tunnel select none")
 rt.command("save")
 rt.syslog(log_level, "TUNNEL[" .. tunnel_num .. "]のリモートアドレスを変更しました。")
end
メインルーチン

local rtn, log, rmt_adr_cfg, rmt_adr_hbt

-- エラーメッセージ
local err_msg1 = "からの情報の取得に失敗しました。(TUNNEL["
local err_msg2 = "])"

while true do
 rtn, log = rt.syslogwatch(ptn_hbt)

 if rtn > 0 then

  -- 対向ルーターの設定上のIPv6アドレスを取得
  rmt_adr_cfg = get_address_config(tunnel_num)

  if rmt_adr_cfg then

   -- ログから対向ルーターの現在のIPv6アドレスを取得
   rmt_adr_hbt = get_remote_address(log[1])

   -- IPv6アドレスが異なれば、設定を変更する
   if rmt_adr_hbt then

    if string.match(rmt_adr_cfg, rmt_adr_hbt) == nil then
      change_config(tunnel_num, rmt_adr_hbt)
    end

   else
    rt.syslog(log_level, "ログ" .. err_msg1 .. tostring(tunnel_num) .. err_msg2)
   end
  else
   rt.syslog(log_level, "設定ファイル" .. err_msg1 .. tostring(tunnel_num) .. err_msg2)
  end

 end

end

[注釈の説明]

注釈1:
Netvolante DNSへ名前を登録する手順

(1) 名前の設定
  まず、次のコマンドを実行してください。
  netvolante-dns hostname host pp [HOSTNAME]
  HOSTNAMEには登録したい名前を設定してください。

(2) NetVolante DNSへの登録
  次のコマンドを実行してください。
  netvolante-dns go pp 1
  このときに、ルーターはNetVolante DNSに対して登録を行います。
  登録が成功すると、設定の変更を保存するかどうかを確認しますので、'y'と入力し、設定を確定してください。
  名前はHOSTNAME.aa0.netvolante.jpと設定されます。
  詳細は  http://www.rtpro.yamaha.co.jp/RT/FAQ/NetVolanteDNS/netvolante-dns-use-command.html
  を参照してください。