抓包神器TCPDUMP的分析总结-涵盖各大使用场景、高级用法【转】

技术杂谈96

一、前言

网络故障排查中,经常要抓包,windows有wireshark,linux最常用的是tcpdump,其中被问得最多的一个问题:"iptables限制后,tcpdump还能抓到包吗?",首先看下数据包进入OS及出去的顺序:

网卡nic -> tcpdump -> iptables(netfilter) -> app -> iptables(netfilter) -> tcpdump -> 网卡nic

显而易见,数据包到达网卡后,tcpdump有能力直接捕获到,不受iptables的影响,此时数据包还没有到达iptables的 PREROUTING链,到达APP后,处理完报文从iptables出去,出去最终要走到 POSTROUTING链再到tcpdump,所以此时受到iptables的 OUTPUTPOSTROUTING链影响,这两条链的规则决定tcpdump能不能抓到出去的包,iptables各个链工作顺序如下(图片来源于网络):

本文将汇总日常工作使用中的一些用法和技巧,同时附上tcpdump官方文档:https://www.tcpdump.org/tcpdump_man.html

二、tcpdump常用参数详解

1.指定网卡和主机抓包(-i、host)

指定所有网卡并限定主机为192.168.1.1

tcpdump -i any host 192.168.1.1      #-i指定网卡为所有

复制

此时如果和对端主机有数据交互,那么屏幕上有输出信息,同时这些信息不会保存在文件里,比如下面这个icmp包:

CTRL + C给进程发送 SIGINT信号,中断tcpdump当前抓包,会发现这些数据包默认会显示在屏幕上,如果是简单数据包直接拿tcpdump分析是没问题的,但在报文交互很大的场景下,要过滤特定流,此时用tcpdump分析效率会很低,正确的做法是tcpdump抓包保存为抓包文件(.pcap.cap都行),再用wireshark分析。

同时这里还有问题,tcpdump默认会将IP反向解析成host或域名-nn参数可以禁止反向解析,增加可读性。

2.写入文件并查阅报文(-w、-r)

那么改进后的抓包命令可以是:

tcpdump -i any host 192.168.1.1 -nn -v -w client.pcap

复制

-nn:禁止反向解析

-v:显示详细抓包信息

-w:写入到client.pcap

可以看到第一条命令,IP不再反解成host或域名,第二条命令 -w写入到client.pcap后,使用 -r参数指定报文文件查阅内容。

3.指定来源IP或目的IP或网段(src、dst、net)

如果只想抓一个方向的流,使用 src指定源或者 dst指定目标:

tcpdump -i any src host 192.168.1.1 -nn

复制

这样一来只抓一个方向的流,如图只有1.1方向过来 icmp reply,以及arp报文,arp缓存表过期后则会发送一次广播,以获得mac地址。

dst指定到达目的方向的包,过滤本端发给对端的 icmp request

tcpdump -nn -i any dst 192.168.1.1

复制

指定网段:

tcpdump -nn -i any net 192.168.1.1/32

复制

4.指定每个报文抓包字节数(-s)

有时候我们分析包一般分析头部就行了,不需要分析每个包的data数据部分,这样可以尽量减小抓包文件的大小, -s指定每个报文抓前面多少个字节:

tcpdump -nn -i any -s 84 host 192.168.1.1  #imcp协议默认为"56字节"数据字节+"28字节"的ICMP头,一共是84字节

复制

如果不指定 -s参数,tcpdump默认只会抓每个报文的前面56个字节, -s 0可以不限制字节数,每次都抓完整的包:

tcpdump -nn -i any -s 0 host 192.168.1.1

复制

如果是icmp,56+8个字节的icmp头部,默认是64个字节:

5.指定端口和协议(port、portrange、protocol)

全量抓不如抓出问题的端口或协议,对症下药,语法也很简单:

tcpdump -nn -i any -s 0 icmp  #只抓icmp协议

复制

icmp运行在网络层偏上,所以并没有端口的定义,抓icmp并不需要指定端口,那么抓tcp端口可以这样写:

tcpdump -nn -i any -s 60 tcp port 80  #作为演示,这里只抓60个头部字节

复制

同理,那么udp可以这样写:

tcpdump -nn -i any -s 0 udp port 22

复制

抓端口范围,需要用到 portrange参数:

tcpdump -nn -i any tcp portrange 53-80

复制

