web-dev-qa-db-fra.com

Calcul de la somme de contrôle UDP

La structure d'en-tête UDP définie dans /usr/include/netinet/udp.h est la suivante

struct udphdr
{
  u_int16_t source;
  u_int16_t dest;
  u_int16_t len;
  u_int16_t check;
};

Quelle valeur est stockée dans le champ de contrôle de l'en-tête? Comment vérifier si la somme de contrôle est correcte? Je voulais dire sur quelles données la somme de contrôle est-elle calculée? (Est-ce juste l'en-tête udp ou l'en-tête udp plus la charge utile qui le suit?)

Merci.

23
Deepak

La somme de contrôle UDP est effectuée sur l'ensemble de la charge utile, et les autres champs de l'en-tête, et certains champs de l'en-tête IP. Un pseudo-en-tête est construit à partir de l'en-tête IP afin d'effectuer le calcul (qui se fait sur ce pseudo-en-tête, l'en-tête UDP et la charge utile). La raison pour laquelle le pseudo-en-tête est inclus est d'attraper les paquets qui ont été routés vers la mauvaise adresse IP.

Fondamentalement, à la réception, tous les mots de 16 bits des en-têtes plus la zone de données sont additionnés (habillage à 16 bits) et le résultat est vérifié par rapport à 0xffff.

Côté envoi, c'est un peu plus complexe. La somme du complément à un est effectuée sur toutes les valeurs de 16 bits, puis le complément à un (c'est-à-dire inverser tous les bits) est pris de cette valeur pour remplir le champ de somme de contrôle (avec la condition supplémentaire qu'une somme de contrôle calculée de zéro sera changée en tous un bit).

La somme du complément à un n'est pas juste la somme de toutes les valeurs du complément à un. C'est un peu plus complexe.

Fondamentalement, vous avez un accumulateur 16 bits en cours d'exécution commençant à zéro et vous ajoutez chaque valeur 16 bits à cela. Chaque fois que l'un de ces ajouts entraîne un report, la valeur est enroulée autour et vous ajoutez à nouveau un à la valeur. Cela prend efficacement le bit de report de l'addition 16 bits et l'ajoute à la valeur.


En passant, et c'est de la pure conjecture de ma part, mais cela pourrait probablement être fait efficacement en utilisant l'instruction ADC (ajouter avec report) plutôt que ADD (assez surprenant, ajouter), ou toutes les instructions équivalentes étaient disponibles sur votre CPU à l'époque.

S'il n'y avait pas de report, ADC ajouterait simplement le bit zéro du report. À l'époque où ce truc était fait (et oui, malheureusement, je suis aussi vieux), la mémoire était bien plus une contrainte que la vitesse, pas si de nos jours, donc économiser quelques octets dans votre code pourrait bien vous élever au niveau de demi-dieu-empereur-de-l'univers :-)


Notez que vous n'avez jamais eu à vous soucier du report la deuxième fois (ou un report de deux avec le prochain ADC si vous utilisez cette méthode mentionnée dans le paragraphe précédent) puisque les deux plus grandes valeurs 16 bits, une fois additionné, produire (tronqué de 0x1fffe) 0xfffe - en ajouter un ne provoquera jamais un autre report.

Une fois que la somme du complément calculé est calculée, a ses bits inversés et est insérée dans le paquet, ce qui provoquera le calcul à l'extrémité de réception pour produire 0xffff, en supposant bien sûr qu'il n'y ait aucune erreur de transmission.

Il convient de noter que la charge utile est toujours remplie pour garantir un nombre entier de mots de 16 bits. Si elle était complétée, le champ de longueur vous indique la longueur réelle.

RFC768 est la spécification qui détaille cela.

37
paxdiablo

Un exemple agréable et facile à comprendre de calcul de la somme de contrôle UDP est fait par Gerd Hoffmann.

Vous pouvez google pour "net-checksum.c Gerd Hoffmann" ou consulter le fichier ici:

https://Gist.github.com/fxlv/81209bbd150abfeaceb1f85ff076c9f

Vous pouvez utiliser la fonction net_checksum_tcpudp, Lui donner la longueur de la charge utile UDP, les IP proto, src et dst, puis la charge utile UDP elle-même et elle fera la bonne chose.

À la fin, vous devez appeler htons() sur la somme de contrôle et vous êtes bon.

1
fxlv

Je cherchais sur le net un code qui calculera l'en-tête udp (avec l'en-tête pseudo ip comme mentionné ci-dessus).

Enfin, j'ai trouvé le paquet dhclient open-bsd:

https://github.com/openbsd/src/blob/master/sbin/dhclient/packet.c

découvrez la fonction assemble_udp_ip_header()

0
Guy L