Tcp Checksum Berechnung



    1. schrieb:

    Schöne Geschichte. 😎

    leider ohne happy end 😞 🤡



  • 😋



  • Hi

    Hat den Niemand eine Idee was an der Berechnung nicht stimmen könnte? Auf unsinvolle Forenbeiträge siehe oben habe ich kein Bock.

    LG Joe



  • Was heisst falsch?

    Wieso sollte das von den Daten abhängen (mal angenommen Du meinst die Daten aus buf)? Die stehen zu dem Zeitpunkt ja noch nicht in b. In der angebenen Zeile wird checksumme über die Daten der beiden Strukturen FORCSUM und TCPHDR berechnet. Wann ist das Ergebnis richtig?



  • Hi

    Folgendes: sind in Buf Daten enthalten und Buflen nicht 0, dann ist die TCP Header Checksum false. Das überprüfe ich mit Ethereal (Checksum: 0xeec5 [incorrect, shold be 0x8d61]).

    Ist jedoch Buf leer, und Buflen 0 dann ist die TCP Header Checksum richtig (Checksum: 0xeec5 [correct]).

    Bei dedarf kann ich dir mein Projekt mailen.

    LG



  • Wenn Du Dir Deinen Code anschaust, wirst Du feststellen, dass der Inhalt des Buffers nicht in Deine Checksumme eingeht. Also ist auch der Wert mit und ohne Buffer Inhalt gleich (genau wie Du es beschreibst).

    Dein Code:
    1. Kopiere FORCSUM nach b
    2. Kopiere TCPHDR dahinter
    3. Berechne Checksumme aus den beiden
    4. Kopiere IPHDR nach b
    5. Kopiere TCPHDR dahinter
    6. Berechne Checksumme aus IPHDR und TCPHDR
    7. Kopiere Daten hinter TCPHDR

    Die Checksumme ist also unabhängig von den Daten.
    Du scheinst aber folgendes zu wollen
    1. Kopiere FORCSUM nach b
    2. Kopiere TCPHDR dahinter
    3. Kopiere Daten hinter TCPHDR
    4. Berechne Checksumme aus 1-3
    5. Kopiere IPHDR nach b
    6. Kopiere TCPHDR dahinter
    7. Kopiere Daten hinter TCPHDR
    8. Berechne Checksumme aus IPHDR und TCPHDR und Daten ???

    Davon mal abgesehen, sieht die doppelte Nutzung des Buffers b relativ gefährlich aus. Du kopierst einmal sizeof( TCPHDR) + sizeof( FORCSUM) Bytes nach b und einmal sizeof( TCPHDR) + sizeof( IPHDR) + buflen Daten nach b. Ist sichergestellt, dass sizeof( TCPHDR) + sizeof( IPHDR) + buflen > sizeof( TCPHDR) + sizeof( FORCSUM) ist? Wenn die Bedingung verletzt ist, gibt es eine Zugriffsverletzung. Wenn Du das wie oben beschrieben machst, wird die Bedingung noch härter: sizeof( TCPHDR) + sizeof( IPHDR) + buflen > sizeof( TCPHDR) + sizeof( FORCSUM) + buflen
    Du solltest sicherheitshalber das Maximum aus beiden berechnen und entsprechend Speicher reservieren.
    BTW, eventuell wäre es zu überlegen std::vector einzusetzen.



  • Hi niemand

    Ich habe deine Antwort gründlich studiert. Hier mein neuer Code:

    //Überprüfung
    
    	if (sizeof(ip) >  sizeof(forcsum)) {
    
    	//forcsum in den buffer kopieren
    
    	memcpy(b, &forcsum, sizeof(forcsum)); 
    
    	//tcp hinter forcsum in den buffer kopieren
    
    	memcpy(b+sizeof(forcsum), &tcp, sizeof(tcp));
    
    	//daten hinter forcsum und tcp in den buffer kopieren
    
    	memcpy(b+sizeof(forcsum)+sizeof(tcp), buf, buflen);
    
    	//TCP Checksum berechen
    
    	tcp.checksum = csum(b, sizeof(forcsum)+sizeof(tcp)+buflen); 
    
    	//ip in den buffer kopieren
    
    	memcpy(b, &ip, sizeof(ip));
    
    	//tcp hinter ip in den buffer kopieren
    
    	memcpy(b+sizeof(ip), &tcp, sizeof(tcp));
    
    	//daten hinter ip und tcp in den buffer kopieren
    
    	memcpy(b+sizeof(ip)+sizeof(tcp), buf, buflen);
    
    	//IP Checksum berechnen
    
    	ip.checksum = csum(b, sizeof(ip)+sizeof(tcp)+buflen);
    
    	//senden
    
    	iErr = sendto(fd, b, lenTotal, 0,(struct sockaddr*)&to, sizeof(to));
    
    	}
    

    Leider stimmt die Checksumme immer noch nicht 🙄. Der TCP Checksumwert ist zwar nun nicht mehr der selbe, wenn Buf Daten enthält oder leer ist, trotzdem erhalte ich wieder eine Meldung incorrect Checksum, should be 0x8656 in Ethereal.

    LG Joe



  • Hi

    Ich habe nun folgendes festgestellt: wenn buf = "a" dann ist die Checksumme genau um 1 falsch (0x86c5 [incorrect, should be 0x86c4]). Wenn buf = "aa" dann ist die Checksumme um 2 falsch (0x865d [incorrect, should be 0x865b]).

    LG



  • In Deiner Checksum Berechnung ist ein kleiner Fehler:

    int csum(const void *bufv, int length) 
     {
        const unsigned short *buf = (const unsigned short *)bufv; 
        unsigned long result = 0;
    
        while (length > 1) {
            result += *(buf++);  
            length  -= sizeof(*buf);
        }
        if (length) result += *(unsigned char*)buf;  
        while( result >> 16) {
          result = (result >> 16) + (result & 0xFFFF); 
        }
        result = (~result);
    
        return (int)result;
     }
    

    Mal gespannt, ob das den Fehler beseitigt.

    Die Kommentare waren übrigens falsch; sollten aus dem Code entfernt werden.
    Ansonsten findest Du Erklärungen dazu im RFC 1071.



  • Hi

    Leider nein. Die Checksumme ist immer noch um die Bufferlänge falsch. Bei einem Buffer von einem Zeichen 0x86c5 [incorrect, should be 0x86c4], bei zwei Zeichen 0x8661 [incorrect, should be 0x865f].

    LG



  • Setzt sich dass fort, d.h. bei 3 Zeichen eine Abweichung um 3?
    Ich wüsste allerdings nicht, wie das entstehen sollte.
    Wenn ich richtig gerechnet habe, ist die Differenz zwischen den beiden Werten, die Du für 'a' und 'aa' angibst 105 statt 97 (kleine 'a'). Hast Du tatsächlich mit 'a' getestet?
    Bei leerem Buffer ist die checksum immer noch richtig?
    Wenn ja, schick noch mal die Daten, die Du für
    1. leeren Buffer
    2. Buffer mit 'a'
    3. Buffer mit 'aa'
    4. Buffer mit 'aaa'

    bekommst. Vielleicht kann ich daran was erkennen.



  • Buffer = "" -> Checksum: 0xeec5 [correct]
    Buffer = "a" -> Checksum: 0x8dc5 [incorrect, should be 0x8dc4]
    Buffer = "aa" -> Checksum: 0x8d64 [incorrect, should be 0x8d62]
    Buffer = "aaa" -> Checksum: 0x2c64 [incorrect, should be 0x2c61]



  • Ich habe das jetzt mit 2 anderen RFC 1071 Checksum-Berechnungen verglichen und bekomme dieselben Ergebnisse wie Deine Routine.
    Hmm, offensichtlich muss das Problem noch irgendwas anderes sein (ich kenne mich nicht wirklich mit Raw Sockets aus).
    So zum Ausprobieren würde ich einfach mal die Länge des Buffers am Ende auf die Checksum addieren, dann müsste es Deiner Beobachtung nach ja stimmen. Eine Lösung ist das aber nicht.



  • Du kannst doch mit Ethereal einen Dump von dem Paket mal posten. Da müsste man doch genau sehen, was in dem Paket drinsteht und dann probieren wir es damit mal.



  • tcp.checksum = csum(b, sizeof(forcsum)+sizeof(tcp)+buflen)+buflen;
    

    buffer = "" -> Checksum: 0xeec5 [correct]
    buffer = "a" -> Checksum: 0x8ec5 [incorrect, should be 0x8dc4]
    buffer = "aa" -> Checksum: 0x8f64 [incorrect, should be 0x8f64]
    buffer = "aaa" -> Checksum: 0x2f64 [incorrect, should be 0x2c61]

    Hm ich verstehe das nicht! Obwohl ich buflen dazu addiert habe, stimmt das immer noch nicht :(!



  • Dump mit Buffer = "aa"

    Frame 179 (60 bytes on wire, 60 bytes captured)
    Arrival Time: Sep 13, 2005 21:35:26.134344000
    Time delta from previous packet: 2.572850000 seconds
    Time since reference or first frame: 2.572850000 seconds
    Frame Number: 179
    Packet Length: 60 bytes
    Capture Length: 60 bytes
    Protocols in frame: eth:ip:tcp:data
    Ethernet II, Src: 192.168.2.100 (00:e0:18:b9:13:8f), Dst: 192.168.2.99 (00:a0:cc:d3:c6:c6)
    Destination: 192.168.2.99 (00:a0:cc:d3:c6:c6)
    Source: 192.168.2.100 (00:e0:18:b9:13:8f)
    Type: IP (0x0800)
    Trailer: 61206469
    Internet Protocol, Src: 192.168.2.100 (192.168.2.100), Dst: 192.168.2.99 (192.168.2.99)
    Version: 4
    Header length: 20 bytes
    Differentiated Services Field: 0x00 (DSCP 0x00: Default; ECN: 0x00)
    Total Length: 42
    Identification: 0x0100 (256)
    Flags: 0x00
    Fragment offset: 0
    Time to live: 128
    Protocol: TCP (0x06)
    Header checksum: 0xb3b6 [correct]
    Source: 192.168.2.100 (192.168.2.100)
    Destination: 192.168.2.99 (192.168.2.99)
    Transmission Control Protocol, Src Port: 1024 (1024), Dst Port: 24 (24), Seq: 0, Ack: 0, Len: 2
    Source port: 1024 (1024)
    Destination port: 24 (24)
    Sequence number: 0 (relative sequence number)
    Next sequence number: 2 (relative sequence number)
    Header length: 20 bytes
    Flags: 0x0002 (SYN)
    Window size: 64240
    Checksum: 0x8f64 [incorrect, should be 0x8d62]
    Data (2 bytes)

    0000 00 a0 cc d3 c6 c6 00 e0 18 b9 13 8f 08 00 45 00 ..............E.
    0010 00 2a 01 00 00 00 80 06 b3 b6 c0 a8 02 64 c0 a8 .*...........d..
    0020 02 63 04 00 00 18 0d 8e 2e 6e 00 00 00 00 50 02 .c.......n....P.
    0030 fa f0 8f 64 00 00 61 61 61 20 64 69 ...d..aaa di



  • Bei der Berechnung ändert sich nur das Hi-Byte (und natürlich subtrahieren anstatt addieren). Müsste also:

    tcp.checksum = csum(b, sizeof(forcsum)+sizeof(tcp)+buflen)- (buflen << 8);
    

    sein.

    Bei dem Paket sehe ich leider zumindest nichts offensichtliches.



  • Weshalb muss ich hier nur das HiByte subtrahieren?



  • Little/Big Endian?
    Wenn Du 1 auf Deinen Checksumme addierst und aus 0x8dc5 jetzt 0x8ec5 wird, heisst dass wohl, dass deine Zahl in Deinem Programm 0xc58d war. Ansonsten ist mir nicht klar, wie aus den Werten die Du vor dem Addieren der Bufferlänge gepostet hast, die Werte nach der Addition werden sollten.

    Bei der Berechnung der Checksumme könntest Du den Buffer mitausgeben. Der sollte mit dem von Ethereal ausgegebenen Paket identisch sein (plus Header). Vielleicht siehst Du ja dort eine Abweichung.



  • was definierst du als zahl in meinem Program? Wie kommst du von 0x8dc5 und 0x8ec5 auf 0xc58d? Verstehe immer noch nicht richtig weshalb ich nur die 8bit des Integerwertes subtrahieren muss?

    Lg Joe


Anmelden zum Antworten