前言:

linux下tcpdump的地位可类比为windows下的wireshark,二者在语法和过滤条件上都是相通的

 

基础语法:

  • 过滤主机

抓取所有经过eth1,目的或源地址是192.168.1.1的网络数据
tcpdump -i eth1 host 192.168.1.1
指定源地址
tcpdump -i eth1 src host 192.168.1.1
指定目的地址
tcpdump -i eth1 dst host 192.168.1.1

  • 过滤端口

抓取所有经过eth1,目的或源端口是25的网络数据
tcpdump -i eth1 port 25
指定源端口
tcpdump -i eth1 src port 25
指定目的端口
tcpdump -i eth1 dst port 25

  • 过滤网段

tcpdump -i eth1 net 192.168
tcpdump -i eth1 src net 192.168
tcpdump -i eth1 dst net 192.168

  • 协议过滤

tcpdump -i eth1 arp
tcpdump -i eth1 ip
tcpdump -i eth1 tcp
tcpdump -i eth1 udp
tcpdump -i eth1 icmp

  • 常用表达式

非 : ! or "not" (去掉双引号)  
且 : && or "and"  
或 : || or "or"
抓取所有经过eth1,目的地址是192.168.1.254或192.168.1.200端口是80的TCP数据
tcpdump -i eth1 '((tcp) and (port 80) and ((dst host 192.168.1.254) or (dst host 192.168.1.200)))'
抓取所有经过eth1,目标MAC地址是00:01:02:03:04:05的ICMP数据
tcpdump -i eth1 '((icmp) and ((ether dst host 00:01:02:03:04:05)))'
抓取所有经过eth1,目的网络是192.168,但目的主机不是192.168.1.200的TCP数据
tcpdump -i eth1 '((tcp) and ((dst net 192.168) and (not dst host 192.168.1.200)))'

 

进阶用法:

首先了解如何从包头过滤信息:
(这里的proto指某种协议,比如tcp,ip,tipc等等,可以直接把proto换成相应的协议名)
(这里x,y都是字节数,不是“比特位”)

proto[x:y]          : 过滤从x字节开始的y“字节数”。比如ip[2:2]过滤出3、4字节(第一字节从0开始排)
proto[x:y] & z = 0  : proto[x:y]和z的与操作为0      (可以用来过滤报文中某一段字节是否为某个值)
proto[x:y] & z !=0  : proto[x:y]和z的与操作不为0    (可以用来过滤报文中某一段字节是否为某个值)
proto[x:y] & z = z  : proto[x:y]和z的与操作为z      (可以用来过滤报文中某一段字节是否为某个值)
proto[x:y] = z      : proto[x:y]等于z               (可以用来过滤报文中某一段字节是否为某个值)

操作符 :

>, <, >=, <=, =, !=

例如:(判断ip协议的第一个字节“按位与”15(0x0f)之后的值)
tcpdump -i eth1 'ip[0] & 15 > 5'
或者
tcpdump -i eth1 'ip[0] & 0x0f > 5'

tcpdump考虑了一些数字恐惧症者的需求,提供了部分常用的字段偏移名字:

icmptype (ICMP类型字段)
icmpcode (ICMP符号字段)
tcpflags (TCP标记字段)

ICMP类型值有:
icmp-echoreply, icmp-unreach, icmp-sourcequench, icmp-redirect, icmp-echo, icmp-routeradvert, icmp-routersolicit, icmp-timxceed, icmp-paramprob, icmp-tstamp, icmp-tstampreply, icmp-ireq, icmp-ireqreply, icmp-maskreq, icmp-maskreply

TCP标记值:
tcp-fin, tcp-syn, tcp-rst, tcp-push, tcp-push, tcp-ack, tcp-urg

这样上面按照TCP标记位抓包的就可以写直观的表达式了:
只抓SYN包:

tcpdump -i eth1 'tcp[tcpflags] = tcp-syn'

抓SYN, ACK:

tcpdump -i eth1 'tcp[tcpflags] & tcp-syn != 0 and tcp[tcpflags] & tcp-ack != 0'

 

例子:

抓SMTP数据:
tcpdump -i eth1 '((port 25) and (tcp[(tcp[12]>>2):4] = 0x4d41494c))'
抓取数据区开始为"MAIL"的包,"MAIL"的十六进制为0x4d41494c。

抓HTTP GET数据
tcpdump -i eth1 'tcp[(tcp[12]>>2):4] = 0x47455420'
"GET "的十六进制是47455420

抓SSH返回
tcpdump -i eth1 'tcp[(tcp[12]>>2):4] = 0x5353482D'
"SSH-"的十六进制是0x5353482D
tcpdump -i eth1 '(tcp[(tcp[12]>>2):4] = 0x5353482D) and (tcp[((tcp[12]>>2)+4):2] = 0x312E)'
抓老版本的SSH返回信息,如"SSH-1.99.."

     

*****注:从上面这些看出,HTTP,SMTP和SSH都是TCP包的一种类型,时寄生在TCP报文中的自定义应用数据结构*****

 

一些技巧:

保存抓包数据到文件:

如果是为了查看数据内容,建议用“tcpdump -s 0 -w filename”把数据包都保存下来,然后用wireshark的Follow TCP Stream/Follow UDP Stream来查看整个会话内容。

-s 0是抓取完整数据包,否则默认只抓68字节。

数据量过大会导致宕机:

-c参数对于运维人员来说也比较常用,因为流量比较大的服务器,靠人工CTRL+C还是抓的太多,甚至导致服务器宕机,于是可以用-c参数指定抓多少个包。

计算抓包时间:

time tcpdump -nn -i eth0 'tcp[tcpflags] = tcp-syn' -c 10000 > /dev/null

上面的命令计算抓10000个SYN包花费多少时间,可以判断访问量大概是多少。

参考资料:

​http://linuxwiki.github.io/NetTools/tcpdump.html​