Create kernel UDP packet and send

644 views Asked by At

I need your help :/ I've made a module to create an UDP packet, with data, udp header, ip header and ethernet header, in a kernel.

I've look lots of topic, sites and blogs but nothing help me. I didn't success to do what i want :(

Now, i want to send it to the device, or to the wire (loopback).

#include <linux/init.h>
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/ip.h>
#include <net/ip.h>
#include <Create6.h>

void compute_udp_checksum(struct iphdr *pIph, unsigned short *ipPayload) {
    register unsigned long sum = 0;
    struct udphdr *udphdrp = (struct udphdr*)(ipPayload);
    unsigned short udpLen = htons(udphdrp->len);

    sum += (pIph->saddr>>16)&0xFFFF;
    sum += (pIph->saddr)&0xFFFF;
    sum += (pIph->daddr>>16)&0xFFFF;
    sum += (pIph->daddr)&0xFFFF;
    sum += htons(IPPROTO_UDP);
    sum += udphdrp->len;
    udphdrp->check = 0;

    while (udpLen > 1) {
        sum += * ipPayload++;
        udpLen -= 2;
    }

    if(udpLen > 0) {
        sum += ((*ipPayload)&htons(0xFF00));
    }

      while (sum>>16) {
          sum = (sum & 0xffff) + (sum >> 16);
      }

      sum = ~sum;

    udphdrp->check = ((unsigned short)sum == 0x0000)?0xFFFF:(unsigned short)sum;
}

void compute_ip_checksum(struct iphdr* iphdrp){
  iphdrp->check = 0;
  iphdrp->check = compute_checksum((unsigned short*)iphdrp, iphdrp->ihl<<2);
}

static unsigned short compute_checksum(unsigned short *addr, unsigned int count) {
  register unsigned long sum = 0;
  while (count > 1) {
    sum += * addr++;
    count -= 2;
  }

  if(count > 0) {
    sum += ((*addr)&htons(0xFF00));
  }

  while (sum>>16) {
      sum = (sum & 0xffff) + (sum >> 16);
  }

  sum = ~sum;
  return ((unsigned short)sum);
}

void aff_skb_info(struct sk_buff *skb){
    printk(KERN_INFO "Skb  : %x", (unsigned int) skb);
    printk(KERN_INFO "Head : %x", (unsigned int) skb->head);
    printk(KERN_INFO "Data : %x", (unsigned int) skb->data);
    printk(KERN_INFO "Tail : %x", (unsigned int) skb->tail);
    printk(KERN_INFO "End  : %x", (unsigned int) skb->end);
    printk(KERN_INFO "Mac header  : %x", (unsigned int) skb->mac_header);
    printk(KERN_INFO "Transport header  : %x", (unsigned int) skb->transport_header);
    printk(KERN_INFO "Network header  : %x", (unsigned int) skb->network_header);
}

static int temp_init(void)
{
    struct sk_buff *skb = NULL;
    struct iphdr *newip = NULL;
    struct udphdr *newudp = NULL;
    struct ethhdr *neweth = NULL;
    u_char *data_for = NULL;
    int i=0;

    printk(KERN_INFO "Create6 : Registering LKM...\n");

    /************************************ ALLOCATION *****************************************/
    printk(KERN_INFO " --------------------------------------  ALLOCATION -------------------------------------- \n");
    skb = alloc_skb(320,GFP_KERNEL);
    aff_skb_info(skb);

    /************************************ RESERVE ESPACE HEADER ****************************************/
    printk(KERN_INFO " --------------------------------------  RESERVE ESPACE HEADER -------------------------------------- \n");
    skb_reserve(skb, 70);
    aff_skb_info(skb);

    /************************************ DATA ****************************************/
    printk(KERN_INFO " --------------------------------------  DATA -------------------------------------- \n");    
    u_char payload[] = "AAAAAAAAAA";
        u32 payload_len = 10;

    skb_push(skb, payload_len); 
    memset(skb->data, 0, payload_len);
    memcpy(skb->data, payload, payload_len);

    aff_skb_info(skb);
    i=1;
    for(data_for = skb->data; data_for<skb->tail; data_for++ ){ 
        printk(KERN_INFO "\tPayload %d\t: %.2x à l'adresse : %x", i, *data_for, (unsigned int) data_for);
        i++;
    }

    /************************************ UDP *****************************************/
    printk(KERN_INFO " --------------------------------------  UDP -------------------------------------- \n");    
    skb->transport_header = (void *)skb_push(skb, sizeof(struct udphdr));
    memset(skb->data,0,sizeof(struct udphdr));

    newudp = udp_hdr(skb);
    newudp->source = htons(59046);
    newudp->dest   = htons(5001);
    newudp->len    = htons(sizeof(struct udphdr));
    newudp->check  = 0;
    newudp->check = csum_tcpudp_magic(in_aton("169.254.121.80"),in_aton("169.254.121.80"),sizeof(struct udphdr), IPPROTO_UDP,csum_partial(newudp, sizeof(struct udphdr), 0));

    aff_skb_info(skb);
    printk(KERN_INFO "Source Port : %x à l'adresse %x", newudp->source,&(newudp->source));
    printk(KERN_INFO "Dest Port : %x à l'adresse %x", newudp->dest,&(newudp->dest));
    printk(KERN_INFO "Len  : %x à l'adresse %x", newudp->len,&(newudp->len));
    printk(KERN_INFO "Check  : %x à l'adresse %x", newudp->check,(&newudp->check));
    i=1;
    for(data_for = skb->data; data_for<skb->tail; data_for++ ){ 
        printk(KERN_INFO "\tPayload %d\t: %.2x à l'adresse : %x", i, *data_for, (unsigned int) data_for);
        i++;
    }

    /************************************ IP *****************************************/
    printk(KERN_INFO " --------------------------------------  IP -------------------------------------- \n");  
    skb->network_header = (void *)skb_push(skb, sizeof(struct iphdr));
    memset(skb->data,0,sizeof(struct iphdr));

    newip = iph_hdr(skb);
    newip->version  = 4;
    newip->ihl      = 4;
    newip->tos      = 0;
    newip->id       = 0;
    newip->frag_off = 0;
    newip->ttl = 64;
    newip->protocol = IPPROTO_UDP;
    newip->saddr    = in_aton("169.254.121.80");
    newip->daddr    = in_aton("169.254.121.80");
    newip->check    = 0;
    compute_ip_checksum(newip);

    aff_skb_info(skb);
    printk(KERN_INFO "\n"); 
    printk(KERN_INFO "Version  : %x", newip->version);
    printk(KERN_INFO "Ihl  : %x", newip->ihl);
    printk(KERN_INFO "TOS  : %x à l'adresse %x", newip->tos,&(newip->tos));
    printk(KERN_INFO "ID  : %x à l'adresse %x", newip->id,(&newip->id));
    printk(KERN_INFO "Frag Off  : %x à l'adresse %x", newip->frag_off,&(newip->frag_off));
    printk(KERN_INFO "TTL  : %x à l'adresse %x", newip->ttl,&(newip->ttl));
    printk(KERN_INFO "Protocol  : %x à l'adresse %x", newip->protocol,&(newip->protocol));
    printk(KERN_INFO "Source @  : %x à l'adresse %x", newip->saddr,&(newip->saddr));
    printk(KERN_INFO "Destination @  : %x à l'adresse %x", newip->daddr,&(newip->daddr));
    printk(KERN_INFO "Check IP : %x à l'adresse %x", newip->check,&(newip->check));
    i=1;
    for(data_for = skb->data; data_for<skb->tail; data_for++ ){ 
        printk(KERN_INFO "\tPayload %d\t: %.2x à l'adresse : %x", i, *data_for, (unsigned int) data_for);
        i++;
    }

    /************************************ ETHERNET *****************************************/
    printk(KERN_INFO " --------------------------------------  ETHERNET -------------------------------------- \n");    
    skb->mac_header = (void *)skb_push(skb, sizeof(struct ethhdr));
    memset(skb->data,0,sizeof(struct ethhdr));

    neweth = eth_hdr(skb);
    neweth->h_dest[0] = 0x04;neweth->h_dest[1] = 0x7d;neweth->h_dest[2] = 0x7b;neweth->h_dest[3] = 0x4d;neweth->h_dest[4] = 0xa8;neweth->h_dest[5] = 0x75;
    neweth->h_source[0] = 0x04;neweth->h_source[1] = 0x7d;neweth->h_source[2] = 0x7b;neweth->h_source[3] = 0x4d;neweth->h_source[4] = 0xa8;neweth->h_source[5] = 0x75;
    neweth->h_proto = ETH_P_IP;

    aff_skb_info(skb);
    printk(KERN_INFO "\n"); 
    printk(KERN_INFO "MAC Destination : %x", neweth->h_dest);
    printk(KERN_INFO "MAC Source : %x", neweth->h_source);
    printk(KERN_INFO "Protocole : %x à l'adresse %x", neweth->h_proto);
    i=1;
    for(data_for = skb->data; data_for<skb->tail; data_for++ ){ 
        printk(KERN_INFO "\tPayload %d\t: %.2x à l'adresse : %x", i, *data_for, (unsigned int) data_for);
        i++;
    }

    dev_queue_xmit(skb);

    kfree_skb(skb);
    printk(KERN_INFO "\nCreate7 : LKM loaded.\n");
    return 0;
}

static void temp_exit(void)
{
    printk(KERN_INFO "Create7 : Unregistering LKM...\n");
    printk(KERN_INFO "Create7:  Unloaded LKM\n");
}

module_init(temp_init);
module_exit(temp_exit);

Here is my code. I think there is 2 problems.

First, i don't know how to build my net_device structure for skb->dev The, how to send my packet on my loopback ? I see to used hard_start_xmit(skb,dev) or dev_queue_xmit(skb) but i've kernel panic when i do it.

So, if you know how do to this, thank you very much !!!

0

There are 0 answers