tcpdump
转储网络流量(dump traffic on a network)。tcpdump打印输出指定网络接口上,匹配指定布尔表达式(过滤器)的数据包。
tcpdump 能截获指定网络接口上所有你感兴趣的包,不足之处是tcpdump对截获的数据并没有进行彻底解码,数据包内的大部分内容是使用十六进制的形式直接打印输出的。显然这不利于分析网络故障,通常的解决办法是先使用带-w参数的tcpdump 截获数据并保存到文件中,然后再使用其他程序(如Wireshark)进行解码分析。当然也应该定义过滤规则,以避免捕获的数据包填满整个硬盘。
通过使用 -w 标志可以把数据包保存到文件,以供稍后分析。
通过时用 -r 标志可以从一个保存的包文件中,而不是一个网络接口读取数据包。
使用格式:tcpdump [ -r file] [ -w file]
表达式实际上就是tcpdump的过滤器。表达式用于决定哪些数据包将被打印。如果没有指定表达式,就会答应输出网络接口截获的所有的包。
表达式由一个或多个表达元组成。 表达元可理解为组成表达式的基本元素。一个表达元通常由一个或多个关键字后跟一个参数组成。有三种不同类型的关键字:
第一种类型是关于类型(type)的关键字,主要包括host, net, port, portrange。例如:host 192.168.1.210,指明192.168.1.210是一台主机。 net 192.168.1.0,指明192.168.1.0是一个网络。port 53指明53是一个端口。portrange 5000-5005指定端口范围为5000至5005。 缺省类型是host。
第二种类型是关于方向(dir)的关键字,主要包括src, dst, dst or src, dst and src,这些关键字指明了传输的方向。 例如:dst host 192.168.1.210指明ip包中目标地址是192.168.1.210。缺省是dst or src。
第三种是协议(proto)的关键字,主要包括fddi, ether, tr, wlan, ip, ip6, arp, rarp, decnet, tcp, udp, http等。ether, fddi, tr, 具体含义未知, 需补充。 可理解为物理以太网传输协议,光纤分布数据网传输协议,以及用于路由跟踪的协议。 wlan, 无线局域网协议;ip,ip6 即通常的TCP/IP协议栈中所使用的ipv4以及ipv6网络层协议;arp, rarp 即地址解析协议,反向地址解析协议;decnet, Digital Equipment Corporation开发的, 最早用于PDP-11 机器互联的网络协议; tcp and udp, 即通常TCP/IP协议栈中的两个传输层协议。如果没有指定任何协议,则tcpdump将会监听所有协议的包。例如:arp net 128.3:发往或来自128.3网络的arp协议数据包。
除了上述三种类型,其它重要的关键字还包括:gateway, broadcast, less, greater。less, greater用于指定数据包的长度。
表达元之间可以通过and, or以及not进行连接, 也可以使用相应的&&, ||, !。从而可以组成比较复杂的条件表达式。例如, tcpdump -i eth0 ip and host www.baidu.com:截获发送或来自www.baidu.com的所有ip包。
借助括号以及相应操作符,可把表达元组合在一起使用(由于括号是shell的特殊字符, 所以在shell脚本或终端中使用时必须对括号进行转义, 即'(' 与')'需要分别表达成'\(' 与 '\)')。
-A 以ASCII码方式显示每一个数据包(不会显示数据包中链路层头部信息)。在抓取包含网页数据的数据包时,可方便查看数据。
-c count
在接收到count个包后退出
-D 打印系统中所有tcpdump可以在其上进行抓包的网络接口。每一个接口会打印出数字编号,相应的接口名字, 以及可能的一个网络接口描述。其中网络接口名字和数字编号 可以用在tcpdump 的-i flag 选项。
-e 每行的打印输出包括数据链路层的头部信息
-i interface
指定tcpdump 需要监听的接口。如果没有指定,tcpdump 会从系统接口列表中搜寻编号最小的已配置好的接口(不包括 loopback 接口)。一但找到第一个符合条件的接口,搜寻马上结束。
-F file
使用file 文件作为过滤条件表达式的输入, 此时命令行上的输入将被忽略。
-n 不对地址(比如, 主机地址, 端口号)进行数字表示到名字表示的转换。
-xx tcpdump 会打印每个包的头部数据, 同时会以16进制打印出每个包的数据, 其中包括 数据链路层的头部.
-X 当分析和打印时, tcpdump 会打印每个包的头部数据, 同时会以16进制和ASCII码形式打印出每个包的数据(但不包括连接层的头部).这对于分析一些新协议的 数据包很方便.
-XX 当分析和打印时, tcpdump 会打印每个包的头部数据, 同时会以16进制和ASCII码形式打印出每个包的数据, 其中包括数据链路层的头部.这对于分析一些新协议 的数据包很方便。
-C file-size
该选项使得tcpdump 在把原始数据包直接保存到文件中之前, 检查此文件大小是否超 过file-size. 如果超过了, 将关闭此文件,另创一个文件继续用于原始数据包的记录. 新 创建的文件名与-w 选项指定的文件名一致, 但文件名后多了一个数字.该数字会从1开 始随着新创建文件的增多而增加. file-size的单位是百万字节。
-s snaplen
-s 0: 抓取数据包时默认抓取长度为68字节。加上-s 0 后可以抓到完整的数据包。
截获发送到或来自主机www.baidu.com的数据包
tcpdump host www.baidu.com
截获本机与主机www.google.com或主机www.uc.cn之间的通信
tcpdump host localhost and \( www.google.com or www.uc.cn\ )
TCP头中有8位控制位:
CWR | ECE | URG | ACK | PSH | RST | SYN | FIN
假定我们想要观察用于创建TCP连接的包。我们知道TCP使用三次握手SYN > SYN-ACK >ACK来创建一个连接。
现在我们对只设置了SYN位的包感兴趣。注意,我们只想要初始的SYN包(三次握手的第一步),不想要也设置了ACK位的包(三次握手的第二步)。我们应该怎样写正确的过滤表达式呢?
我们来看看不带选项的TCP头:
0 15 31
-----------------------------------------------------------------
| source port | destination port |
-----------------------------------------------------------------
| sequence number |
-----------------------------------------------------------------
| acknowledgment number |
-----------------------------------------------------------------
| HL | rsvd |C|E|U|A|P|R|S|F| window size |
-----------------------------------------------------------------
| TCP checksum | urgent pointer |
-----------------------------------------------------------------
无选项的TCP头是20字节。上图中第一行包含0-3字节,第二行是4-7字节,以此类推...
从0算起,TCP的控制位包含在第13字节:
0 7| 15| 23| 31
----------------|---------------|---------------|----------------
| HL | rsvd |C|E|U|A|P|R|S|F| window size |
----------------|---------------|---------------|----------------
| | 13th octet | | |
进一步看看第13字节:
|C|E|U|A|P|R|S|F|
|---------------|
|0 0 0 0 0 0 1 0|
|---------------|
|7 6 5 4 3 2 1 0|
观察控制位区域,我们发现只有bit 1(SYN)被设置了。把第13字节看做是一个网络字节序的8位无符号整型数。该字节的二进制表示为:00000010,它的十进制表示为:
7 6 5 4 3 2 1 0
0*2 + 0*2 + 0*2 + 0*2 + 0*2 + 0*2 + 1*2 + 0*2 = 2
我们快知道答案了,因为现在我们知道只有SYN被设置,TCP头中的第13字节,当被解释为8位无符号整型数时,它的值正好是2。这个关系可以表达为:
tcp[13] = 2
我们可以使用这个表达式作为tcpdump的过滤器来监视仅仅设置了SYN位的包:
tcpdump -i eth0 tcp[13] = = 2
这个表达式的意思是:让TCP包的第13字节的值为2,这正是我们想要的。
我们来看另外一个例子。假设我们需要截获SYN包,这一次我们不关系ACK是否被设置。我们先来看看当SYN-ACK数据报到来时,TCP头的第13字节的情况:
|C|E|U|A|P|R|S|F|
|---------------|
|0 0 0 1 0 0 1 0|
|---------------|
|7 6 5 4 3 2 1 0|
第13字节的第1位和第4位被置为1,它的二进制表示为:
00010010
十进制为18
我们不能简单的使用 ‘tcp[13] == 18’这个表达式,因为这样只能截获SYN-ACK包,而我们想要的是设置了SYN的包。记住我们不关心ACK或其它的控制位是否被设置。好了,不多说了,正确的表达式是:
tcpdump -i xl0 'tcp[13] & 2 == 2'
一些常用的偏移和位能用名称表示就好多了。例如tcp[13]可以用tcp[tcpflags]替换。tcpdump是支持这种表达的。可以使用的tcp标志域值有:tcp-fin, tcp-syn, tcp-rst, tcp-push, tcp-act, tcp-urg
一个示例:
tcpdump -i xl0 'tcp[tcpflags] & tcp-push != 0'
注意:要使用单引号或者转义字符,避免shell对‘&’进行解释和替换(‘&’是shell的特殊字符)
使用tcpdump抓取http包
tcpdump -Xs 0 -i eth0 tcp[20:2]=0x4745 or tcp[20:2]=0x4854
0x4745 为"GET"前两个字母"GE",0x4854 为"HTTP"前两个字母"HT"。
如果使用tcpdump -Xs 0 -i eht0 tcp port 80 会抓取到很多额外的包
tcpdump支持强大的过滤表达式,不足之处是,解码方面比较弱,只支持简单的ASCII码或16进制输出。除了上面所阐述的常用功能外,tcpdump还有很多其它功能,有待研究。
参考:
http://petermis.blog.51cto.com/2336802/997564
http://www.tcpdump.org/tcpdump_man.html