30分钟掌握tcpdump

开发 开发工具
史上最难杀死的ARP病毒横行数十年依然如此无敌,作为一名老司机我要手把手教你做病毒,分分钟让你的网络陷入瘫痪(还可以让你“精准”打击网络内任何一个人——让她上不了网然后伪装成老司机修电脑)。

这是一篇关于tcpdump的文章,分为使用tcpdump、解读输出两部分。其中“解读输出”部分中关于分片的解释是个人认为最有价值的,当然如果你肯花30分钟自己动手抓个包尝试用本文介绍的方式还原IP、TCP头部肯定会对你调试网络程序有帮助(成为老司机专治各种网络疑难杂症想想是不是挺激动?)。

使用tcpdump

格式:tcpdump [选项] [表达式]

我常用的选项

  • -n 禁用域名解析,tcpdump会对每次收到的数据包尝试域名解析这会导致有些时候“迟迟看不到输出”。加上这个选项让tcpdump直接输出IP地址。
  • -X 按16进制输出完成的数据包,不加这个选项tcpdump会只输出ip,tcp/udp头部信息。加上这个选项会让tcpdump把整个数据包都打印出来。
  • -i 指定网卡,不指定网卡的情况tcpdump会使用***个网卡。
  • -vvvv 是两个选项的组合-v会输出稍微详细一点的信息包括校验和ttl之类的;-vvv会尝试解析应用层协议,输出详细的信息。二者组合就能拿到完整的详细信息

表达式用来过滤数据包,特别是加上X选项(输出数据包的详细内容会让你的屏幕快速飞过~~),如果不指定表达式基本上是刷屏的速度。我一般会限制协议类型、主机地址或者端口。比如抓取HTTP数据包,我会tcpdump -X -i eth0 -vvvv -n port 80,指定抓取80端口的数据(对端80和本机80)

解读tcpdump输出

提到网络就不能不提ISO分层模型、TCP/IP分层模型,这两部分的内容教材的太多了我就不絮叨了。从现实意义上说其实网络只有三层。物理层和数据链路层就是指网卡所以我们无需关心;IP层、TCP/UDP、应用层这三部分是我们最常接触到的,其实它们是指一个东西。比如看一个HTTP GET请求。

这是用tcpdump抓到的一个GET请求,

***行,12:53:07.156463 IP (tos 0x2,ECT(0), ttl 64, id 22767, offset 0, flags [DF], proto TCP (6), length 577)

输出了当前时间(本机)、IP头部信息;

第二行,192.168.200.1.59222 > 192.168.200.10.80: Flags [P.], cksum 0x98a6 (correct), seq 966819399:966819924, ack 3158680476, win 4096, options [nop,nop,TS val 341138922 ecr 204637], length 525

说明了这个数据包是从 192.168.200.1的59222端口发送到 192.168.200.10的80端口,后面是TCP头部信息。

第三行可不是“实际内容”,它是整个数据包的16进制输出和对应的ASCII(包括IP头部和TCP头部)。

所以网络分层其实就是指一个数据包拥有不同的头部。这种设计是一种封装,通过划分“层”让应用更容易开发。我们来剖析一下IP头和TCP头,掌握了这部分内容就算得上“精通网络”了(我没说错,是精通~~)。

IP头部

盗用一下wiki的图(遍地都是这种图我就不自己画了)

最小的IP头部是20个字节(不包含选项),上图中每一行4个字节(32个bit),一共6行(***一行大小不固定,最多40个字节。)。

结合我们的例子,其实tcpdump已经帮我们把关键的IP信息输出了。

我们直接看16进制的数据(验证tcpdump输出的IP信息和16进制表示的数据包是否吻合),每16bit一组。

  1. 4502 0241 58ef 4000 4006 ce68 c0a8 c801 
  • ***个4是表示是IPv4(占4bit);5表示头部长度为5个32bit(这个IP头部一共20个字节,说明这个数据包没有包含“选项”);后面这个字段需要特别注意,有些资料直接把它解释成TOS,不是完全正确的。它有两部分含义DSCP就是传统意义上的TOS,这里02是一个字节(8个二进制位)前6bit用来表示TOS,这里是0(很多设备是忽略TOS字段的);后面2bit显式拥塞通告(ECN)是一种新增的特性(甚至Windows7还不支持)用来显示告知对方自己是否支持拥塞控制(如果对端发生了拥塞会自动通过这两个字段告知你——我忙不过来了,兄弟你慢一点~~)。二进制10(十进制2)表示支持ECN特性。(tcpdump ip头部输出tos 0x2,ECT(0)表示支持ECT,不支持会显示成Not-ECT)
  • 0241是数据的总长度,这里是16进制的它的10进制值是577(和tcpdump IP头部输出的lenght 577吻合)
  • 58ef是数据包的唯一标识,一般约定双方在TCP三次握手的时候随机生成一个ID,每发送一个数据包彼此自增一下。它的主要用途是为了重传,但是其实IP协议从来没有实现过“重传”(后面介绍)。(和tcpdump IP头部输出的id 22767吻合)
  • 4是分片标志,基本上所有的IP数据包它都为4。因为IP数据包不会进行分片和重传。