如果不确定协议,只指定 port即可:

tcpdump -nn -i any -s 0 port 22

复制

6.tcpdump的逻辑表达式(or、and、not)

逻辑语句,顾名思义,只要接触过一点编程,就知道指的是或与非,及 orandnot,其中 not也可以用作 !,此三个参数较常用,可以帮我们过滤出有用的信息,指哪打哪。

使用 and指定目标和协议:

tcpdump -nn -i any -s 0 host 192.168.1.1 and icmp

复制

使用 or指定多个过滤条件:

tcpdump -nn -i any -s 0 host 192.168.1.1 or icmp or src net 192.168.1.1/32

复制

使用 or!排除过滤条件:

tcpdump -nn -i any -s 0 ! net 172.16.0.0/16 and icmp and ! tcp

复制

指定要抓包的网段掩码即可,那么综合以上,你可以举一反三,把它们搭配起来灵活运用,只要抓包逻辑语法正确即可,哪怕又臭又长:

tcpdump -nn -i any -s 0 dst host 192.168.1.197 and icmp and src net 192.168.1.1/32 or \( host 192.168.1.1 \) and ! tcp

复制

bash解析每条命令最多255个字符,又臭又长无意义的语句不是拿来用于生产环境,而是平时练手可以多拼凑组合测试,到达炉火纯青的那一刻,生产环境想抓什么包想怎么搭配使用信手拈来。

7.指定数据包大小过滤(greater、less)

tcpdump提供指定每个报文大小的过滤方式,在需要过滤大包或特定大小的包场景特别好用。

过滤大于1000字节的包:

tcpdump -nn -s 0 -i any host 192.168.1.1 and greater 1000 and icmp

复制

过滤小于1000字节的包:

tcpdump -nn -s 0 -i any host 192.168.1.1 and less 1000 and icmp

复制

结合使用,缩小范围:

tcpdump -nn -s 0 -i any host 192.168.1.1 and less 800 and greater 690

复制

8.Flags标记解读

下面的命令抓取一个完整连接,包括三次握手和四次挥手:

每个Flags含义如下:

[S]

SYN

[.]

ACK

[S.]

SYN、ACK

[P.]

PUSH

[R.]

RST

[F.]

FIN

[DF]

Don't Fragment(不分片),当DF=0时,允许分片

[FP.]

FIN、PUSH、ACK

前面说过,如果使用tcpdump不好直观分析报文,可 -w保存到文件后使用wireshark分析:

建立三次握手后, Tcp Keep-Alive一直保留连接,之后客户端主动挥手断开连接,客户端对应的行为是这样的:

9.指定抓包数量、抓包大小、及轮询抓包(-c、-W、-C、-G)

在某些场景需要分割抓包文件,轮询抓包,那么这几个参数可以排上用上:

  • -c指定抓多少个包
  • -W最多写入多少个抓包文件,以MB为单位
  • -C写入到抓包文件的大小上限

-c指定抓2个包:

tcpdump -i any -s 0 net 192.168.1.1/32 -c 2

复制

-C指定写入到文件的大小上限为1M:

tcpdump -i any -s 0 -C 1 -v -w client.pcap

复制

-W指定写入到10个抓包文件,每个文件只抓1M,循环写入:

tcpdump -i any -s 0 -C 1M -v -W 10 -w client.pcap

复制

保存格式将在文件后缀加入从0-N的编号。

-G参数指定间隔多少秒轮询保存一次文件,通常是以时间格式命令:

tcpdump -nn -i any -s 0 -G 5 -Z root -v -w %m-%d-%H:%M:%S.pcap  #每隔五秒保存一次文件

复制

-Z参数指定每次写入新文件用 root权限执行, -w的时间格式为 date命令的时间格式取值,可以之间拿来用。

-G通常配合 -C来使用,指定每次每个文件抓固定大小:

tcpdump -nn -i any -s 0 -C 1 -G 5 -v -w %m-%d-%H:%M:%S.pcap

复制

同时也可以配合 timeout命令使用,抓固定时间后停止抓包:

timeout 10 tcpdump -nn -i any -s 0 -G 5 -v -w %m-%d-%H:%M:%S.pcap

复制

只抓10s,每间隔5s轮询保存一次文件。

10.抓取指定Flag位的报文

