2012-04-09 3 views
1

Так вот что я пытаюсь сделать (тривиально, я знаю, я делаю это, чтобы узнать что-то для проекта): Я построил этот модуль, чтобы поймать все исходящий трафик, проверьте, является ли это трафик эхо-сообщений ICMP. Если это так, он просто пересчитывает контрольную сумму ICMP-пакета и затем отпускает его на своем пути.Я не могу правильно изменить ICMP-трафик в модуле ядра

Каждый раз, когда я устанавливаю этот модуль, весь PING-трафик выходит из строя. < Не могли бы вы рассказать мне, что я здесь делаю неправильно?

/* 
     Coder: Adel *. ******* 
    Creation Date: April/7th/2012 
    Last Modification Date: April/9th/2012 
    Purpose: This module is merely a prototype on how to change the IP/ICMP pakcet information and still let it go without problems 
    Testing: This module is being tested on a machine running the Linux kernel 2.6.32-33 on a 64bits Intel Processor  
    Notes: N/A 
*/ 


#include <linux/module.h> 
#include <linux/kernel.h> 
#include <linux/init.h> 

#include <linux/inet.h> 
#include <linux/ip.h> 
#include <linux/icmp.h> 
#include <linux/tcp.h> 
#include <linux/in.h> 

#include <linux/netfilter.h> 
#include <linux/netfilter_ipv4.h> 

static struct nf_hook_ops nfho; 
static void printICMPHeader(struct icmphdr *icmph); 

/* 
* in_cksum -- 
* Checksum routine for Internet Protocol 
* family headers (C Version) 
*/ 
unsigned short in_cksum(unsigned short *addr, int len) 
{ 
    register int sum = 0; 
     u_short answer = 0; 
     register u_short *w = addr; 
     register int nleft = len; 
     /* 
     * Our algorithm is simple, using a 32 bit accumulator (sum), we add 
     * sequential 16 bit words to it, and at the end, fold back all the 
     * carry bits from the top 16 bits into the lower 16 bits. 
     */ 
     while (nleft > 1) 
     { 
      sum += *w++; 
      nleft -= 2; 
     } 
     /* mop up an odd byte, if necessary */ 
     if (nleft == 1) 
     { 
      *(u_char *) (&answer) = *(u_char *) w; 
      sum += answer; 
     } 
     /* add back carry outs from top 16 bits to low 16 bits */ 
     sum = (sum >> 16) + (sum & 0xffff);  /* add hi 16 to low 16 */ 
     sum += (sum >> 16);    /* add carry */ 
     answer = ~sum;    /* truncate to 16 bits */ 
     return (answer); 
} 

static unsigned int icmp_check(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 icmphdr *icmph; 
    struct tcphdr *tcph; 

    if(skb == NULL) 
     return -1; 
    iph = ip_hdr(skb); 
    if(iph->protocol == IPPROTO_ICMP){ 
     printk(KERN_DEBUG"ICMP traffic!\n"); 
     icmph = icmp_hdr(skb); 
     if(icmph->type == ICMP_ECHO){ 
      printICMPHeader(icmph); 
      icmph->checksum = in_cksum((unsigned short *)icmph, sizeof(struct icmphdr)); 
      printICMPHeader(icmph); 
     } 
    }/* If IPPROTO_ICMP */ 
    return NF_ACCEPT; 
} 


static void printICMPHeader(struct icmphdr *icmph) 
{ 
    printk(KERN_DEBUG "ICMP print function begin \n"); 
    printk(KERN_DEBUG "ICMP type = %d\n", icmph->type); 
    printk(KERN_DEBUG "ICMP code = %d\n", icmph->code); 
    printk(KERN_DEBUG "ICMP checksum = %d\n", icmph->checksum); 
    printk(KERN_DEBUG "ICMP id = %d\n", icmph->un.echo.id); 
    printk(KERN_DEBUG "ICMP sequence = %d\n", icmph->un.echo.sequence); 
    printk(KERN_DEBUG "ICMP print function exit \n");  
} 


static int __init startup(void) 
{ 
     printk(KERN_INFO "Loading Test module...\n"); 
     printk(KERN_ALERT "Hello world\n"); 

     /* Fill in our hook structure */ 
     nfho.hook = icmp_check;   /* Handler function */ 
     nfho.hooknum = NF_INET_POST_ROUTING; /* Just before it hits the wire */ 
     nfho.pf  = PF_INET; 
     nfho.priority = NF_IP_PRI_FILTER; 
     nf_register_hook(&nfho); 
    //pinger(); 
    return 0; 
} 

static void __exit cleanup(void) 
{ 
    nf_unregister_hook(&nfho); 
    printk(KERN_ALERT "Goodbye Mr.\n"); 
} 

module_init(startup); 
module_exit(cleanup); 

EDIT: Для отладки кода немного, я сделал свою собственную утилиту пользовательского пространства пинг, и я заполнил все его IP и ICMP заголовки с использованием RAW_SOCKETS

icmp->type   = ICMP_ECHO; 
    icmp->code   = 0; 
    icmp->un.echo.id  = 0; 
    icmp->un.echo.sequence = 0; 
    icmp-> checksum  = in_cksum((unsigned short *)icmp, sizeof(struct icmphdr)); 

Эта утилита работает отлично, если мой модуль не загружен. достаточно Жутко, когда я загружаю мой модуль и проверьте файл отладки ядра, обратите внимание на то, что я получаю:

