2015-07-12 129 views
4

我使用libnetfilter_queueiptables以及NFQUEUE目標將傳入數據包存儲在三個不同隊列中,其中--queue-num x用NFQUEUE發送排隊的數據包?

我成功地創建了三個隊列與libnetfilter_queue功能,綁定他們,聽取他們的意見,並從他們的內容如下:

/* given 'h' as a handler of one of my three queues */ 
fd = nfq_fd(h); 
while ((rv = recv(fd, buf, sizeof(buf), 0)) && rv >= 0) { 
    nfq_handle_packet(h, buf, rv); 
} 

回調函數,觸發與nfq_handle_packet,有nfq_set_verdict(qh, id, NF_ACCEPT, 0, NULL);命令,其中它發送數據包儘快處理完畢。 問題是:我不要希望每個數據包立即發送,因爲我需要將它們存儲在自定義結構(下面寫)。

所以我遇到了一個潛在的解決方案:我可能會調用NF_DROP判決而不是NF_ACCEPT我想排隊的每個數據包(所以它不會立即發送),將其存儲在我的自定義結構中,然後(更快或後來)根據我的需要重新注入它。

聽起來不錯,但情況是:我不知道如何從我的用戶空間應用程序我的樂趣重新注入排隊的數據包。在我的代碼的同一點再次使用nfq_set_verdict是正確的,但用NF_ACCEPT判定?或者我應該打開一個插座(也許是一個原始的)?

這是我的自定義結構

struct List { 
    int queue; 
    int pktsize; 
    unsigned char *buffer; 
    struct nfq_q_handle *qh; 
    struct nfqnl_msg_packet_hdr *hdr; 
    struct List *next; 
}; 

代表抓住上面的規則的數據包。

這些是我的隊列在哪裏存儲數據包。

struct List *List0 = NULL; // low priority 
struct List *List1 = NULL; // medium priority 
struct List *List2 = NULL; // high priority 

我有Ubuntu 14.04 3.13.0-57-generic

任何建議,將不勝感激。

+0

我想你只需要簡單地推遲這些數據包的'nfq_set_verdict()'調用,直到你準備好將它們推回堆棧爲止。整個問題是他們在內核中排隊。 AFAIK,你不必立即調用'nfq_set_verdict()'來獲取數據包。您可以將數據包或ID保存在列表中,稍後再調用。 –

回答

3

你的想法很有道理。事實上,我看到一個非常類似的方案在我所從事的商業產品中實施。它必須以高速率處理單獨的數據包,因此它總是會複製傳入的數據包,並立即設置一個NF_DROP判決。然後它會執行處理,如果它決定應該轉發數據包,它會將副本發送到出站接口。所以你並不孤單。

據我所知,nfq_set_verdict每個包只能調用一次。一旦判決被設置,NFQUEUE將數據包發送到目的地(在你的情況下是包天堂)。它不保留額外的數據包副本,以防萬一您改變主意。因此,要將數據包發送回網絡,您必須存儲它的副本並使用您自己的套接字發送它。是的,如果你想發送接收到的數據包(包括頭文件),出站套接字必須是raw

+0

很多工作要做,我會開始閱讀'原始'插座。 我不知道每個數據包只能調用一次'nfq_set_verdict',因爲我用'NF_DROP'來使用它,所以我需要使用別的東西來重新注入數據包。 非常感謝。 – elmazzun

1

我不知道這是否適合您的應用程序模型,但Frottle只是將數據包保存在緩存中,直到決定是否接受它們或丟棄它們。這種方法的「新穎性」依賴於您在NFQUEUE回調函數本身期間不需要調用nfq_set_verdict;你可以稍後和netfilter循環之外調用它。它會使用更多的內核內存,但替代方案只是使用更多的用戶模式內存,因此它不會有太大的損失。

希望這會有所幫助!