自己动手用ICMP写ping程序

来源:互联网 发布:光纤网络监控安装图解 编辑:程序博客网 时间:2024/06/03 16:43

ICMP是(Internet Control Message Protocol)Internet控制报文协议,它传数据,但是对数据有监督功能,比如你的数据没到达,则会返回一个icmp报文。

icmp最常见的应用就是ping程序,可以探测两个主机之间是否连通。

ICMP是网络层协议,但它又和IP一起发送(由IP承载)。

[cpp] view plaincopy
  1. /* 
  2.                ICMP协议格式 
  3.    0        8       16                32 
  4.    +--------+--------+-----------------+ 
  5.    |  类型  |  代码   |      校验和      | 
  6.    +--------+--------+-----------------+ 
  7.    |          不同的类型和代码           | 
  8.    |            有不同的内容            | 
  9.    +-----------------------------------+ 
  10.    ///////////////////////////////////// 
  11.    请求和回显 
  12.    +-----------------------------------+ 
  13.    |      标识符      |      序号       | 
  14.    +-----------------+-----------------+ 
  15. */  
  16.   
  17. struct ICMP_HEADER  
  18. {  
  19.     byte type;  
  20.     byte code;  
  21.     byte checkSum[2];  
  22.     //byte other[512];  
  23. };  
由于icmp有多种应用场景,所以它只有前4个字节是固定的,类型+代码唯一标识了一种应用。

总的来说ICMP的报文分三种,ICMP请求报文、ICMP回答报文和ICMP差错报文。由于这里是写ping程序,只用到请求报文和回答报文,所以只介绍这两种。

[cpp] view plaincopy
  1. /* 
  2.              ICMP 请求报文                             ICMP 应答报文 
  3.     +--------+--------+---------------+        +--------+--------+---------------+ 
  4.     |  类型  |  代码   |       描述     |        |  类型  |  代码  |      描述      | 
  5.     +--------+--------+---------------+        +--------+--------+---------------+ 
  6.     |    8   |    0   |     回显请求   |        |    0   |    0   |     回显回答   | 
  7.     +--------+--------+---------------+        +--------+--------+---------------+ 
  8.     |   10   |    0   |    路由器请求  |        |    9   |    0   |     路由器回答  | 
  9.     +--------+--------+---------------+        +--------+--------+---------------+ 
  10.     |   13   |    0   |    时间戳请求  |        |   14   |    0   |     时间戳回答  | 
  11.     +--------+--------+---------------+        +--------+--------+---------------+ 
  12.     |   15   |    0   |  信息请求(废弃) |        |   16   |    0   |  信息回答(废弃)| 
  13.     +--------+--------+---------------+        +--------+--------+---------------+ 
  14.     |   17   |    0   |   地址掩码请求  |        |   18   |    0   |  地址掩码回答  | 
  15.     +--------+--------+---------------+        +--------+--------+---------------+ 
  16.  
  17.                                 ICMP协议请求 / 回答报文格式 
  18.                         0        8       16                32 
  19.                             +--------+--------+-----------------+ 
  20.                             |  类型   |  代码  |      校验和      | 
  21.                             +--------+--------+-----------------+ 
  22.                             |      标识符      |       序号       | 
  23.                             +-----------------+-----------------+ 
  24.                             |             回显数据               | 
  25.                             +-----------------+-----------------+ 
  26.  
  27.  */  
由此可见,在发送ping请求时type = 0, code = 0,回答请求时type=0, code =0。