抓指定标志位虽然不常用,通常是使用wireshark分析过滤,但如果这个功能在tcpdump上使用熟练,知道自己想要什么包,那么tcpdump这一层就能筛选出对你有用的报文,减少不必要的报文量。

只抓SYN标志位不为0的,并且只抓一个包:

tcpdump -nn -i any -s 0 -c 1 'tcp[tcpflags] & tcp-syn != 0'

复制

抓一次完整握手需要的标志位:

tcpdump -nn -i any -s 0 'tcp[tcpflags] & (tcp-syn|tcp-ack|tcp-fin) != 0' and host 192.168.1.1

复制

同时,也可以用二进制表示,不过可读性较差:

tcpdump -nn -i any -s 0 'tcp[13] & (1|2|18) != 0' and net 192.168.1.1/32 and tcp port 80

复制

tcp字段在tcp头第十四字节存储,编程里面都是从0开始计数,那么tcp13就是表示tcp头部字段,附上过滤常用的几个字段含义:

tcp13 = 2

捕获SYN包,二进制为:00000010

tcp23 = 18

捕获回给SYN的ACK包,二进制为:00010010

tcp13 & 2 = 2

捕获SYN和SYN对应的ACK包

tcp13 = 24

捕获PSH-ACK包

tcp13 & 1 = 1

捕获FIN-ACK包

tcp13 & 4 = 4

捕获RST包

其他协议也是以此类推,比如icmp:

tcpdump -nn -i any -c 2 -s 0 host 192.168.1.1 and 'icmp[icmptype] = icmp-echo or icmp[icmptype] = icmp-echoreply'

复制

三、总结

以上总结的是一些工作中较常用的使用方法及技巧,在不同的问题场景下,知道抓什么包,明确自己需要什么包,包抓的越精准,定位问题就不会像大海捞针一样,分析包的过程也会变的会事半功倍、气定神闲。

转自

抓包神器TCPDUMP的分析总结-涵盖各大使用场景、高级用法 - 云+社区 - 腾讯云
https://cloud.tencent.com/developer/article/1858612

Original: https://www.cnblogs.com/paul8339/p/16400238.html
Author: paul_hch
Title: 抓包神器TCPDUMP的分析总结-涵盖各大使用场景、高级用法【转】



相关阅读

Title: “银行家算法”大揭秘!在前端表格中利用自定义公式实现“四舍六入五成双”

银行的盈利模式是什么?三个字:信息差!从储户手中收拢资金,然后放贷出去,而所谓的"利润"就是这其中的利息差额。
在我国,人民银行规定每个季度月末的20号为银行结息日,每一年四次结息,因此每年需要非常频繁的计算付给储户的利息。在计算利息时,小数点如何处理就变得很重要,并成为决定利润多少的关键细节。

抓包神器TCPDUMP的分析总结-涵盖各大使用场景、高级用法【转】

(图片来自于网络)

通常,我们都知道在保留小数点的时候,常常会用到四舍五入。小于5的数字被舍去,大于等于5的数字进位后舍去,由于所有位上的数字都是自然计算出来的,按照概率计算可知,被舍入的数字均匀分布在0到9之间。
我们不妨以10笔存款利息计算作为模型,以银行家的身份来思考这个算法:

四舍,舍弃的值包含: 0.000、0.001、0.002、0.003、0.004,对银行而言舍弃的内容就不再需要支付,所以舍弃的部分我们可以理解为"赚到了"。

五入,进位的内容包括:0.005、0.006、0.007、0.008、0.009,对银行而言进位内容会造成亏损,对应亏损的金额则是: 0.005、0.004、0.003、0.002、0.001。
因为舍弃和进位的数字是在0到9之间均匀分布的,所以对于银行家来说,每10笔存款的利息因采用四舍五入而获得的盈利是:
0.000 + 0.001 + 0.002 + 0.003 + 0.004 - 0.005 - 0.004 - 0.003 - 0.002 - 0.001 = -0.005
总体来讲每10笔的利息,通过四舍五入计算就会导致0.005元的损失,即每笔利息计算损失0.0005元。假设某家银行有5千万储户,每年仅仅因为四舍五入的误差而损失的金额是:

public class Client {
     public static void main(String[] args) {
          //银行账户数量,5千万
          int accountNum =5000*10000;
          //按照人行的规定,每个季度末月的20日为银行结息日
          double cost = 0.0005 * accountNum * 4 ;
          System.out.println("银行每年损失的金额:" + cost);
     }
}

