2012-09-21 7 views
5

私は、カーネル空間のパケットにいくつかのデータを追加しようとしています。私はエコークライアントとサーバーを持っています。コマンドラインに./client "message"と入力すると、サーバはただそれを返信します。サーバーは./serverで実行されました。カーネル空間からパケットにデータを追加するには?

ここで、クライアントとサーバーは2つの異なるマシンにあります(VMである可能性があります)。私は、クライアントマシン上で動作するカーネルモジュールを作成しています。その作業はパケットがマシンから出て行く間に "メッセージ"の後に "12345"を付加することです。私は以下のコードを提示しています。

/* 
* This is ibss_obsf_cat.c 
*/ 

#include <linux/module.h> 
#include <linux/moduleparam.h> 
#include <linux/kernel.h> 
#include <linux/netfilter.h> 
#include <linux/skbuff.h> 
#include <linux/netdevice.h> 
#include <linux/udp.h> 
#include <linux/ip.h> 

#undef __KERNEL__ 
#include <linux/netfilter_ipv4.h> 
#define __KERNEL__ 


/* 
* Function prototypes ... 
*/ 

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

static void hex_dump (char str[], int len) 
{ 

} 

/* 
* struct nf_hook_ops instance initialization 
*/ 

static struct nf_hook_ops cat_obsf_ops __read_mostly = { 
    .pf = NFPROTO_IPV4, 
    .priority = 1, 
    .hooknum = NF_IP_POST_ROUTING, 
    .hook = cat_obsf_begin, 
}; 

/* 
* Module init and exit functions. 
* No need to worry about that. 
*/ 

static int __init cat_obsf_init (void) 
{ 
    printk(KERN_ALERT "cat_obsf module started...\n"); 
    return nf_register_hook(&cat_obsf_ops); 
} 

static void __exit cat_obsf_exit (void) 
{ 
    nf_unregister_hook(&cat_obsf_ops); 
    printk(KERN_ALERT "cat_obsf module stopped...\n"); 
} 

/* 
* Modification of the code begins here. 
* Here are all the functions and other things. 
*/ 

static unsigned int cat_obsf_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 dt[] = "12345"; 
    unsigned char *tmp; 
    unsigned char *ptr; 

    int i, j, len; 

    if (skb){ 
     iph = ip_hdr(skb); 

     if (iph && iph->protocol && (iph->protocol == IPPROTO_UDP)){ 
      udph = (struct udphdr *) ((__u32 *)iph + iph->ihl); 
      data = (char *)udph + 8; 

      if(ntohs(udph->dest) == 6000){ 
       for (i=0; data[i]; i++); 
       len = i; 

       //printk(KERN_ALERT "\nData length without skb: %d", len); 
       //printk(KERN_ALERT "Data is: %s", data); 
       //printk(KERN_ALERT "dt size: %lu", sizeof(dt)); 
       //printk(KERN_ALERT "skb->len: %d", skb->len); 
       tmp = kmalloc(200*sizeof(char), GFP_KERNEL); 

       memcpy(tmp, data, len); 
       ptr = tmp + len; 
       memcpy(ptr, dt, sizeof(dt)); 

       printk(KERN_ALERT "tmp: %s", tmp); 


       printk(KERN_ALERT "skb->tail: %d", skb->tail); 
       //skb_put(skb, sizeof(dt)); 
       printk(KERN_ALERT "skb->end: %d", skb->end); 
       printk(KERN_ALERT "skb->tail: %d", skb->tail); 
       printk(KERN_ALERT "skb->tail(int): %d", (unsigned int)skb->tail); 

       //memset(data, 0, len + sizeof(dt)); 

       //memcpy(data, tmp, len + sizeof(dt)); 

       //skb_add_data(skb, tmp, len+sizeof(dt)); 

       printk(KERN_ALERT "Now data is: %s", data); 
       for(i=0; data[i]; i++); 
       printk(KERN_ALERT "data length: %d", i); 

       kfree(tmp); 

      }  
     } 
    } 
    return NF_ACCEPT; 
} 