[cpp]
 view plaincopy
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <pcap.h>  
  4. #include <winsock2.h>  
  5. #include <process.h>  
  6.   
  7. #pragma comment(lib, "../common/lib/Packet.lib")  
  8. #pragma comment(lib, "../common/lib/wpcap.lib")  
  9. #pragma comment(lib, "ws2_32.lib")  
  10.   
  11.   
  12. /*                       IP报文格式 
  13.     0            8           16                        32 
  14.     +------------+------------+-------------------------+ 
  15.     | ver + hlen |  服务类型   |          总长度          | 
  16.     +------------+------------+----+--------------------+ 
  17.     |           标识位         |flag|    分片偏移(13位)   | 
  18.     +------------+------------+----+--------------------+ 
  19.     |   生存时间  | 高层协议号   |        首部校验和        | 
  20.     +------------+------------+-------------------------+ 
  21.     |                   源 IP 地址                       | 
  22.     +---------------------------------------------------+ 
  23.     |                  目的 IP 地址                      | 
  24.     +---------------------------------------------------+ 
  25.  
  26. */  
  27. struct IP_HEADER  
  28. {  
  29.     byte versionAndHeader;  
  30.     byte serviceType;  
  31.     byte totalLen[2];  
  32.     byte seqNumber[2];  
  33.     byte flagAndFragPart[2];  
  34.     byte ttl;  
  35.     byte hiProtovolType;  
  36.     byte headerCheckSum[2];  
  37.     byte srcIpAddr[4];  
  38.     byte dstIpAddr[4];  
  39. };  
  40.   
  41. /* 
  42.                ICMP协议格式 
  43.    0        8       16                32 
  44.    +--------+--------+-----------------+ 
  45.    |  类型  |  代码   |      校验和      | 
  46.    +--------+--------+-----------------+ 
  47.    |          不同的类型和代码           | 
  48.    |            有不同的内容            | 
  49.    +-----------------------------------+ 
  50.    ///////////////////////////////////// 
  51.    请求和回显 
  52.    +-----------------------------------+ 
  53.    |      标识符      |      序号        | 
  54.    +-----------------+-----------------+ 
  55. */  
  56.   
  57. struct ICMP_HEADER  
  58. {  
  59.     byte type;  
  60.     byte code;  
  61.     byte checkSum[2];  
  62.     //byte other[512];  
  63. };  
  64.   
  65. /* 
  66.                ICMP 请求报文                             ICMP 应答报文 
  67.     +--------+--------+---------------+        +--------+--------+---------------+ 
  68.     |  类型  |  代码   |      描述      |        |  类型  |  代码  |      描述     | 
  69.     +--------+--------+---------------+        +--------+--------+---------------+ 
  70.     |    8   |    0   |    回显请求    |        |    0   |    0   |    回显回答   | 
  71.     +--------+--------+---------------+        +--------+--------+---------------+ 
  72.     |   10   |    0   |   路由器请求   |        |    9   |    0   |   路由器回答  | 
  73.     +--------+--------+---------------+        +--------+--------+---------------+ 
  74.     |   13   |    0   |   时间戳请求   |        |   14   |    0   |   时间戳回答  | 
  75.     +--------+--------+---------------+        +--------+--------+---------------+ 
  76.     |   15   |    0   | 信息请求(废弃)  |        |   16   |    0   | 信息回答(废弃)| 
  77.     +--------+--------+---------------+        +--------+--------+---------------+ 
  78.     |   17   |    0   | 地址掩码请求    |        |   18   |    0   | 地址掩码回答  | 
  79.     +--------+--------+---------------+        +--------+--------+---------------+ 
  80.  
  81.                                 ICMP协议请求 / 回答报文格式 
  82.                             0        8       16                32 
  83.                             +--------+--------+-----------------+ 
  84.                             |  类型   |  代码   |     校验和      | 
  85.                             +--------+--------+-----------------+ 
  86.                             |      标识符      |      序号       | 
  87.                             +-----------------+-----------------+ 
  88.                             |             回显数据               | 
  89.                             +-----------------+-----------------+ 
  90.  
  91.  */  
  92. struct ETHERNET_HEADER  
  93. {     
  94.     byte dstMacAddr[6];  
  95.     byte srcMacAddr[6];  
  96.     byte ethernetType[2];  
  97. };  
  98.   
  99. unsigned short CheckSum(unsigned short packet[], int size )  
  100. {  
  101.     unsigned long cksum = 0;  
  102.     while (size > 1)   
  103.     {  
  104.         cksum += *packet++;  
  105.         size -= sizeof(USHORT);  
  106.     }  
  107.     if (size)   
  108.     {  
  109.         cksum += *(UCHAR*)packet;  
  110.     }  
  111.     cksum = (cksum >> 16) + (cksum & 0xFFFF);  
  112.     cksum += (cksum >>16);  
  113.   
  114.     return (USHORT)(~cksum);  
  115. }  
  116.   
  117. char *FormatIpAddr( unsigned uIpAddr, char szIp[] )  
  118. {  
  119.     IN_ADDR addr;  
  120.     addr.S_un.S_addr = uIpAddr;  
  121.       
  122.     strcpy( szIp, inet_ntoa( addr ) );  
  123.     return szIp;  
  124. }  
  125.   
  126. void HandlePacketCallBack(unsigned char *param,const struct pcap_pkthdr* packet_header, const unsigned char *packet)  
  127. {  
  128.     ETHERNET_HEADER *pEthHeader = ( ETHERNET_HEADER *)packet;  
  129.     if ( *((unsigned short *)(pEthHeader->ethernetType)) != htons(0x0800) )  return;  
  130.   
  131.     IP_HEADER *pIpHeader = ( IP_HEADER *)(packet + sizeof(ETHERNET_HEADER ) );  
  132.       
  133.     if ( pIpHeader->hiProtovolType != 0x01 ) return ;  
  134.       
  135.     char srcIp[32], dstIp[32];  
  136.     FormatIpAddr(*(unsigned int *)(pIpHeader->srcIpAddr), srcIp );  
  137.     FormatIpAddr(*(unsigned int *)(pIpHeader->dstIpAddr), dstIp );  
  138.   
  139.     ICMP_HEADER *pIcmpHeader = (ICMP_HEADER *)(packet + sizeof(ETHERNET_HEADER) +sizeof(IP_HEADER ) );  
  140.     char data[512];  
  141.     memcpy(data, (char *)pIcmpHeader + sizeof(ICMP_HEADER) + sizeof(int) , 512 );  
  142.     printf("%s -->%s : %s\n", srcIp, dstIp, data);  
  143. }  
  144.   
  145.   
  146. int main()  
  147. {  
  148.     char data[] = "hello world";  
  149.   
  150.     ICMP_HEADER icmpHeader;  
  151.     memset(&icmpHeader, 0x00, sizeof icmpHeader );  
  152.     icmpHeader.code = 0x00;  
  153.     icmpHeader.type = 0x08;  
  154.     //memcpy(icmpHeader.other, data, sizeof data );  
  155.   
  156.     byte flagAndIndex[4];  
  157.     *(unsigned short *)flagAndIndex = htons(0x01);  
  158.     *(unsigned short *)(flagAndIndex + 2 ) = htons(0x11);  
  159.   
  160.     byte icmpPacket[512];  
  161.     memset(icmpPacket, 0x00, sizeof icmpPacket );  
  162.     memcpy(icmpPacket, &icmpHeader, sizeof icmpHeader );  
  163.     memcpy(icmpPacket + sizeof icmpHeader, flagAndIndex, sizeof flagAndIndex );  
  164.     memcpy(icmpPacket + sizeof icmpHeader + sizeof flagAndIndex, data, sizeof data );  
  165.   
  166.     int icmpSize = sizeof icmpHeader + sizeof flagAndIndex + sizeof data;  
  167.     *(unsigned short *)(((ICMP_HEADER *)icmpPacket)->checkSum) = CheckSum((unsigned short *)icmpPacket, icmpSize );  
  168.   
  169.     IP_HEADER ipHeader;  
  170.     memset( &ipHeader, 0, sizeof ipHeader );  
  171.     unsigned char versionAndLen = 0x04;  
  172.     versionAndLen <<= 4;  
  173.     versionAndLen |= sizeof ipHeader / 4; //版本 + 头长度  
  174.   
  175.     ipHeader.versionAndHeader = versionAndLen;  
  176.     *(unsigned short *)ipHeader.totalLen = htons( sizeof(IP_HEADER) + icmpSize );  
  177.   
  178.     ipHeader.ttl = 0xFF;  
  179.     ipHeader.hiProtovolType = 0x01;  
  180.   
  181.     *(unsigned int *)(ipHeader.srcIpAddr) = inet_addr("10.126.72.37");  
  182.     *(unsigned int *)(ipHeader.dstIpAddr) = inet_addr("10.126.72.36");  
  183.     *(unsigned short *)(ipHeader.headerCheckSum) = CheckSum( (unsigned short *)&ipHeader, sizeof ipHeader );  
  184.   
  185.     //90-2B-34-9A-C2-BB  
  186.      //00-e0-b6-04-4e-b2  
  187.     byte srcMac[] = {0x90, 0x2B, 0x34, 0x9A, 0xC2, 0xBB };  
  188.     byte dstMac[] = {0x00, 0xE0, 0xB6, 0x04, 0x4E, 0xB2 }; //目标mac地址,如果是外网机器,这儿要写本地网关的mac地址  
  189.     ETHERNET_HEADER ethHeader;  
  190.     memset(ðHeader, 0, sizeof ethHeader);  
  191.     memcpy(ethHeader.dstMacAddr, dstMac, 6);  
  192.     memcpy(ethHeader.srcMacAddr, srcMac, 6);  
  193.     *(unsigned short *)ethHeader.ethernetType = htons(0x0800);  
  194.   
  195.     byte packet[1024];  
  196.     memset(packet, 0x00, sizeof packet );  
  197.     memcpy( packet, ðHeader, sizeof ethHeader );  
  198.     memcpy( packet + sizeof ethHeader, &ipHeader, sizeof ipHeader );  
  199.     memcpy( packet + sizeof ethHeader + sizeof ipHeader, icmpPacket, icmpSize);  
  200.   
  201.     const char *lpszAdapterName = "\\Device\\NPF_{1DDB19E0-EC33-46E2-ACB5-085E87EF6489}";  
  202.     char szError[PCAP_ERRBUF_SIZE];  
  203.     pcap_t *handle = pcap_open_live(lpszAdapterName, 65536, 1, 1000, szError );  
  204.       
  205.     //system("pause");  
  206.     int size = sizeof ethHeader + sizeof ipHeader + sizeof icmpHeader + sizeof flagAndIndex + sizeof data ;  
  207.     pcap_sendpacket(handle, packet, size );  
  208.     pcap_loop( handle, -1, HandlePacketCallBack, NULL );  
  209.       
  210. }  


由于在抓包中没有过滤请求包,所以这个地方抓到了两个,一个是请求,一个是回答。

0 0