学习啦>学习电脑>操作系统>Linux教程>

tcpdump命令的使用方法(4)

春健分享

  连接顺序对应,并带有相应TCP控制标志的数据包如下:

  1) 连接发起方(nt:Caller)发送SYN标志的数据包

  2) 接收方(nt:Recipient)用带有SYN和ACK标志的数据包进行回应

  3) 发起方收到接收方回应后再发送带有ACK标志的数据包进行回应

  0 15 31

  -----------------------------------------------------------------

  | source port | destination port |

  -----------------------------------------------------------------

  | sequence number |

  -----------------------------------------------------------------

  | acknowledgment number |

  -----------------------------------------------------------------

  | HL | rsvd |C|E|U|A|P|R|S|F| window size |

  -----------------------------------------------------------------

  | TCP checksum | urgent pointer |

  -----------------------------------------------------------------

  一个TCP头部,在不包含选项数据的情况下通常占用20个字节(nt | rt:options 理解为选项数据,需回译). 第一行包含0到3编号的字节,

  第二行包含编号4-7的字节.

  如果编号从0开始算, TCP控制标志位于13字节(nt:第四行左半部分).

  0 7| 15| 23| 31

  ----------------|---------------|---------------|----------------

  | HL | rsvd |C|E|U|A|P|R|S|F| window size |

  ----------------|---------------|---------------|----------------

  | | 13th octet | | |

  让我们仔细看看编号13的字节:

  | |

  |---------------|

  |C|E|U|A|P|R|S|F|

  |---------------|

  |7 5 3 0|

  这里有我们感兴趣的控制标志位. 从右往左这些位被依次编号为0到7, 从而 PSH位在3号, 而URG位在5号.

  提醒一下自己, 我们只是要得到包含SYN标志的数据包. 让我们看看在一个包的包头中, 如果SYN位被设置, 到底

  在13号字节发生了什么:

  |C|E|U|A|P|R|S|F|

  |---------------|

  |0 0 0 0 0 0 1 0|

  |---------------|

  |7 6 5 4 3 2 1 0|

  在控制段的数据中, 只有比特1(bit number 1)被置位.

  假设编号为13的字节是一个8位的无符号字符型,并且按照网络字节号排序(nt:对于一个字节来说,网络字节序等同于主机字节序), 其二进制值

  如下所示:

  00000010

  并且其10进制值为:

  0_^7 + 0_^6 + 0_^5 + 0_^4 + 0_^3 + 0_^2 + 1_^1 + 0_^0 = 2(nt: 1 _2^6 表示1乘以2的6次方, 也许这样更

  清楚些, 即把原来表达中的指数7 6 ... 0挪到了下面来表达)

  接近目标了, 因为我们已经知道, 如果数据包头部中的SYN被置位, 那么头部中的第13个字节的值为2(nt: 按照网络序, 即大头方式, 最重要的字节

  在前面(在前面,即该字节实际内存地址比较小, 最重要的字节,指数学表示中数的高位, 如356中的3) ).

  表达为tcpdump能理解的关系式就是:

  tcp[13] 2

  从而我们可以把此关系式当作tcpdump的过滤条件, 目标就是监控只含有SYN标志的数据包:

  tcpdump -i xl0 tcp[13] 2 (nt: xl0 指网络接口, 如eth0)

  这个表达式是说"让TCP数据包的第13个字节拥有值2吧", 这也是我们想要的结果.

  现在, 假设我们需要抓取带SYN标志的数据包, 而忽略它是否包含其他标志.(nt:只要带SYN就是我们想要的). 让我们来看看当一个含有

  SYN-ACK的数据包(nt:SYN 和 ACK 标志都有), 来到时发生了什么:

  |C|E|U|A|P|R|S|F|

  |---------------|

  |0 0 0 1 0 0 1 0|

  |---------------|

  |7 6 5 4 3 2 1 0|

  13号字节的1号和4号位被置位, 其二进制的值为:

  00010010

  转换成十进制就是:

  0_^7 + 0_^6 + 0_^5 + 1_^4 + 0_^3 + 0_^2 + 1_^1 + 0_ = 18(nt: 1 _2^6 表示1乘以2的6次方, 也许这样更

  清楚些, 即把原来表达中的指数7 6 ... 0挪到了下面来表达)

  现在, 却不能只用'tcp[13] 18'作为tcpdump的过滤表达式, 因为这将导致只选择含有SYN-ACK标志的数据包, 其他的都被丢弃.

  提醒一下自己, 我们的目标是: 只要包的SYN标志被设置就行, 其他的标志我们不理会.

  为了达到我们的目标, 我们需要把13号字节的二进制值与其他的一个数做AND操作(nt:逻辑与)来得到SYN比特位的值. 目标是:只要SYN 被设置

  就行, 于是我们就把她与上13号字节的SYN值(nt: 00000010).

  00010010 SYN-ACK 00000010 SYN

  AND 00000010 (we want SYN) AND 00000010 (we want SYN)

  -------- --------

  = 00000010 = 00000010

  我们可以发现, 不管包的ACK或其他标志是否被设置, 以上的AND操作都会给我们相同的值, 其10进制表达就是2(2进制表达就是00000010).

  从而我们知道, 对于带有SYN标志的数据包, 以下的表达式的结果总是真(true):

  ( ( value of octet 13 ) AND ( 2 ) ) ( 2 ) (nt: value of octet 13, 即13号字节的值)

  灵感随之而来, 我们于是得到了如下的tcpdump 的过滤表达式

  tcpdump -i xl0 'tcp[13] & 2 2'

  注意, 单引号或反斜杆(nt: 这里用的是单引号)不能省略, 这可以防止shell对&的解释或替换.

892697