解构BPF过滤器的tcpdump

问题描述:

试图解构tcpdump的BPF风格的过滤器,并需要一些帮助:解构BPF过滤器的tcpdump

'tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x47455420' 

其从已经采取了更好地了解here

所采取的步骤是怎么回事:

1. Lets convert the 0x47455420 to ascii 
    ===> GET 
    ===> tcp[((tcp[12:1] & 0xf0) >> 2):4] = GET 
2. Examine the inner tcp filter: (tcp[12:1] & 0xf0) 
    ===> the 0xf0 == 0000 0000 1111 0000 ===> I suppose it is save to discard the upper zeros so I can write 1111 0000 
    ===> tcp[12:1] == 08 (start filtering from byte 13 (0 based indexing, so you could also say start with the byte that has index 12) for 1 byte, so only 13th byte); 
    ===> 08 == 0000 1000 
    ===> 0000 1000 & 1111 0000 == 0000 (bitwise and = if both are 1 then end result is one) 

这是我困惑的地方。在我上面提供的超链接的解释是说

multiply it by four ((tcp[12:1] & 0xf0)>>2) which should give the tcp header length

不可能的,如果它是零。请:

  1. 帮我找到我的计算错误(也许我混合TCP和IP标头?
  2. 为我的逻辑是否正确提供了一些指导。

这是分组:

19:10:30.091065 IP (tos 0x0, ttl 63, id 40127, offset 0, flags [DF], proto TCP (6), length 2786) 
10.240.35.81.47856 > 172.17.13.201.8080: Flags [P.], cksum 0xf2ef (incorrect -> 0xb8f8), seq 2263020471:2263023205, ack 4187927811, win 28, options [nop,nop,TS val 1906863883 ecr 214445688], length 2734 
0x0000: 1a17 8e8a a3a0 026d 627d 049c 0800 4500 .......mb}....E. 
     0,1 2,3 ... ... ... ... 12,13 ...     <=== byte indexes 
     1,2 3,4 ... ... ... ... 13,14 ...     <=== counting how many bytes 
0x0010: 0ae2 9cbf 4000 3f06 ac3b 0af0 2351 ac11 [email protected]?..;..#Q.. <=== 0x0010 number correctly identifies that the first two diggits are the 16th byte 
     16,17 ... ... 
0x0020: 0dc9 baf0 1f90 86e2 f3b7 f99e b503 8018 ................ 
0x0030: 001c f2ef 0000 0101 080a 71a8 6f0b 0cc8 ..........q.o... 
0x0040: 2e78 4745 5420 2f69 636f 6e73 2f75 6e6b .xGET./icons/unk 
0x0050: 6e6f 776e 2e67 6966 2048 5454 502f 312e nown.gif.HTTP/1. 
0x0060: 310d 0a68 6f73 743a 2070 6870 2d6d 696e 1..host:.php-min 

tcp[12:1]处于从TCP报头的开头的12个字节偏移字节; 12是而不是从数据包开始的偏移量,它是从TCP报头(它是tcp[12:1],而不是ether[12:1]或诸如此类的东西)开始的偏移量。 “1”是被引用的字节数。

根据RFC 793这是TCP的规范,从the TCP header开始的偏移量为12字节的字节包含高4位的数据偏移量,低4位为保留位。数据偏移量是“TCP报头中32位字的数量”,其中“指示数据从何处开始”。

数据包中的数据显示为一个字节对序列。如果以单个字节序列的形式呈现,则会更容易理解,因此:

0x0000: 1a 17 8e 8a a3 a0 02 6d 62 7d 04 9c 08 00 45 00 
     eth dest   eth src   etype IP hdr 

数据包的前6个字节是以太网目标地址。

数据包的下6个字节是以太网源地址。

之后的2个字节是以太网类型值;它是big-endian,所以它的值是0x0800,它是IPv4的以太网类型值。

接下来的2个字节是IPv4标头的前2个字节。根据作为IPv4规范的RFC 791the IPv4 header的第一个字节包含IP版本的高4位和低4位的报头长度。该字节的值为0x45,因此IP版本为4(因为它应该是IPv4)并且标头长度为5.标头长度“是32位字中互联网标头的长度”,所以这是5 32位字或20个字节。

所以,现在,让我们跳过IPv4报头,并转到TCP报头:

0x0020: 0d c9 ba f0 1f 90 86 e2 f3 b7 f9 9e b5 03 80 18 
       TCP header       12 13 

所以TCP报头的12个字节是0x80的。 0x80 & 0xf0是0x80,并且0x80 >> 2是0x20,它是32;这与该字节的高4位是数据偏移是一致的,32位字为8 * 4 = 32。

tcp[((tcp[12:1] & 0xf0) >> 2):4]因此,对于这个分组,tcp[32:4],即在偏移处的4个字节从TCP头部开始的32。从TCP报头的开头

