2016-11-30 33 views
0

我创建TCP套接字:连接过滤器,TCP套接字在Linux

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发送任何东西。 但是如果我只留下一个instr使用:

(018) ret  #65535 

一切都OK。 如何生成正确的过滤器代码?

回答

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数据包的工作,即以太网净荷,这意味着:

  • 望着以太是没有意义的,它是不可达。
  • 到达要在包中检查的字段的偏移量是不同的(低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端口号检查的说明。我调整了偏移量和跳转指令的参考。其余指示未变。但我还没有测试过,所以没有保证。

+0

作为一个事后考虑,我想知道你是否可以通过'SOCK_STREAM'套接字访问IP标头?我的程序可能只在原始套接字上有效(我引用的问题使用套接字(PF_INET,SOCK_RAW,IPPROTO_TCP);'如果是这样,只保留最后六条指令并尝试加载字段而不使用'X'寄存器。 – Qeole

+0

谢谢,我测试它的工作原理。我将尝试访问IP头与SOCK_STREAM使用Linux bpf扩展。 – flypig