P2P协议数据识别
本文档的Copyleft归yfydz所有,使用GPL发布,可以自由拷贝,转载,转载时请保持文档的完整性,严
1. 前言
目前P2P应用越来越普遍,如BT、eDonkey、eMule等,这些新一代的P2P突破了老一代数据传输如FTP协议只能两台机器之间传输的瓶颈,可以用多线程多主机/服务器间的连接,可以把网络带宽利用到极限。
由于这些应用对网络带宽带来了很大压力,因此很多场合下P2P成了运营商、网管们所痛恨的对象,运营商迫于压力不敢作限制,但很多网管在所管的防火墙上都进行了P2P的限制。
现在的P2P软件都可以使用动态端口来进行数据连接,而且也可以使用其他协议的标准端口如80等进行通信,因此普通的端口封禁很难奏效,只能从通信内容中进行判断。
netfilter的pom中提供了ipp2p匹配,可匹配很多种P2P协议,本文就是根据ipt_ipp2p.c文件说明各种p2p协议的数据特征。
以下说明都是跳过TCP/UDP头而直接到数据部分。
2. UDP
2.1 eMule/eDonkey/Kad
这几个协议用二进制数进行协商:
--------------------------------------------------------------------第一字节 | 第二字节 | 第三字节 | 其他字节 | UDP长度 | 类型
-------------------------------------------------------------------- 0xe3 | 0x9a | any | any | 26 | edonkey
0xe3 | 0x96 | any | any | 14 | edonkey
-------------------------------------------------------------------- 0xc5 | 0x91 | !0 | any | 12 | emule
0xc5 | 0x90 | !0 | any | 26 | emule
0xc5 | 0x92 | any | any | 10 | emule
0xc5 | 0x93 | any | any | 10 | emule
-------------------------------------------------------------------- 0xe4 | 0x50 | any | any | 12 | kad
0xe4 | 0x58 | !0 | any | 14 | kad
0xe4 | 0x59 | any | any | 10 | kad
0xe4 | 0x30 | any | 0x01(19) | >26 | kad
0xe4 | 0x28 | any | 0x00(69) | >76 | kad
0xe4 | 0x20 | !0 | !0(35) | 43 | kad
0xe4 | 0x00 | any | 0x00(27) | 35 | kad
0xe4 | 0x10 | any | 0x00(27) | 35 | kad
0xe4 | 0x18 | any | 0x00(27) | 35 | kad
0xe4 | 0x40 | any |1(19)0(20)| >40 | kad
--------------------------------------------------------------------
2.2 Gnutella
就是明文检查起始数据是否为"GNUTELLA "或"GND"
2.3 KaZaA
UDP数据部分的结尾6个字节是: "KaZaA/0"
2.4 BitTorrent
UDP长度24字节(含UDP头), 起始8个字节为: 00 00 04 17 27 10 19 80
3. TCP
3.1 Ares
--------------------------------------------------------------------数据长度 | 类型 | 数据内容
-------------------------------------------------------------------- 6 | 连接 | 二进制数: 03 00 5a 04 03 05
60 | 下载 | 字符串: "PUSH SHA1:", 数据结尾为"/n/n"
--------------------------------------------------------------------
3.2 SoulSeek
前8个字节格式为: xx xx 00 00 yy zz 00 00, 其中xx xx为16位负载长度-4, yy!=0, zz任意或者数据长度8字节,全0
或者数据格式为: 01 xx 00 00 00 yy .. zz 00 00 00 .., 其中负载长度大于xx+6, 负载第xx+4+1字节(zz)不为0, 而负载第xx+5+1字节, 第xx+6+1字节为0.
3.3 WinMX
负载长度为4字节时负载内容为"SEND"或负载长度为3字节时负载内容为"GET"
其他情况负载长度必须大于10, 负载必须以"SEND"或"GET"开头, 而且负载内容中出现 0x20 0x22, 之后出现 0x22 0x20.
3.4 appleJuice
负载起始数据为"ajprot/r/n"
3.5 BitTorrent
负载第一字节为0x13, 而且后续数据为: "BitTorrent protocol"
3.6 KaZaA命令
负载最后以"/r/n"结尾, 而且起始数据为: "GET /.hash="
3.7 gnutella 命令
负载最后以"/r/n"结尾, 而且
起始数据为: "GET /get/",
或者是: "GET /uri-res/",
3.8 各种类型的gnutella
负载最后以"/r/n"结尾, 而且
起始数据为: "GNUTELLA CONNECT/",
或者是: "GNUTELLA/"
或者是: "GET /get/", 或 "GET /uri-res/", 而且负载中包含"/r/nX-Gnutella-"或"/r/nX-Queue:"
3.8 各种类型的KaZaA
负载最后以"/r/n"结尾, 而且
起始数据为: "GIVE ",
或者是: "GET /", 而且负载中包含"/r/nX-Kazaa-Username: "
3.9 edonkey文件碎片传输
负载第一字节为0xe3, 第6字节为0x47
3.10 各种类型的edonkey/emule
负载第一字节为0xd4, 而且第2,3字节表示的长度等于负载长度减5, 而且第6字节为0x82
或0x15负载第一字节为0xc5, 而且第2,3字节表示的长度等于负载长度减5, 而且第6字节为0x01/0x02/0x60/
0x81/0x82/0x85/0x86/0x87/0x40/0x92/0x93/0x12
负载第一字节为0xe3, 如果第2,3字节表示的长度等于负载长度减5, 而且第6字节为0x01/0x50/0x16/
0x58/0x48/0x54/0x47/0x46/0x4c/0x4f/0x59/0x65/0x66/0x51/0x52/0x4d/0x5c/0x38/0x69/0x19/
0x42/0x34/0x94/0x1c/0x6a; 如果第2,3字节等表示的长度大于负载长度减5, 而且第4,5字节为0, 第6字节为0x01或0x4c; 如果第2,3字节等表示的长度小于负载长度减5,则负载偏移该长度字节后的第6字节为0xe3/0xc5
3.11 直接连接(Direct Connect)
负载第一字节为0x24, 之后数据为: "Send|"
3.12 各种直接连接(Direct Connect)
负载第一字节为0x24, 而且最后一个字节为0x7c, 而且从负载第2字节的数据格式为:"Lock "/"Key "/"Hello "/"MyNick "/"Search "/"Send"
4. 结论
ipt_ipp2p.c中定义了很多P2P软件的数据的判断模式, 对于二进制的数据可能误判少些, 但文本数据误判可能性就大得多,从协议标准看,eMule/eDonkey的判断应该是比较准确的, 其他的有效性没测试过。
注意程序中将网络数据转换为16位,32位整数的宏:
#define get_u16(X,O) (*(__u16 *)(X + O))
#define get_u32(X,O) (*(__u32 *)(X + O))
因为这些协议都是在Intel硬件,Microsoft操作系统实现,定义的时候就所有数据就都定义为“小头”序而不是一般网络协议中的“大头”序,所以不需要进行ntohs和ntohl转换。
http://svn.dd-wrt.com:8000/dd-wrt/browser/src/linux/ar531x/linux-2.6.23/net/ipv4/netfilter/ipt_ipp2p.c?rev=8169