第一招:
通俗的说,tcpdump是一个抓包工具,用于抓取互联网上传输的数据包。
形象的说,tcpdump就好比是国家海关,驻扎在出入境的咽喉要道,凡是要入境和出境的集装箱,海关人员总要打开箱子,看看里面都装了点啥。
学术的说,tcpdump是一种嗅探器(sniffer),利用以太网的特性,通过将网卡适配器(NIC)置于混杂模式(promiscuous)来获取传输在网络中的信息包。
【抓人生中的第一个包】
要用tcpdump抓包,请记住,一定要切换到root账户下,因为只有root才有权限将网卡变更为“混杂模式”。
然后呢,就是用ifconfig的方法查看好你的服务器的网卡名称。(我的叫做eth0,一般都是这个名字)
# tcpdump -i eth0 -nn -X ‘port 53′ -c 1
1
2
3
4
5
6
7
8
9
10
|
tcpdump: verbose output suppressed, use - v or -vv for full protocol decode listening on eth0, link- type EN10MB (Ethernet), capture size 65535 bytes 19:48:33.285838 IP 116.255.245.206.47940 > 8.8.8.8.53: 22768+ A? www.baidu.com. (31) 0x0000: 4500 003b c341 0000 4011 3c93 74ff f5ce E..;.A..@.<.t... 0x0010: 0808 0808 bb44 0035 0027 b457 58f0 0100 .....D.5.'.WX... 0x0020: 0001 0000 0000 0000 0377 7777 0562 6169 .........www.bai 0x0030: 6475 0363 6f6d 0000 0100 01 du .com..... 1 packets captured 1 packets received by filter 0 packets dropped by kernel |
在此,我重点解释下这个命令:
-i选项:
是interface的含义,是指我们有义务告诉tcpdump希望他去监听哪一个网卡。这在我们一台服务器有多块网卡时很有必要。
-nn选项:
意思是说当tcpdump遇到协议号或端口号时,不要将这些号码转换成对应的协议名称或端口名称。比如,众所周知21端口是FTP端口,我们希望显示21,而非tcpdump自作聪明的将它显示成FTP。
-X选项:
告诉tcpdump命令,需要把协议头和包内容都原原本本的显示出来(tcpdump会以16进制和ASCII的形式显示),这在进行协议分析时是绝对的利器。
‘port 53′:
这是告诉tcpdump不要看到啥就显示啥。我们只关心源端口或目的端口是53的数据包,其他的数据包别给我显示出来。
-c选项:
是Count的含义,这设置了我们希望tcpdump帮我们抓几个包。我设置的是1,所以tcpdump不会帮我再多抓哪怕一个包回来。
第二招:
在第一招中,我们给大家演示了用tcpdump抓包的简单方法。接下来,我们会比较系统的来介绍tcpdump工具了。
从我的理解来看,tcpdump可以分为三大部分内容,第一是“选项”,第二是“过滤表达式”,第三是“输出信息”。
下面的文章,会分别从这三个方面来重点介绍。
==
tcpdump的选项,我还真是专门数了一下,总共有50个之多。在这个系列文章中,实在很难全都覆盖,我尽量挑选重要且常用的选项来讲解,
一些不常用的选项,大家抽空可以自己去了解一下。
在《第一招》中讲到了-i选项、-nn选项、-c选项、-X选项。今天,我们继续介绍另外两个重要的选项,即-e选项和-l选项。
【-e选项】- 增加以太网帧头部信息输出
闲言少叙,直接给出例子,大家就能看到区别了:
1
2
3
4
5
6
7
8
|
# tcpdump -i eth0 -c 1 tcpdump: verbose output suppressed, use - v or -vv for full protocol decode listening on eth0, link- type EN10MB (Ethernet), capture size 65535 bytes 16:36:18.490875 IP 116.255.245.206.snapenetio > 61.135.169.73.56503: Flags [P.], seq 990974500:990974696, ack 4001909970, win 270, length 196 # tcpdump -i eth0 -c 1 -e tcpdump: verbose output suppressed, use - v or -vv for full protocol decode listening on eth0, link- type EN10MB (Ethernet), capture size 65535 bytes 16:36:09.910296 00:15:5d:f5:4b:37 (oui Unknown) > 00:00:0c:07:ac:15 (oui Cisco), ethertype IPv4 (0x0800), length 250: 116.255.245.206.snapenetio > 61.135.169.73.56503: Flags [P.], seq 990973640:990973836, ack 4001909762, win 270, length 196 |
如果还是看不懂,说明你忘记了以太网协议的头格式,我再这里补充下,帮大家回忆回忆:
1
2
3
4
5
|
struct sniff_ethernet { u_char ether_dhost[ETHER_ADDR_LEN]; /* 目的主机的地址 */ u_char ether_shost[ETHER_ADDR_LEN]; /* 源主机的地址 */ u_short ether_type; /* IP? ARP? RARP? etc */ }; |
在刚才加-e选项的输出中,会发现有oui Unknown的字样,这oui是什么东东呢?在这里顺便科普一下咯:
OUI,即Organizationally unique identifier,是“组织唯一标识符”,在任何一块网卡(NIC)中烧录的6字节MAC地址中,前3个字节体现了OUI,其表明了NIC的制造组织。通常情况下,该标识符是唯一的。
【-l选项】- 使得输出变为行缓冲
-l选项的作用就是将tcpdump的输出变为“行缓冲”方式,这样可以确保tcpdump遇到的内容一旦是换行符即将缓冲的内容输出到标准输出,以便于利用管道或重定向方式来进行后续处理。
众所周知,Linux/UNIX的标准I/O提供了全缓冲、行缓冲和无缓冲三种缓冲方式。标准错误是不带缓冲的,终端设备常为行缓冲,而其他情况默认都是全缓冲的。
大家在使用tcpdump时,有时会有这样的需求:“对于tcpdump输出的内容,提取每一行的第一个域,即”时间域”,并输出出来,为后续统计所用”,这种场景下,我们就需要使用到-l来将默认的全缓冲变为行缓冲了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
# tcpdump -i eth0 -l |awk '{print $1}' tcpdump: verbose output suppressed, use - v or -vv for full protocol decode listening on eth0, link- type EN10MB (Ethernet), capture size 65535 bytes 22:56:57.571680 22:56:57.572103 22:56:57.599515 22:56:57.706286 22:56:57.888108 22:56:57.888296 22:56:57.973546 22:56:57.973768 22:56:57.975660 22:56:58.019052 22:56:58.019318 ^C146 packets captured 161 packets received by filter 0 packets dropped by kernel |
如果不加-l选项,那么只有全缓冲区满,才会输出一次,这样不仅会导致输出是间隔不顺畅的,而且当你ctrl-c时,很可能会断到一行的半截,损坏统计数据的完整性。
第三招:
截止到目前,我们一直在围绕tcpdump的选项部分进行讲解,已经介绍过的选项包括-i选项、-nn选项、-c选项、-X选项、-e选项、-l选项。
今天仍然不例外,我们继续有关选项的内容。
==
【-t选项】- 输出时不打印时间戳
这个选项非常好理解,直接看例子吧:
1
2
3
4
5
6
7
8
|
# tcpdump -i eth0 -c 1 tcpdump: verbose output suppressed, use - v or -vv for full protocol decode listening on eth0, link- type EN10MB (Ethernet), capture size 65535 bytes 01:52:10.433391 ARP, Request who -has 116.255.247.61 tell 116.255.247.125, length 64 # tcpdump -i eth0 -c 1 -t tcpdump: verbose output suppressed, use - v or -vv for full protocol decode listening on eth0, link- type EN10MB (Ethernet), capture size 65535 bytes ARP, Request who -has 116.255.245.35 tell 116.255.245.62, length 64 |
【-v选项】- 输出更详细的信息
加了-v选项之后,在原有输出的基础之上,你还会看到tos值、ttl值、ID值、总长度、校验值等。
至于上述值的含义,需要你专门去研究下IP头、TCP头的具体协议定义咯。
1
2
3
4
5
6
7
8
|
# tcpdump -i eth0 -c 1 tcpdump: verbose output suppressed, use - v or -vv for full protocol decode listening on eth0, link- type EN10MB (Ethernet), capture size 65535 bytes 01:53:09.162644 IP 116.255.245.206.snapenetio > 221.223.255.234.54198: Flags [P.], seq 1443040202:1443040398, ack 3517061690, win 353, length 196 # tcpdump -i eth0 -c 1 -v tcpdump: listening on eth0, link- type EN10MB (Ethernet), capture size 65535 bytes 01:52:57.902894 IP (tos 0x10, ttl 64, id 18293, offset 0, flags [DF], proto TCP (6), length 172) 116.255.245.206.snapenetio > 221.223.255.234.54198: Flags [P.], cksum 0x4dd9 (correct), seq 1443039302:1443039434, ack 3517061430, win 353, length 132 |
【-F选项】- 指定过滤表达式所在的文件
还记得我们在第一招中所提到的命令么,我帮助大家回忆一下:
tcpdump -i eth0 -nn -X ‘port 53′ -c 1
这里面的’port 53′便叫做“过滤表达式”,用于设置我们抓包的条件的,只有满足过滤条件的网络包,才会被抓过来。
当这个过滤条件非常复杂,或者我们需要将一个过滤条件固化下来复用的时候,就会想到把它存到一个文本文件中。
此时,-F选项就会派上用场。请看例子:
1
2
3
4
5
6
7
8
9
|
# cat filter.txt port 53 # tcpdump -i eth0 -c 1 -t -F filter.txt tcpdump: verbose output suppressed, use - v or -vv for full protocol decode listening on eth0, link- type EN10MB (Ethernet), capture size 65535 bytes IP 116.255.245.206.54357 > ns.sc.cninfo.net.domain: 36720+ A? www.baidu.com. (31) 1 packets captured 6 packets received by filter 0 packets dropped by kernel |
我们建立了一个filter.txt文本文件来存储过滤表达式,然后通过-F来指定filter.txt,这样tcpdump就会心知肚明地读取filter.txt中的内容作为过滤条件。
第四招:
本文会是“选项内容”的最后一期讲解,主要会讲讲-w和-r两个选项。tcpdump的选项很多,多达50个,其他我没有涉及的选项,还是要大家自己通过man tcpdump的方式来学习了。实在研究不懂的,可以找我探讨:)
==
做过网络流量分析的同学,或许都有一个共同的需求,那就是“流量保存”和“流量回放”,这就恰好对应了今天要讲解的-w选项和-r选项。
“流量保存”就是把抓到的网络包能存储到磁盘上,保存下来,为后续使用。
“流量回放”就是把历史上的某一时间段的流量,重新模拟回放出来,用于流量分析。
【-w选项】- 将流量保存到文件中
1
2
3
4
5
|
# tcpdump -i eth0 -w flowdata tcpdump: listening on eth0, link- type EN10MB (Ethernet), capture size 65535 bytes ^C327 packets captured 327 packets received by filter 0 packets dropped by kernel |
通过上面的例子可以看到,通过-w选项将流量都存储在了flowdata文件中了。大家是否有兴趣less下flowdata,看看里面都是什么东东?
1
2
|
# less flowdata "flowdata" may be a binary file . See it anyway? |
悲剧,原来都是二进制格式的,无法直接通过文本方式查看。嗯,买了个关子,把真像告诉大家吧!
tcpdump的-w方式是把raw packets(原始网络包)直接存储到文件中了,也就是存储的都是结构体形式,而非是分析之后的文本格式的信息,因此大家是无法直接通过less命令查看的。
那么,怎么查看呢?大家想必也想到了,就是用-r选项。
【-r选项】- 读取raw packets文件
1
2
3
4
5
6
7
8
|
# tcpdump -r flowdata reading from file flowdata, link- type EN10MB (Ethernet) 16:43:36.202443 IP 116.255.245.206.snapenetio > 61.135.169.73.52414: Flags [P.], seq 4082702792:4082702924, ack 3248983965, win 291, length 132 16:43:36.222033 IP 61.135.169.73.52414 > 116.255.245.206.snapenetio: Flags [.], ack 132, win 61, length 0 16:43:36.277407 IP 116.255.245.62 > ospf-all.mcast.net: OSPFv2, Hello, length 48 16:43:36.370846 ARP, Request who -has 116.255.245.203 tell 116.255.245.254, length 64 16:43:36.521947 ARP, Request who -has 116.255.245.203 tell 116.255.245.253, length 64 16:43:36.635472 ARP, Request who -has 116.255.245.214 tell 116.255.245.253, length 64 |
其实上面的命令就是在不知不觉中进行了“流量回放”,你会发现网络包被“抓”的速度都按照历史进行了回放,真像一个“时光机”啊!
由于是按raw packets来存储的,所以你完全可以使用-e、-l和过滤表达式来对输出信息进行控制,十分方便。
第五招:
前四招都是围绕tcpdump的选项来介绍的,从这招起,我们会把目光转向更加常用的“过滤表达式”内容。
通过这几招的学习,你将具备“心无旁骛,潜心专注”的武功。
==
【师傅领进门】
可以给tcpdump传送“过滤表达式”来起到网络包过滤的作用,而且可以支持传入单个或多个过滤表达式,从这一点来说tcpdump还是很大肚能容的。
当你传入的过滤表达式含有shell通配符时,别忘使用单引号把表达式括起来,以防shell自作主张的把含有通配符的表达式先进行了解释和通配。
如果你希望自己研究“过滤表达式”,没问题,我会告诉你如何“进门”,方法就是:
man pcap-filter
你会发现,过滤表达式大体可以分成三种过滤条件,“类型”、“方向”和“协议”,这三种条件的搭配组合就构成了我们的过滤表达式。
【我只想抓UDP的包,不想被TCP的包打扰】
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
# tcpdump -i eth0 -c 10 'udp' tcpdump: verbose output suppressed, use - v or -vv for full protocol decode listening on eth0, link- type EN10MB (Ethernet), capture size 65535 bytes 11:25:20.801612 IP 116.255.245.48.54808 > 229.111.112.12.csd-mgmt-port: UDP, length 4 11:25:20.802120 IP 116.255.245.206.54313 > ns.sc.cninfo.net.domain: 5256+ PTR? 12.112.111.229. in -addr.arpa. (45) 11:25:21.145126 IP ns.sc.cninfo.net.domain > 116.255.245.206.54313: 5256 NXDomain 0 /0/0 (45) 11:25:21.145315 IP 116.255.245.206.46658 > ns.sc.cninfo.net.domain: 15551+ PTR? 48.245.255.116. in -addr.arpa. (45) 11:25:21.153966 IP 116.255.245.43.62220 > 229.111.112.12.csd-mgmt-port: UDP, length 4 11:25:21.180135 IP 116.255.245.61.hsrp > all-routers.mcast.net.hsrp: HSRPv0-hello 20: state=active group=21 addr=116.255.245.33 11:25:21.231151 IP ns.sc.cninfo.net.domain > 116.255.245.206.46658: 15551 NXDomain 0 /0/0 (45) 11:25:21.231430 IP 116.255.245.206.46158 > ns.sc.cninfo.net.domain: 31924+ PTR? 69.2.139.61. in -addr.arpa. (42) 11:25:21.277087 IP ns.sc.cninfo.net.domain > 116.255.245.206.46158: 31924 1 /0/0 PTR ns.sc.cninfo.net. (72) 11:25:21.277824 IP 116.255.245.206.42656 > ns.sc.cninfo.net.domain: 806+ PTR? 206.245.255.116. in -addr.arpa. (46) 10 packets captured 20 packets received by filter 0 packets dropped by kernel |
举这个例子,是为了说明tcpdump具有根据网络包的协议来进行过滤的能力,我们还可以把udp改为ether、ip、ip6、arp、tcp、rarp等。
或许你会提问“为啥这些协议里没有应用层协议呢?”,其实理由很简单,应用层协议非基础类网络协议,经常会新增或淘汰,tcpdump不会深入到应用层部分去智能解析。所以,你现在看到的tcpdump支持的protocol都是应用层以下的。
【我想专门查看这个源机器和那个目的机器之间的网络包,不想被其他无关的机器打扰】
这个其实很简单,也很直观,只要设置src(source)和dst(destination)就好了,而且方便的是,tcpdump还支持使用and和or来进行搭配组合呢!
如果没有设置的话,默认是src or dst。
1
2
3
4
5
6
7
8
9
10
|
# tcpdump -i eth0 'dst 8.8.8.8' tcpdump: verbose output suppressed, use - v or -vv for full protocol decode listening on eth0, link- type EN10MB (Ethernet), capture size 65535 bytes 13:21:23.281978 IP 116.255.245.206 > google-public-dns-a.google.com: ICMP echo request, id 23081, seq 1, length 64 13:21:24.286663 IP 116.255.245.206 > google-public-dns-a.google.com: ICMP echo request, id 23081, seq 2, length 64 13:21:25.288612 IP 116.255.245.206 > google-public-dns-a.google.com: ICMP echo request, id 23081, seq 3, length 64 ^C 3 packets captured 5 packets received by filter 0 packets dropped by kernel |
【我只想查目标机器端口是53或80的网络包,其他端口的我不关注】
1
2
3
4
5
6
7
8
9
|
# tcpdump -i eth0 -c 3 'dst port 53 or dst port 80' tcpdump: verbose output suppressed, use - v or -vv for full protocol decode listening on eth0, link- type EN10MB (Ethernet), capture size 65535 bytes 13:29:04.530130 IP 114.255.192.96.29832 > 116.255.245.206.http: Flags [S], seq 3169042560, win 5840, options [mss 1460,sackOK,TS val 2949111416 ecr 0], length 0 13:29:04.530660 IP 116.255.245.206.43211 > ns.sc.cninfo.net.domain: 40188+ PTR? 206.245.255.116. in -addr.arpa. (46) 13:29:04.548589 IP 114.255.192.96.29832 > 116.255.245.206.http: Flags [.], ack 3709396068, win 5840, options [nop,nop,TS val 2949111475 ecr 1601243970], length 0 3 packets captured 10 packets received by filter 0 packets dropped by kernel |
我们可以设置过滤类型,上面例子中我们使用了port这个类型,就是来指定端口。当然,tcpdump还支持如下的类型:
1 host:指定主机名或IP地址,例如’host roclinux.cn’或’host 202.112.18.34′
2 net :指定网络段,例如’arp net 128.3′或’dst net 128.3′
3 portrange:指定端口区域,例如’src or dst portrange 6000-6008′
如果我们没有设置过滤类型,那么默认是host。
第六招:
第六招,仍然会讲解tcpdump的过滤表达式,这次思路很简单,就是直接举例子,其实就是man tcpdump中的例子,很直观,很受用。
==
【例子1】- 我想抓到那些通过eth0网卡的,且来源是roclinux.cn服务器或者目标是roclinux.cn服务器的网络包
tcpdump -i eth0 'host roclinux.cn'
【例子2】- 我想抓通过eth0网卡的,且roclinux.cn和baidu.com之间通讯的网络包,或者,roclinux.cn和qiyi.com之间通讯的网络包
tcpdump -i eth0 'host roclinux.cn and (baidu.com or qiyi.com)'
【例子3】- 我想获取使用ftp端口和ftp数据端口的网络包
tcpdump 'port ftp or ftp-data'
大家是不是会有一个疑问“这个ftp、ftp-data到底对应哪个端口?除了ftp/ftp-data,还有哪些服务名称我可以直接用呢?”
嗯,这是个好问题,答案现在揭晓咯。
在Linux系统中,/etc/services这个文件里面,就存储着所有知名服务和传输层端口的对应关系。这个对应关系是由IANA组织(the Internet Assigned Numbers Authority,互联网数字分配机构)来全权负责的,你可以到这个链接http://www.iana.org/assignments/port-numbers通过Web方式查到。
如果你直接把/etc/services里的ftp对应的端口值从21改为了8888,那么tcpdump就会去抓端口含有8888的网络包了。
【例子4】- 我想获取roclinux.cn和baidu.com之间建立TCP三次握手中第一个网络包,即带有SYN标记位的网络包,另外,目的主机不能是qiyi.com
tcpdump 'tcp[tcpflags] & tcp-syn != 0 and not dst host qiyi.com'
这个语句看着比较复杂,其实如果要把这段解释清楚的确不容易,需要你具备计算机网络专业知识才行。这个我会安排一章来讲。
【例子5】- 打印IP包长超过576字节的网络包
tcpdump 'ip[2:2] > 576'
【例子6】- 打印广播包或多播包,同时数据链路层不是通过以太网媒介进行的。
tcpdump 'ether[0] & 1 = 0 and ip[16] >= 224'
最后三个例子,或许你看得有些晕头转向,没关系,先有个感官认识,看完接下来的几篇文章后,相信保证你就明白了:)
第七招:
在上一招中,最后的3个例子比较复杂,大家可能会感觉云里雾里。我们现在回顾下这三个例子,然后今天的第七招就是教大家如何看懂他们!
tcpdump 'tcp[tcpflags] & tcp-syn != 0 and not dst host qiyi.com' tcpdump 'ip[2:2] > 576' tcpdump 'ether[0] & 1 = 0 and ip[16] >= 224'
==
在讲解前,需要你熟练掌握ETHER/IP/TCP/UDP等协议的包头定义格式,能够知道每一位的作用和含义。
有关ETHER的,可以参考《计算机网络协议包头赏析-以太网》;
有关IP的,可以参考《计算机网络协议包头赏析-IP》;
有关TCP的,可以参考《计算机网络协议包头赏析-TCP》;
有关UDP的,可以参考《计算机网络协议包头赏析-UDP》。
==
磨刀不误砍柴工,如果本系列的前六篇文章你都仔细看过了,同时,几种协议的包格式也都了然于心了,那我们就切入正题,介绍下过滤表达式的高级语法。
其实我们需要着重讲解的只有一种语法,即proto [ expr : size],只要掌握了这个语法格式,相信大家就能看懂上面的三个稀奇古怪的表达式了。
proto就是protocol的缩写,表示这里要指定的是某种协议的名称,比如ip、tcp、ether。其实proto这个位置,总共可以指定的协议类型有15个之多,包括:
- ether – 链路层协议
- fddi - 链路层协议
- tr - 链路层协议
- wlan - 链路层协议
- ppp - 链路层协议
- slip - 链路层协议
- link - 链路层协议
- ip
- arp
- rarp
- tcp
- udp
- icmp
- ip6
- radio
expr用来指定数据报偏移量,表示从某个协议的数据报的第多少位开始提取内容,默认的起始位置是0;而size表示从偏移量的位置开始提取多少个字节,可以设置为1、2、4。
如果只设置了expr,而没有设置size,则默认提取1个字节。比如ip[2:2],就表示提取出第3、4个字节;而ip[0]则表示提取ip协议头的第一个字节。
在我们提取了特定内容之后,我们就需要设置我们的过滤条件了,我们可用的“比较操作符”包括:>,<,>=,<=,=,!=,总共有6个。
好,掌握了上面内容之后,我可以很负责任的告诉你,你已经掌握了tcpdump过滤表达式的最重要语法了。我们先来小试牛刀,看一个例题:
ip[0] & 0xf != 5
IP协议的第0-4位,表示IP版本号,可以是IPv4(值为0100)或者IPv6(0110);第5-8位表示首部长度,单位是“4字节”,如果首部长度为默认的20字节的话,此值应为5,即”0101″。ip[0]则是取这两个域的合体。0xf中的0x表示十六进制,f是十六进制数,转换成8位的二进制数是“0000 1111”。而5是一个十进制数,它转换成8位二进制数为”0000 0101″。
有了上面这些分析,大家应该可以很清楚的知道,这个语句中!=的左侧部分就是提取IP包首部长度域,如果首部长度不等于5,就满足过滤条件。言下之意也就是说,要求IP包的首部中含有可选字段。
大家可能已经有所体会,在写过滤表达式时,你需要把协议格式完全背在脑子里,才能把表达式写对。可这对大多数人来说,可能有些困难。为了让tcpdump工具更人性化一些,有一些常用的偏移量,可以通过一些名称来代替,比如icmptype表示ICMP协议的类型域、icmpcode表示ICMP的code域,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-ack, tcp-urg。
如果一个过滤表达式有多个过滤条件,那么就需要使用逻辑符了,其中,!或not都可以表示“否定”,&&与and都可以表示“与”,而||与or都可以表示“或”。
==
好了,大功告成,如果你真的仔细阅读并掌握了上面的内容,我相信你有能力自己来分析下面这三个语句,而且一定能明白它们的“言下之意”的!
tcpdump 'tcp[tcpflags] & tcp-syn != 0 and not dst host qiyi.com' tcpdump 'ip[2:2] > 576' tcpdump 'ether[0] & 1 = 0 and ip[16] >= 224'
谢谢!
第八招:
在这个系列文章的开篇部分,我提到“学习tcpdump,要掌握的是三个部分,即选项、过滤表达式和输出内容”。本篇文章,我们就进入“输出内容”的讲解。
还记得我们在第一篇文章里的“人生中第一次抓包”么,我们这次就来好好剖析剖析这第一个包。
1
2
3
4
5
6
7
8
9
10
11
|
# tcpdump -i eth0 -nn -X 'port 53' -c 1 tcpdump: verbose output suppressed, use - v or -vv for full protocol decode listening on eth0, link- type EN10MB (Ethernet), capture size 65535 bytes 19:48:33.285838 IP 116.255.245.206.47940 > 8.8.8.8.53: 22768+ A? www.baidu.com. (31) 0x0000: 4500 003b c341 0000 4011 3c93 74ff f5ce E..;.A..@.<.t... 0x0010: 0808 0808 bb44 0035 0027 b457 58f0 0100 .....D.5.'.WX... 0x0020: 0001 0000 0000 0000 0377 7777 0562 6169 .........www.bai 0x0030: 6475 0363 6f6d 0000 0100 01 du .com..... 1 packets captured 1 packets received by filter 0 packets dropped by kernel |
【第2行】
“tcpdump: verbose output suppressed, use -v or -vv for full protocol decode”
这一行,是一句贴心的提醒,简单易懂,就是说你的命令里没有用到-v和-vv,如果希望看到更全的输出内容,可以使用这两个选项。
如果你有兴趣,可以试试,看看加上-vv后,到底输出内容里会多些什么。
【第3行】
“listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes”
这一句表示我们监听的是通过eth0这个NIC设备的网络包,且它的链路层是基于以太网的,要抓的包大小限制是65535字节。
包大小限制值可以通过-s选项来设置,如果你要追求高性能,建议把这个值调低,这样可以有效避免在大流量情况下的丢包现象。
【第4行】
“19:48:33.285838 IP 116.255.245.206.47940 > 8.8.8.8.53: 22768+ A? www.baidu.com. (31)”
“19:48:33.285838”,分别对应着这个包被抓到的“时”、“分”、“秒”、“微妙”。
“IP”,表示这个包在网络层是IP包。
“116.255.245.206.47940”,表示这个包的源IP为116.255.245.206,源端口为47940。
“>”,这个大于号表示数据包的传输方向。
“8.8.8.8.53“,表示这个包要发向的目的端IP是8.8.8.8,目标端口为53,也就是我们熟知的DNS服务端口。
“22768+ A? www.baidu.com. (31)“,这是DNS协议的内容,即请求www.baidu.com的A纪录。
【第5/6/7/8行】
0x0000: 4500 003b c341 0000 4011 3c93 74ff f5ce E..;.A..@.<.t... 0x0010: 0808 0808 bb44 0035 0027 b457 58f0 0100 .....D.5.'.WX... 0x0020: 0001 0000 0000 0000 0377 7777 0562 6169 .........www.bai 0x0030: 6475 0363 6f6d 0000 0100 01 du.com.....
接下来便是IP包的内容了,是除去了以太网之后剩下的内容,其中左侧红色字体部分是十六进制内容,右侧天蓝色字体部分是相应的ASCII码内容。
如果想看懂上面这些十六进制数字,前提就是大家要对IP、TCP/UDP的包格式很熟悉才可以。正好Linux大棚有一个系列文章就是来介绍这些重要协议:
计算机网络协议包头赏析-以太网
计算机网络协议包头赏析-IP
计算机网络协议包头赏析-TCP
计算机网络协议包头赏析-UDP
好,下面我们就来给大家解读下那些“晦涩的十六进制数字”。
0x0000: 【45】00 003b c341 0000 4011 3c93 74ff f5ce E..;.A..@.<.t... 0x0010: 0808 0808 bb44 0035 0027 b457 58f0 0100 .....D.5.'.WX... 0x0020: 0001 0000 0000 0000 0377 7777 0562 6169 .........www.bai 0x0030: 6475 0363 6f6d 0000 0100 01 du.com.....
如上,最外层是IP数据包,最开始的一个字节(8bit)中,前4bit表示IP的版本,此处为4,表示这是一个IPv4版本的IP包;后4bit表示这IP包的首部长度,此处的数字是5,由于单位是“4字节”,因此可以计算得出这个IP包的首部长度是固定的20字节。如下绿色字体部分都是IP数据包的首部部分:
0x0000: 【4500 003b c341 0000 4011 3c93 74ff f5ce E..;.A..@.<.t... 0x0010: 0808 0808】 bb44 0035 0027 b457 58f0 0100 .....D.5.'.WX... 0x0020: 0001 0000 0000 0000 0377 7777 0562 6169 .........www.bai 0x0030: 6475 0363 6f6d 0000 0100 01 du.com.....
如下所示,在IP版本和首部长度之后,接下来的一个字节(8bit)是“00”,这是IP协议的服务类型域(TOS),由于已经很少使用,因此此处被置为00。
0x0000: 45【00】003b c341 0000 4011 3c93 74ff f5ce E..;.A..@.<.t... 0x0010: 0808 0808 bb44 0035 0027 b457 58f0 0100 .....D.5.'.WX... 0x0020: 0001 0000 0000 0000 0377 7777 0562 6169 .........www.bai 0x0030: 6475 0363 6f6d 0000 0100 01 du.com.....
如下所示,后面的2字节(16bit)是“003b”,表示整个IP包的总长度(首部长度+数据长度),单位是字节,因此可以知道这个IP包的总长度是59字节(0x3b需要转换为十进制)。你可以数数下面的红色部分,应该是正好59个字节
0x0000: 4500 【003b】 c341 0000 4011 3c93 74ff f5ce E..;.A..@.<.t... 0x0010: 0808 0808 bb44 0035 0027 b457 58f0 0100 .....D.5.'.WX... 0x0020: 0001 0000 0000 0000 0377 7777 0562 6169 .........www.bai 0x0030: 6475 0363 6f6d 0000 0100 01 du.com.....
再向下的2字节(16bit)是“标识域”,如果IP包的大小超过了数据链路层的MTU限制,就需要对IP包进行分拆,此时就要用这个域来表示哪些包在分拆前是同一组的。此处的标识域值为0xc341。
0x0000: 4500 003b 【c341】 0000 4011 3c93 74ff f5ce E..;.A..@.<.t... 0x0010: 0808 0808 bb44 0035 0027 b457 58f0 0100 .....D.5.'.WX... 0x0020: 0001 0000 0000 0000 0377 7777 0562 6169 .........www.bai 0x0030: 6475 0363 6f6d 0000 0100 01 du.com.....
再继续向向下看,便是3bit的标志位,最高位为保留位,中间一位为DF(don’t fragment),最低位为MF(more fragments),可以看到这三位是用来控制IP拆包后的组装所用。由于此包没有拆包,因此这三位都被置为0,如下所示:
0x0000: 4500 003b c341 【0】000 4011 3c93 74ff f5ce E..;.A..@.<.t... 0x0010: 0808 0808 bb44 0035 0027 b457 58f0 0100 .....D.5.'.WX... 0x0020: 0001 0000 0000 0000 0377 7777 0562 6169 .........www.bai 0x0030: 6475 0363 6f6d 0000 0100 01 du.com.....
和上面的标志位配合的是紧接着的13bit的片便宜,但由于本包没有拆包,因此此域也无用,因此为0。
0x0000: 4500 003b c341 【0000】 4011 3c93 74ff f5ce E..;.A..@.<.t... 0x0010: 0808 0808 bb44 0035 0027 b457 58f0 0100 .....D.5.'.WX... 0x0020: 0001 0000 0000 0000 0377 7777 0562 6169 .........www.bai 0x0030: 6475 0363 6f6d 0000 0100 01 du.com.....
如下,紧接着是8bit的TTL(Time To Live,即生存周期),此包的值为0×40,换算成十进制是64,这表明这个网络包,如果经过了超过64个中间路由节点,则认为目的地不可达,中间路由器会将此包抛弃掉。
0x0000: 4500 003b c341 0000 【40】11 3c93 74ff f5ce E..;.A..@.<.t... 0x0010: 0808 0808 bb44 0035 0027 b457 58f0 0100 .....D.5.'.WX... 0x0020: 0001 0000 0000 0000 0377 7777 0562 6169 .........www.bai 0x0030: 6475 0363 6f6d 0000 0100 01 du.com.....
继续的8bit为协议域,用于指代上一层协议类型。此处的值为0×11,对应十进制的17,而17是UDP协议的代号,因此可以知道这个网络包所用的传输层协议是UDP,而非TCP(TCP的协议号是6、TCMP的协议号是1)。
0x0000: 4500 003b c341 0000 40【11】 3c93 74ff f5ce E..;.A..@.<.t... 0x0010: 0808 0808 bb44 0035 0027 b457 58f0 0100 .....D.5.'.WX... 0x0020: 0001 0000 0000 0000 0377 7777 0562 6169 .........www.bai 0x0030: 6475 0363 6f6d 0000 0100 01 du.com.....
接下来的2个字节表示IP首部校验和,此处计算出来的结果是3c93。
0x0000: 4500 003b c341 0000 4011 【3c93】 74ff f5ce E..;.A..@.<.t... 0x0010: 0808 0808 bb44 0035 0027 b457 58f0 0100 .....D.5.'.WX... 0x0020: 0001 0000 0000 0000 0377 7777 0562 6169 .........www.bai 0x0030: 6475 0363 6f6d 0000 0100 01 du.com.....
如下,再往下就是大家非常熟悉的4字节的IP源地址,即“74 ff f5 ce”,转换成IP地址则为116.255.245.206。
0x0000: 4500 003b c341 0000 4011 3c93 【74ff f5ce】 E..;.A..@.<.t... 0x0010: 0808 0808 bb44 0035 0027 b457 58f0 0100 .....D.5.'.WX... 0x0020: 0001 0000 0000 0000 0377 7777 0562 6169 .........www.bai 0x0030: 6475 0363 6f6d 0000 0100 01 du.com.....
以此类推,再下面的4字节则为IP目的地址,即“08 08 08 08”,转换成IP地址则为8.8.8.8,这是著名的Google-DNS服务器地址。
0x0000: 4500 003b c341 0000 4011 3c93 74ff f5ce E..;.A..@.<.t... 0x0010: 【0808 0808】 bb44 0035 0027 b457 58f0 0100 .....D.5.'.WX... 0x0020: 0001 0000 0000 0000 0377 7777 0562 6169 .........www.bai 0x0030: 6475 0363 6f6d 0000 0100 01 du.com.....
至此,网络层IP协议的首部20字节已经分析完了。再向下我们即将进入传输层UDP协议的包分析阶段。
相对于TCP包来说,UDP包的首部还是比较简单的,总共只有8个字节,如下绿色部分便是UDP首部部分:
0x0000: 4500 003b c341 0000 4011 3c93 74ff f5ce E..;.A..@.<.t... 0x0010: 0808 0808 【bb44 0035 0027 b457】 58f0 0100 .....D.5.'.WX... 0x0020: 0001 0000 0000 0000 0377 7777 0562 6169 .........www.bai 0x0030: 6475 0363 6f6d 0000 0100 01 du.com.....
UDP首部的前2个字节(如下棕色部分)为源端口,此处为“bb 44”,即47940;而接下来的2字节(如下粉色部分)为目的端口,值为“00 35”,即53(DNS服务)。
0x0000: 4500 003b c341 0000 4011 3c93 74ff f5ce E..;.A..@.<.t... 0x0010: 0808 0808 【bb44】 【0035】 0027 b457 58f0 0100 .....D.5.'.WX... 0x0020: 0001 0000 0000 0000 0377 7777 0562 6169 .........www.bai 0x0030: 6475 0363 6f6d 0000 0100 01 du.com.....
而接下来的2字节(如下棕色部分)则表示UDP包的总长度(报头+数据部分),此处的值为“00 27”,这算成十进制则为39,就表示此UDP包的总长度为39字节,减去首部的8字节外,还有31字节来存储真正要传输的数据。
0x0000: 4500 003b c341 0000 4011 3c93 74ff f5ce E..;.A..@.<.t... 0x0010: 0808 0808 bb44 0035 【0027】 【b457】 58f0 0100 .....D.5.'.WX... 0x0020: 0001 0000 0000 0000 0377 7777 0562 6169 .........www.bai 0x0030: 6475 0363 6f6d 0000 0100 01 du.com.....
而UDP首部的最后两个字节(如上粉色部分)则是校验和部分,此处的值为0xb457。
再向下的部分(绿色部分),则是应用层协议的内容(本例中是DNS协议)了,如果你有兴趣,可以继续了解下DNS协议、HTTP协议、FTP协议等众多的应用层协议,这非常有利于大家在学习协议、追查网络问题时,透过现象看本质。
0x0000: 4500 003b c341 0000 4011 3c93 74ff f5ce E..;.A..@.<.t... 0x0010: 0808 0808 bb44 0035 0027 b457 【58f0 0100 .....D.5.'.WX... 0x0020: 0001 0000 0000 0000 0377 7777 0562 6169 .........www.bai 0x0030: 6475 0363 6f6d 0000 0100 01】 du.com.....
谢谢!