--[[

  ●ルーターの IPv6アドレスを取得し、設定を変更するスクリプト
  show ipv6 address の出力結果からルーターの IPv6アドレスを取得し、
  IPv6アドレスに変更があった場合には、コマンドを再設定するスクリプトです。

  <説明>
  ・このファイルを RTFS か外部メモリに保存してください。
  ・本項目の config の設定では schedule at コマンドでルーター起動時に Lua スク
    リプトが実行されるように設定しています。
  ・スクリプトを停止するときは terminate lua コマンドを実行してください。
  ・再度、Lua スクリプトを実行する場合は lua コマンドで実行してください。
  ・★マークの付いた設定値は変更が可能です。

  <ノート>
 ・設定を変更した時に出力する SYSLOG レベルを指定可能です。
  SYSLOG のレベルを指定するには、log_level を設定してください。
  debug レベル、notice レベルの SYSLOG を出力するためには、それぞれ以下の設定
  が必要です。
   debug レベル ・・・ syslog debug on
   notice レベル・・・ syslog notice on
 ・本スクリプトファイルを編集する場合、文字コードは必ず Shift-JIS を使用してく
  ださい。

]]

--------------------------##  設定値  ##--------------------------------
-- 出力する 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