2006年05月02日

Linux 2.6 kernel の IPsec と NAT -- 2.6.15 と 2.6.16 の IPsec の違い

はてなブックマークに登録

先に結論から書くと,2.6 kernel の IPsec を NAT と絡めて使う場合,NAT の方向によっては 2.6.16 以後のカーネルを使う必要がある,というお話です.2.6.15 系までのカーネルでは,意図したとおりに NAT が適用され無いことがあります.これは,IPsec のチャンネルを通るパケットが ESP パケットにカプセル化されるタイミング,に依るものです.

Linux ではパケットはここ(日本語のページはこちら)にある図のように,iptables の各テーブルとチェインを順に辿っていきます.次のように IPsec 接続されたネットワークがあるとします.

                IPsec
 LAN 1 -- GW1 ======= GW2 -- LAN2
この場合,LAN1 から LAN2 に流れるパケットが GW1 でカプセル化されるタイミングは,2.6.15 系のカーネルでは,filter テーブルを出た直後になります.即ち
      ┌────────- GW1 ───────────┐
 │                      │
 │ nat filter nat   │
 │ PREROUTING FORWARD POSTROUTING │
(raw)->│-------------->--------->[ESP]------------->│->(ESP)
 │                      │
 └──────────────────────┘
    (図1)
です.つまりこの場合,例えば
 iptables -t nat -A POSTROUTING -s LAN1 -j SNAT --to newip ‥‥‥ (ex.1)

として POSTROUTING で SNAT をかけようとしても,POSTROUTING にたどり着く前に既にカプセル化されているので,本来 NAT したいパケットを扱うことができません.ちなみにこのパケットを SNAT ではなく, PREROUTING で DNAT する分には問題なくできます.例えば
 iptables -t nat -A PREROUTING -s LAN1 -d oldip -j DNAT --to newip ‥‥‥(ex.2)

のようなルールです.ところが,同じ DNAT でも逆向きのパケットに DNAT をかけようとした場合は,やはり上手くいきません.つまり
 iptables -t nat -A PREROUTING -s LAN2 -d oldip -j DNAT --to newip ‥‥‥(ex.3)

のような,IPsec のチャンネルから入ってきたパケットに対して,GW1 で DNAT することを狙ったルールです.この場合の(行きの)パケットの流れは,実は次のようになります.
       ┌───────── GW1 -──────────┐
│                      │
│ filter nat     │
│   INPUT PREROUTING │
│ +--<----------<------------<---│<-(ESP)
│ un capsulate             │
│ +--------->>------>>---------+ │
│  nat filter nat    | │
│  POSTROUTING  FORWARD PREROUTING | │
(raw)<-│<---------------<----------<------------<-+ │
│                      │
└──────────────────────┘
    (図2)

つまり,ESP パケット自体は自分宛になっていますので,いったん INPUT まで到達します.その後カプセル化されていたパケットが取り出されて,再び iptables の中を,あたかも普通に着信したかのように流れていきます.ご覧の通り,生の状態のパケットが PREROUTING を通りますので,このケースでも DNAT 自体は問題なく行われます.ところが,帰りのパケットは図1の経路を通ります.ここで問題になるのは,行きの DNAT に対応した帰りのパケットの SNAT が,POSTROUTING チェインを通らないため適用されない,ということです.
iptables で NAT のために明示的に設定するルールは,DNAT にしても SNAT にしても行きのパケットに関してのみです.けれども当然ながら,行きのパケットを NAT すれば帰りのパケットも逆の NAT をしてあげないと,通信は上手くいきません.これは行きのパケットとペアになるものですから,iptables が暗黙的に追加します.ex.2 のルールが意図したとおりに動作するのは,行き(図1)も帰り(図2)も NAT されるべき場所(チェイン)を生の状態で通過するからです.ex.3 の場合,行き(図2)の場合は生の状態で通過しますが,帰り(図1)の場合はカプセル化された状態で通過します.なので,通信が上手くいかないのです.


さて,これが 2.6.16 になると,図1の方向のパケットの流れが次のようになります.

       ┌───────── GW1 -──────────┐
│                      │
│ nat filter nat     │
│ PREROUTING   FORWARD POSTROUTING │
(raw)->│->-------------->---------->------------>-+ │
│                en capsulate│
│ +---------<<------<<---------+ │
│       | filter nat     │
│       |  OUTPUT POSTROUTING  │
│       +-->---------->-------------->-│->(ESP)
│                      │
└──────────────────────┘
    (図3)

つまり,図2のケースと同じように,生の状態のままで全てのチェインを通った後 ESP パケットにカプセル化され,ESP パケット自体は自身から外へと出て行くようになります.このため,POSTROUTING での SNAT が正しく動くようになります.

klab_gijutsu2 at 15:26│Comments(0)TrackBack(0)ipsec 

トラックバックURL

この記事にコメントする

名前:
URL:
  情報を記憶: 評価: 顔   
 
 
 
Blog内検索
Archives
このブログについて
DSASとは、KLab が構築し運用しているコンテンツサービス用のLinuxベースのインフラです。現在5ヶ所のデータセンタにて構築し、運用していますが、我々はDSASをより使いやすく、より安全に、そしてより省力で運用できることを目指して、日々改良に勤しんでいます。
このブログでは、そんな DSAS で使っている技術の紹介や、実験してみた結果の報告、トラブルに巻き込まれた時の経験談など、広く深く、色々な話題を織りまぜて紹介していきたいと思います。
最新コメント