/* 
* Nothing to be touched hereafter 
*/ 

module_init(cat_obsf_init); 
module_exit(cat_obsf_exit); 

MODULE_AUTHOR("Rifat"); 
MODULE_DESCRIPTION("Module for packet mangling"); 
MODULE_LICENSE("GPL"); 

カーネルスペースからクライアントマシンを送信しているときに、「メッセージ」を「メッセージ12345」にしたいと考えています。サーバーが "message12345"を取得してそれをエコーバックすると、クライアントは単に "message12345"と読むでしょうが、skb_put()とskb_add_data()関数に問題があります。私は何が間違っているのか分かりません。コードを手伝ってくれる人があれば、とても感謝しています。前もって感謝します。私は便宜のためにMakefileも与えています。これはビルドカーネル用であり、ビルドカーネル用ではありません。 skb->テール 私はカーネル空間で新しいパケットを作成する必要がありますほど小さい -

#If KERNELRELEASE is defined, we've been invoked from the 
#kernel build system and use its language 
ifneq ($(KERNELRELEASE),) 
    obj-m := ibss_obsf_cat.o 

#Otherwise we were called directly from the command 
#line; invoke the kernel build system. 
else 

    KERNELDIR ?= /lib/modules/$(shell uname -r)/build 
    PWD := $(shell pwd) 

default: 
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules 

endif 

今私は skb->終わりがあることはかなり確信しています。私は使用しました alloc_skb() skb_reserve() skb_header_pointer() と新しいskbを作成するための他の有用なskb関数ですが、アイデアが不足しているということは、新しく作成されたパケットをパケットフローパス。使用方法
ip_route_me_harder() 私はxtables-addonsパッケージで提案を探しましたが、使用した機能はlinux kernelとは異なります。どんな提案も歓迎されます。

答えて

3

1年ほど前、カーネル2.6.26のために私はこのようにそれをやった:

// Do we need extra space? 
if(len - skb_tailroom(skb) > 0){ 

    // Expand skb tail until we have enough room for the extra data 
    if (pskb_expand_head(skb, 0, extra_data_len - skb_tailroom(skb), GFP_ATOMIC)) { 
    // allocation failed. Do whatever you need to do 
    } 

    // Allocation succeeded 

    // Reserve space in skb and return the starting point 
    your_favourite_structure* ptr = (your_favourite_structure*) 
            skb_push(skb, sizeof(*ptr)); 

    // Now either set each field of your structure or memcpy into it. 
    // Remember you can use a char* 

} 

を忘れないでください:

  • 再計算UDPチェックサム、あなたが転送されたデータ内のデータを変更されたため、 。

  • パケットにデータを追加したため、ipヘッダーのフィールドtot_len(全長)を変更します。

  • tot_lenフィールドを変更したため、IPヘッダーチェックサムを再計算します。

エクストラノート: これは単純なものです。あなたのコードでは、tmpを200バイトの配列として割り当て、メッセージのデータを格納するために使用しています。より大きいパケットを送信すると、メモリオーバーフローのためにカーネルがクラッシュするため、デバッグが難しくなります。

+0

ご協力ありがとうございます。はい、長さのフィールドは私に多くの問題を抱えていました。 –

+0

また、カーネル空間でのチェックサムは、当初私にはあまりにも漠然としていました。 –

+0

@Fredあなたもこれにコメントすることができますhttp://stackoverflow.com/questions/12529497/how-to-append-data-on-a-packet-from-kernelspace – user2087340

1

私はこの問題を解決しました。それは些細なことでした。そして、私は将来の参照と議論のために自分のコードを投稿するだけです。

#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> 

#undef __KERNEL__ 
#include <linux/netfilter_ipv4.h> 
#define __KERNEL__ 

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

static unsigned int pkt_mangle_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_mangle_ops __read_mostly = { 
    .pf = NFPROTO_IPV4, 
    .priority = 1, 
    .hooknum = NF_IP_LOCAL_OUT, 
    .hook = pkt_mangle_begin, 
}; 

