用Golang自己构造ICMP数据包 - 疯狂奔跑

时间:2024-02-19 07:01:13

用Golang自己构造ICMP数据包

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 ...
   +-+-+-+-+-

 

 

代码:

 

[java] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. package main  
  2.   
  3. import (  
  4.     "bytes"  
  5.     "encoding/binary"  
  6.     "fmt"  
  7.     "net"  
  8. )  
  9.   
  10. type ICMP struct {  
  11.     Type        uint8  
  12.     Code        uint8  
  13.     Checksum    uint16  
  14.     Identifier  uint16  
  15.     SequenceNum uint16  
  16. }  
  17.   
  18. func CheckSum(data []byte) uint16 {  
  19.     var (  
  20.         sum    uint32  
  21.         length int = len(data)  
  22.         index  int  
  23.     )  
  24.     for length > 1 {  
  25.         sum += uint32(data[index])<<8 + uint32(data[index+1])  
  26.         index += 2  
  27.         length -= 2  
  28.     }  
  29.     if length > 0 {  
  30.         sum += uint32(data[index])  
  31.     }  
  32.     sum += (sum >> 16)  
  33.   
  34.     return uint16(^sum)  
  35. }  
  36.   
  37. func main() {  
  38.     var (  
  39.         icmp  ICMP  
  40.         laddr net.IPAddr = net.IPAddr{IP: net.ParseIP("192.168.137.111")}  //***IP地址改成你自己的网段***  
  41.         raddr net.IPAddr = net.IPAddr{IP: net.ParseIP("192.168.137.1")}  
  42.     )  
  43.     //如果你要使用网络层的其他协议还可以设置成 ip:ospf、ip:arp 等  
  44.     conn, err := net.DialIP("ip4:icmp", &laddr, &raddr)  
  45.     if err != nil {  
  46.         fmt.Println(err.Error())  
  47.         return  
  48.     }  
  49.     defer conn.Close()  
  50.   
  51.     //开始填充数据包  
  52.     icmp.Type = //8->echo message  0->reply message  
  53.     icmp.Code = 0  
  54.     icmp.Checksum = 0  
  55.     icmp.Identifier = 0  
  56.     icmp.SequenceNum = 0  
  57.   
  58.     var (  
  59.         buffer bytes.Buffer  
  60.     )  
  61.     //先在buffer中写入icmp数据报求去校验和  
  62.     binary.Write(&buffer, binary.BigEndian, icmp)  
  63.     icmp.Checksum = CheckSum(buffer.Bytes())  
  64.     //然后清空buffer并把求完校验和的icmp数据报写入其中准备发送  
  65.     buffer.Reset()  
  66.     binary.Write(&buffer, binary.BigEndian, icmp)  
  67.   
  68.     if _, err := conn.Write(buffer.Bytes()); err != nil {  
  69.         fmt.Println(err.Error())  
  70.         return  
  71.     }  
  72.     fmt.Printf("send icmp packet success!")  
  73. }  

 


执行后可以用wireshark抓下包看看,可以看到远方网关传来了reply响应:

 

看看我们构造的ICMP是否正确:

 

 

 

如果转载请注明出处:http://blog.csdn.NET/gophers/article/details/21481447