flea heart なwiki - iptables編
トラフィック制御をiptablesでやってみました。

インストール

iptablesはデフォルトで入っているのでインストール等は不要!

iptablesについて

本来iptablesにはテーブルという制御テーブルがあってそれらのテーブルを実行する順番が決まっていたりします。 通常Firewall用途で使用するのはfilterテーブルと呼ばれるものになります。 パケットを変換するNATなども実はiptablesの別のテーブルで出来てしまったりするのです。 ちなみに以下は各テーブルの説明です。 そしてトラフィック制御はfilterテーブルに設定します。
filter
このテーブルがデフォルトです。 このテーブルには * INPUT (ローカルマシン宛てのパケットに対するチェイン) * FORWARD (自分を経由して転送されるパケットに対するチェイン) * OUTPUT (自分から外部へ送信するパケットに対するチェイン) という3つのチェインがあり、これに独自のチェインを作成したりして制御します。
nat
このテーブルは新しい接続を開くパケットで使われるようですが、使ったことないのでよくわかりません。ちなみに PREROUTING (受信パケットを変換するためのチェイン) OUTPUT (自分から送信するパケットを変換するためのチェイン) POSTROUTING (パケットが出て行くときに変換するためのチェイン) という 3 つのチェインがあるそうです。
mangle
このテーブルは特別なパケット変換に使われるようですが、やはりこれも使ってないので不明。 PREROUTING (受信パケットを変換するためのチェイン) OUTPUT (自分から送信するパケットを変換するためのチェイン) INPUT (受信パケットに対するチェイン) FORWARD (自分を経由して転送するパケットに対するチェイン) POSTROUTING (パケットが出て行くときに変換するためのチェイン)    こいつは5つあるそうです。
raw
このテーブルは、接続追跡 (connection tracking) の対象外を設定するのに使われるようです。 つまりこれに定義されるやつはインスペクション対象外ってことになるのかな? PREROUTING (入力パケットに対するチェイン) OUTPUT (ローカルプロセスが生成したパケットに対するチェイン) があるそうな。
security
このテーブルは、名前通りセキュリティに関するアクセス制御のためのものらしく「強制アクセス制御 (Mandatory Access Control; MAC) 」の定義用ということらしい。 おそらくSELinuxを有効にしないと使えないのだろう。 INPUT (受信パケットに対するチェイン) OUTPUT (自分から外部へ送信するパケットに対するチェイン) FORWARD (自分を経由して転送されるパケットに対するチェイン)    があるとのことです。

書式

コマンドで投入する方法です。

# iptables -I [chain] -p [protocol] --dport [port] -m [protocol] -m hashlimit --hashlimit-name limit --hashlimit-upto [speed] --hashlimit-burst [burst] -j ACCEPT

制限値内のトラフィックは上のルールに合致します。 これを超えるトラフィックが発生した場合はDROPしないといけないので、この後にDROPする行が必要になります。

使ってみた


まずはデフォルトの状態。


結構入ってます。 ディストリビューションによっては空だったりするのですが。。。
で、本題のトラフィック制御は以下のようにします。

  # iptables -I INPUT -p tcp --dport 80 -m tcp -m hashlimit --hashlimit-name limit --hashlimit-upto 3666/s --hashlimit-burst 3666 -j ACCEPT
  # iptables -I INPUT 2 -p tcp --dport 80 -j DROP

この2行はセットで入れる必要があります。 1行目のように「-I INPUT」で定義するとINPUTチェインの最初に定義されます。 そして「-I INPUT 2」で定義すると2番めに定義されます。 このため上の定義は以下のようになります。
  • 1行目:INPUTチェイン(パケットが入ってくる時にフィルタ)で、80/tcp宛の通信は1秒間に3666パケットは許可します
  • 2行目:INPUTチェイン(パケットが入ってくる時にフィルタ)で、80/tcp宛の通信はすべて破棄します

となるのです。 2行目を書かないとpolicyがACCEPTなんかだったら結局意味がないので注意してくださいね。

もう1回定義を確認すると確かにちゃんと入っていました。


ちなみに設定は「3666/s」だったはずなのに、「5000/sec」で設定されています。 これはおそらくOSの割り込みタイミングなどで都合の良いあたりに修正されているものと思いますので、これ以上は調べません。

で、5000/secは実際どれくらいかというと。。。。

5,000 パケット/秒 = 5,000 * 1,500 バイト/秒 = 5,000 * 1,500 * 8 ビット/秒


となるので(1パケット1,500バイト前提ですが)、 60Mbps ということになりますね。 でもiptablesの制御は挙動といい、なんか納得いきませんね。 後一番の問題はインタフェース単位の設定ができないということでしょうか? サーバなど複数のインタフェースを持っている場合で特定のインタフェースだけ狙って制御したい場合は候補にすらなりません。

iptables の hashlimit について

この記事ではトラフィック制御に「hashlimit」という拡張機能を使ってますが、他の方の記事を見ると、「limit」を使っていたりします。 それでも実現は可能なようですが、「man iptables-extensions」 を見ると以下の記述があるので、私は「hashlimit」を使いました。

"xt_limit has no negation support - you will have to use -m hashlimit ! --hashlimit rate in this case whilst omitting --hashlimit-mode."

「xt_limit」は limit 拡張機能を使う際のモジュール名です。
たとえば、iptablesで limit を使って設定します。 こんな感じで(limit使えばなんでもいいです)。



でその後、「lsmod | grep limit」を実行すると「xt_limit」が出てきます。


英語はよくわからんが、 「limit じゃなくて hashlimit を使え! hashmode を省略すれば同じだから!」、多分こんな感じだろう。