32个字节是:

0x0040: 2e78 4745 5420 2f69 636f 6e73 2f75 6e6b 
      ^

那里,而这在HTTP请求的“GET”报头,在TCP数据段的开头开始。所讨论的4个字节是“GET”。

所以在tcp[12:1]的12 的从分组的开始偏移,这是从TCP报头(这是tcp[12:1],不ether[12:1]或为一些诸如)开始偏移。

而且,在回答中数据包的字节,它们是什么问题:

0x0000: 1a 17 8e 8a a3 a0: Ethernet destination 
     02 6d 62 7d 04 9c: Ethernet source 
     08 00: Ethernet type/length field - 0x0800 = IPv4 

所以第14(0x000e)数据包的字节是以太网报头。

在该分组,以太网类型/长度字段为0x0800,所以以太网有效载荷,所述以太网报头以下,是IPv4分组,具有一个IPv4标头开始:

  45: IPv4 version/header length 
     00: IPv4 Type of Service/Differentiated Service 
0x0010: 0a e2: IPv4 total length 
     9c bf: IPv4 identification 
     40 00: IPv4 flags/fragment offset 
     3f: IPv4 time-to-live 
     06: IPv4 (next) protocol - 6 = TCP 
     ac 3b: IPv4 header checksum 
     0a f0 23 51: IPv4 source address 
     ac 11: first 2 bytes of IPv4 destination address 
0x0020: 0d c9: second 2 bytes of IPv4 destination address 

IPv4标头长度是5,所以IPv4标头是20个字节。这是最小的IPv4标头长度;它不能更小,但如果在头部的固定长度部分之后有IPv4选项,则它可以更大。在这种情况下没有任何东西。

由于协议字段具有值6,IPv4的有效载荷是一个TCP包:

  ba f0: TCP source port (47856) 
     1f 90: TCP destination port (8080) 
     86 e2 f3 b7: TCP sequence number 
     f9 9e b5 03: TCP acknowledgment number 
     80: TCP data offset + reserved bits 
     18: reserved bits + TCP flags 
0x0030: 00 1c: TCP window 
     f2 ef: TCP checksum 
     00 00: TCP urgent pointer 

这就是TCP报头的20字节固定长度的部分;然而,TCP报头长度是32个字节,所以有一个额外的12个字节的TCP选项在标题:

  01: TCP No-Operation option 
     01: TCP No-Operation option 
     08 0a 71 a8 6f 0b 0c c8: first 8 bytes of TCP Timestamp option 
0x0040: 2e 78: last 2 bytes of TCP Timestamp option 

甲TCP报头的长度必须是32位的倍数,即4个字节的倍数; TCP选项的长度可能不是4的倍数 - TCP时间戳选项的长度为10个字节 - 因此无操作选项用于填充。

那么这32个字节就是TCP头;接下来是TCP有效载荷。显然,这是一个HTTP连接上(该分组被发送到端口8080,这是一个备用HTTP端口),并且这是HTTP GET请求的开始:

  47 45 54 20 2f 69 63 6f 6e 73 2f 75 6e 6b 
0x0050: 6e 6f 77 6e 2e 67 69 66 20 48 54 54 50 2f 31 2e 
0x0060: 31 0d 0a 68 6f 73 74 3a 20 70 68 70 2d 6d 69 6e 

所以:

  • 因为这是在以太网或Wi-Fi网络(不处于监控模式)时捕获的(或者在某些其他类型的使用以太网接头的网络上,或者适配器或驱动程序提供“假以太网”与Wi-Fi),数据包将以以太网报头开始;
  • 由于以太网类型值为0x0800,所以后面跟着一个IPv4标头;
  • 由于IPv4协议值是6,所以后面跟着一个TCP报头;
  • 作为TCP端口号之一是通常由HTTP(8080)使用的端口号,它的可能是后面是某种类型的HTTP数据(但不保证,但是 - TCP端口号更像是提示) 。

对于ARP在同一个网络,你会再有一个以太网的头部(ffff ffff是以太网广播地址,所以该数据包是正在播出,如ARP请求通常是),使用以太网类型0x0806 ,这是ARP的以太网类型值。

对于通过同一网络的ICMP,您将再次拥有以太网标头,并且您还将拥有IPv4标头,因此以太网类型将为0x0800。对于ICMP,IPv4标头中协议字段的值将为1。

+0

非常感谢。我认为我缺少的是对“数据偏移”的正确理解。在接受答案之前,请让我问你:(1)什么是数据包结构 - 第一个0x0010字节是以太网协议头? (2)然后IP协议头? (3)你怎么知道这一点(某些情况下需要如何理解期望的数据包类型)。让我们与ARP tcpdump(ffff ffff ffff 0026 ...)或ICMP(0800 27b9 caba 0026 ...)相比较。我怎么知道什么数字代表什么时候? – 2015-02-08 19:50:09