static int __init pkt_mangle_init(void) 
{ 
    printk(KERN_ALERT "\npkt_mangle module started ..."); 
    return nf_register_hook(&pkt_mangle_ops); 
} 

static void __exit pkt_mangle_exit(void) 
{ 
    nf_unregister_hook(&pkt_mangle_ops); 
    printk(KERN_ALERT "pkt_mangle module stopped ..."); 
} 

static unsigned int pkt_mangle_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 int data_len; 
    unsigned char extra_data[] = "12345"; 
    unsigned char *temp; 
    unsigned int extra_data_len; 
    unsigned int tot_data_len; 

    unsigned int i; 

    __u16 dst_port, src_port; 

    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 (src_port == 6000) { 
       printk(KERN_ALERT "UDP packet goes out"); 
       data = (unsigned char *) skb_header_pointer (skb, IP_HDR_LEN+UDP_HDR_LEN, 0, NULL); 
       data_len = skb->len - TOT_HDR_LEN; 

        temp = kmalloc(512 * sizeof(char), GFP_ATOMIC); 
       memcpy(temp, data, data_len); 

       unsigned char *ptr = temp + data_len - 1; 
       extra_data_len = sizeof(extra_data); 
       memcpy(ptr, extra_data, extra_data_len); 
       tot_data_len = data_len + extra_data_len - 1; 

       skb_put(skb, extra_data_len - 1); 

       memcpy(data, temp, tot_data_len); 

       /* Manipulating necessary header fields */ 
       iph->tot_len = htons(tot_data_len + TOT_HDR_LEN); 
       udph->len = htons(tot_data_len + UDP_HDR_LEN); 

       /* Calculation of IP header checksum */ 
       iph->check = 0; 
       ip_send_check (iph); 

       /* Calculation of UDP checksum */ 
       udph->check = 0; 
       int offset = skb_transport_offset(skb); 
       int len = skb->len - offset; 
       udph->check = ~csum_tcpudp_magic((iph->saddr), (iph->daddr), len, IPPROTO_UDP, 0); 

       } 
     } 
    } 
    return NF_ACCEPT; 
} 


module_init(pkt_mangle_init); 
module_exit(pkt_mangle_exit); 

MODULE_AUTHOR("Rifat Rahman Ovi: <[email protected]>"); 
MODULE_DESCRIPTION("Outward Packet Mangling and Decryption in Kernel Space"); 
MODULE_LICENSE("GPL"); 

ここでは、長さフィールドを更新するのを忘れて、チェックサムを更新するのを忘れていました。ここでコードを正しく提示すれば、すべてうまくいくはずです。ここには含まれていない他のヘルパー関数がいくつかあります( )。

+2

私はこのコードがまったく良いとは思わない。 1)あなたは決してkfree(temp)なのでメモリリークがあります2)skb_putはバッファを展開しないので、実際にそのメモリを所有せずにskb内のUDPペイロードの終わりにバイトをつけています。問題。 –

+0

ya ...あなたは正しいです。それはこんにちは世界以外の初めてのモジュールでした。そしてそれは問題を引き起こす。したがって、パケットを増やすには、新しいバッファを割り当て、いくつかの操作を実行する必要があります。 skb_put()を使用しても、それが使用されているように損害を与えないことは保証されていません。ちなみに、パケットの中にいくつかのバイトを実際に埋め込むために書かれていましたが、最終的にカーネルのパニックが発生した後は明らかでした。しかし、私はその投稿を忘れてしまった。その点をありがとう。私はすぐにコードを調整します。 Uはモジュールの説明を参照してください。ちょうどここで述べた巨大なプロジェクトの始まりに過ぎません。ありがとう。 –

+0

こんにちは!私はこれが非常に古いスレッドであることに気づいていますが、send/receiveチェーンのどこにこのフックがあるのか​​を教えてください。 –

関連する問題