2012-10-25 28 views
5

我想在內核空間中回顯一個數據包。我使用端口6000在這臺機器上運行一個回顯服務器。 現在客戶端在另一臺機器上運行,將數據發送到回顯服務器。現在,我想要做的是從內核空間回顯數據包。我不想用數據包來困擾服務器,它會從內核空間靜靜地迴應。我在下面提供我的代碼:如何使用netfilter掛鉤在內核空間中回顯數據包?

#include <linux/kernel.h> 
#include <linux/module.h> 
#include <linux/skbuff.h> 
#include <linux/netfilter.h> 
#include <linux/netdevice.h> 
#include <linux/ip.h> 
#include <linux/udp.h> 
#include <linux/mm.h> 
#include <linux/err.h> 
#include <linux/crypto.h> 
#include <linux/init.h> 
#include <linux/crypto.h> 
#include <linux/scatterlist.h> 
#include <net/ip.h> 
#include <net/udp.h> 
#include <net/route.h> 
#include <net/checksum.h> 
#include <linux/netfilter_ipv4.h> 

#define IP_HDR_LEN 20 
#define UDP_HDR_LEN 8 
#define TOT_HDR_LEN 28 

static unsigned int pkt_echo_begin(unsigned int hooknum, 
         struct sk_buff *skb, 
         const struct net_device *in, 
         const struct net_device *out, 
         int (*okfn)(struct sk_buff *)); 

static struct nf_hook_ops pkt_echo_ops __read_mostly = { 
    .pf = NFPROTO_IPV4, 
    .priority = 1, 
    .hooknum = NF_INET_PRE_ROUTING, 
    .hook = pkt_echo_begin, 
}; 

static int __init pkt_echo_init(void) 
{ 
    printk(KERN_ALERT "\npkt_echo module started ..."); 
    return nf_register_hook(&pkt_echo_ops); 
} 

static void __exit pkt_echo_exit(void) 
{ 
    nf_unregister_hook(&pkt_echo_ops); 
    printk(KERN_ALERT "pkt_echo module stopped ..."); 
} 

static unsigned int pkt_echo_begin (unsigned int hooknum, 
         struct sk_buff *skb, 
         const struct net_device *in, 
         const struct net_device *out, 
         int (*okfn)(struct sk_buff *)) 
{ 
    struct iphdr *iph; 
    struct udphdr *udph; 
    unsigned char *data; 

    unsigned char *temp; 

    __u16 dst_port, src_port; 
    int data_len; 



    if (skb) { 
     iph = (struct iphdr *) skb_header_pointer (skb, 0, 0, NULL); 

     if (iph && iph->protocol &&(iph->protocol == IPPROTO_UDP)) { 
      udph = (struct udphdr *) skb_header_pointer (skb, IP_HDR_LEN, 0, NULL); 
      src_port = ntohs (udph->source); 
      dst_port = ntohs (udph->dest); 

      if (dst_port == 6000) { 
       printk(KERN_ALERT "\nUDP packet goes in"); 

       data = (unsigned char *) skb_header_pointer (skb, TOT_HDR_LEN, 0, NULL); 
       data_len = skb->len - TOT_HDR_LEN; 

       struct sk_buff *newskb; 
       struct iphdr *newiph; 
       struct udphdr *newudph; 
       unsigned char *newdata; 
       unsigned int newdata_len; 

       newskb = skb_copy(skb, GFP_ATOMIC); 
       newiph = (struct iphdr *) skb_header_pointer (newskb, 0, 0, NULL); 
       newudph = (struct udphdr *) skb_header_pointer (newskb, IP_HDR_LEN, 0, NULL); 
       newdata = (unsigned char *) skb_header_pointer (newskb, TOT_HDR_LEN, 0, NULL); 

       newiph->saddr = iph->daddr; 
       newiph->daddr = iph->saddr; 

       newudph->source = udph->dest; 
       newudph->dest = udph->source; 

       struct sk_buff *tempskb; 

       tempskb = skb_copy(skb, GFP_ATOMIC); 

       *tempskb = *skb; 
       *skb = *newskb; 
       *newskb = *tempskb; 

       kfree_skb(newskb); 

      } 
     } 
    } 
    return NF_ACCEPT; 
} 


module_init(pkt_echo_init); 
module_exit(pkt_echo_exit); 

MODULE_AUTHOR("Rifat Rahman Ovi: <[email protected]>"); 
MODULE_DESCRIPTION("Echoing a packet from kernel space."); 
MODULE_LICENSE("GPL"); 

