コピー&リダイレクトパターン(仮)実装編

先日「EC2でパケットをミラーリングしたい時ー」に書いたEC2インスタンスでパケットをキャプチャして別のコレクションポイントに送る構成を実装する方法について書いてみたいと思います。

インバウンドのパケットだけコピー&リダイレクト出来ればいい場合

まず、EC2インスタンスに入ってくるインバウンドのパケットだけをミラー&リダイレクトするのでしたら話は簡単ですので、この場合について書いておきます。

この場合であれば、iptablesのteeというターゲットを使えば簡単に実行出来ます。

例えば、下記のようにすればTCPの80番ポートで受信されるパケットのコピーを作って指定したIPアドレスに宛先を付け替えて送り出すことが出来ます。


sudo iptables -t mangle -A PREROUTING -p tcp --dport 80 -j TEE --gateway <IP of HOST B>

ちなみに、インバウンドのパケットだけで良ければと註釈したのにはわけがあります。

次の図を見ればわかるかと思いますが、teeを使った場合、宛先IPアドレスを書き換えてしまうので、アウトバウンドのパケットにこれを適用すると、リクエスト元のIPアドレスがパケットから失われてしまい、アクセス解析等を行いたい場合には使えない内容になってしまうのです。
(黄色がクライアントのアドレスだとすると、それがコレクタには届かない)

iptables-tee

両方向のパケットを宛先と送信元含めてキャプチャしたい場合はteeでは役不足となります。

別の方法としては、パケットのコピーを作った後、L2で宛先を書き換えてコレクタに送るという手があるかと思います。

この場合、上記の問題は起きませんが、コレクタとキャプチャポイントが同一サブネットにいる必要があること、という条件が付きます。

サブネットが異なれば当然L2フレームを届けることは出来ませんので。

また、EC2-Classicではそもそも出来ません。

なぜならL2はインスタンスからは見えないブラックボックスとなっている為です。

はarpコマンドの出力例。fe:ff:ff:ff:ff:ffというアドレスがプロキシーARPのようになっていて、そこにすべてのパケットが送られるようになっているのですね。

ec2classic-arp

L3でトンネルしてコレクションポイントに集める

 サブネット越えもしつつ、送信先・送信元アドレスを残したままパケットを別の宛先に送りたいとすると、やはりトンネルしかなくなってきます。

とはいえ、オーバーヘッドは最小限にしたいですし、出来れば特別なソフトウェアを使うのも避けたい、カーネルに処理をさせたい、等々考えると自ずと選択肢は狭まってきます。

例えばここで取り上げるIP-in-IPは上記のようなポイントを考慮すると1つよい選択肢だろうと思います。

その名の通り、IPパケットを別のIPパケットのペイロードとして送る仕組みです(RFC1853)。

これを使えば、次の図のようにうまいことコレクションポイントにパケットを集めることが出来ますし、キャプチャポイントにもコレクションポイントにも特別なソフトウェアは必要ありません。

また、一方向の転送しかしないことを活かして、複数あるキャプチャポイント側のトンネルエンドポイントにすべて同じIPアドレスを指定すれば、コレクションポイント側では単一のトンネルインターフェースで全パケットを受け付けることが出来ます。(キャプチャポイントごとにトンネルインターフェースを作る必要がない)

ip-in-ip

tcのmirred(mirror & redirect)アクションを使えば特定のパケットを指定したインターフェースに再送出来るので、トンネルインターフェースを作った後はその設定を追加すればいけるはず。
設定例は次のような感じ。

キャプチャポイント側(Webサーバなど)の設定


#トンネルインターフェースを作成

ip tunnel add ipip0 mode ipip remote 192.168.1.10 local 192.168.1.20 ttl 64

#受信したパケットをトンネルインターフェースに流す設定
tc qdisc add dev eth0 ingress

tc filter add dev eth0 parent ffff: prio 10 protocol ip u32 match ip protocol 6 0xff match ip dport 80 0xffff flowid 10:1 action mirred egress mirror dev ipip0

#送信するパケットをトンネルインターフェースに流す設定

tc qdisc add dev eth0 root handle 10: prio

tc filter add dev eth0 parent 10: prio 10 protocol ip u32 match ip protocol 6 0xff match ip sport 80 0xffff flowid 10:1 action mirred egress mirror dev ipip0

コレクションポイント側の設定


ip tunnel add ipip0 mode ipip remote 192.168.1.20 local 192.168.1.10 ttl 64

上記設定をしていざ動かすと、、、なんとOSごとハングアップ orz…

どうも送信するパケットをトンネルインターフェースに流そうとすると逝ってしまわれるようで、受信したパケットのみを流す(上記設定の前半)分に関しては特に問題なし。
また、トンネルインターフェースでないネットワークインターフェース(eth1やlo)に流すと、受信・送信パケットともに問題なく流れます。

EC2インスタンスでも物理PCでも試したところ同じ現象が起きるので、どうやらLinuxカーネルが原因っぽい。

パケットがループしているということも考えたけど、それにしては受信側に1つもパケットが流れてこない不思議。

とりあえずトンネルインターフェースから出るパケットが再びeth0を通らないような設定にするとOSがハングアップしないことを確認。

ひとまずこれでパケットをキャプチャ出来るのでしてみることに。

そして見つけたのがこれだ、1, 2, 3.

capture

こちら、IP-in-IPのトンネルインターフェースにtcpdumpを走らせたところなんですが、本来パケット先頭にあるはずのIPヘッダが、赤い四角のところから始まっているのです。

そしてその手前には14 octetsの不可思議なゴミが。

14 octets,,, 14 octets, おー、なんと!Ethernetのヘッダじゃないですか!

よく見ればご丁寧にMACアドレスらしきバイト列の後にEthernet的に次に続くのはIPヘッダと書いてくれてます。(パケットキャプチャを見慣れているとHex文字列が読めてくる不思議)

つまり、実際に送信されるパケットは| IP | Ethernet | IP | 元のペイロード |という状態になっているということ。

わかったはいいけど、なぜ付いているのかは謎のまま。

どうやらtcを使ってingress以外のルールでトンネルインターフェースに出したときにのみ生じる現象のようで。

おそらくカーネルのバグですかね。

OSがハングアップしたのも、このなぜかIPヘッダの後ろにEthernetヘッダが続くパケットを処理出来ずにカーネルが刺さったのが原因かと。

カーネルのデバッグまで出来たら時間を見つけてやりたいところですが、一旦コンセプトを確認する為に、簡単なコードを書いて確認することにしました。

これで無事にコレクションポイントでIP-in-IPのインターフェースでキャプチャを行うことで、期待通り複数のキャプチャポイントでキャプチャしたパケットを集めることが出来ることを確認出来ました。
出来ればtc周りのカーネルのコードを見て問題を直してやりたいと思います。
今日はこの辺で。

コピー&リダイレクトパターン(仮)実装編」への3件のフィードバック

  1. ピンバック: EC2でブロードキャスト/マルチキャスト | Techy? Geeky? Whatever!

  2. Centos 使われています?
    私は今Centos 6.4上でTEEターゲットが含まれているxtables-addonをインストールしようとしていますがなかなか難しいですので、もしCentos使われていればxtablesのインストールのしかた是非教えてください。

    • こちら試したのはAmazon Linuxですね。Centosと同様、パッケージマネージャはyumです。
      特にパッケージインストールで苦労した覚えはないのですが、忘れているだけかもしれないので、何か思い出したら書きます。

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中