7

我正在爲linux編寫以太網驅動程序。我想接收數據包,編輯並重新發送它們。 我知道如何編輯packet_interceptor函數中的數據包,但是如何在此函數中丟棄傳入數據包?如何使用net_dev_add()API過濾和截獲Linux數據包?

#include <linux/netdevice.h> 
#include <linux/skbuff.h> 
#include <linux/ip.h> 
#include <net/sock.h> 

struct packet_type my_proto; 

int packet_interceptor(struct sk_buff *skb, 
    struct net_device *dev, 
    struct packet_type *pt, 
    struct net_device *orig_dev) { 

    // I dont want certain packets go to upper in net_devices for further processing. 
    // How can I drop sk_buff here?! 

    return 0; 
} 

static int hello_init(void) { 
    printk(KERN_INFO "Hello, world!\n"); 

    my_proto.type = htons(ETH_P_ALL); 
    my_proto.dev = NULL; 
    my_proto.func = packet_interceptor; 

    dev_add_pack(&my_proto); 
    return 0; 
}  

static void hello_exit(void) { 
    dev_remove_pack(&my_proto); 
    printk(KERN_INFO "Bye, world\n"); 
} 

module_init(hello_init); 
module_exit(hello_exit); 
+0

您是否使用我的解決方案進行了測試? – Atle

+0

嗨@Atle,這幾天我的電腦有問題。感謝您的迴應,我會盡快啓動PC:D。但我記得貝弗我問你,我測試了這個解決方案,但它沒有奏效。我會再次托盤。 –

回答

6

你正在讓你的模塊處理所有的以太網數據包。 Linux將發送數據包給所有匹配的協議處理程序。由於IP已經在您的內核中註冊,您的模塊和ip_rcv都將接收所有帶有IP頭的SKB。

如果不更改內核代碼,則無法更改此行爲。一種可能性是改爲創建一個netfilter模塊。這樣,您可以在ip_rcv函數之後截獲數據包,如果您想(在Netfilters PREROUTING鉤子中)放棄它。

這是一個小的Netfilter模塊,我從我已經寫過的代碼中提取出來。這個模塊是未完成的,但主要的東西已經到位。

#include <linux/netfilter.h> 
#include <linux/netfilter_ipv4.h> 

// Handler function 
static unsigned int my_handler (
    unsigned int hook, 
    struct sk_buff *skb, 
    const struct net_device *in, 
    const struct net_device *out, 
    int (*okfn)(struct sk_buff *)) 
{ 
    return NF_ACCEPT; 
// or 
    return NF_DROP; 
} 

// Handler registering struct 
static struct nf_hook_ops my_hook __read_mostly = { 
    .hook = my_handler, 
    .pf = NFPROTO_IPV4, 
    .hooknum = (1 << NF_INET_PRE_ROUTING), 
    .priority = NF_IP_PRI_FIRST // My hook will be run before any other netfilter hook 
}; 

int my_init() { 
    int err = nf_register_hook (&my_hook); 
    if (err) { 
      printk (KERN_ERR "Could not register hook\n"); 
    } 
    return err; 
} 
+0

我測試過netfilter,它工作得很好,但是我需要用'dev_add_pack()'掛鉤放下。我的問題是,如果系統有兩個處理程序(ip_rcv,my_packet_interceptor),當我在我的處理程序中更改skb時,它們中的哪些有效? (假設我已經改變了my_packet_interceptor中的skb,所以我有兩個skb,'original'和'changed',哪一個進一步處理?) –

+1

處理程序在彼此之後運行。我猜測IP是先運行的,因爲它可能是在你的模塊之前註冊的。我不認爲SKB在這個階段被複制,所以在你改變它之前,IP可能會被完成。 – Atle

+0

因此,如果處理程序在彼此之後運行,爲什麼我不能丟棄數據包? –

6

我通過內核去網絡代碼(有一年的時間我沒有內部有什麼),我認爲你應該做能夠做到不泄露任何東西:

kfree_skb(skb); 
return NET_RX_DROP; 

編輯

這是在其他協議處理程序,如ip_rcvarp_rcv(最後一個返回0而不是NET_RX_DROP,但我不認爲返回值很重要)完成。如果你刪除skb,請記得不要打電話給任何其他處理程序。

看在ip.c ip_rcv代碼(在底部):http://lxr.free-electrons.com/source/net/ipv4/ip_input.c#L375

如果一切順利,它通過SKB來Netfilter的,然後調用ip_rcv_finish(如果它不下降的話)。如果出現問題,它會釋放skb並返回。

編輯

如果超過一個協議處理器的SKB匹配,內核將其發送給所有的人。當您在其中一個模塊中使用kfree_skb()時,SKB仍將繼續存在於其他處理程序中。

+0

今天我測試了一下,但沒有奏效。它有什麼問題? –

+0

你的意思是「沒有工作」是什麼意思?系統接收到數據包而不是droppen嗎?數據包甚至進入你的模塊? – Atle

+1

我收到'packet_interceptor'處理程序中的所有數據包,但系統收到所有數據包。 http://paste.ubuntu.com/6324987/ –