2012-04-09 7 views
1

Also hier ist was ich versuche zu tun (trivial, ich weiß; ich mache das, um etwas für ein Projekt zu lernen): Ich habe dieses Modul um alle zu fangen gebaut Ausgehender Datenverkehr, überprüfen Sie, ob es sich um ICMP-Echo-Nachrichtenverkehr handelt. Wenn es ist, berechnet es einfach die Prüfsumme des ICMP-Pakets neu und lässt es dann weiterlaufen.Ich ICMP-Verkehr in einem Kernelmodul nicht korrekt ändern

Jedes Mal, wenn ich dieses Modul insmod, schlägt der gesamte PING Verkehr fehl>. < Können Sie mir bitte sagen, was ich hier falsch mache?

/* 
     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: Um den Code ein wenig zu debuggen, ich habe mein eigenes User-Space-Ping-Dienstprogramm gemacht und ich habe alle seine IP und ICMP-Header mit gefüllt 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)); 

Dieses Dienstprogramm funktioniert einwandfrei, solange mein Modul nicht geladen ist. Seltsam genug, wenn ich mein Modul laden und die Kernel-Debug-Datei überprüfen, schauen, was ich bekomme:

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! 

Das bedeutet im Wesentlichen, dass ich aus irgendeinem seltsamen Grunde, bin nicht einmal in der Lage, das ECHO Verkehr zu fangen in mein Modul! (Wenn ich es nicht fangen kann, geht es einfach aus und arbeitet völlig in Ordnung) PS Ich habe versucht, den Haken zu ändern LOCAL_OUT und bekam das gleiche Ergebnis

EDIT2: Ergebnisse der DEBUG-Datei geändert hat, ist diese

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 

Beachten Sie jedoch, dass dies das Ergebnis des Linux Utility Ping ist, nicht mein handgeschriebenes PING (welches ich aus irgendeinem Grund nicht abfangen kann). Und der Linux-Ping funktioniert nicht, solange mein Modul geladen ist.

Antwort

1

Sie berechnen die Prüfsumme nicht korrekt ... wie Sie in Ihren Protokollen sehen können. Die ICMP-Prüfsumme wird über die gesamte Nachricht und nicht nur über den Header berechnet. Also in Ihrem Fall:

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

werden sollten:

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

auch, nicht vergessen, das Feld zu initialisieren auf 0

1

Es sieht aus wie Sie die Prüfsumme sind Fehleinschätzung durch die uninitialised Prüfsummenfeld selbst mit:

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

AVRnet docs sagen, dass die Prüfsumme Feld auf 0 initialisiert werden sollte, bevor die Prüfsumme berechnet wird. Also versuchen Sie es einfach:

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

Dies ist nur eine Vermutung wirklich; Ich hatte nie das Pech, TCP/IP zu codieren: D Aber ich denke, selbst wenn der Kernel schlau genug ist, um diesen Wert auf 0 für Prüfsummencode zu initialisieren, ist RE-checksumming, also würde ein Problem sein.

+0

versucht genau das und noch nichts :( – Fingolfin

+0

Hmm. Dann weiß ich es nicht .. Aber es * scheint * klar, dass die Checksumme falsch ist, wenn man ihre Vorher-Nachher-Debug-Ausgabe angibt.Ich schätze, entweder ist Ihr Prüfsummenalgorithmus selbst falsch oder Sie pumpen nicht die richtigen Daten durch, um summiert zu werden. Stellen Sie sicher, dass Ihr Checkusum-Algorithmus gegen bekannt gute Daten/Ergebnisse arbeitet. Stellen Sie dann sicher, dass Sie alle richtigen Felder aus dem Paket einschließen, und keines, das nicht dort sein sollte. –

+0

Das kann auch nicht stimmen, weil ich genau die gleiche Funktion benutzt habe, um die Prüfsumme in meinem handschriftlichen Ping-Programm zu berechnen. (Ich habe auch gerade verifiziert, dass mein PING einwandfrei funktioniert und es eine ECHO_REPLY-Nachricht erhält). – Fingolfin

Verwandte Themen