ICMP是用来对网络状况进行反馈的协议,可以用来侦测网络状态或检测网路错误。
限于当前Golang在网络编程方面的代码稀缺,资料甚少,所以分享一个用Golang来构造ICMP数据包并发送ping程序的echo消息的实例。
RFC792定义的echo数据包结构:
0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Type | Code | Checksum | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Identifier | Sequence Number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Data ... +-+-+-+-+-
package main import ( "bytes" "encoding/binary" "fmt" "net" ) type ICMP struct { Type uint8 Code uint8 Checksum uint16 Identifier uint16 SequenceNum uint16 } func CheckSum(data []byte) uint16 { var ( sum uint32 length int = len(data) index int ) for length > 1 { sum += uint32(data[index])<<8 + uint32(data[index+1]) index += 2 length -= 2 } if length > 0 { sum += uint32(data[index]) } sum += (sum >> 16) return uint16(^sum) } func main() { var ( icmp ICMP laddr net.IPAddr = net.IPAddr{IP: net.ParseIP("192.168.137.111")} //***IP地址改成你自己的网段*** raddr net.IPAddr = net.IPAddr{IP: net.ParseIP("192.168.137.1")} ) //如果你要使用网络层的其他协议还可以设置成 ip:ospf、ip:arp 等 conn, err := net.DialIP("ip4:icmp", &laddr, &raddr) if err != nil { fmt.Println(err.Error()) return } defer conn.Close() //开始填充数据包 icmp.Type = 8 //8->echo message 0->reply message icmp.Code = 0 icmp.Checksum = 0 icmp.Identifier = 0 icmp.SequenceNum = 0 var ( buffer bytes.Buffer ) //先在buffer中写入icmp数据报求去校验和 binary.Write(&buffer, binary.BigEndian, icmp) icmp.Checksum = CheckSum(buffer.Bytes()) //然后清空buffer并把求完校验和的icmp数据报写入其中准备发送 buffer.Reset() binary.Write(&buffer, binary.BigEndian, icmp) if _, err := conn.Write(buffer.Bytes()); err != nil { fmt.Println(err.Error()) return } fmt.Printf("send icmp packet success!") }
执行后可以用wireshark抓下包看看,可以看到远方网关传来了reply响应:
看看我们构造的ICMP是否正确:
如果转载请注明出处:http://blog.csdn.net/gophers/article/details/21481447
有疑问加站长微信联系(非本文作者)