下面这段推翻了网络上很多传言(好吧,好像包括Wiki)

每个以太网卡都有MTU(***传输单元)的限制,这个表示网卡每次可以接收一个数据包的大小。所以即便IP数据包可以达到2^32=65535字节也不能一次发送这么大的数据包。每个IP数据包的大小被限制在1500个字节(最常见的MTU大小),除去最小的IP头部(20)、最小TCP头部(20)还剩下1460字节,这就是一个IP数据包可以携带的准确数据。如果超过这个设定就必须“分片”。

如果你是UDP协议基本上是自己考虑分片,UDP协议本身不会重传,重组。所以一般用UDP协议都是“一枪头买卖”——在一个数据包里包含所有信息不进行分片。(如果你用UDP协议一般传送数据不要操过1380否则程序就必须考虑处理分片——也就是MTU-***IP头60字节-***TCP头60字节)

如果是TCP就很幸运了,TCP会帮你做分片和重组。(后面会讲)

因为TCP已经考虑过分片了所以IP数据包无需再次分片,“标志”字段基本上都是——4(不分片)。(大家可以抓一下163之类的网站看看HTML被分段传送的时候***行有没有4000)

  • 因为不考虑分片后面的偏移也没有任何用途了——000
  • 4006,存活时间40就是10进制的64,这是一个常用的值,一个数据包如果经过64次路由就可以被丢弃了(和Tcpdump输出一致);06表示这是TCP协议(如果是01表示是ICMP、UDP是0x11)
  • ce68校验和,不管它
  • c0a8 c801源IP地址,c0a8 c80a目标地址

用一段代码表示如何自己构造IP数据包

对于同一个TCP会话来说IP头是非常固定的。

TCP头部

最小的TCP头部是20个字节(不包含选项),上图中每一行4个字节(32个bit),一共6行(***一行大小不固定,最多40个字节。)。

结合我们的例子,其实tcpdump已经帮我们把关键的IP信息输出了。

注意这里的length是指数据的大小不包括IP头和TCP头

我们直接看16进制的数据,每16bit一组。

e756 0050 39a0 7e47 bc45 a39c

  • e756来源端口5922,0050是目标端口80
  • 39a07 e47=966819399,是seq号(序号)
  • bc45 a39c=3158680476,是ack号

TCP约定通讯双方三次握手的时候发送端会随机生成一个seq号通过***个SYN协议发送给对端,对端也会随机生成一个seq号同时设置ack+1响应对端。发送端则回复seq=自己seq+1,ack=对端 seq+1。通俗的说法,seq是自己的序号,ack是期望对端发送的数据,所以如果你拿到一个数据包seq=1024,ack=522;那么只要回复一条seq=522,ack=1025就可以实现“TCP会话劫持”(是不是很可怕?相当于不但可以探测到你的通话内容还可以“无缝介入”到你的谈话,***冒充对方而不会产生任何违和感)。

第三行8018 1000 98a6 0000 0101 080a 1455

  • 8表示8个32bit(这个TCP头大小是8*4=32个字节)
  • 0是保留
  • 18是标志位,对应tcpdump中的flag。

FIN=0x01,表示数据已经发送完了可以释放连接了,用于关闭TCP连接

SYN=0x02,这个太喜闻乐见了,用于TCP握手

RST=0x04,直接关闭TCP连接(不经过FIN)

PUSH=0x08,官方的解释“尽快交给应用不等待缓冲区装满”,其实这个标志位会一直存在。只要你传送数据一定会有这个标志位。

ACK=0x10,确认数据

