L7-filter的工作原理
L7-filter为我们实现了可以从应用层实现过滤的功能,它的实现原理仍然是基于特征的关键字匹配。但是它不是简单的匹配某个单字和词,它使用了更高级“正则”来进行匹配。
 正则表达式(regular expression)描述了一种字符串匹配的模式,可以用来检查一个串是否含有某种子串、将匹配的子串做替换或者从某个串中取出符合某个条件的子串等。
正则表达式是由普通字符(例如字符 a z)以及特殊字符(称为元字符)组成的文字模式。正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。
L7-filter在默认情况下,将同一个连接中的10个数据包或者2KB的数据包内容放在缓存中。并将缓存中的内容作为一段普通的文本,用模板文件中的正则去搜索,如果发现有正则匹配的内容,就会在netfilter中将这几个数据包DROP掉或者给数据包打上标记。
以上就是L7-filter的实现原理
模板文件格式
文件的名字必须和匹配的协议要相同。 (如果你要匹配的协议是“ftp”, 那你的文件名必须是 “ftp.pat”) 文件的内容格式如下:
  1. 第一行是协议的名字,要和文件名相同。
  2. 第二行是这个协议正则表达式定义。
正则表达式
l7-filter 使用 Version 8 正则表达式。 使用这个版本的正则有很多限制,只能使用一些基本的正则表达式。例如, 你不能使用范围限制 ("foo{3}"), 字符分类 ("[[:punct:]]") 或者向后引用。
另外, 我们加入了perl-style hex 来匹配 \xHH 这样的16进制值。(例如匹配一个tab, 则使用 "\x09").如果要匹配以下的字符,应当这样:
\x24 == $ (only matters if it's the last character)
\x28 == (
\x29 == )
\x2a == *
\x2b == +
\x2e == .
\x3f == ?
\x5b == [
\x5c == \
\x5e == ^ (only matters if it's the first character)
\x7c == |
l7-filter 对大小写不敏感l7-filter 对网络数据包当然一段普通的字符串来进行处理,所以对网络数据包中的\x00这样的为零的值是视而不见的,因为00代表没有,所以你不能匹配数据包中为null的字符。例如:一个包中的数据部分为4字节,但是这4字节的内容的某一个或者多个字节的值可能为零。这样的话,在l7-filter看来,这个数据包的长度有可能是0,也可能是1,也可能是2或者3或者4
例子:
[\x09-\x0d -~] == 可打印字符, 包括空白字符 whitespace
[\x09-\x0d ] == 任何空白字符
[!-~] == non-whitespace printable characters
怎样写一个好的模板
1)一个模板既不要写得太详细,也不要写得太宽泛。太精细了,会导致效率降低,太宽泛了会导致误杀其它网络协议。
模板 "bear" 没有写得比较精确. 这样的话,凡是连接中包含有"bear" 的都会被匹配到。如,一个HTTP 请求[url]http://bear.com[/url] 也会被匹配到。
具体写模板的方法
一、首先便是抓包了。用Ethereal抓包,观察数据包的内容的特征和规律。
以下以QQ的数据包为例:
怎样写L7-filter 的模板文件_休闲
我们看它数据包的数据内容部分(不管IP层,只看应用层),对比每一个数据包的内容,就可以发现一个规律,每一个包的第一个字节是0216进制值),最后一个字节是0316进制值)。
有了这个规律,我们就可以用正则表达式来表达它了。
一、正则表达式的相关知识。
只讲最基本,如果不明白的,可以查一些相关的资料。
^代表首字符,$代表末字符,.代表任意一个字符,.?代表零个或者一个字符,.+代表一个或者任意多个字符,\是代表转义字符(\x02这个表示匹配16进制的02值)。
二、结合以上知识,因为QQ包的第一个字节是16进制02,所以正则是^\x02,最后一个字节是16进制03,正则是\x03$,在L7-filter的缓存中的QQ数据包中可能有任意个字节,再将两个正则结合起来就应当是^\x02.+ \x03$
三、最后写一个pat文件,文件名就叫qq.pat,文件的内容如下:
qq
^\x02.+ \x03$
再将qq.pat放入/etc/l7-protocols这个目录中。执行iptables命令:
iptables -t mangle -A POSTROUTING -m layer7 --l7proto qq  -j DROP
即可成功阻止QQ的通讯。
 
 
 
另一个迅雷的模板例子:
 
启动迅雷,双击种子文件开始下载后,通过种子文件推算出文件的直接的下载地址。然后直接到下载地址进行下载。再次连接资源服务器,相当于bt服务器:hub4t.sandai.netIP 219.134.132.81向服务器发送tcp查询请求。
28 00 00 00 53 00 00 00 64 00 00 00 05 00 00 00 51 55 45 52 59 00 31 00 00 0016进制值)
第一字节不变                                      (以上四字节不变)
其中第11718192021字节不变。实际上ascii值为:query
服务器返回文件在其它地方的下载地址:
28 00 00 00 53 00 00 00 04 20 00 00 09 00 00 00 51 55 45 52 59 52 45 53 50 01 98
其中第11718192021字节的值不变。实际上ascii值为:query
最后迅雷根据服务器返回的文件的下载地址进行下载。
 
另外,如果返回的地址是另一迅雷用户本机上的文件,会使用以下命令进行下载
29 00 00 00 a9 00 00 00 5d 00 00 00 03 00 00 00 47 45 54 22 00 00 00 47 3a
其中:
1位可能值为28或者29,我觉得可能是迅雷的版本号,171819不变。后四位的值ascii值为:get
 
 
重要一点。迅雷每个命令间用3null值填充。而l7null不敏感。所以表达式为:
^[\x28\x29]...(query|get)
 
 
 
 
特别注意:L7-filter不是匹配每一个包的内容,而是匹配N个包中的全部内容。所以例子中,缓存中可能有NQQ的数据包,但是缓存中的第一个字节肯定是QQ包的第一字节,缓存中的最后个字节肯定是QQ包的最后一个字节。
想得太美  编写此文档  
2006-6-4