2012-09-21 9 views
5

Estoy tratando de agregar algunos datos en un paquete desde el espacio del kernel. Tengo un cliente de eco y servidor. Escribo en la línea de comandos como: ./client "mensaje" y el servidor simplemente lo repite. El servidor se ejecutó con ./server.¿Cómo agregar datos en un paquete desde el espacio del kernel?

Ahora, el cliente y el servidor están en dos máquinas diferentes (pueden ser máquinas virtuales). Estoy escribiendo un módulo kernel que se ejecuta en la máquina cliente. Su trabajo es agregar "12345" después de "mensaje" mientras el paquete sale de la máquina. Estoy presentando el código a continuación.

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

quiero conseguir el "mensaje" a ser "message12345" al enviar fuera de la máquina cliente desde el espacio del núcleo. Para que el servidor reciba "message12345" y lo repita, y el cliente leerá simplemente "message12345". Pero estoy teniendo problemas con las funciones skb_put() y skb_add_data(). No entiendo qué error cometí yo. Si alguien puede ayudarme con el código, estaré muy agradecido. Gracias por adelantado. También estoy dando el Makefile por conveniencia. Esto es para el kernel de distribución, no para un kernel creado.

#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 

Ahora estoy bastante convencido de que skb-> final - skb-> cola es tan pequeña que voy a tener que crear nuevos paquetes en el espacio del núcleo. He usado alloc_skb() skb_header_pointer() skb_header_pointer() y otras funciones skb útiles para crear una nueva skb, pero lo que me está quedando sin idea es cómo enrutar el paquete recién creado en la ruta de flujo de paquetes . Cómo usar
ip_route_me_harder() Busqué en el paquete xtables-addons la sugerencia, pero la función que utilizaron es diferente de la del kernel de linux. Cualquier sugerencia es bienvenida. Hace

Respuesta

3

aproximadamente un año para el kernel 2.6.26 lo hice así:

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

} 

No se olvide:

  • Volver a calcular la suma de comprobación UDP, porque ha cambiado los datos en los datos transportados .

  • Cambie el campo tot_len (longitud total) en el encabezado ip, porque ha agregado datos al paquete.

  • Vuelva a calcular la suma de comprobación del encabezado IP, porque ha cambiado el campo tot_len.

nota adicional: Esto es sólo una cosa simple. Veo en su código que está asignando tmp como una matriz de 200 bytes y usándola para almacenar los datos de su mensaje. Si envía un paquete más grande, tendrá dificultades para depurar esto ya que los bloqueos del kernel debido a los desbordamientos de memoria son demasiado dolorosos.

+0

Gracias por su ayuda. Sí, los campos de longitud me preocuparon mucho. –

+0

Y también la suma de verificación en el espacio del kernel fue bastante vaga para mí al principio. –

+0

@Fred, ¿puedes comentar esto también? Http://stackoverflow.com/questions/12529497/how-to-append-data-on-a-packet-from-kernel-space – user2087340

1

He resuelto el problema. Fue trivial. Y todo lo que voy a hacer es publicar mi código para referencias futuras y discusión.

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

Aquí la cosa es que, se me olvidó actualizar los campos de longitud y se olvidó de actualizar la suma de comprobación. Ahora, si presento el código correctamente aquí, todo debería ir bien.Hay algunas otras funciones auxiliares que no están incluidas aquí.

+2

No creo que este código sea bueno en absoluto. 1) nunca kfree (temp) por lo que hay una pérdida de memoria 2) skb_put no expande el búfer, por lo que está tachando bytes al final de la carga UDP dentro de skb sin tener realmente esa memoria y esperando que ti no cause problemas. –

+0

ya ... tienes razón. Ese fue mi primer módulo aparte del mundo de hola. Y causa problemas. Entonces, para aumentar un paquete, necesito asignar un nuevo buffer y realizar algunas operaciones. No se garantiza que usar skb_put() no cause daños en la forma en que se usó. Por cierto, fue escrito para rellenar algunos bytes en un paquete en realidad, finalmente fue claro para mí después de algunos pánicos kernel. Pero me olvidé de la publicación. Gracias por el punto. Ajustaré el código pronto. Vemos la descripción del módulo ... fue solo el comienzo de un gran proyecto solo mencionado aquí. Gracias. –

+0

¡Hola! Me doy cuenta de que este es un hilo muy antiguo, pero ¿pueden decirme exactamente en qué parte de la cadena de envío/recepción se llama este gancho? –

Cuestiones relacionadas