現在我不明白需要什麼。我在PRE_ROUTING鉤子中捕獲了數據包。 然後我創建了一個新的skb,從舊接收的skb中填充它,然後更改源地址(saddr),目標地址(daddr),源端口(源)和目標端口(dest),以便數據包可以從PRE_ROUTING鉤子轉發。由於路由 的決定是在數據包從鉤子傳遞之後做出的,我尋找要轉發到它的源的數據包。但由於某種原因,它不是這樣做的。數據包被接收,並且所有內容都被更改,但數據包似乎沒有向後移動。我不明白缺失的是什麼,還有什麼需要讓它工作。更具體地說,從PRE_ROUTING鉤子發送數據包到網絡需要什麼?

+2

你卡在哪裏?什麼不起作用? **你的問題是什麼?**(「任何人都可以幫助我嗎?」不是一個可以接受的問題) –

+1

感謝提示:「任何人都可以幫助我嗎?」不是一個可以接受的問題「......我永遠不會發布像這樣的任何東西..不久我會編輯該問題是具體的。放置代碼並尋求幫助實際上是無稽之談。 –

+0

在內核空間中做這件事的原因是什麼?或只是學習? – Fingolfin

回答

5

很多遺漏。

首先,您使用的netfilter鉤子是PRE-ROUTING,它捕獲INCOMING數據包,所以除非使用某些內核函數傳輸您創建的數據包,否則返回NF_ACCEPT將只讓您更改的數據包(或沒有)繼續前進(這是本地系統,而不是它)。
閱讀功能dev_queue_xmit(struct sk_buff *),但請注意,在使用此功能之前,您的SKB必須具有鏈路層報頭,因爲此功能實際上將您的數據包排隊在隊列中以立即發送到NIC,並且您的任務是設置鏈路層地址。其次,請記住,在更改IP標頭地址後,您必須重新計算數據包的校驗和,否則您的數據包將在另一端丟棄。

第三,請注意,在內核空間中做你想做的事情在很大程度上被認爲是一個非常糟糕的做法。 內核模塊的存在是有原因的,這不是其中之一,netfilter是一個很棒的工具,但它並不真正用於發送正常流量。

編輯:

讀你的最新評論;我建議你閱讀關於libPCap庫,它應該很好地爲你服務,並保持你的工作在正確的地方,用戶空間。

+0

「第三,請注意,在內核空間中嘗試去做的事情在很大程度上被認爲是一個非常糟糕的做法,內核模塊的存在是出於某種原因,這不是其中之一,netfilter是一個很棒的工具,但它並不真正用於發送正常的流量。這只是一個實驗。我看到從xtables-addons包helper模塊的xt_ECHO.c中回傳數據包,並試圖從頭開始實現它,因爲它們使用的函數不是Linux內核中存在的函數(在某種程度上與我不同)。所以我試圖用內核中存在的函數來做到這一點。 –

+0

哦,那太好了。 我只是提到這個,因爲我在一個嚴肅的項目中以類似的方式使用了網絡過濾器,它仍然讓我頭痛。 – Fingolfin

+0

實際上,回聲數據包不屬於我的項目。在我的項目中,我需要填充一個數據包,對數據包進行加密 - 解密,合併 - 拆分數據包,等等。爲了進行實驗,我試着迴應實驗。這裏是我的問題的鏈接:http://stackoverflow.com/questions/12529497/how-to-append-data-on-a-packet-from-kernel-space?rq=1和http:// stackoverflow。 COM /問題/ 12999548 /如何對路線最分裂 - 包 - 使用 - 網絡過濾器鉤 - 在內核空間。是的,這在處理內核空間中的非標準內容時非常噁心.. –

1

除了前面的答案,可以被用於從網絡過濾回調回聲一個UDP包的另一種技術是:

發送分組背部,作爲一個新的UDP包,使用:

int sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)

/socket.c中

或也使用netpoll庫,在回答here說。

原始數據包可以使用NF_DROP丟棄。

在netfilter回調中,在「中斷上下文」中運行可能發送數據包,但不可能接收它們(因爲每次嘗試等待都會導致內核崩潰)。 由於這個原因,我提出的解決方案適用於UDP,但不能與TCP協同工作(TCP握手要求必須收到ACK消息)。

無論如何,正如已經說過的,在內核空間中做這種事情是壞事,應該只用於學習目的。

相關問題