计算结果是:"银行每年损失的金额:100000.0"。你可能难以相信,四舍五入小小一个动作,就导致了每年损失10万。但在真实环境中,实际损失可能事更多。
这个情况是由美国的私人银行家发现,为了解决这一情况提出了一个修正算法:
"舍去位的数值小于5时,直接舍去;
舍去位的数值大于等于6时,进位后舍去;
当舍去位的数值等于5时,分两种情况:5后面还有其他数字(非0),则进位后舍去;若5后面是0(即5是最后一个数字),则根据5前一位数的奇偶性来判断是否需要进位,奇数进位,偶数舍去。"
以上这么多,汇成一句话就是:四舍六入五考虑,五后非零就进一,五后为零看奇偶,五前为偶应舍去,五前为奇要进一。
我们举例说明,取2位精度:
10.5551= 10.56
10.555= 10.56
10.545= 10.54

抓包神器TCPDUMP的分析总结-涵盖各大使用场景、高级用法【转】

(图片来自于网络)

简单来说,有了"四舍六入五成双"这样的银行家算法,就可以更为科学精确地处理数据。

在实际应用中,我们使用银行家算法最多的情况就是在大数据量的表格计算中,但是在表格计算中需要通过一系列的内置公式进行复合。对于普通用户来说无论是理解还是最终使用,都很繁琐且复杂。
为了更加方便地解决这个问题,我们可以通过自定义函数来完成这样的需求,这样用户只需要记住自定义的函数名即可使用具有这样一个规则的函数。
接下来我们一起看看,如何在前端表格中快速地实现"四舍六入五成双"。
我们首先需要定义函数的名称,以及里面的参数数目。因为我们想要实现的是,传递两个参数,"1"是需要被约修的数值,"2"是保留小数点后面的位数,根据值和位数进行约修。

var FdaFunction = function() {
             this.name = "FDA";
             this.minArgs = 1;
             this.maxArgs = 2;
         };

接下来就是为了方便用户理解和使用,我们需要对这个自定义函数添加一些描述:

 FdaFunction.prototype.description = function() {
             return {
                 description: "对value进行四舍六入五留双修约,保留小数点后指定位数",
                 parameters: [{
                     name: "value",
                     repeatable: false,
                     optional: false
                 }, {
                     name: "places",
                     repeatable: false,
                     optional: false
                 }]
             }
         }

最后到了关键步骤,也就是函数的逻辑运行都放在evaluate中,我们会对传入的值做一些判断,并且会利用正则表达式做一些匹配。要实现"五成双",那么我们还要对需要约修的最后一个位值做判断,来决定是否进位。具体可以参考附件完整的demo。

         FdaFunction.prototype.evaluate = function(context, num, places) {

            if (!isNaN(parseInt(num)) && !isNaN(parseInt(places))) {
                console.log("evaluate")
                 num = numGeneral(num);
                if (!isNumber(num)) {
                    return num;
                }
                var d = places || 0;
                var m = Math.pow(10, d);
                var n = +(d ? num * m : num).toFixed(8); // Avoid rounding errors
                var i = Math.floor(n),
                    f = n - i;
                var e = 1e-8; // Allow for rounding errors in f
                var r = f > 0.5 - e && f < 0.5 + e ? (i % 2 == 0 ? i : i + 1) : Math.round(n);
                var result = d ? r / m : r;

                if (places > 0) {
                    var s_x = result.toString();
                    var pos_decimal = s_x.indexOf(".");
                    if (pos_decimal < 0) {
                        pos_decimal = s_x.length;
                        s_x += ".";
                    }
                    while (s_x.length <= pos_decimal + places) { s_x ; } return s_x; else result; }else{ "#value!"; < code></=>

体验下载完整demo:
https://gcdn.grapecity.com.cn/forum.php?mod=attachment&aid=MTkyNjA3fDQzMTk2ZmRhfDE2NTAyNzI0NTV8NjI2NzZ8MTQxNjY4

大家如果想了解更多与自定义公式相关内容,可以查看链接:
https://demo.grapecity.com.cn/spreadjs/SpreadJSTutorial/features/calculation/custom-functions/purejs

Original: https://www.cnblogs.com/powertoolsteam/p/16257609.html
Author: 葡萄城技术团队
Title: “银行家算法”大揭秘!在前端表格中利用自定义公式实现“四舍六入五成双”