将过滤器附加到linux中的tcp套接字

时间:2016-11-30 09:33:07

标签: linux sockets

我创建了一个tcp套接字:

sockfd = socket(AF_INET, SOCK_STREAM, 0);

并附上过滤器

setsockopt(sockfd, SOL_SOCKET, SO_ATTACH_FILTER, &Filter, sizeof(Filter))

我使用tcpdump生成过滤器,如下所示:

sudo tcpdump tcp -d  port 9000
(000) ldh      [12]
(001) jeq      #0x86dd          jt 2    jf 8
(002) ldb      [20]
(003) jeq      #0x6             jt 4    jf 19
(004) ldh      [54]
(005) jeq      #0x2328          jt 18   jf 6
(006) ldh      [56]
(007) jeq      #0x2328          jt 18   jf 19
(008) jeq      #0x800           jt 9    jf 19
(009) ldb      [23]
(010) jeq      #0x6             jt 11   jf 19
(011) ldh      [20]
(012) jset     #0x1fff          jt 19   jf 13
(013) ldxb     4*([14]&0xf)
(014) ldh      [x + 14]
(015) jeq      #0x2328          jt 18   jf 16
(016) ldh      [x + 16]
(017) jeq      #0x2328          jt 18   jf 19
(018) ret      #65535
(019) ret      #0

如果我附加此过滤器,程序将无法向端口9000发送任何内容。 但如果我只留下一条指令:

(018) ret      #65535
一切都好。 如何生成正确的过滤器代码?

1 个答案:

答案 0 :(得分:1)

我认为问题与for this question相同。

Tcpdump在以太网帧上工作,从第一个以太网头字节开始。所以使用这些BPF指令:

(000) ldh      [12]                            // Look at ethertype
(001) jeq      #0x86dd          jt 2    jf 8   // If IPv6 jump to (002), else to (008)

[…]
(008) jeq      #0x800           jt 9    jf 19  // If IPv4 jump to (009), else to (019)

... tcpdump检查数据包是否为IP(4或6)。

在原始套接字上,您不能完全相同,因为您处理IP数据包,即以太网有效负载,这意味着:

  • 看看ethertype是没有意义的,它是无法到达的。
  • 到达要在数据包中检查的字段的偏移量是不同的(低14个字节 - 以太网标头的大小)。

我还没有测试过,但你可以试试这样的东西。由于您似乎使用IPv4和TCP,我删除了IPv6部分的指令并检查数据包是否为TCP(如果套接字收到它,我们已经知道它是)。这意味着删除前十一条指令。

(000) ldh      [6]                              // Load fragment offset field
(001) jset     #0x1fff          jt 8   jf 2     // Jump to end if packet is a fragment
(002) ldxb     4*([0]&0xf)                      // Add size of IP header (inc. options) to X
                                                // Now X points to the beginning of TCP hdr
(003) ldh      [x + 0]                          // Load src port field
(004) jeq      #0x2328          jt 7   jf 5     // Is it equal to 9000?
(005) ldh      [x + 2]                          // Else jump to dst port field
(006) jeq      #0x2328          jt 7   jf 8     // Is it equal to 9000?
(007) ret      #65535                           // (If port 9000) return 0x65535
(008) ret      #0                               // Return 0

所以我只保留了片段偏移检查和dst端口号检查的说明。我调整了偏移量和跳转指令的参考。其余说明没有变化。但我还没有测试过,所以不能保证。