WAN6 は IPv6 アドレスを取得済みだが、OpenWrt でインターネット上の IPv6 に ping すると、直ちに次のエラーが返る:

ping: sendto: Network unreachable

調査の結果、現場には mwan3 と一致するマーク付き unreachable ルールが1つ存在していた。そのルールを削除すると IPv6 が復旧した。このケースから、デフォルトルートが存在していても、実際のトラフィックがそれを使うとは限らないことが分かる。

本稿では実際の調査を記録する。インターネット上のソースアドレスはドキュメントの例示アドレスに置き換えている。デバイス名、ルール優先度、mark は自分のデバイスに合わせて確認すること。アンインストールコマンドは opkg を使用する OpenWrt 向けである。

デフォルトルートが存在しているのに、なぜまだ到達できないのか

最初の調査ではデフォルトルートが存在しないことを疑ったが、その後の出力にはソースアドレス条件付きのデフォルトルートがすでに表示されていた:

default from 2001:db8:1234:5600::4 via fe80::1 dev eth1 proto static metric 512 pref medium
default from 2001:db8:1234:5600::/64 via fe80::1 dev eth1 proto static metric 512 pref medium

調査中は一時的に通常のデフォルトルートも追加した:

ip -6 route add default via fe80::1 dev eth1 metric 1024

それでも ping は直ちに Network unreachable を返した。この時点でデフォルトルートをさらに追加しても効果が已经没有なるため、実際の経路選択とポリシールールを確認する必要があった。

まず上流ゲートウェイへの到達性を確認する

ping -6 -I eth1 -c 3 fe80::1

3回のリクエストすべてに返信を受け取り、OpenWrt から上流ゲートウェイへのリンクローカル通信が正常であることが確認できた。IPv6 が先頭 fe80:: のリンクローカルアドレスを次ホップとして使用する,正常な現象である。ここでデバイスを指定するのは、そのアドレスがどのリンクに属するかを特定するためである。

この手順で確認できるのはゲートウェイへの到達性のみであり、インターネット側の出口が正常であることは証明しない。

ルート検索は正常なのに、パケット送信は失敗する

ip -6 route get 2606:4700:4700::1111

出力例:

2606:4700:4700::1111 from :: via fe80::1 dev eth1 src 2001:db8:1234:5600::1234 metric 1024 pref medium

出口、ゲートウェイ、ソースアドレスはすべて選択されたにもかかわらず、通常の ping は失敗した。ルート検索結果のソースアドレスを指定した場合も同様だった:

ping -6 -I 2001:db8:1234:5600::1234 -c 3 2606:4700:4700::1111

上記のソースアドレスは難読化済みの例示にすぎず、実際のテストではデバイスが保持する実アドレスを使用しなければならない。

sing-box を停止した後も障害は解消されなかったため、引き続きポリシールーティングを確認した。

重要な証拠:unreachable ルール

ip -6 rule show

現場での出力:

0:      from all lookup local
2061:   from all fwmark 0x3d00/0x3f00 blackhole
2062:   from all fwmark 0x3e00/0x3f00 unreachable
32766:  from all lookup main

優先度 2062 のルールは、mark にマスク 0x3f00 を適用した値が 0x3e00 に一致するトラフィックを、直ちに到達不能と判定することを意味する。このルールは main テーブルの検索より前にある。

通常の ip -6 route get 検索では mark を指定せず、実際の送信時にファイアウォールが行うマーク付けの処理も通らない。実際のトラフィックが出力経路でマーク付けされると、再ルーティング時にこの unreachable ルールに一致する可能性がある。これが、検索は正常に見えても ping が直ちに失敗する理由である。

現場で確認されたこのルールを一時的に削除して検証した:

ip -6 rule del pref 2062
ping -6 -c 3 2606:4700:4700::1111

削除後に通信が復旧し、このルールが今回の障害に直接関係することが確認できた。

この一連のルールは mwan3 のルール形式と一致する。ただし、現場ではマーク付けチェーンのカウンターや完全な mwan3 設定が保存されていなかったため、どのインターフェース検出処理またはポリシー設定がトラフィックを unreachable ブランチへ誘導したのかは断定できない。ルール自体が「存在すれば必ず障害が生じる」というわけではなく、重要なのはトラフィックがなぜそれに一致するのかという点である。

マルチ WAN が不要な場合は mwan3 をアンインストールする

マルチ WAN の分流やフェイルオーバーに依存している場合は、mwan3 の設定を修正すること。本例では mwan3 を使用しない方針とし、以下は後続のアンインストール手順である。すでに実行完了した結果として示しているわけではない。

まず設定をバックアップする:

[ ! -f /etc/config/mwan3 ] || cp -p /etc/config/mwan3 /root/mwan3.conf.bak

サービスを停止し、自動起動を無効にする:

if [ -x /etc/init.d/mwan3 ]; then
    /etc/init.d/mwan3 stop
    /etc/init.d/mwan3 disable
fi

インストール済みのパッケージを1つずつアンインストールする:

for pkg in luci-i18n-mwan3-zh-cn luci-app-mwan3 mwan3; do
    if opkg list-installed "$pkg" | grep -q "^$pkg "; then
        opkg remove "$pkg"
    fi
done

依存関係の競合が発生した場合は、まず依存しているパッケージを確認する。強制削除は行わず、他のサービスが共有している可能性がある基礎依存関係も、ついでに削除しない。

その後、次のコマンドで確認する:

ip -6 rule show
ping -6 -c 3 2606:4700:4700::1111

本文と完全に一致するルールが残っている場合は、完全な条件を指定して削除する:

ip -6 rule del pref 2061 fwmark 0x3d00/0x3f00 blackhole
ip -6 rule del pref 2062 fwmark 0x3e00/0x3f00 unreachable

そのルールが存在しなければ削除コマンドは実行しない。ポリシールーティングテーブル全体をクリアしてはいけない。適切な时机に再起動した上で、もう一度確認し、他の起動スクリプトがルールを再作成していないことを確認する。

一時ルートの後片付け

調査中に追加した metric 1024 のデフォルトルートは、根本的な修正として検証されたものではない。WAN6 が自動的に生成するデフォルトルートの存在を確認したら:

ip -6 route show default

該当する一時ルートを削除し、再検証する:

ip -6 route del default via fe80::1 dev eth1 metric 1024
ping -6 -c 3 2606:4700:4700::1111

この時点で再び失敗する場合は、自動ルートとソースアドレスの選択を個別に調査する。1つの問題が見つかったからといって、他の設定も必ず正しいと仮定してはいけない。

次に同様の現象に遭遇したら

Network unreachable が直ちに表示される症状では、最初から DNS やインターネット上のパケット損失を調べるのではなく、まずローカルのルートとポリシールールを確認する方が直接的である:

ip -6 route show default
ip -6 route get 2606:4700:4700::1111
ip -6 rule show

WAN に IPv6 アドレスがあること、LAN で使用するための委譲プレフィックスを取得していること、利用可能なデフォルトルートがあることは、それぞれ別の状態である。本例はさらに、通常のデフォルトルートが正常であっても、mark 付きのポリシールールが実際のトラフィックを遮断することがあることを示している。

参考