tcpdump会分别用一个大写字母输出在Flags选项,比如例子中是“P”表示设置了push位,又因为有ack 3158680476所以一定有ACK标志位。不难算出PUSH+ACK=8+10=18

  • 1000这个是数据窗口大小(10进制4096),TCP流量控制关键的技术手段就是这个。包括最近很火爆的“Google BBR”其实就是找到一种算法可以尽可能***的调整这个窗口的大小。(其实ECN更牛B,根本不用“计算”直接通告给你。只是很多操作系统和硬件都不支持。)
  • 98a6 校验和,不管他
  • 0000这个通常和“标志位”配合使用,标志位设置URG (0x20)表示开启“紧急数据”,这个字段就是“紧急数据的序号”。比如你在看一段视频,已经还差1个数据包就可以播放5分钟了但是现在网络都在传送后面的数据,就可以通过这个标志位“紧急”获取关键的数据包。但是这个特性基本上没啥用,设备会无视这些东西的。

这个TCP包是32个字节,上面已经介绍了20个字节所以还有12个字节(6组),它们用来表示TCP的选项。

  • 0101 080a 1455 5dea 0003 1f5d,选项的格式格式是TLV结构(类型、长度、值)。简单来说就是***个字节表示数据类型,不同的类型后面会有不同大小的长度和内容。

TCP常见的选项包括

0 (1字节)什么都没有

1(1字节) 什么都没有,经常用于“填充”

上面的两个其实是同一个意思。

2 ***报文段长度(4字节)一般出现在三次握手的SYN包中,用于说明自己可以接收到的***报文长度(一般是MTU-40,就是以太网***传输单元-最小IP-最小TCP。这也印证了前面的说法——IP永远不分片,TCP负责分片。)

3 窗口扩大因子(4字节),取值0-14。滑动窗口***值是2^16(65535),如果在一个“高延时高带宽”(也叫长肥管道 )网络中这个值会显的特别小(所有的广域网或者乃至整个互联网都是这种网络)。所以新增扩大因子用来扩大窗口的大小,它表示TCP窗口左移的位数(实际窗口大小=窗口*2^窗口多扩大因子)。

8:时间戳(10字节)对端的时间戳(4字节)自己的时间戳(4字节)。这个选项主要用来测量回路时间(RTT),也是TCP做为流量控制的一个关键手段。

例子中0101没有意义,08表示这是时间戳选项(类型),后面0a是值所占字节(选项的整个长度,包括表示类型的1个字节表示长度的一个字节),1455 5dea(341138922) 四个字节表示发送端的时间戳,0003 1f5d(204637) 四个字节表示回显的时间戳。(对应tcpdump输出中的options [nop,nop,TS……])

用一段代码表示如何构造TCP包


对于一个TCP会话来说response、control、seq、ack是变化的,滑动窗口大小则会随着是否网络拥塞产生变化。

后面就是实际的HTTP协议的内容了,4745 5420,0x47是G的ASCII、0x45是E的ASCII、0x54是T的ASCII、0x20是空格。。。。。后面就自己读吧

总结

《TCP/IP协议详解》中很大部分章节是在介绍tcpdump的输出、IP头部、TCP头部(甚至可以说是三卷书都是在说这个),掌握tcpdump对于我们做网络分析或者系统调试是非常有帮助的。大家玩的愉快。

高能预警

哥讲tcpdump是为了下一篇——《手把手教你做ARP病毒》。史上最难杀死的ARP病毒横行数十年依然如此无敌,作为一名老司机我要手把手教你做病毒,分分钟让你的网络陷入瘫痪(还可以让你“精准”打击网络内任何一个人——让她上不了网然后伪装成老司机修电脑)。

【本文是51CTO专栏作者邢森的原创文章,转载请联系作者本人获取授权】

戳这里,看该作者更多好文

责任编辑:武晓燕 来源: 写程序的康德
相关推荐

2013-05-03 10:57:09

泛型泛型教程

2021-06-07 09:51:22

原型模式序列化

2020-05-22 10:20:27

Shiro架构字符串

2009-11-17 14:50:50

Oracle调优

2021-01-29 11:25:57

Python爬山算法函数优化

2021-03-12 09:45:00

Python关联规则算法

2020-12-17 10:00:16

Python协程线程

2017-07-18 11:10:45

2020-12-07 11:23:32

Scrapy爬虫Python

2021-03-23 15:35:36

Adam优化语言

2009-11-05 10:55:22

Visual Stud

2024-08-27 13:43:38

Spring系统业务

2017-06-07 18:40:33

PromiseJavascript前端

2013-12-11 10:00:14

C++新特性C

2020-10-27 10:43:24

Redis字符串数据库

2021-01-11 09:33:37

Maven数目项目

2022-05-30 07:51:13

数据库MySQLQPS

2016-08-03 16:01:47

GitLinux开源

2016-04-06 11:14:48

iOS相机自定义

2022-09-30 15:46:26

Babel编译器插件
点赞
收藏

51CTO技术栈公众号