2012-09-21 25 views
5

Bir paket üzerinde bazı verileri çekirdek alanından eklemeye çalışıyorum. Bir yankı istemcim ve sunucum var. Komut satırına şu şekilde yazdım: ./client "message" ve sunucu sadece onu tekrar yansıtır. Sunucu ./server ile çalıştırıldı.Çekirdek alanından bir pakete nasıl veri eklenir?

Artık, istemci ve sunucu iki farklı makinede (VM olabilir). İstemci makinesinde çalışan bir çekirdek modülü yazıyorum. Paket, makineden çıktığında "mesaj" dan sonra "12345" ibaresini eklemektir. Aşağıdaki kodu ben sunuyorum.

/* 
* 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"); 

ben çekirdek uzaydan istemci makinesinden gönderirken "message12345" olmak "mesajı" almak istiyorum. Böylece sunucu "message12345" mesajını alıp yankılanacak ve istemci sadece "message12345" mesajını okuyacaktır. Ancak skb_put() ve skb_add_data() işlevleriyle ilgili sorun yaşıyorum. Benim için hangi hatanın yapıldığını anlamıyorum. Kimse bana kodla yardım edebilirse, son derece minnettar olacağım. Şimdiden teşekkürler. Ayrıca Makefile'ye kolaylık sağlamak için veriyorum. Bu, bir çekirdek için değil, dağıtım çekirdeği içindir. skb-> kuyruk ben çekirdek uzayda yeni paketleri oluşturmak zorunda kalacak kadar küçüktür ki -

#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 

Şimdi skb-> sonu olduğuna ikna olmuş. alloc_skb() skb_reser() skb_header_pointer() ve yeni bir skb oluşturmak için diğer kullanışlı skb işlevlerini kullandım, ancak şu an aklımda olan şey paket akış yolunda yeni oluşturulan paketin nasıl yönlendirileceğidir. . Nasıl kullanılır?
ip_route_me_harder() Öneri için xtables-addons paketine baktım, ancak kullandıkları işlev linux kernelinden farklı. Herhangi bir öneri memnuniyetle karşılanmaktadır.

cevap

3

bir Hakkında yıl önce kernel 2.6.26 için böyle yaptım:

// 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* 

} 

Unutma:

  • yeniden hesapla UDP sağlama, sen taşınan verilerin verileri değiştirdiği için . Pakete veri eklediğinizden, ip başlığına tot_len (toplam uzunluk) alanını değiştirin (0). tot_len alanını değiştirdiğinizden IP üstbilgi sağlama toplamını yeniden hesaplayın.

Ekstra not: Bu sadece basit bir şeydir. Kodunuzda, tmp'u 200 baytlık bir dizi olarak tahsis ediyor ve mesajınızın verilerini saklamak için kullanıyorsunuz. Daha büyük bir paket gönderirseniz, bellek taşmaları çok acı verici olduğundan çekirdek çöküyorsa, bunu hata ayıklamada zorlanacaksınız.

+0

Yardım için teşekkürler. Evet, uzunluk alanları beni çok rahatsız etti. –

+0

Ayrıca, çekirdek alanında kontrol toplamı benim için oldukça belirsizdi. –

+0

@Fred bunu http://stackoverflow.com/questions/12529497/how-to-append-data-on-a-packet-from-kernel-space – user2087340

1

Sorunu çözdüm. Önemsizdi. Ve tek yapacağım, gelecekteki referanslar ve tartışmalar için kodumu yayınlamak.

#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"); 

Burada, uzunluk alanlarını güncellemeyi unuttum ve sağlama toplamını güncellemeyi unuttum. Şimdi, kodu doğru bir şekilde burada sunursam, herkes iyi gitmeli.Burada yer almayan bazı diğer yardımcı işlevler vardır.

+2

Bu kodun hiç iyi olmadığını düşünüyorum. 1) hiçbir zaman kfree (temp) böylece bir bellek sızıntısı var 2) skb_put arabellek genişletmez, bu yüzden aslında bu belleğe sahip olmadan ve sadece ti neden olmazken skype içindeki UDP yükünün sonuna baytlar gönderiyorsunuz sorunları. –

+0

ya ... haklısınız. Bu merhaba dünyasından başka ilk modülümdü. Ve sorunlara neden olur. Yani, bir paketi arttırmak için yeni bir arabellek ayırmam ve bazı işlemleri gerçekleştirmem gerekiyor. Skb_put() işlevinin, kullanım şekline zarar vermeyeceği garanti edilmez. Bu arada, aslında bir paket içinde bazı baytlar doldurmak için yazılmıştır, sonunda bazı çekirdek paniklerinden sonra bana açıktı. Ama yazıyı unuttum. Konu için teşekkürler. Kodu yakında ayarlayacağım. U modülün açıklamasına bakın .. sadece burada bahsedilen yarım büyük bir projenin başlangıcı oldu. Teşekkürler. –

+0

Merhaba! Bunun çok eski bir iş parçacığı olduğunun farkındayım, fakat bana gönder/alma zincirinin tam olarak nerede bu kanca denir? –