IP Checksum Berechnung



  • Hi,
    ich arbeite gerade an einem Algo, der die IP Checksumme nach folgender Defintion erstellt:

    Header Checksum: 16 bits

    A checksum on the header only. Since some header fields change
    (e.g., time to live), this is recomputed and verified at each point
    that the internet header is processed.

    The checksum algorithm is:

    The checksum field is the 16 bit one's complement of the one's
    complement sum of all 16 bit words in the header. For purposes of
    computing the checksum, the value of the checksum field is zero.

    This is a simple to compute checksum and experimental evidence
    indicates it is adequate, but it is provisional and may be replaced
    by a CRC procedure, depending on further experience.

    Mein Pseudocode sieht bisher so aus:

    Teile die Daten in 16-bit Stücke auf
    Für jedes 16-bit Stück:
    Wende auf 16-bit-Zahl die NOT Operation an (Komplement)
    Addiere dieses Komplement
    Wdh.
    

    Jedoch scheint der Algo nicht richtig zu arbeiten. Jemand irgendwelche Ideen bezüglich dieses Checksum Algos bzw. Pseudocode?

    Danke,
    Neo



  • So wie ich den engl. Text verstehe, ist die Checksumme selbst noch mal ein 1-Komplement,
    also am Ende noch:

    in Pseudocode:

    Checksumme = NOT Checksum;
    

    Außerdem mußt du beim Einlesen des Headers beachten, daß du dir den Checksummenwert merkst, dann auf 0 setzt und anschließend deinen Algo rüberlaufen läßt und am Schluß mit dem Originalwert vergleichst.



  • Danke, das mit dem NOT am Ende habe ich bereits so im Algo eingebaut.

    Ein Problem ist jedoch, dass ich nicht weiß, *welcher* Teil der Daten für die Checksumme verwendet wird. Der Aufbau meines CDP Paketes ist wiefolgt:

    Ethernet
    Logical-Link Protocol
    CDP
    - Version (1 Byte)
    - TTL (1 Byte)
    - Checksum (2 Byte)
    ..

    Nun habe ich durch Veränderungen direkt im CDP Paket und sich ändernder Checksumme die Vermutung, die darüber liegenden Schichten haben nix damit zu tun. Nun ist aber die Frage, ob die Checksumme von den kompletten CDP Daten, nur den ersten paar Bytes oder so gebildet wird.

    Ohne dieses Wissen kann ich nicht sagen, ob ich die falschen Bytes nehme oder ob meine Funktion einfach falsch ist.

    Gruß,
    Neo



  • Also, wenn die Checksumme nur Teil des CDP ist, dann wird wohl auch nur die CDP für die Checksummenberechnung benötigt. Ich nehme an, die ganze CDP-Struktur, sonst macht eine Checksumme ja keinen Sinn (es geht ja darum, ob evtl. Daten während der Übertragung verändert worden sind).



  • Nunja, wenn ich den kompletten CDP Datenteil (oder auch alles was nach der Checksumme kommt) für meine Checksumme verwende kommt nicht derselbe Wert wie bei dem Musterpaket heraus.

    Höchstwahrscheinlich ist meine Funktion also falsch (was ich bezweifle, da sie recht simpel ist). Es kann aber auch sein, dass doch etwas anderes als Checksumme verwendet wird.

    Hat jemand Beispielwerte sammt Checksummen, damit ich prüfen kann, ob meine Funktion funktioniert? Im Inet konnte ich keine finden..



  • For purposes of computing the checksum, the value of the checksum field is zero.

    Hast du die checksumme auch mit 0 initialisiert bevor du sie berechnest ?
    K



  • Japp, habe ich.

    Es muss an etwas größerem liegen. Die Checksume der CDP Daten ist im Musterpaket 46500 (Dezimal). Meine errechnete Checksumme mit meiner Funktion ist weit über 146000.

    Zur Zeit prüfe ich nocheinmal sehr aufmerksam die Funktion. Falls ihr Zeit habt, könnt ihr gerne eine Implementation von Euch posten, die ich dann mit meiner vergleichen kann.



  • NeoInferno schrieb:

    Japp, habe ich.

    Es muss an etwas größerem liegen. Die Checksume der CDP Daten ist im Musterpaket 46500 (Dezimal). Meine errechnete Checksumme mit meiner Funktion ist weit über 146000.

    Zur Zeit prüfe ich nocheinmal sehr aufmerksam die Funktion. Falls ihr Zeit habt, könnt ihr gerne eine Implementation von Euch posten, die ich dann mit meiner vergleichen kann.

    Da muss dann auch der fehler liegen bei 16 bit kann die checksumme nich grösser als 65535 werden.
    K



  • Stimmt, das leuchtet ein. Hier nocheinmal detailierter Pseudocode (nicht wundern, hab einiges recht umständlich gemacht):

    Eingabe: Data
    // Words: Array mit 16-bit Werten
    Für jedes Zeichen in Data:
      Füge Zeichen + Nächstes Zeichen zu Words hinzu
    Wdh.
    
    // Komplemente addieren
    Für jedes Element in Words: 
      Bilde 8-bit des ersten Zeichens
      Bilde 8-bit des zweiten Zeichens
      Hänge diese Werte zu einem 16-bit Zeichen zusammen
    
      Summe = Summe + (NOT DualzuDezimal(16-bit Zahl))
    Wdh.
    
    Summe = NOT Summe
    

    Ich behandle die zwei 8-bit Zeichen getrennt, weil ich nicht weiß, wie ich direkt aus den zwei Zeichen eine Zahl machen kann.

    Hoffentlich findet jemand einen Denkfehler im Code.



  • denke das könnte schon so funktionieren aber es fehlt auf jeden fall eine überprüfung auf überlauf. vielleicht so.

    // Komplemente addieren
    Für jedes Element in Words:
      Bilde 8-bit des ersten Zeichens   // verstehe nicht was du hier meinst
      Bilde 8-bit des zweiten Zeichens
      Hänge diese Werte zu einem 16-bit Zeichen zusammen
    
      Summe = Summe + (NOT DualzuDezimal(16-bit Zahl))
      wenn Summe > 65535 
         Summe = Summe - 65536;
    Wdh.
    

    Kurt



  • ich hab auch noch einen

    UINT16 IP_Checksum (UINT16 *data, UINT16 bytecount)
    {
        UINT32 sum = 0;
        while (bytecount > 1)
        {
            sum += *data++;
            bytecount -= 2;
        }
        if (bytecount == 1)
    #ifdef LITTLE_ENDIAN
            sum += *(UINT8 PTR)data;
    #else
    	sum += ((UINT16)(*(UINT8 PTR)data))<<8;
    #endif
        while (sum >> 16)
            sum = (sum & 0xffff) + (sum >> 16);
    
        return (UINT16)~sum;
    
    }   /*lint !e818 (Pointer parameter could be declared ptr to const) */
    

    -->
    'data' zeigt auf den anfang des arrays
    'bytecount' anzahl _bytes_ des arrays



  • Hi,

    ich verstehe diese Zeile nicht:

    while (bytecount > 1)
        {
            sum += *data++;
            bytecount -= 2;
        }
    

    Damit kriegst du doch nur jedes 2te Zeichen zu 'sum' addiert, oder?

    Und laut deinem Algo, der mit meinem wenig gemein hat, addierst du also zuerst die ganzen 16-bit WORDs zu sum und bearbeitest sie dann nacher mit Komplementbildung?

    Danke,
    Neo



  • Hi NeoInferno,

    die Berechnung von 'net' stimmt, da dort ein Zeiger auf einen 16Bit-Wert (UINT16) genommen wird.
    Aber poste mal deinen Code.



  • Von meinem Code werdet ihr wenig haben - er ist in Visual Basic geschrieben.
    Es geht faktisch ums Problem, den Code übersetze ich mir jedes mal in VB (auch wenns mit Zeigern recht schwierig wird 😃 ).

    Wenn es in VB gar nicht funktioniert, werde ich das ganze wohl in C++ schreiben.



  • NeoInferno schrieb:

    Von meinem Code werdet ihr wenig haben - er ist in Visual Basic geschrieben.
    Es geht faktisch ums Problem, den Code übersetze ich mir jedes mal in VB (auch wenns mit Zeigern recht schwierig wird 😃 ).
    Wenn es in VB gar nicht funktioniert, werde ich das ganze wohl in C++ schreiben.

    schreib den code in c# (die syntax ist c-ähnlich), dann saugst du dir sharpdevelop
    --> http://www.icsharpcode.net/OpenSource/SD/
    und damit machste vb-code draus (der kann das konvertieren)



  • Sorry, dass ich erst jetzt antworte, kann nicht so oft online zur Zeit.

    Hier eine Lösung die ich in C++ geschrieben habe, um die Funktion dann als DLL zu exportieren (und in VB zu verwenden). Sie liefert zwar gute Checksummen, wenn ich aber mit z.B. IP vergleiche scheinen sie trotzdem nicht zu stimmen. Findet jemand einen Fehler?

    DLLEXPORT uint getipchecksum(string &text, string &checksum) {
        uint    len = text.length()-1;
        ushort  tmp;
        ushort  sum;
    
        // Evtl. für gerade Zeichenanzahl Zeichen anhängen
        if (len % 2 != 0) {
            text += " ";
            text[++len] = uchar(0);
        }
    
        // Stückweise Komplemente bilden
        for (uint i = 0 ; i < len ; i += 2) {
            tmp = frombytes(text.substr(i,2));
            cout<<i<<" + "<<~tmp<<nl;
            sum += (~tmp);
        }
    
        // Summe als 2 Bytes zurückgeben
        checksum = tobytes( (~sum),2 );
    
        return 0;
    }
    

    Danke nochmal für eure Hilfe, dieses Problem ist mir wirklich sehr wichtig, da ich es auf zig andere Protokolle übertragen kann. 🙂


Anmelden zum Antworten