夜、自宅のルーターの管理画面が開かなくなりました。Wi-Fiのアイコンは普通に繋がった顔をしているのに、192.168.1.1 にアクセスするとひたすら読み込み中のまま終わらない。

結論から書くと、犯人はルーターのファームウェア自動更新でした。更新後に立ち上がったルーターが、約256バイトを超えるイーサネットフレームだけを転送しないという壊れ方をしていた。厄介なのは、この状態のルーターが「生きているように見える」ことです。

「生きて見えるのに全部壊れる」の正体

最初に私を混乱させたのは、pingが普通に通ることでした。ルーターにもLAN内のサーバーにも、損失ゼロで応答が返ってくる。ARPも解決する。機器としては明らかに動いている。

それなのに、実際の通信は片端から死んでいました。

  • 管理画面が開かない
  • 新しく繋いだ端末がDHCPでアドレスを取れない(no server になる)
  • サーバーへのsshが、認証に入る前で止まる
  • 家のサーバーがインターネットに出られなくなり、VPN経由でも見えなくなる

これらに共通するのは、やり取りするデータのサイズです。

通信フレーム長結果
ping / ARP / sshのバナー84〜96バイト通る
DHCPのDISCOVER・OFFER約300バイト落ちる
TLSハンドシェイク1KB超落ちる
sshの鍵交換(KEXINIT)1KB超落ちる

Wi-Fiの接続そのものは小さなフレームで完結するので、認証だけは通ってしまう。だから「Wi-Fiには繋がるのにルーターが開かない」という、いかにも不可解な訴えになるわけです。

そしてこの障害は放置すると悪化します。DHCPの更新も落ちるので、リースの期限が切れた端末から順に脱落していく。何か操作するたびに状況が悪くなるように見えて、実際には何もしなくても悪くなっていました。

決め手はpingのサイズ別損失率

原因の切り分けに効いたのは、pingをサイズを変えながら打って、成否ではなく損失率で見るという測り方でした。数発だと偶然に見えるので、10発以上打って割合で判断します。

for s in 56 200 250 1000 1472; do
  r=$(ping -c 10 -i 0.2 -t 3 -s $s 192.168.1.1 2>/dev/null | grep -o '[0-9.]*% packet loss')
  echo "size=$s loss=$r"
done

このときの実測結果がこれです。

size=56    loss=0.0%     (フレーム 84バイト)
size=200   loss=0.0%     (フレーム 242バイト)
size=250   loss=100.0%   (フレーム 292バイト)   ← ここで切れる
size=1000  loss=100.0%
size=1472  loss=100.0%

242バイトは全部通り、292バイトは全部落ちる。ランダムな損失ではなく、硬い境界がある。正常なネットワークでこの形にはなりません。ここまで出れば、機器そのものではなく経路装置を疑って電源を抜き挿しする、という判断ができます。

踏んだ罠その1:MTUを下げると自分の測定が壊れる

「大きいフレームが落ちるなら、MTUを下げれば通るのでは」と考えるのは自然です。私もそうしました。これが罠でした。

MTUを250にしたインターフェースは、250バイトを超える応答フレームを自分で捨てます。 相手が大きな応答を返す限り届かないので、「MTUを下げても直らない、ということはサイズの問題ではないのだ」と誤った結論に進んでしまう。

TCPも助けになりませんでした。MSSが210なら実際のフレームは

210(データ) + 20(TCP) + 20(IP) + 14(Ethernet) = 264バイト

で、閾値をわずかに超えたままです。sshは相変わらず止まる。

この罠のせいで、私は一度サイズ説を捨てて、存在しないLANケーブルの不良を疑うところまで遠回りしました。最初の測定は正しかったのに、自分で作った測定の欠陥をデータの否定と読み違えたわけです。回復したかどうかの判定は、必ずMTUを1500に戻してから行うべきでした。

踏んだ罠その2:再起動コマンドは届いていなかった

管理画面が死んでいるということは、再起動の指示そのものが届かないということでもあります。UIもAPIもTLSを使うからです。

私はこれに気づかず、一度リモートから再起動を試みて「効果がなかった」と判断していました。実際には実行すらされていなかった

