转载

30 分钟掌握 tcpdump

这是一篇关于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请求。

30 分钟掌握 tcpdump

这是用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的图(遍地都是这种图我就不自己画了)

30 分钟掌握 tcpdump

最小的IP头部是20个字节(不包含选项),上图中每一行4个字节(32个bit),一共6行(最后一行大小不固定,最多40个字节。)。 结合我们的例子,其实tcpdump已经帮我们把关键的IP信息输出了。
我们直接看16进制的数据(验证tcpdump输出的IP信息和16进制表示的数据包是否吻合),每16bit一组。 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数据包

30 分钟掌握 tcpdump 对于同一个TCP会话来说IP头是非常固定的。

TCP头部

30 分钟掌握 tcpdump 最小的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包 30 分钟掌握 tcpdump 对于一个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病毒横行数十年依然如此无敌,作为一名老司机我要手把手教你做病毒,分分钟让你的网络陷入瘫痪(还可以让你“精准”打击网络内任何一个人——让她上不了网然后伪装成老司机修电脑)。
封面是Linux kernel的网络“流程图”。这里是高清无码版 https://wiki.linuxfoundation.org/images/1/1c/Network_data_flow_through_kernel.png

欢迎关注公众账号了解更多信息“写程序的康德——思考、批判、理性”

30 分钟掌握 tcpdump

原文  http://mp.weixin.qq.com/s?__biz=MzIxMjAzMDA1MQ==&mid=2648945706&idx=1&sn=9e0c53430969a31058c47d4fa18adcd3&chksm=8f5b5326b82cda30461c4f1cd7a41898f5e819180e3edafeced9f4024f2e5d585f706ec566fb
正文到此结束
Loading...