Vyatta で P2P 帯域制御装置を作ろう

ISP 的なところに勤めていればおそらくどこでも「P2P ユーザが帯域を占有しちゃって困っちゃうなー」的な話に出くわしますよね。もしかしたら「なにを今更」って感じなのかもしれませんけど。いや、 P2P が悪いとかそういう話じゃなくて、 P2P みたいな応答性を必要としないトラヒックのためにそれ以外のトラヒックが遅くなるのはなんかなぁ、と。てか「もっとトランジット買え」ってのはとりあえず置いといて。

Linux の iptables の拡張モジュールに ipp2p ていうのがあって、これじつは Vyatta にも搭載されているんですが、残念なことに Winny と Share には対応していないんですよね。ちょっと調べるとすぐわかると思うんですけど、 Winny と Share って秘匿性を高めるために通信を全部暗号化しているので、途中経路の端末でそのパケットが Winny や Share であることを識別するのって結構めんどくさいんです。でもこのへんこのへんにプロトコル解説があったりして、なんとかがんばれば ipp2p に Winny/Share 検知機能追加できんじゃね?ということで実装してみました。

ただ ipp2p を Winny/Share 対応にするだけじゃつまらんので Vyatta に組み込んでお手軽 P2P 帯域制御装置をつくってみましょう、と。

まじめに試験してないのでもしかしたら不安定かも。不具合等ありましたら @m_asama まで教えてくだされ。

用意

ISO イメージをここに置いておきます。普通に Vyatta としてインストールしてください。

自分で ISO イメージを作りたいというひとは以下の 3 つのパッケージにそれぞれパッチを当ててから ISO イメージを作ってください。

設定はこんな感じにします。

firewall {
    modify FW1 {
        default-action accept
        rule 10 {
            action modify
            modify {
                mark 1
            }
            p2p {
                all
            }
        }
    }
}
interfaces {
    ethernet eth0 {
        firewall {
            in {
                modify FW1
            }
        }
        traffic-policy {
            out SH1
        }
    }
    ethernet eth1 {
        firewall {
            in {
                modify FW1
            }
        }
        traffic-policy {
            out SH1
        }
    }
}
traffic-policy {
    shaper SH1 {
        bandwidth 100mbit
        class 10 {
            bandwidth 100kbit
            match p2p {
                mark 1
            }
        }
        default {
            bandwidth 100mbit
        }
    }
}

eth0 と eth1 には適当にアドレス振ってください。

ちなみに “set firewall modify FW1 rule 10 p2p” の部分は P2P プロトコルを個別に指定できます。こんな感じ:

vyatta@vyatta# set firewall modify FW1 rule 10 p2p 
Possible completions:
  all		AppleJuice/BitTorrent/Direct Connect/eDonkey/eMule/Gnutella/KaZaA application packets
  applejuice	AppleJuice application packets
  bittorrent	BitTorrent application packets
  directconnect	Direct Connect application packets
  edonkey	eDonkey/eMule application packets
  gnutella	Gnutella application packets
  kazaa		KaZaA application packets
  share		Share application packets
  winmx		WinMX application packets
  winny		Winny application packets

あ、 all の説明に WinMX/Winny/Share が抜けてるけど気にしないでください。ちゃんと入ってます。ていうか help 書き換えるの忘れてた。

そうだ、帯域制限するんじゃなくて P2P トラヒックをロープライオリティキューにいれちゃう、なんて設定もできますかね。 QoS よくわかってないんで想像で言ってますけど。

説明

Netfilter(iptables) には nf_conntrack というコネクションをトラッキングするための仕組みがあるのでそいつを利用して nf_conntrack_ipp2p というカーネルモジュールを作りました。 nf_conntrack_ipp2p は Winny/Share の Hello パケットを検知して以降そのフローのパケットに印をつけます。もともとある ipt_ipp2p はその印がついていたら Winny/Share であるとして match を返します。

Vyatta の firewall にはあるルールに一致するパケットにマークをつける機能がありますが、この機能を使って P2P トラヒックにマークをつけます。

Vyatta の QoS には firewall によりマークが付けられたものを特定のクラスとして設定できるので、そのクラスの上限帯域幅を設定します。

本当はブリッジで利用できるようにして透過型 P2P 帯域制御装置にしたかったんだけど Vyatta がいまのところ ebtables に対応していないようなので諦めました。

あ、あと nf_conntrack ってポート番号を指定しないとトラッキングできないみたいなんですけど Winny/Share はポート番号もランダムなので (1) 通常の nf_conntrack 検索 (2) なかったらポート番号 0 の nf_conntrack 検索 というふうにヘルパを改造してます。これはなんとなくかっこわるいのでほかにいい方法があったら書き換えたいかも。ちなみに nf_conntrack_ipp2p はすべてのフローで nf_conntrack を走らせることになるので性能はかなり劣化しそう。暇を見てベンチマークとかとってみようかな。

謝辞

Share の復号化で躓いたとき @tori932 さんからヒント(2006-08-09 ■[Java] Winny/Shareの初期ノード暗号アプレット)を教えてもらいました。この情報がなかったら諦めてたと思います。ありがとうございました!

宣伝

6/10(金) に Interop のエデュケーショナルコンファレンス で Vyatta の拡張性について話してきます。プログラムのタイトルは “仮想ルータ Vyatta の活用と実態” で、自分は最後の方です。もし Vyatta の拡張に興味のある方はご検討ください。プログラムの詳細はこちら。事前登録はこちらから。

Comments are closed.