这是我在写sniffer程序过程中发现设置的BPF规则出现过滤错误后,用一个等价问题在白云黄鹤BBS的linux版面提出的讨论,后来scz进行了文字化的总结。我懒,所以直接把scz的文章复制过来了(http://www.opencjk.org/~scz/200503141619.txt),呵呵。当然,文后再附一篇Karno@白云黄鹤对规则写法的解释。
原题:================================================================
标 题: tcpdump的一个bug
发信站: 武汉白云黄鹤站 (2005年03月13日22:14:34 星期天), 站内信件
tcpdump 'ip and udp src port 53' or 'ip and udp src port 1233' or arp
居然无法抓到源端口是53的udp包
======================================================================
标题: tcpdump/libpcap过滤规则解析中的BUG
2005-03-14 16:19
今天收到"quickmouse@华中"的一封信,他想捕捉源端口为53/UDP或1233/UDP的报文以及ARP报文。当时我说可以这样:
tcpdump 'ip and udp and src port 53 or 1233' or arp
结果他回信说这个命令将捕捉部分TCP报文,我觉得很奇怪,感觉上不太可能,于是执行了如下命令测试:
telnet <target> 53
这里<target>上并未侦听53/TCP,于是将回送一个RST报文。我在前述tcpdump命令的输出中并未看到这个RST报文。可耗子这样说,肯定不会空穴来风,他让我用-d确认一下,结果看到这个输出:
# tcpdump 'ip and udp and src port 53 or 1233' or arp -d
(000) ldh [12]
(001) jeq #0x800 jt 2 jf 17
(002) ldb [23]
(003) jeq #0x11 jt 4 jf 10
(004) ldh [20]
(005) jset #0x1fff jt 19 jf 6
(006) ldxb 4*([14]&0xf)
(007) ldh [x + 14]
(008) jeq #0x35 jt 18 jf 9
(009) jeq #0x4d1 jt 18 jf 19
(010) jeq #0x84 jt 12 jf 11 <== 0x84(132)不知从哪里来的
(011) jeq #0x6 jt 12 jf 19
(012) ldh [20]
(013) jset #0x1fff jt 19 jf 14
(014) ldxb 4*([14]&0xf)
(015) ldh [x + 14]
(016) jeq #0x4d1 jt 18 jf 19 <== 源端口为1233/TCP的报文
(017) jeq #0x806 jt 18 jf 19
(018) ret #68
(019) ret #0
这个输出意味着上述命令将捕捉到源端口为1233/TCP的报文。用如下命令测试:
telnet <target> 1233
果然捕捉到一个RST报文。显然,耗子所说的解析BUG确实存在,最明显的是0x84不知从哪里冒出来的。
现在检查如下过滤规则:
# tcpdump 'udp src port 53 or 1233' or arp -d
(000) ldh [12]
(001) jeq #0x800 jt 2 jf 10 IP报文
(002) ldb [23]
(003) jeq #0x11 jt 4 jf 12 UDP报文
(004) ldh [20]
(005) jset #0x1fff jt 12 jf 6 第一个IP碎片
(006) ldxb 4*([14]&0xf)
(007) ldh [x + 14]
(008) jeq #0x35 jt 11 jf 9 源端口为53/UDP
(009) jeq #0x4d1 jt 11 jf 12 源端口为1233/UDP
(010) jeq #0x806 jt 11 jf 12 ARP报文
(011) ret #68
(012) ret #0
这次才是如我们所愿的过滤规则。两个教训,一是过滤规则写得长了,一些看似冗余而无害的条件可能因BUG而变得有害,二是安全起见务必动用-d先期检查过滤规则。
不过,这个BUG可能是某些版本的tcpdump/libpcap相配合时出现的BUG:
# tcpdump -V
tcpdump version 3.8.3
libpcap version 0.8.3
真正解析过滤规则的部件是libpcap,而不是tcpdump。libpcap采用pcap_compile()和pcap_setfilter()结合的办法屏蔽了各种链路层支持的不同。
在bash命令行上还可以这样写:
# tcpdump \(udp src port 53 or 1233\) or arp
转义符\的出现是因为圆括号()对于bash本身有其它意义。
由于Ethereal/Winpcap使用类似的过滤规则,很可能存在类似的BUG,务必小心。在Ethereal的对话框中并不支持变异的单引号,如下规则将报错:
'udp src port 53 or 1233' or arp
Ethereal的对话框中圆括号没有类似bash元字符那样的特殊意义,因此也不需要转义符,如下规则将报错:
\(udp src port 53 or 1233\) or arp
在Ethereal中,只能按最原始的显示指定过滤规则:
(udp src port 53 or 1233) or arp
2005-03-15 08:24
晚上又想了想,算不上是软件BUG,是我的BUG,看下面的注释:
# tcpdump 'ip and udp and src port 53 or 1233' or arp -d
(000) ldh [12]
(001) jeq #0x800 jt 2 jf 17 IP报文
(002) ldb [23]
(003) jeq #0x11 jt 4 jf 10 UDP报文
(004) ldh [20]
(005) jset #0x1fff jt 19 jf 6 第一个IP碎片
(006) ldxb 4*([14]&0xf)
(007) ldh [x + 14]
(008) jeq #0x35 jt 18 jf 9 源端口为53/UDP
(009) jeq #0x4d1 jt 18 jf 19 源端口为1233/UDP
(010) jeq #0x84 jt 12 jf 11 0x84(132)与0x11(17)、0x06平行
(011) jeq #0x6 jt 12 jf 19 TCP报文
(012) ldh [20]
(013) jset #0x1fff jt 19 jf 14 第一个IP碎片
(014) ldxb 4*([14]&0xf)
(015) ldh [x + 14]
(016) jeq #0x4d1 jt 18 jf 19 源端口为1233/TCP
(017) jeq #0x806 jt 18 jf 19 ARP报文
(018) ret #68
(019) ret #0
or的优先级低于and,导致1233是单独的一个规则,不受"ip and udp and"的约束。
检查如下过滤规则:
# tcpdump src port 1233 -d
(000) ldh [12]
(001) jeq #0x800 jt 2 jf 12 IP报文
(002) ldb [23]
(003) jeq #0x84 jt 6 jf 4 0x84(132)与0x11(17)、0x06平行
(004) jeq #0x6 jt 6 jf 5 TCP报文
(005) jeq #0x11 jt 6 jf 12 UDP报文
(006) ldh [20]
(007) jset #0x1fff jt 12 jf 8 第一个IP碎片
(008) ldxb 4*([14]&0xf)
(009) ldh [x + 14]
(010) jeq #0x4d1 jt 11 jf 12 源端口为1233/UDP或1233/TCP
(011) ret #68
(012) ret #
==============================================================================
发信人: Karno (小米), 信区: Linux
标 题: Re: tcpdump的一个bug
发信站: 武汉白云黄鹤站 (2005年03月14日10:31:17 星期一)
好像按你写的是不能抓到包,不过你的用法好像有点问题。 因为tcpdump 处理expression。因为你给了好几个 ' '对, 我不知道它是不是只接受最后一个。而tcpdump manual中的expression改变优先级用的是( )对。
如(ip and udp src 53) or (ip and udp src 1233) or arp
这样,这个才是一个expression。而你给的只是向个字符串的''的or ,我就不太清楚他对你的参数是如何处理的了,或许它忽略了不认识的吧。 如果用上面正确的expression就可能抓到dns的包了。
rice:/home/karno# tcpdump '(ip and udp src port 53) or (ip and udp src port 1233) or arp'
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes
10:22:38.137579 arp who-has 222.20.42.41 tell mygw
10:22:38.167852 IP server20.hust.edu.cn.domain > freerice.com.32806: 47850 NX Domain 0/1/0 (123)
10:22:38.170761 IP server20.hust.edu.cn.domain > freerice.com.32806: 47851* 1 /2/2 (168)
10:22:39.270346 arp who-has 222.20.42.220 tell mygw
10:22:39.482040 arp who-has 222.20.42.114 tell mygw
10:22:39.564906 arp who-has 222.20.42.162 tell mygw
10:22:41.149940 arp who-has 222.20.42.41 tell mygw
10:22:41.381754 arp who-has 222.20.42.165 tell mygw
10:22:41.559200 arp who-has 222.20.42.136 tell mygw
10:22:42.314795 arp who-has 222.20.42.114 tell mygw
10:22:42.520728 arp who-has 222.20.42.57 tell mygw
10:22:42.559913 arp who-has 222.20.42.162 tell mygw
10:22:42.591134 arp who-has 222.20.42.247 tell mygw
Trackback: http://tb.donews.net/TrackBack.aspx?PostId=317245