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バイト目までが対象範囲となる。