Rumah > Artikel > pembangunan bahagian belakang > Bagaimanakah cara saya memastikan ketepatan paket IPv4 yang dibuat untuk pelaksanaan "ping" asli?
editor php Strawberry akan memperkenalkan kepada anda cara memastikan ketepatan paket IPv4 yang dibuat untuk pelaksanaan "ping" tempatan. Dalam komunikasi rangkaian, gunakan arahan Ping untuk menguji ketersambungan antara hos. Walau bagaimanapun, dalam aplikasi praktikal, kita perlu memastikan ketepatan paket data IPv4 yang dihantar untuk mengelakkan ralat atau kehilangan. Untuk tujuan ini, kami boleh mengambil beberapa langkah untuk memastikan ketepatan dan kesempurnaan paket data untuk memastikan kami mendapat keputusan Ping yang tepat. Seterusnya, mari kita lihat langkah-langkah ini.
Saya telah mengusahakan projek sampingan yang pada asasnya merupakan alat penyelesaian masalah rangkaian. Matlamat saya adalah untuk mendalami pemahaman saya tentang asas rangkaian dan menjadi mahir dalam menggunakan alat penyelesaian masalah yang disediakan oleh sistem pengendalian.
Ini adalah aplikasi CLI yang akan mendapat nama hos dan cuba mendiagnosis masalah jika ada. Rancangannya adalah untuk melaksanakan ping dan traceroute terlebih dahulu dan kemudian secara beransur-ansur melaksanakan alat lain berdasarkan tahap keselesaan saya.
Walau bagaimanapun, pelaksanaan ping saya tidak tepat kerana paket IPv4 rosak. Inilah yang dikatakan wireshark.
1 0.000000 192.168.0.100 142.250.195.132 ICMP 300 Unknown ICMP (obsolete or malformed?)
Beginilah cara saya mencapai 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>
Saya tidak pasti sama ada kecacatan paket disebabkan oleh satu punca atau berbilang punca. Saya rasa masalahnya terletak pada salah satu daripada dua tempat ini (atau kedua-duanya?):
40 字节(wordsize = 4 字节)
. Tulis medan struktur dalam susunan yang menghalang rasuah struktur.
Saya merujuk kepada sumber ini untuk maklumat tentang pelbagai jenis saiz. <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>
Terdapat beberapa bahagian yang tiada dalam pelaksanaan, seperti mengkonfigurasi kiraan, menetapkan nombor jujukan pada paket, dsb., tetapi sebelum itu pelaksanaan asas perlu diperbaiki, iaitu menerima respons untuk paket ICMP ECHO. Baik untuk mengetahui di mana saya membuat kesilapan.
Terima kasih!
Mengambil kira nasihat yang saya dapat dalam ulasan, saya telah mengemas kini kod untuk membetulkan susunan bait dan menggunakan bait mentah untuk alamat sumber, alamat destinasi. Walau bagaimanapun, itu sahaja tidak menyelesaikan masalah, paket masih cacat, jadi mesti ada perkara lain yang berlaku.
Saya akhirnya berjaya melakukannya. Saya harus bercakap tentang beberapa isu dengan kod.
Seperti yang Andy nyatakan dengan betul, saya menghantar objek JSON, bukan bait mentah dalam susunan bait rangkaian. Ini telah dibetulkan menggunakan binary.Write(buf, binary.BigEndian, field)
Walau bagaimanapun, memandangkan kaedah ini hanya berfungsi dengan nilai saiz tetap, saya perlu melakukan ini untuk setiap medan struct, menjadikan kod berulang dan agak hodoh.
Saya tahu untuk menukar nilai medan Version
和 IHL
字段组合在一起以优化内存的做法,这就是为什么我的结构中有这个单个字段 VersionIHL
。但是在序列化时,字段值(在本例中为 4 和 5)将被单独序列化,而我没有这样做。相反,我将整个 VersionIHL
kepada bait.
Akibatnya, saya mendapati diri saya menghantar oktet yang tidak dijangka 69
,该字节流来自将 4
和 5
组合在一起的 0100 0101
dalam strim bait.
Struktur ICMP saya tidak mengandungi medan pengecam dan nombor jujukan. Maklumat yang diberikan dalam bahagian pengepala datagram ICMP di Wikipedia terasa agak generik. Walau bagaimanapun, saya dapati butiran pada halaman RFC (halaman 14) lebih bernas.
Ini terasa pelik memandangkan kepentingan nombor siri utiliti ping. Semasa pelaksanaan, saya sering tertanya-tanya di mana nombor siri diletakkan dengan sewajarnya dalam kod. Sehinggalah saya terjumpa halaman RFC barulah saya mempunyai idea yang jelas tentang bila dan di mana untuk memasukkan nombor siri.
Bagi sesiapa yang mungkin berminat, inilah kod fungsiyang telah saya susun.
Atas ialah kandungan terperinci Bagaimanakah cara saya memastikan ketepatan paket IPv4 yang dibuat untuk pelaksanaan "ping" asli?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!