Apr 9 10:42:10 DHS-1022CYB kernel: [ 2521.862356] ICMP traffic! 
Apr 9 10:42:58 DHS-1022CYB kernel: [ 2569.572346] ICMP traffic! 
Apr 9 10:43:22 DHS-1022CYB kernel: [ 2593.317201] ICMP traffic! 
Apr 9 10:43:56 DHS-1022CYB kernel: [ 2627.331320] ICMP traffic! 
Apr 9 10:44:05 DHS-1022CYB kernel: [ 2636.802236] ICMP traffic! 
Apr 9 10:44:08 DHS-1022CYB kernel: [ 2639.876490] ICMP traffic! 
Apr 9 10:45:27 DHS-1022CYB kernel: [ 2718.422229] ICMP traffic! 

В основном это означает, что я, по какой-то причине, я даже не в состоянии поймать трафик ECHO в мой модуль! (Когда я не могу поймать его, он просто выходит и отлично работает) PS Я попытался изменить крюк LOCAL_OUT и получил тот же результат

EDIT2: результаты отладочный файл изменен это

Apr 9 10:57:24 DHS-1022CYB kernel: [ 3435.916336] ICMP print function exit 
Apr 9 10:57:25 DHS-1022CYB kernel: [ 3436.922656] ICMP traffic! 
Apr 9 10:57:25 DHS-1022CYB kernel: [ 3436.922665] ICMP print function begin 
Apr 9 10:57:25 DHS-1022CYB kernel: [ 3436.922670] ICMP type = 8 
Apr 9 10:57:25 DHS-1022CYB kernel: [ 3436.922674] ICMP code = 0 
Apr 9 10:57:25 DHS-1022CYB kernel: [ 3436.922677] ICMP checksum = 50252 
Apr 9 10:57:25 DHS-1022CYB kernel: [ 3436.922681] ICMP id = 3673 
Apr 9 10:57:25 DHS-1022CYB kernel: [ 3436.922685] ICMP sequence = 512 
Apr 9 10:57:25 DHS-1022CYB kernel: [ 3436.922688] ICMP print function exit 
Apr 9 10:57:25 DHS-1022CYB kernel: [ 3436.922691] ICMP print function begin 
Apr 9 10:57:25 DHS-1022CYB kernel: [ 3436.922695] ICMP type = 8 
Apr 9 10:57:25 DHS-1022CYB kernel: [ 3436.922698] ICMP code = 0 
Apr 9 10:57:25 DHS-1022CYB kernel: [ 3436.922702] ICMP checksum = 11090 
Apr 9 10:57:25 DHS-1022CYB kernel: [ 3436.922705] ICMP id = 3673 
Apr 9 10:57:25 DHS-1022CYB kernel: [ 3436.922709] ICMP sequence = 512 
Apr 9 10:57:25 DHS-1022CYB kernel: [ 3436.922712] ICMP print function exit 

Обратите внимание, что это результат использования утилиты Linux ping, а не моего написанного вручную PING (который я по-прежнему почему-то не могу перехватить). И пинг Linux не работает, пока мой модуль загружен.

ответ

1

Вы не правильно вычисляете контрольную сумму ... как вы можете видеть по вашим журналам. Контрольная сумма ICMP вычисляется по всему сообщению, а не только по заголовку. Так что в вашем случае:

icmph->checksum = in_cksum((unsigned short *)icmph, sizeof(struct icmphdr)); 

Должно быть:

icmph->checksum = 0; 
icmph->checksum = in_cksum((unsigned short *)icmph, 
          ntohs(iph->tot_len) - (iph->ihl << 2)); 

также, не забудьте инициализировать поле до 0.

1

Похоже, вы переоцениваете контрольную сумму, путем включения неиницализированных полей контрольной суммы себя:

icmph->checksum = in_cksum((unsigned short *)icmph, sizeof(struct icmphdr)); 

AVRnet docs говорит, что поле контрольной суммы должно быть инициализировано до 0, прежде чем контрольная сумма вычисляются. Так что попробуйте, просто:

icmph->checksum = 0; 
icmph->checksum = in_cksum((unsigned short *)icmph, sizeof(struct icmphdr)); 

Это на самом деле догадка; У меня никогда не было несчастья в кодировании TCP/IP: D Но я думаю, даже если ядро ​​достаточно умное, чтобы инициализировать это значение 0 для кода контрольной суммы, вы проверяете RE-контрольные суммы, так что это будет проблемой.

+0

Просто попытался это, и все еще ничего :( – Fingolfin

+0

Хм. Тогда я не знаю. Но кажется, что ясно, что контрольная сумма ошибочна, учитывая ваш результат до и после отладки.Я бы предположил, что либо ваш алгоритм контрольной суммы сам по себе не прав, либо вы не накачиваете нужные данные, чтобы их суммировать. Убедитесь, что ваш алгоритм проверки работает с хорошо известными данными/результатами. Затем убедитесь, что вы включили все нужные поля из пакета, и никого из них не должно быть. –

+0

Это тоже не так, потому что я использовал ту же самую функцию для вычисления контрольной суммы в моей ручной программе ping. (Я также просто подтвердил, что мой PING работает отлично, и он получает сообщение ECHO_REPLY). – Fingolfin

Смежные вопросы