ICMP是用来对网络状况进行反馈的协议,可以用来侦测网络状态或检测网路错误。
限于当前Golang在网络编程方面的代码稀缺,资料甚少,所以分享一个用Golang来构造ICMP数据包并发送ping程序的echo消息的实例。
RFC定义的echo数据包结构:
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Type
Code
Checksum
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Identifier
SequenceNumber
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Data...+-+-+-+-+-
代码:
packagemainimport( "bytes" "encoding/binary" "fmt" "net")typeICMPstruct{ Typeuint8 Codeuint8 Checksumuint16 Identifieruint16 SequenceNumuint16}funcCheckSum(data[]byte)uint16{ var( sumuint32 lengthint=len(data) indexint ) forlength1{ sum+=uint32(data[index])8+uint32(data[index+1]) index+=2 length-=2 } iflength0{ sum+=uint32(data[index]) } sum+=(sum16) returnuint16(^sum)}funcmain(){ var( icmpICMP laddrnet.IPAddr=net.IPAddr{IP:net.ParseIP("...")}//***IP地址改成你自己的网段*** raddrnet.IPAddr=net.IPAddr{IP:net.ParseIP("...1")} ) //如果你要使用网络层的其他协议还可以设置成ip:ospf、ip:arp等 conn,err:=net.DialIP("ip4:icmp",laddr,raddr) iferr!=nil{ fmt.Println(err.Error()) return } deferconn.Close() //开始填充数据包 icmp.Type=8//8-echomessage0-replymessage icmp.Code=0 icmp.Checksum=0 icmp.Identifier=0 icmp.SequenceNum=0 var( bufferbytes.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("sendicmppacketsuccess!")}
执行后可以用wireshark抓下包看看,可以看到远方网关传来了reply响应:
看看我们构造的ICMP是否正确: