Die unter /usr/include/netinet/udp.h definierte UDP-Header-Struktur lautet wie folgt
struct udphdr
{
u_int16_t source;
u_int16_t dest;
u_int16_t len;
u_int16_t check;
};
Welcher Wert wird im Prüffeld des Headers gespeichert? Wie überprüfe ich, ob die Prüfsumme korrekt ist? Ich meinte, auf welchen Daten wird die Prüfsumme berechnet? (Ist es nur der udp-Header oder der udp-Header plus die darauf folgende Nutzlast?)
Vielen Dank.
Die UDP-Prüfsumme wird über die gesamte Nutzlast durchgeführt, und die anderen Felder in der Kopfzeile, und einige Felder aus dem IP-Header. Aus dem IP-Header wird ein Pseudo-Header konstruiert, um die Berechnung durchzuführen (die über diesen Pseudo-Header, den UDP-Header und die Payload erfolgt). Der Pseudo-Header wird eingefügt, um Pakete abzufangen, die an die falsche IP-Adresse weitergeleitet wurden.
Grundsätzlich werden auf der Empfangsseite alle 16-Bit-Wörter der Header plus Datenbereich zusammenaddiert (Wrapping bei 16 Bit) und das Ergebnis gegengeprüft 0xffff
.
Auf der Senderseite ist es etwas komplexer. Eine Einerkomplementsumme wird für alle 16-Bit-Werte durchgeführt, dann wird das Einerkomplement (d. h. alle Bits invertieren) von diesem Wert genommen, um das Prüfsummenfeld zu füllen (mit der zusätzlichen Bedingung, dass eine berechnete Prüfsumme von Null in alle geändert wird Eins-Bits).
Die Einerkomplementsumme ist nicht nur die Summe aller Einerkomplementwerte. Es ist etwas komplexer.
Grundsätzlich haben Sie einen laufenden 16-Bit-Akkumulator, der bei Null beginnt, und Sie addieren jeden 16-Bit-Wert dazu. Immer wenn eine dieser Additionen zu einem Übertrag führt, wird der Wert umgebrochen und Sie addieren erneut eins zum Wert. Dies nimmt effektiv das Übertragsbit der 16-Bit-Addition und addiert es zum Wert.
Nebenbei bemerkt, und dies ist eine reine Vermutung meinerseits, aber dies könnte wahrscheinlich durch die Verwendung von effizient durchgeführt werden ADC
(add with carry) Anweisung statt ADD
(überraschenderweise, fügen Sie hinzu) oder welche gleichwertigen Anweisungen zu diesem Zeitpunkt auf Ihrer CPU verfügbar waren.
Wenn es keinen Carry gäbe, ADC
würde nur das Nullbit aus dem Übertrag hinzufügen. In den Tagen, als diese Sachen gemacht wurden (und ja, leider, ich bin so alt), war der Arbeitsspeicher weit mehr eine Einschränkung als die Geschwindigkeit, was heutzutage nicht mehr so sehr der Fall ist, so dass das Speichern von ein paar Bytes in Ihrem Code Sie durchaus auf die Ebene des Halbgott-Imperators des Universums heben könnte :- )
Beachten Sie, dass Sie sich beim zweiten Mal keine Gedanken über das Tragen machen mussten (oder ein Tragen von zwei beim nächsten Mal). ADC
wenn Sie die im vorherigen Absatz erwähnte Methode verwenden), da die beiden größten 16-Bit-Werte, wenn sie summiert werden, (abgeschnitten von 0x1fffe
) 0xfffe
– Das Hinzufügen von einem wird niemals einen weiteren Übertrag verursachen.
Sobald die berechnete Einerkomplementsumme berechnet ist, ihre Bits invertiert und in das Paket eingefügt werden, bewirkt dies, dass die Berechnung am empfangenden Ende produziert wird 0xffff
vorausgesetzt natürlich, dass keine Übertragungsfehler auftreten.
Es ist erwähnenswert, dass die Nutzlast immer aufgefüllt wird, um sicherzustellen, dass es eine ganzzahlige Anzahl von 16-Bit-Wörtern gibt. Wenn es war aufgefüllt, das Längenfeld gibt Ihnen die tatsächliche Länge an.
RFC768 ist die Spezifikation, die dies detailliert.
Ein schönes und leicht verständliches Beispiel für die UDP-Prüfsummenberechnung stammt von Gerd Hoffmann.
Sie können nach “net-checksum.c Gerd Hoffmann” googeln oder sich die Datei hier ansehen:
https://gist.github.com/fxlv/81209bbd150abfeaceb1f85ff076c9f3
Sie können verwenden net_checksum_tcpudp
Funktion, geben Sie ihr die UDP-Nutzdatenlänge, proto, src und dst IPs und dann die UDP-Nutzdaten selbst und es wird das Richtige tun.
Am Ende muss man anrufen htons()
auf die Prüfsumme und gut ist.
Ich habe im Netz nach Code gesucht, der den UDP-Header berechnet (mit dem Pseudo-IP-Header, wie oben erwähnt).
Endlich habe ich das open-bsd dhclient packet.c gefunden:
https://github.com/openbsd/src/blob/master/sbin/dhclient/packet.c
schau dir mal die funktion an assemble_udp_ip_header()