TCPDump技术介绍及常见使用案例¶
在进行网络应用程序开发时,如果多人合作开大型软件包括服务器端和客户端软件,并运行在特定网络上,经常会遇到一些网络上的问题,这些可能是服务器或者是客户端或者是真正的网络线路问题,经常会相互争论到底是哪一部分出了问题。程序员通常会自信的怀疑对方的功能出了问题。
例如我曾经遇到一个问题是防火墙上报访问URL地址到日志服务器,经常会用少量报文丢失情况。这时抓包软件TCPDump就派上了用场。TCPDump简单来说就是输出网络上的数据报文。可以根据使用者的选择来对网络上的数据报文进行截获并进行分析。可以根据网络协议、物理接口、IP地址和端口号等各种条件进行过滤,还可以对捕获报文大小进行控制等等。
1,抓取报文¶
最简单的开始捕获报文方法是直接使用tcpdump并指定捕获的网卡名称即可。
tcpdump -i eth0
可以使用快捷键Ctrl+C来结束运行中的捕获程序。另外如果设置了触发停止的条件,捕获达到条件时会自动停止,例如设置到达指定数量的数据包来停止捕获。Tcpdump的可视化输出功能有限,通常是捕获报文并保存下来使用图形用户界面软件wireshark来分析。使用-w选项来指定文件名即可将报文保存下来。例如以下命令:
tcpdump -i eth0 -s 1500 -w aaa0326.cap
这个命令将捕获网卡eth0的所有报文,报文最大长度为1500字节,并保存为aaa0326.cap文件。
tcpdump有很多参数来控制在哪里捕获、如何捕获,以及捕获文件如何保存处理等选项,表1-1列出tcpdump的常用选项。
表1-1 tcpdump的常用选项
选项 | 含义 |
---|---|
-i <interface> | 指定监听的物理网卡接口 |
-s | 指定每个报文中截取的数据长度 |
-w <filename> | 把原始报文保存到文件中 |
-c | 当收到指定报文个数后退出,可当作软件执行结束的条件 |
-C | 指定捕获的报文文件大小。在将报文写入文件时,检查文件是否大于这个值,如果大于则关闭文件,在打开一个新的文件。新的文件和第一个保存的文件会有相同的>前缀,后续文件会从1开始增加。 |
-n | 不要将IP地址和端口号进行转换,进行转换会耗费CPU时间 |
-G <rotate_seconds> | 每隔指定的时间,将捕获的报文循环保存为新文件 |
-D | 输出tcpdump可以捕获的接口列表,包含接口编号和接口名称 |
-v | 当解析和打印时,输出详细的信息,例如报文的生存时间TTL,ID等IP报文选项 |
-r | 从文件中读取报文,这个报文是先前使用-w选项保存的报文 |
-Z | 如果tcpdump运行在root用户下,在打开捕获设备或输入文件后,保存文件使用指定的用户和用户组。 |
最常用的选项是-i来指定监听网卡物理接口,因为现代计算机通常有多个接口设备,如果不指定接口,tcpdump将在系统的所有接口列表中,寻找编号最小的,已经配置为启动的接口(回环接口除外)。接口可以指定为“any”,表示捕获所有接口的报文。捕获所有接口设备的报文时不能捕获到混杂模式的报文。例如路由器的通常至少有两个接口,eth0连接互联网, eth1连接局域网,如果你想捕获到达互联网的数据,你可以指定eth0接口。
常用的选项还有-s,指定从每个报文中截取指定字节的数据,而不是缺省的68字节。如果你仅仅对报头感兴趣,就可以不使用该选项,指定为0说明不限制报文长度,捕获整个报文。一般以太网接口的MTU值为1500,因此指定长度为1500即可。
通常我们不在命令行进行分析,因为其输出格式有限,我们将抓包保存下来使用wireshark来分析,这时就用到-w选项,直接将原始报文保存到文件中,如果文件参数为“-”, 就写到标准输出中。
每隔指定的时间,将捕获的报文循环保存为新文件,这个需要使用-G选项。需要和-w参数配合使用,并指定时间格式才能循环保存为文件,否则覆盖之前捕获的文件。常用的时间格式有以下几种。
- %d 每月中的第几天,十进制数字从01到31。
- %H表示当前的小时时间,十进制数字从00到23。
- %M表示当前的分钟时间,十进制数字从00到59。
- %S表示当前的秒时间,十进制的00到60。
-p 禁止本命令把接口修改为混杂模式。这样将仅抓取和本机通讯的报文。注意接口有可能因其他原因而处于混杂模式。
-r 从文件中读取报文(文件是由-w选项抓包创建的)。
例1 tcpdump -i eth0 -s 1500 -G 60 -w zhang%H%M%S.pcap
这个命令指定抓取eth0接口的报文,每一个报文长度限制在1500字节以内。指定每间隔60秒时间来保存一个文件。文件名称格式为zhang开头,紧接着是抓取报文的开始时间时分秒,这样可以保存下来便于分析。
例2 tcpdump -i eth0 -n –vv -c 500
这个命令抓取eth0接口的全部报文并输出到屏幕中,不进行地址到域名的转换,并在抓取报文到达500个之后退出。通常在命令行是时会加上-n选项,这样将减少tcpdump的域名查询的输出对分析的干扰。
2 报文匹配规则¶
在抓包的过程中,如果不指定匹配规则,网络流量比较大时,经常有一些无关的报文也被抓取下来,这样报文占用空间比较大,在智能路由器这样的嵌入式平台存储空间经常不足,因此需要能仅抓取指定规则条件的报文。Tcpdump支持根据匹配规则来抓取报文。这些匹配规则就是一些组合起来的表达式,只有当符合表达式要求的报文才会被抓取到。
表达式由一个或多个基本元素加上连接符组成,这些基本元素也称原语,是指不可分割的最小单元。基本元素由一个ID和一个或多个修饰符组成,有3种不同类型的修饰符。
第1种是类型修饰符,共4个类型修饰符,分别为host、net、port 和 portrange。host修饰符用于指定需要捕获报文的主机或IP地址,net修饰符用于指定需要捕获报文的子网,port和portrange这两个分别指定端口和端口范围,这两个修饰符是指传输层协议tcp和udp的端口号。
第2种是传输方向修饰符,包括src和dst。如果没有指明方向则任何方向均匹配。例如dst 8.8.8.8表示匹配目的地址为8.8.8.8。如果你想匹配离开指定机器的报文,可以使用src限定符,例如src 192.168.6.100,如果不指定类型,则是指host类型。传输方向修饰符不仅可以修饰地址,也可以用来修饰传输端口,在下面例子仅捕获目标端口为80的报文。
tcpdump -i eth0 ‘dst port 80’ –v
如果我们为服务器,我们有很多用户访问,那我们可以限定仅捕获指定源IP的报文,例如我们是一个VOIP服务器,我们可以使用以下命令抓取报文。
tcpdump -i eth0 ‘port 5060 and src 192.168.6.100 ‘ -v
第3种是协议修饰符,可以基于特定协议来进行过滤,可以是ip、arp、rarp、icmp、tcp和udp等协议类型,例如tcp port 21、udp port 5060等。
另外这些原语可以使用and、or和not来进行集合运算组合。集合运算符含义如下。
- and 也可以写为’ &&’,取两个集合的交集。
- or 也可以写为’||’,取两个集合的并集。
- not 也可以写为’!’,所修饰的集合取补集。
所有的报文集合是全集,可以进行交、并和补集运算。在多个层次的集合运算时,可以使用小括号来分隔其集合运算符的结合关系。
例如“host bjbook.net and port http”,表示满足两者的交集,即符合主机 bibook.net的流量并且端口为80的报文。这些所有关键字可以组合起来构成强大的组合条件来满足各种匹配规则的需要,表1-2列出一些常用的表达式。
表1-2 tcpdump报文过滤表达式
表达式 | 含义 |
---|---|
host bjbook.net | 捕获和主机bjbook.net交互的数据包,包含到达和来源的报文 |
net 191.0.0.0/24 | 捕获指定网段191.0.0.0/24范围内的数据包 |
port 20 | 捕获指定端口20的数据包,指定tcp或udp协议端口匹配,端口号可以是数字也可以是一个名称,这个名称在/etc/services文件中和端口号数字相对应,例如port http则匹配80端口的所有流量,包括tcp和udp 80端口的流量 |
portrange 8000-8080 | 捕获端口范围8000-8080的数据包 |
dst port 80 | 捕获目的端口为80的报文,包含UDP和TCP报文,dst指明报文的方向,也可以修饰主机名和IP地址 |
src 192.168.6.100 | 捕获源IP为192.168.6.100的报文,src也可以修饰传输层端口号 |
ip multicast | IPv4组播报文,即目标地址为组播地址的报文 |
arp | 只捕获arp协议报文,不包含IP报文 |
ip | 捕获IP协议报文,不包含arp等协议报文 |
tcp | 指定tcp协议 |
udp | 指定udp协议 |
udp port 53 | 指定udp协议并且端口为53,即是DNS协议的报文 |
port 5060 or port 53 | 指定端口为5060或端口为53的报文,这在使用IP电话时经常用到 |
not host bjbook.net | 所有非主机bjbook.net的报文 |
例1、tcpdump udp and port 53 -v
只抓取UDP端口53的报文,即只捕获DNS协议报文,然后输出到标准输出终端中。
例2、tcpdump -i eth0 -s0 -w zhang.pcap host 10.0.2.15
在网卡eth0上抓取报文,报文的IP地址是10.0.2.15,并且不限制报文长度,将报文的全部内容保存下来到zhang.pcap这个文件中。
3,更复杂的案例¶
通常我们在路由器使用tcpdump抓取报文,然后将报文传输下来后使用图形软件wireshark来分析报文,在路由器上使用需要安装tcpdump软件,我们使用以下命令来安装。
opkg update
opkg install tcpdump
如果使用ubuntu系统则使用以下命令进行安装
apt-get update
apt-get install tcpdump
例如我曾经碰到一个问题是,在系统启动时,ARP协议来请求目标IP地址的MAC地址,但这个IP地址并非和本地机器同网段,这在网关机器带有ARP代理情况下工作正常,但是如果下一跳路由器如果没有ARP代理,就会因为没有目标IP的MAC响应而通讯失败。我们在启动时就可以仅抓取ARP协议、TFTP协议、DNS协议及ICMP协议。
示例1-1
tcpdump -i eth0 -w aaa.pcap port 59 or port 53 or port 80 or arp or icmp
该命令将抓取TFTP协议、DNS协议、HTTP协议、ARP协议和ICMP协议的报文。
示例1-2
假定我们需要抓取网络上的报文,但网络非常繁忙,如果在白天的工作时段,那有可能因为硬盘性能不足,报文不能保存下来,那只能在凌晨闲事进行抓包。在闲事也需要限制捕获报文的数量,否则可能会撑爆硬盘,使用“-c”来限制捕获报文数量。命令如下:
tcpdump -i eth0 -s 0 -G 1800 -c 100000000 -w /srv /bjbook%H%M%S.pcap -Z root
命令其选项含义如下:
- -i eth0 指定捕获接口为eth0
- -s 0 不限制报文大小
- -G 1800 每1800秒保存一个报文,防止保存的报文文件太大。
- -c 100 000 000 指定所捕获的报文的包数共1亿,通常网络上的报文大小平均为500字节,这样保存下来的报文大约50GB。
- -Z root 使用root权限来保存。在某些系统上必须使用-Z root,否则后续的报文捕获保存。
写完该命令之后,我们保存到/srv/tcpdump.sh下,我们可以在crontab中增加定时任务来完成定时启动了。定时任务增加以下内容:
0 3 * * * root /src/tcpdump.sh
然后重启crontab。注意一定要进行重启crontab,定时任务才能生效。命令如下:
service cron restart
如果保存下来的报文文件空间占用还是比较大,但我们只使用比较小的报文文件,我们可以对报文文件按大小进行拆分,我们可以使用split工具进行分开,这里使用tcpdump来对pcap文件进行拆分,命令如示例1-3所示。
示例1-3:tcpdump -r bjbook.pcap -C 5M -w openwrt.pcap -Z root
- -r bjbook.pcap 从文件bjbook.pcap中读取报文。
- -C 5M 指定捕获的报文文件大小为5M字节。如果有多个文件,则文件名后面序列号从1开始累加。
- -w openwrt.pcap 将文件保存为openwrt.pcap.
- -Z root 使用root权限来保存。
如果抓取下来的是全量报文,即所有协议的报文都抓取下来了,但我们只使用一部分协议,那我们就要对报文进行过滤。我们关注的是 diameter协议,该协议在rfc3588(https://tools.ietf.org/html/rfc3588)中定义, 协议标准端口为tcp3868,在实际处理中,中兴的认证服务器使用端口6004。我们的过滤命令如示例1-4所示:
tcpdump -r bjbook.pcap -w only_diameter.pcap “tcp port 3868 or 6004”
如果我们抓取的报文在链路层使用了vlan协议,那我们对二层报文解析解析,那我们的过滤命令就需要加上vlan过滤。
tcpdump -r bjbook.pcap -w only_diameter.pcap “vlan and tcp port 3868 or 6004”
- -r bjbook.pcap从文件bjbook.pcap中读取报文。
- -w only_diameter.pcap将文件保存为only_diameter.pcap。
- “vlan and tcp port 3868 or 6004” 过滤vlan协议,并且上层承载的是tcp协议,端口为3868或6004。
我还遇到一个使用场景是过滤GRE协议中的上层的某个协议。那我们就应用到了内容过滤了。GRE协议的全称是通用路由封装协议(Generic Routing Encapsulation)。是用于将一种协议报文封装到另外一种协议报文上进行网络传输。用于规避一些特殊路由和防火墙的问题。GRE协议的前两个字节为版本号,再接着两个字节是所传输的报文协议。
例如我需要过滤gre协议上层是IP协议的报文。命令如1-5所示:
tcpdump -r bjbook.pcap –w gre_ip.pcap “proto gre and ip[22:2]=0x0800”
- -r bjbook.pcap从文件bjbook.pcap中读取报文。
- -w only_diameter.pcap将文件保存为only_diameter.pcap
- proto gre 表示协议为gre协议
- and ip[22:2]=0x0800,表示从IP字段22字节开始的其后两个字节的值为0x0800,即gre的协议类型为0x0800。
相信读者通过以上5个示例,可以掌握tcpdump的使用,我的图书<智能路由器开发指南>包含了部分示例,欢迎各位阅读。
4. 参考资料¶
- Tcpdump手册 http://www.tcpdump.org/manpages/tcpdump.1.html
- PCAP-FILTER使用手册 http://www.tcpdump.org/manpages/pcap-filter.7.htm
- 智能路由器开发指南(15.2 节)http://openwrt.bjbook.net/go.html
- https://tools.ietf.org/html/rfc3588