自宅ゲートウェイで敢えて今 UPnP を正しく有効にした件


こう書くと非常に大仰だが、MiniUPnPd を起動しているにもかかわらず、MiniUPnPd が動的にルールを追加するチェインに飛ばないように設定しているのに気付かなかったので色々と見直してみた。

そもそもUPnPとは

UPnP は Universal Plug and Play の略で、ネットワーク上のデバイスを検知したりデバイスをコントロールしたりするプロトコルになる。DLNA が UPnP で実装されているらしいが、一般家庭で UPnP を意識するのは、自動でポート開放してくれる位のレベル感でだろう。

ただ、今時は UPnP なんてほぼ意識する必要はないし、パッシブに通信を確立する必要はほぼないので、UPnP が有効化されていなくてもほぼ問題はない。
敢えて意識する必要があるとしたら、ごく一部のオンライン対戦のときくらいだろう。実際、スプラトゥーン 2 などは UPnP が有効化されていなくても問題なくオンライン対戦ができる

セキュリティ上のリスク

一方、UPnP を通じてルータのポート開放を動的に行える。仕様上は認証も可能だが、認証まで含めた実装はそこまで多くなく、かつては Flash を利用した UPnP exploit なども存在した。そのため、UPnP は無効にすべきという議論も存在する。

実際、UPnP を WAN に解放すると実質的にファイアウォールが存在しないに等しい状態になる。そのため、UPnP を有効にする場合は諸々気をつける必要がある。

MiniUPnPd とは

MiniUPnPd は、Linux や FreeBSD といった OS でルータを実装する際に UPnP を実現するための実装の一つになる。
かつては Linux-IGD が使われていたがメンテされなくなったこともあって、ここ 15 年ほどは MiniUPnPd が Linux や FreeBSD でルータを実装する際の UPnP の定番ではないだろうか。

今回気付いた問題

これまでずっと自宅ゲートウェイでは MiniUPnPd も起動していたし、UPnP が動作していると思い込んでいた。

が、しばらく前に “Call of Duty: Modern Warfare” を購入したのに、起動時に “Server Disconnected” となってタイトル画面しか表示されない問題が発生した。

ググると色々出てはくるが、大体はインターネット側の問題のパターンだった。そこで iptables -L で UPnP が使われているかを確認したが、

Chain MINIUPNPD (1 references)
target     prot opt source               destination         
ACCEPT     udp  --  anywhere             192.168.2.141  udp dpt:xbox

見た感じ、特に問題はないように見える。UPnPCJ でもテストをしてみたが、ポートは開放できているように見えた。

が、実際のところは……

しかし、実際のところは「ポートが開放されているように見えていた」だけだった。

確かに MINIUPNPD チェインにルールは動的に追加・削除されるのだが、iptables -L の結果を全部確認したところ、そもそもFORWARD チェインから MINIUPNPD にジャンプするルールが存在していないので MINIUPNPD チェインが存在しないに等しい状態だった。

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         
TCPMSS     tcp  --  anywhere             anywhere             tcp flags:SYN,RST/SYN TCPMSS clamp to PMTU

なので、FORWARD チェインから MINIUPNPD チェインに飛ぶルールを追加すればよい。

なぜこうなっていたのか

そもそも余計なことをしていなければ、この辺のルールは自動的に設定される。Gentoo Portage の実装の場合、 /etc/miniupnpd/iptables_init.sh でチェインの初期化を行っており、その中で FORWARD チェインから MINIUPNPD チェインに飛ぶルールも追加している。

# MINIUPNPD chain for filter
if [ "$FDIRTY" = "${CHAIN}Chain" ]; then
	echo "Filter table dirty; Cleaning..."
elif [ "$FDIRTY" = "Chain" ]; then
	echo "Dirty filter chain but no reference..? Fixing..."
	$IPTABLES -t filter $ADDCMD FORWARD -i $EXTIF ! -o $EXTIF -j $CHAIN
else
	echo "Filter table clean..initalizing.."
	$IPTABLES -t filter -N MINIUPNPD
	$IPTABLES -t filter $ADDCMD FORWARD -i $EXTIF ! -o $EXTIF -j $CHAIN
fi

にもかかわらずうちで有効になっていなかったのは、

  • 起動ごとに明示的にスクリプトで iptables を再設定していた。
  • /etc/miniupnpd/iptables_init.sh の呼び出しをそのスクリプトの先頭でやっていて、呼び出し後に FORWARD チェインをフラッシュしていた。

という凡ミスだった。

これを修正して再度 Call of Duty を起動したところ、無事にタイトル画面まで遷移できた。

他の workaround; UPnP を無効にする

なお、その他の解消方法として UPnP を無効にするというのもある。Call of Duty もそうだが、UPnP が有効になっているからこそ UPnP を利用するのであって、UPnP が無効であればそれ前提にサーバに接続にいく

実際、Call of Duty も MiniUPnPd を落とせば問題なくタイトル画面まで遷移する。セキュリティという観点でも実は UPnP を無効にするのが正しい選択かも知れない。

最後に MiniUPnPd の設定を確認しておく

最後に、改めて MiniUPnPd の設定に問題がないかを確認しておいた。確認ポイントは以下となる。

  • LAN 側と WAN 側のインターフェイスが正しく指定されているか (今回は LAN 側が eth1、WAN 側が ppp0)
  • /etc/miniupnpd/miniupnpd.confsecure_mode=yes になっているかどうか
  • インターネット側に MiniUPnPd がオープンになっていないか (nmap でスキャンすると分かりやすい)

あまりにも初歩的なミスではあったが、UPnP などそうそう確認する箇所でもないのでいい機会になったと思う。

もちろん既製のルータを買うと諸々楽ではあるが、エンジニアとしてはこの辺はまず自分でまかなうところから始めると色々と理解が捗ると思っている。