2016-11-30 79 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