pfでNAPTしている物好きさんがDSのwifiでエラー86420を発生させないように生きる方法

Posted on 2010/11/22(Mon) 19:03 in technical

昨今、ポケットモンスター ブラック/ホワイトが発売されたために、自宅で孵化作業に勤しむサラリーマンも増えていることであろう。

そして、自宅のルーターは何を思ったかFreeBSDで作った PPPoE + NAPT BOXだったりするかもしれない。

そういう話の通じる人向け。

環境

ルーター

  • FreeBSD 7.3-R
  • pf  + mpd5

クライアント

  • DS lite ポケットモンスター ブラック(協力相手)/ホワイト(自分)
  • テスト用ノード(windows7)

注記

  • 元々NAPT構成が組まれており、内部からの開始セッション(応答トラフィックを含む)は全て許可されている。
  • サーバ等をrdr(リダイレクト)して公開している

解決策

pf.confに下記のような設定を加える。:

#-----------------------------------------------
# Define
#-----------------------------------------------
ext_if = "ng0"

#-----------------------------------------------
# Define for DS
#-----------------------------------------------
ds = "192.168.1.101"
ds_udp_port = "{49152:65535}"
ds_tcp_port = "{27900,27901,28910,29900,29901,29920}"

#-----------------------------------------------
# IPv4 NAT for DS
#-----------------------------------------------
nat on $ext_if from $ds to any -> ($ext_if) static-port

#もし、元々natの設定を投入している場合、それより上の行に記載する。

#-----------------------------------------------
# redirect
#-----------------------------------------------
#--- Static NAT for DS
rdr on $ext_if inet proto udp from any to ($ext_if) port $ds_udp_port -> $ds
rdr on $ext_if inet proto tcp from any to ($ext_if) port $ds_tcp_port -> $ds

#-----------------------------------------------
# Nintendo DS.
#-----------------------------------------------
pass in on $ext_if proto udp from any to any port $ds_udp_port
pass in on $ext_if proto tcp from any to any port $ds_tcp_port flags S/SA

解決(緩和)される症状

  • wifiコネクションには繋がるのに、いざ交換等をしようとすると86420エラーになる
  • 任天堂の提供する 接続チェック が接続不可と出る

この手法の問題点

  • 49152~65535/UDPがDS向きになっちゃう
  • 複数台のDSが存在する時どうするの?
  • リダイレクト先を複数選択しておけば、確率の問題で接続確立は可能だったので、複数行書けばたぶん大丈夫

類似する問題の要点

  • pfはデフォルトのNATタイプがデフォルトではSymmetricになっている
  • DSはUDPによってやり取りされる開放ポート通知をパケット内部に記載してネゴシエートする

ネゴシエートには、以下の仕様があると推測した。

  • ネゴシエート用のポートは、基本的に29700/UDPと29701/UDPを使用する
  • その後の転送は、ネゴシエートされた49152~65535/UDPを使用する(範囲は若干曖昧だが、観測結果からUDPポートのDynamic Port Numberと類推する)
  • ポート番号らしきデータは確認できたけど、他のデータはよく見えてない

SIPと同じ問題だね!

よって、類似の問題は以下の2点によって解決できると考えられる。

  • DSの持つIPアドレスに対してはstatic-port(Port Restrict)を適応するようにする
  • ネゴシエート後に使用されると類推されるUDPポートをあて先とするパケットは、DSにリダイレクトする(こちらが、一般に叫ばれているポート開放と呼ばれる処置)

pfの設定について

pfの場合は以下のようにNATタイプを選択することが出来る。(デフォルトはSymmetric、下記はPort Restrict):

nat on $ext_if from $ds to any -> ($ext_if) static-port
  • pfのNATの設定は、先にヒットした方が優先される
  • 設定変更したら # pfctl -f /etc/pf/pf.conf みたいにして読み込めばすぐに適応される

その他

  • 任天堂公開の「動作済みインターネット接続機器一覧」に×と記載のある物はSymmetric NATの可能性が高い
  • 同様に、〇の場合はCone NAT またはRestrict NATの可能性が高い
  • 任天堂の提供する「接続チェック」で接続不可と出ても、接続可能な場合がある
  • Symmetric NATを強制されるルータを使用している場合、ルータの買い替え以外に根本的な解決が不可能
  • 非常に低い確率で接続できてしまう場合もあると思うけど根本的には解決してない
  • プライベートアドレスが払い出されるISPでも接続可能な場合、当該ISPはCone NAT またはRestrict NATであるか、事実上のNAT(≠NAPT)である可能性が高い
  • 同時接続者数が多い場合に繋がりにくい(エラー86420が発生する)のは、 同一送信元ポートを選択したノードが付近に存在し、NAPTする装置が重複回避のために送信元ポートを変更したためと考えられる

ひとりQ&A

  • Q: TCPの80番、443番ポートを開けるって聞いたんだけど・・・
  • A: おそらく不要です。
  • Q: UDPのポート全部を開けるって聞いたんだけど・・・
  • A: ポケモン以外では使うこともあるのかもしれませんが、おそらく不要です。よく知らなくてごめんなさい
  • Q: 僕の無線ルータじゃ駄目ってことですか?
  • A: 市販品のことは知りません。メーカにNATタイプを聞くのも手です

繋がらなくても諦めないでね!

Happy DS life !