• tcpdump


    第一招:

    通俗的说,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.....
    

    谢谢!

     转自:http://roclinux.cn/

  • 相关阅读:
    Linux下C语言执行shell命令
    netstat实现原理
    安装docker
    springboot启动提示连接mysql报错:java.sql.SQLNonTransientConnectionException: CLIENT_PLUGIN_AUTH is required
    linux删除用户报错:userdel: user prize is currently used by process 28021
    centos的6.9版本安装openjdk1.8
    centos的6.9版本安装mysql
    安装mysql报错:Can't find messagefile '/usr/share/mysql/english/errmsg.sys'和/usr/bin/mysqladmin: error while loading shared libraries: libmysqlclient.so.16: cannot open shared object file: No such file or
    安装docker报错:https://download.docker.com/linux/centos/7/i386/stable/repodata/repomd.xml: [Errno 14] PYCURL ERROR 22
    linux配置docker报错:ImportError: No module named yum
  • 原文地址:https://www.cnblogs.com/maowang1991/p/3420075.html
Copyright © 2020-2023  润新知