iptablesのstringモジュールでバイト列にマッチさせる
特定の内容の通信だけを遮断したくなり、きっとiptablesに何かあるだろうと調べたらstringモジュールがあった。iptables 1.4.6のmanpageから引用する。
string This modules matches a given string by using some pattern matching strategy. It requires a linux kernel >= 2.6.14. --algo {bm|kmp} Select the pattern matching strategy. (bm = Boyer-Moore, kmp = Knuth-Pratt-Morris) --from offset Set the offset from which it starts looking for any matching. If not passed, default is 0. --to offset Set the offset from which it starts looking for any matching. If not passed, default is the packet size. [!] --string pattern Matches the given pattern. [!] --hex-string pattern Matches the given pattern in hex notation.
遮断の条件に指定したい内容が非ASCIIのバイト列だったので--hex-stringを指定した。--hex-string 'e7a781e381aee5908de5898de381af...'のように。ところがうまくいかず、ありそうな書式をいくつか試しても変わりがない。ふと、試しに、文字列をそのまま(16進数表記にせずに)指定したところ、当初の意図の通りにマッチした。
どうやら何かの書式があるらしいと、iptablesのコードにあたったところ、以下のルールに従ってバイト列に変換されることがわかった。
- 「|」にはさまれた部分はバイト列の16進数表記として処理される
- それ以外の部分にある文字はその文字自身を表す
- ただし「\」により続く文字の特別な意味をキャンセルできる(「\|」や「\\」)
先の例については--hex-string '|e7a781e381aee5908de5898de381af...|'とするのが正しいやり方となる。また、--hex-string 'a|62|c'は「abc」にマッチし、--string abcや--hex-string abcを指定したのと同じ結果となる。指定できるバイト列の長さ(変換後の長さ)は128バイトまでのようだ。
--fromや--toの指定を加えると、マッチ対象とする範囲を指定できる。--from 20ならTCPヘッダ(など)以降(〜65535バイト目まで)が対象となり、特に指定しなければIPパケットの先頭から65535バイト目までが対象範囲となる。