


Comment puis-je m'assurer de l'exactitude des paquets IPv4 créés pour l'implémentation native du « ping » ?
l'éditeur php Strawberry vous présentera comment garantir l'exactitude des paquets IPv4 créés pour l'implémentation locale du "ping". En communication réseau, utilisez la commande Ping pour tester la connectivité entre les hôtes. Cependant, dans les applications pratiques, nous devons garantir l’exactitude des paquets de données IPv4 envoyés pour éviter les erreurs ou les pertes. À cette fin, nous pouvons prendre certaines mesures pour garantir l’exactitude et l’exhaustivité des paquets de données afin de garantir l’obtention de résultats Ping précis. Examinons ensuite ces mesures.
Contenu des questions
Aperçu
J'ai travaillé sur un projet parallèle qui est essentiellement un outil de dépannage réseau. Mon objectif est d'approfondir ma compréhension des bases des réseaux et de maîtriser l'utilisation des outils de dépannage fournis par le système d'exploitation.
Il s'agit d'une application CLI qui obtiendra le nom d'hôte et tentera de diagnostiquer le problème le cas échéant. Le plan est d'implémenter d'abord ping et traceroute, puis d'implémenter progressivement d'autres outils en fonction de mon niveau de confort.
Cependant, mon implémentation de ping n'est pas précise car les paquets IPv4 sont mal formés. C’est ce que Wireshark a à dire.
1 0.000000 192.168.0.100 142.250.195.132 ICMP 300 Unknown ICMP (obsolete or malformed?)
Code
C'est ainsi que j'ai réalisé ping
<code>package ping import ( "encoding/json" "net" "github.com/pkg/errors" ) var ( IcmpProtocolNumber uint8 = 1 IPv4Version uint8 = 4 IPv4IHL uint8 = 5 ICMPHeaderType uint8 = 8 ICMPHeaderSubtype uint8 = 0 ) type NativePinger struct { SourceIP string DestIP string } type ICMPHeader struct { Type uint8 Code uint8 Checksum uint16 } type ICMPPacket struct { Header ICMPHeader Payload interface{} } type IPv4Header struct { SourceIP string DestinationIP string Length uint16 Identification uint16 FlagsAndOffset uint16 Checksum uint16 VersionIHL uint8 DSCPAndECN uint8 TTL uint8 Protocol uint8 } type IPv4Packet struct { Header IPv4Header Payload *ICMPPacket } func (p *NativePinger) createIPv4Packet() (*IPv4Packet, error) { versionIHL := (IPv4Version << 4) | IPv4IHL icmpPacket := &ICMPPacket{ Header: ICMPHeader{ Type: ICMPHeaderType, Code: ICMPHeaderSubtype, }, } ipv4Packet := &IPv4Packet{ Header: IPv4Header{ VersionIHL: versionIHL, DSCPAndECN: 0, Identification: 0, FlagsAndOffset: 0, TTL: 64, Protocol: IcmpProtocolNumber, SourceIP: p.SourceIP, DestinationIP: p.DestIP, }, Payload: icmpPacket, } ipv4Packet.Header.Length = 40 bytes, err := json.Marshal(icmpPacket) if err != nil { return nil, errors.Wrapf(err, "error converting ICMP packet to bytes") } icmpPacket.Header.Checksum = calculateChecksum(bytes) bytes, err = json.Marshal(ipv4Packet) if err != nil { return nil, errors.Wrapf(err, "error converting IPv4 packet to bytes") } ipv4Packet.Header.Checksum = calculateChecksum(bytes) return ipv4Packet, nil } func calculateChecksum(data []byte) uint16 { sum := uint32(0) // creating 16 bit words for i := 0; i < len(data)-1; i++ { word := uint32(data[i])<<8 | uint32(data[i+1]) sum += word } if len(data)%2 == 1 { sum += uint32(data[len(data)-1]) } // adding carry bits with lower 16 bits for (sum >> 16) > 0 { sum = (sum & 0xffff) + (sum >> 16) } // taking one's compliment checksum := ^sum return uint16(checksum) } func (p *NativePinger) ResolveAddress(dest string) error { ips, err := net.LookupIP(dest) if err != nil { return errors.Wrapf(err, "error resolving address of remote host") } for _, ip := range ips { if ipv4 := ip.To4(); ipv4 != nil { p.DestIP = ipv4.String() } } // The destination address does not need to exist as unlike tcp, udp does not require a handshake. // The goal here is to retrieve the outbound IP. Source: https://stackoverflow.com/a/37382208/3728336 // conn, err := net.Dial("udp", "8.8.8.8:80") if err != nil { return errors.Wrapf(err, "error resolving outbound ip address of local machine") } defer conn.Close() p.SourceIP = conn.LocalAddr().(*net.UDPAddr).IP.String() return nil } func (p *NativePinger) Ping(host string) error { if err := p.ResolveAddress(host); err != nil { return errors.Wrapf(err, "error resolving source/destination addresses") } packet, err := p.createIPv4Packet() if err != nil { return errors.Wrapf(err, "error creating IPv4Packet") } conn, err := net.Dial("ip4:icmp", packet.Header.DestinationIP) if err != nil { return errors.Wrapf(err, "error eshtablishing connection with %s", host) } defer conn.Close() bytes, err := json.Marshal(packet) if err != nil { return errors.Wrapf(err, "error converting IPv4 packet into bytes") } _, err = conn.Write(bytes) if err != nil { return errors.Wrapf(err, "error sending ICMP echo request") } buff := make([]byte, 2048) _, err = conn.Read(buff) // The implementation doesn't proceed beyond this point if err != nil { return errors.Wrapf(err, "error receiving ICMP echo response") } return nil } </code>
Introspection
Je ne sais pas si la malformation du paquet est causée par une seule cause ou par plusieurs causes. Je pense que le problème réside à l'un de ces deux endroits (ou les deux ?) :
- Le calcul de la longueur de l'en-tête est incorrect J'ai calculé manuellement la longueur
40 字节(wordsize = 4 字节)
. Écrivez les champs de structure dans un ordre qui empêche toute corruption de la structure. Je me réfère à cette source pour obtenir des informations sur différents types de tailles.
<code>// 1 word (4 bytes) type ICMPHeader struct { Type uint8 // 8 bit Code uint8 // 8 bit Checksum uint16 // 16 bit } // 3 words (3*4 = 12 bytes) type ICMPPacket struct { Header ICMPHeader // 1 word Payload interface{} // 2 words } // 7 words (7*4 = 28 bytes) type IPv4Header struct { // Below group takes 4 words (each string takes 2 words) SourceIP string DestinationIP string // Following group takes 2 words (each 16 bits) Length uint16 Identification uint16 FlagsAndOffset uint16 Checksum uint16 // Below group takes 1 word (each takes 8 bits) VersionIHL uint8 DSCPAndECN uint8 TTL uint8 Protocol uint8 } // 10 words (40 bytes) type IPv4Packet struct { Header IPv4Header // 7 words as calculated above Payload ICMPPacket // 3 words as calculated above } </code>
- Le calcul de la somme de contrôle est incorrectJ'ai implémenté l'algorithme de somme de contrôle Internet. Si ce n'est pas ce que je suis censé faire ici, dites-le-moi s'il vous plaît.
Il manque certaines parties dans l'implémentation, telles que la configuration des décomptes, l'attribution de numéros de séquence aux paquets, etc., mais avant cela, l'implémentation de base doit être corrigée, c'est-à-dire la réception des réponses pour les paquets ICMP ECHO. C'est bon de savoir où j'ai commis l'erreur.
Merci !
Mise à jour le 24 août 2023
En tenant compte des conseils que j'ai reçus dans les commentaires, j'ai mis à jour le code pour corriger l'ordre des octets et utiliser des octets bruts pour l'adresse source, l'adresse de destination. Cependant, cela ne résout pas le problème à lui seul, le paquet est toujours mal formé, il doit donc se passer autre chose.
Solution
Je l'ai enfin fait fonctionner. Je devrais parler de quelques problèmes avec le code.
Problème de sérialisation
Comme Andy l'a souligné à juste titre, j'envoie un objet JSON, pas des octets bruts dans l'ordre des octets du réseau. Cela a été corrigé en utilisant binary.Write(buf, binary.BigEndian, field)
Cependant, comme cette méthode ne fonctionne qu'avec des valeurs de taille fixe, je dois le faire pour chaque champ de structure, ce qui rend le code répétitif et quelque peu laid.
L'optimisation de la structure et la sérialisation sont des problèmes différents.
Je sais convertir la valeur du champ Version
和 IHL
字段组合在一起以优化内存的做法,这就是为什么我的结构中有这个单个字段 VersionIHL
。但是在序列化时,字段值(在本例中为 4 和 5)将被单独序列化,而我没有这样做。相反,我将整个 VersionIHL
en octets.
En conséquence, je me suis retrouvé à envoyer un octet inattendu 69
,该字节流来自将 4
和 5
组合在一起的 0100 0101
dans le flux d'octets.
Paquet ICMP incomplet
Ma structure ICMP ne contient pas de champs d'identifiant et de numéro de séquence. Les informations fournies dans la section d'en-tête du datagramme ICMP sur Wikipedia semblent un peu génériques. Cependant, j'ai trouvé les détails sur la page RFC (page 14) beaucoup plus perspicaces.
Cela semble étrange compte tenu de l'importance du numéro de série de l'utilitaire ping. Lors de la mise en œuvre, je me suis souvent demandé où le numéro de série était placé de manière appropriée dans le code. Ce n'est que lorsque je suis tombé sur la page RFC que j'ai eu une idée claire du moment et de l'endroit où incorporer les numéros de série.
Pour tous ceux qui pourraient être intéressés, voici le code de fonctionque j'ai mis en place.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Outils d'IA chauds

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

AI Hentai Generator
Générez AI Hentai gratuitement.

Article chaud

Outils chauds

Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Le Bitcoin, en tant que crypto-monnaie, a connu une volatilité importante sur le marché depuis sa création. Cet article fournira un aperçu du prix historique du Bitcoin depuis sa naissance pour aider les lecteurs à comprendre ses tendances de prix et ses moments clés. En analysant les données historiques sur les prix du Bitcoin, nous pouvons comprendre l'évaluation de sa valeur par le marché, les facteurs affectant ses fluctuations et fournir une base pour les décisions d'investissement futures.

Depuis sa création en 2009, le prix de Bitcoin a connu plusieurs fluctuations majeures, passant à 69 044,77 $ en novembre 2021 et tombant à 3191,22 $ en décembre 2018. En décembre 2024, le dernier prix a dépassé 100 204 $.

Prix USD Bitcoin en temps réel Facteurs qui affectent le prix du bitcoin Indicateurs pour prédire les prix des futurs bitcoins Voici quelques informations clés sur le prix du bitcoin en 2018-2024:

Oui, la production de pages H5 est une méthode de mise en œuvre importante pour le développement frontal, impliquant des technologies de base telles que HTML, CSS et JavaScript. Les développeurs construisent des pages H5 dynamiques et puissantes en combinant intelligemment ces technologies, telles que l'utilisation du & lt; Canvas & gt; Tag pour dessiner des graphiques ou utiliser JavaScript pour contrôler le comportement d'interaction.

La méthode de personnalisation des symboles de redimension dans CSS est unifiée avec des couleurs d'arrière-plan. Dans le développement quotidien, nous rencontrons souvent des situations où nous devons personnaliser les détails de l'interface utilisateur, tels que l'ajustement ...

Comment utiliser JavaScript ou CSS pour contrôler le haut et la fin de la page dans les paramètres d'impression du navigateur. Dans les paramètres d'impression du navigateur, il existe une option pour contrôler si l'écran est ...

Concernant les raisons et les solutions pour l'affichage mal aligné des éléments de blocage en ligne. Lors de la mise en page de la page Web, nous rencontrons souvent des problèmes d'affichage apparemment étranges. Comparer...

Le problème de l'ouverture des conteneurs en raison d'une omission excessive du texte sous disposition flexible et de solutions est utilisé ...
