构造填充用于PING的ICMP

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了构造填充用于PING的ICMP相关的知识,希望对你有一定的参考价值。

  ping命令是使用非常普遍的用于诊断网络连通性的工具,ping命令使用了icmp协议,icmp的完整拼写是Internet Control Message Protocol,即网络控制消息协议。


  在ICMP中关于用来探测网络连通性的部分有两个,一个是类型,一个是代码,通过这两个代码完成了echo request和echo reply,也就是请求和应答。当类型为8,代码为0时,icmp进行的是echo request,当类型为0,代码也为0时,icmp进行的是echo reply。


  通过抓包可以很容易的得到验证,打开Wireshark,然后在协议过滤的位置输入“icmp”,也就是查看关于ICMP的包。设置好Wireshark后,在cmd下ping其他主机的地址,然后观察Wireshark中的抓包情况,分别查看echo request和echo reply的包如下:

技术分享

技术分享

  上面的图片是echo request的包,可以看到type为8,code为0;下面的图片是echo reply的包,可以看到type为0,code也为0。


  关于ICMP的过多的细节就不讨论了,下面通过C来介绍ICMP的填充。


  ICMP的定义如下:

// ICMP Header
typedef struct _ICMPHEADER
{
    unsigned char  i_type;
    unsigned char  i_code;
    unsigned short i_chsum;
    unsigned short i_id;
    unsigned short i_seq;
    unsigned long  i_timestamp;
    unsigned char  i_data[32];
}ICMPHEADER, *PICMPHEADER;

  上面就是ICMP在C语言中的定义,下面介绍ICMP结构体的填充,代码如下:

// 填充ICMP包头信息
memset((LPVOID)&icmpHeader, ‘A‘, sizeof(icmpHeader));
icmpHeader.i_type      = 8;  // icmp echo
icmpHeader.i_code      = 0;
icmpHeader.i_chsum     = 0;
icmpHeader.i_id        = (unsigned short)GetCurrentProcessId();
icmpHeader.i_seq       = 0;
icmpHeader.i_timestamp = (unsigned long)::GetTickCount();

  代码是基于Windows系统的,在代码中id使用了当前进程的ID,时间戳使用了GetTickCount()这个API函数来进行填充。在上面的填充当中,有一个位置是错误的,就是对i_chsum进行的赋值,该值是一个校验和,在进行校验和计算前,将该值赋值为0进行计算。计算校验和算法的代码如下:

unsigned short *buf = (unsigned short *)&icmpHeader;

// 计算校验和
int nLeft = sizeof(icmpHeader);
int sum = 0;
unsigned short crc = 0;

// 每两个字节进行循环相加
while ( nLeft > 1 )
{
    sum = sum + *(buf ++);
    nLeft -= 2;
}

// 如果还有一个字节没加,也加上
if ( nLeft == 1 )
{
    *(unsigned char *)(&crc) = *(unsigned char *)buf;
    sum += crc;
}

// 因为是16位,如果相加后超过16位
// 那么高16位与低16位相加
sum = (sum >> 16) + (sum & 0xffff);
// 上一步相加如果再次超过16位
// 那么在进行一次高16位与低16位相加
sum += (sum >> 16);
// 取反得到最终的CRC
crc = ~sum;

// 填充校验和
icmpHeader.i_chsum = crc;

  校验和的是16位的无符号整型,将每个字进行相加保存到一个32位的正向当中,然后让这个32位的高16位与低16位进行相加,然后取反即是最后的校验和。将校验和填充至ICMP结构体中。


 以上就是关于ICMP的填充,与ICMP校验和的计算过程,至于实现ping的话,那么使用socket创建原始套接字将构造好的ICMP进行发送即可。



本文出自 “无觉的BLoG” 博客,请务必保留此出处http://wujue.blog.51cto.com/11999347/1877520

以上是关于构造填充用于PING的ICMP的主要内容,如果未能解决你的问题,请参考以下文章

用Golang自己构造ICMP数据包

Ping命令与ICMP协议

ICMP协议与ping

PING命令就是向主机发UDP数据包,但是啥端口

ping使用的icmp协议的疑问?

ping某个域名的详细过程