むろっちのStacking

日々の中で学んだIT知識をメモして置く場所

YAMAHAルーター+lua scriptで簡易的な冗長構成を組んでみた

VRRPやHAが組めない異機種間で冗長構成を組みたかったのでlua scriptでなんとかしてみた

はじめに

我が家ではメインルーターとしてSophos XG FirewallVMとして稼働している このルーターが利用できないときにYAMAHAルーターをバックアップとして自動的に利用するスクリプトを書いてみた


普通の冗長構成

HA構成(sophos XG Firewall)

HAは同機種間のみサポート。そのためHA構成を組む場合はXG Firewallがもう一台必要。我が家ではXGFirewall用にもう一台VMを用意するのがランニング的に見合わなかったので不採用

VRRP構成

標準規格なのでSophos XG - YAMAHA RTX間で組めるかなと思いきや、Sophos XG側で未対応

以上から自力で YAMAHAlua script機能を利用して簡易的な冗長構成を作成することにした


構成

インターネットプロバイダの制約上、プロバイダ貸し出し機器以外へ直接グローバルIPを割り振れない構成上、少し特殊な構成になっている

Sophos XG側がDefaultGWになっており、このルーターDHCP機能も兼ねている

f:id:murochi:20210111132502p:plain
nw構成

よってYAMAHA RTXが障害時に担う役割は以下である * DefaultGWのIPを引き継ぐ * DHCPサーバー機能を稼働する


障害時の想定

障害時にはSophox XG側のlan側IP、wan側のIPが不通となる想定


設定

YAMAHA config

DHCP設定のみ投入し、サービスは無効 IPは.2設定(≒非defaultGW)

ip lan1 address 192.168.0.2/24

dhcp server rfc2131 compliant except remain-silent
dhcp scope 1 192.168.0.50-192.168.0.100/24 gateway 192.168.0.1

-- recovery用スクリプト。後述
schedule at 1 startup * lua /scripts/recovery.lua

※ 関連箇所のみ抜粋

lua script

以下の動作を想定したスクリプト Primaryに昇格 1. default GW宛に疎通確認。疎通確認が取れない場合2へ 2. YAMAHA RTX側が外部疎通できるか確認。確認が取れたら3へ 3. IPをdefault GW(192.168.0.1)に差し替え、DHCP機能ON

Secondaryに降格 1. Sophos XG、WAN側IPへ疎通確認。疎通確認が取れた場合は2へ 2. YAMAHARTX側のIPを192.168.0.2へ、DHCP機能をOFF

recovery.lua

function check_loss_rate(ipaddress, count)
  command = "ping -c "..count.." "..ipaddress
  rt.syslog("debug","command:"..command)
  res, text = rt.command(command)

  rt.syslog("debug", "result:"..text)
  loss = string.match(text, "(%d+)%.%d+%%")

  if (loss ~= nil) then
    return tonumber(loss)
  end

  return 0
end

function get_promoted()
  rt.command("dhcp service server")
  rt.command("ip lan1 address 192.168.0.1/24")
  rt.syslog("info", "primaryに昇格しました")
end

function get_relegated()
  rt.command("no dhcp service server")
  rt.command("ip lan1 address 192.168.0.2/24")
  rt.syslog("info", "secondaryに降格しました")
end

local local_gw = "192.168.0.1"
local external = "8.8.8.8"
local primary_wan_addr = "192.168.254.253"

function execute()
  mode = "secondary"
  rt.syslog("debug", "start script mode:"..mode)

  while true do
    if mode == "secondary" then
      -- 内部接続チェック
      internal_loss_rate = check_loss_rate(local_gw, 5)
      if internal_loss_rate > 50 then
        -- 外部接続チェック
        external_loss_rate = check_loss_rate(external, 5)
        if external_loss_rate == 0 then
          get_promoted()
          mode = "primary"
        end
      end
    else
      -- primary稼働中
      loss_rate = check_loss_rate(primary_wan_addr, 30)
      if loss_rate == 0 then
        get_relegated()
        mode = "secondary"
      end
    end
  end
end

execute()

RTX向けのAPI一覧は以下に一覧がある

www.rtpro.yamaha.co.jp

scriptのアップロード

今回はSFTP機能でアップロードした

# SFTP接続
sftp 192.168.0.2

# script用dir作成
mkdir scripts

# scriptの設置
put [ローカルのスクリプトDir]/recovery.lua recovery.lua

scriptのスケジュール(先述のconfigに記載済み)

今回は常駐型のscriptで記載しているのでルーター起動時に1度のみ起動すればOK そのため以下の記載とした

-- recovery用スクリプト。後述
schedule at 1 startup * lua /scripts/recovery.lua

YAMAHA上でlua scriptの操作

# scriptの実行
lua /scripts/recovery.lua

# scriptの実行ステータス確認
show status lua

# scriptの強制終了
terminate lua file /scripts/recovery.lua

注意点

本構成はあくまで簡易的な冗長構成のため、ダウンタイム数分程度発生する。 具体的には * sophos XG Firewallがダウンしたと検知されるまでの時間 * YAMAHA RTXがIP差し替え後、コンピューターのARPテーブルがXG FirewallMACアドレスからYAMAHRTXのMACアドレスに書き換わる時間

ARPテーブルのキャッシュ期間はコンピューターによりまちまちで、自身の環境では * google home: キャッシュ数秒-30秒程度 * Mac: 2-3分程度

となり、実質的には上記のARPキャッシュ時間がダウンタイムの時間と大きく直結する


やってみて

殆どの人がそうだと思うが、luaスクリプトを書いた経験がなく基本文法を調べながら書く為時間が取られた。script言語であればnodejsやpythonでもかけるようにしてほしい。(パフォーマンス面でluaが優れているとの記載があったので難しいかもしれないが)

本格的にscriptを書くとなるとYAMAHAAPIのmockを書く必要があり、mock用のライブラリや開発環境を用意してくれれば実機コピー後に意図しない動作等を防ぐことができるのでなお嬉しい。

rt.commandで殆どすべてのコマンドが実行可能なのでできることはかなり広いが、上記のテスタビリティの理由によりユーザー向けには公式で出している設定例以外のスクリプトはあまり利用したくないなといった印象だった