我创建了一个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
一切都好。
如何生成正确的过滤器代码?
答案 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数据包,即以太网有效负载,这意味着:
我还没有测试过,但你可以试试这样的东西。由于您似乎使用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端口号检查的说明。我调整了偏移量和跳转指令的参考。其余说明没有变化。但我还没有测试过,所以不能保证。