IPsec先着一名様問題

このメモでも書いたように、光でんわルータに付属のVPNサーバ機能を使って家のネットワークに接続していたんだけど、同一LAN下にある複数のマシンから家のルータに同時にコネクションを貼ることができなかった。当たり前というか仕方がないことだとわかったんだけど、学びになったのでメモ。いやほんとネットワーク全然わかってないなあ…。

原因

結局の所、IPマスカレードを前提としたIPv4 LAN網と、レイヤ3のVPNであるIPSecの相性が悪いということ。

詳しく

IPSecは、暗号化されたIPパケットをESPというプロトコルでカプセル化して送るのだけど、これはそもそもレイヤ3なのでTCPでもUDPでもないから、ポート番号は存在しない。そのため、NAT(=IPアドレスの変換)まではできるんだけど、IPマスカレード(=送信元ポートの変換)ができない。

普段、LAN側のマシンがシームレスにWAN側のアドレスにアクセスできているのは、IPマスカレードにより送信元ポートもあわせて変換しているところが大きい。ローカルIPよりはるかに少ない(というか普通1個しかない)グローバルIPしかなくても、送信元ポート番号と宛先IPの両方を合わせてローカルIPとその送信元ポート番号にマップすることでコネクションを問題なく張ることができるというわけ。(もちろん、所詮65535個しかポート番号はないのでローカルアドレスが無茶苦茶コネクションを貼りまくったら原理的にはポートが枯渇してIPマスカレードもうまくいかなくなるんだろうけど。でかい組織のネットワークとかで問題にならないんだろうか)

逆に言うと、IPマスカレードがないと、複数LANアドレスが同一WANアドレスにアクセスしようとすると、NATゲートウェイは返答をどのLANマシンに返せばよいかわからなくなってしまう。そのため通信がうまくいかなくなる。同様のことがレイヤ3プロトコルであるIPSecでも起きる。具体的には、ESPプロトコルがコケてしまいL2TPコネクションが貼れなかったというわけ。

もちろん、同様の問題は原理的にはその他のレイヤ3/4プロトコルでも生じうるはず(ところでOSIモデルって同レイヤでもIPとIPSecみたいに明らかに上位下位の別がある場合もあって、まあそもそも本質的にきっちり分けられないものなので結局雰囲気なんですよね)。まあわけのわからんどマイナープロトコルならともかく、ICMPは現実的に問題になったりしないのかしら?と思ってぐぐったらこんなのが出てきた。少なくともヤマハのルーターではICMP Echo/Echo Replyに関してはIdentifierをポート番号のように書き換えることで”ICMPマスカレード”を行っているらしい。どっちも16bitなのでまあ素直な実装ではある。RFCとかで定められているかどうかは面倒なので探していないけど。とはいえ、その他のパケットではやっぱり同じように問題が生じうるので、覚えておくとなにかの役に立つ…ことはまあねえだろうな。

解決方法

IPSecをUDPに乗っけてしまえばよい。strongSwanの場合、forceencapsというオプションで、無理やりESPをUDPに乗っけることができる(どうも送信元も特定のポートを使うことを要求するIKEでコケると勝手にやってくれるようだが、ルータが気を利かせてくれている場合同時に繋ぎでもしなきゃそういうことは起きないよね。多分バカなルータだと勝手にうまく行くのだろう。まさに地獄への道はなんとやらという話だなあ)。AndroidのIPSec/L2TPには対応するオプションが見当たらず。

この方法の欠点を挙げるとすると、IPSecをUDPに乗っけるなら最初からOpenVPN on UDPにすりゃいいのでは?という気持ちになるところ。まあ、光電話のルータが対応していないからね…。

Comments

comments powered by Disqus