これを確かめる方法があります。ルーターが再起動すればスイッチのポートが必ず落ちるので、有線で繋がっているLinuxマシンのカーネルログを見れば、再起動の有無が分かります。

sudo journalctl --since "00:00:00" --no-pager \
  | grep -E "Lost carrier|Gained carrier|NIC Link is|DHCPv4 address"

このときのログがこれです。

20:16:07  Lost carrier / NIC Link is Down     ← 自動更新に伴う再起動
20:16:52  DHCPv4 address 192.168.1.60/24 acquired
          (この間 1時間38分、リンクの変化ゼロ = 再起動は起きていない)
21:54:45  Lost carrier                        ← 物理的な電源の抜き挿し
21:56:14  DHCPv4 address 192.168.1.60/24 acquired

1時間38分のあいだ、リンクは一度も落ちていません。この故障モードの復旧手段は、物理的な電源の抜き挿しだけでした。

DHCPが死んでいてもLANを調べる方法

DHCPが応答しないと、そもそも調査用の端末をLANに参加させられません。ここで効いたのがIPv6のリンクローカルアドレスです。DHCPもルーターも要らず、L2に繋がってさえいれば生存している機器を列挙できます。

ping6 -c 4 -I en6 ff02::1   # 応答した fe80:: が生きている機器
ndp -an | grep en6          # fe80:: とMACアドレスの対応

これで「サーバーは生きている」「ルーターも応答している」までは即座に確認できました。ただしsshは通りません。鍵交換が閾値を超えるからです。生存確認までが限界でした。

IPv4で調べたいときは、手動でアドレスを当ててしまうのが早いです。既定の経路には触らないので、作業中の接続は切れません。

sudo ifconfig en6 inet 192.168.1.211/24 alias   # 一時的に参加
sudo ifconfig en6 -alias 192.168.1.211          # 後片付け
sudo ipconfig set en6 DHCP

原因の確定

復旧後、ルーターのローカルAPIを叩いて原因が確定しました。更新前のバージョンが記録として残っているので、直前に更新が走ったことを証明できます。

version:          10.6.101     ← 現在
previous_version: 10.5.67      ← 更新前

障害の始まりは20時16分。管理アプリケーションがこの時刻に自動更新され、再起動して、壊れた状態で立ち上がっていました。

なお、このAPIはインターネットが死んでいてもLAN経由で叩けます。WANが落ちている状況の調査では、これがかなり効きます。

やったこと、やらなかったこと

復旧そのものは電源を10秒抜いて挿し直しただけです。機器の交換も設定変更も要りませんでした。サーバー類は一台も壊れておらず、再起動すらしていません。

再発防止として、ファームウェアの自動更新を切りました。
安定した構成なら、自動更新の利点より「深夜や外出中に勝手に壊れる」リスクのほうが大きいというのが今回の判断です。更新は自分の都合のいいタイミングで、手元で見ながらやることにしました。

もう一つ、今回はっきりした弱点があります。外から自宅を復旧する手段が、すべて自宅のインターネット回線を通るということです。VPNも、メーカーのクラウド経由のリモートアクセスも、回線そのものが死ねば同時に使えなくなる。今回はたまたま私が家にいたので電源を抜けましたが、外出中なら手も足も出ませんでした。

ここは宿題として残っています。本気で解決するなら携帯回線を使った別経路を用意するしかなく、現実的な落としどころとしては、常時起動しているLAN内の小さなサーバーに「インターネットが一定時間死んだらルーターの電源を入れ直す」役をやらせるあたりかと考えています。ルーターへの小さなHTTPリクエストは、今回のような壊れ方でも通っていたはずなので、LAN内で完結する見張り役は機能したはずです。

まとめ

同じ症状に出会った人のために、要点だけ並べておきます。

  • pingが通ってもルーターが健全とは限らない。 小さいフレームしか通っていない可能性がある
  • サイズを変えたpingの損失率を見れば、境界の有無が1分で分かる
  • MTUを下げて回避を試すと、自分の受信側が応答を捨てて測定が壊れる。 判定はMTUを戻してから
  • 管理画面が開かない状態では、再起動コマンドは届いていない。有線マシンのcarrierログで実行の有無を確認できる
  • DHCPが死んでいても、IPv6リンクローカルでL2の生存確認はできる
  • 直し方は物理的な電源の抜き挿し