ICMP是(Internet Control Message Protocol)Internet控制报文协议,它传数据,但是对数据有监督功能,比如你的数据没到达,则会返回一个icmp报文。
icmp最常见的应用就是ping程序,可以探测两个主机之间是否连通。
ICMP是网络层协议,但它又和IP一起发送(由IP承载)。
- /*
- ICMP协议格式
- 0 8 16 32
- +--------+--------+-----------------+
- | 类型 | 代码 | 校验和 |
- +--------+--------+-----------------+
- | 不同的类型和代码 |
- | 有不同的内容 |
- +-----------------------------------+
- /
- 请求和回显
- +-----------------------------------+
- | 标识符 | 序号 |
- +-----------------+-----------------+
- */
- struct ICMP_HEADER
- {
- byte type;
- byte code;
- byte checkSum[2];
- //byte other[512];
- };
总的来说ICMP的报文分三种,ICMP请求报文、ICMP回答报文和ICMP差错报文。由于这里是写ping程序,只用到请求报文和回答报文,所以只介绍这两种。
- /*
- ICMP 请求报文 ICMP 应答报文
- +--------+--------+---------------+ +--------+--------+---------------+
- | 类型 | 代码 | 描述 | | 类型 | 代码 | 描述 |
- +--------+--------+---------------+ +--------+--------+---------------+
- | 8 | 0 | 回显请求 | | 0 | 0 | 回显回答 |
- +--------+--------+---------------+ +--------+--------+---------------+
- | 10 | 0 | 路由器请求 | | 9 | 0 | 路由器回答 |
- +--------+--------+---------------+ +--------+--------+---------------+
- | 13 | 0 | 时间戳请求 | | 14 | 0 | 时间戳回答 |
- +--------+--------+---------------+ +--------+--------+---------------+
- | 15 | 0 | 信息请求(废弃) | | 16 | 0 | 信息回答(废弃)|
- +--------+--------+---------------+ +--------+--------+---------------+
- | 17 | 0 | 地址掩码请求 | | 18 | 0 | 地址掩码回答 |
- +--------+--------+---------------+ +--------+--------+---------------+
- ICMP协议请求 / 回答报文格式
- 0 8 16 32
- +--------+--------+-----------------+
- | 类型 | 代码 | 校验和 |
- +--------+--------+-----------------+
- | 标识符 | 序号 |
- +-----------------+-----------------+
- | 回显数据 |
- +-----------------+-----------------+
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <pcap.h>
- #include <winsock2.h>
- #include <process.h>
- #pragma comment(lib, "../common/lib/Packet.lib")
- #pragma comment(lib, "../common/lib/wpcap.lib")
- #pragma comment(lib, "ws2_32.lib")
- /* IP报文格式
- 0 8 16 32
- +------------+------------+-------------------------+
- | ver + hlen | 服务类型 | 总长度 |
- +------------+------------+----+--------------------+
- | 标识位 |flag| 分片偏移(13位) |
- +------------+------------+----+--------------------+
- | 生存时间 | 高层协议号 | 首部校验和 |
- +------------+------------+-------------------------+
- | 源 IP 地址 |
- +---------------------------------------------------+
- | 目的 IP 地址 |
- +---------------------------------------------------+
- */
- struct IP_HEADER
- {
- byte versionAndHeader;
- byte serviceType;
- byte totalLen[2];
- byte seqNumber[2];
- byte flagAndFragPart[2];
- byte ttl;
- byte hiProtovolType;
- byte headerCheckSum[2];
- byte srcIpAddr[4];
- byte dstIpAddr[4];
- };
- /*
- ICMP协议格式
- 0 8 16 32
- +--------+--------+-----------------+
- | 类型 | 代码 | 校验和 |
- +--------+--------+-----------------+
- | 不同的类型和代码 |
- | 有不同的内容 |
- +-----------------------------------+
- /
- 请求和回显
- +-----------------------------------+
- | 标识符 | 序号 |
- +-----------------+-----------------+
- */
- struct ICMP_HEADER
- {
- byte type;
- byte code;
- byte checkSum[2];
- //byte other[512];
- };
- /*
- ICMP 请求报文 ICMP 应答报文
- +--------+--------+---------------+ +--------+--------+---------------+
- | 类型 | 代码 | 描述 | | 类型 | 代码 | 描述 |
- +--------+--------+---------------+ +--------+--------+---------------+
- | 8 | 0 | 回显请求 | | 0 | 0 | 回显回答 |
- +--------+--------+---------------+ +--------+--------+---------------+
- | 10 | 0 | 路由器请求 | | 9 | 0 | 路由器回答 |
- +--------+--------+---------------+ +--------+--------+---------------+
- | 13 | 0 | 时间戳请求 | | 14 | 0 | 时间戳回答 |
- +--------+--------+---------------+ +--------+--------+---------------+
- | 15 | 0 | 信息请求(废弃) | | 16 | 0 | 信息回答(废弃)|
- +--------+--------+---------------+ +--------+--------+---------------+
- | 17 | 0 | 地址掩码请求 | | 18 | 0 | 地址掩码回答 |
- +--------+--------+---------------+ +--------+--------+---------------+
- ICMP协议请求 / 回答报文格式
- 0 8 16 32
- +--------+--------+-----------------+
- | 类型 | 代码 | 校验和 |
- +--------+--------+-----------------+
- | 标识符 | 序号 |
- +-----------------+-----------------+
- | 回显数据 |
- +-----------------+-----------------+
- */
- struct ETHERNET_HEADER
- {
- byte dstMacAddr[6];
- byte srcMacAddr[6];
- byte ethernetType[2];
- };
- unsigned short CheckSum(unsigned short packet[], int size )
- {
- unsigned long cksum = 0;
- while (size > 1)
- {
- cksum += *packet++;
- size -= sizeof(USHORT);
- }
- if (size)
- {
- cksum += *(UCHAR*)packet;
- }
- cksum = (cksum >> 16) + (cksum & 0xFFFF);
- cksum += (cksum >>16);
- return (USHORT)(~cksum);
- }
- char *FormatIpAddr( unsigned uIpAddr, char szIp[] )
- {
- IN_ADDR addr;
- addr.S_un.S_addr = uIpAddr;
- strcpy( szIp, inet_ntoa( addr ) );
- return szIp;
- }
- void HandlePacketCallBack(unsigned char *param,const struct pcap_pkthdr* packet_header, const unsigned char *packet)
- {
- ETHERNET_HEADER *pEthHeader = ( ETHERNET_HEADER *)packet;
- if ( *((unsigned short *)(pEthHeader->ethernetType)) != htons(0x0800) ) return;
- IP_HEADER *pIpHeader = ( IP_HEADER *)(packet + sizeof(ETHERNET_HEADER ) );
- if ( pIpHeader->hiProtovolType != 0x01 ) return ;
- char srcIp[32], dstIp[32];
- FormatIpAddr(*(unsigned int *)(pIpHeader->srcIpAddr), srcIp );
- FormatIpAddr(*(unsigned int *)(pIpHeader->dstIpAddr), dstIp );
- ICMP_HEADER *pIcmpHeader = (ICMP_HEADER *)(packet + sizeof(ETHERNET_HEADER) +sizeof(IP_HEADER ) );
- char data[512];
- memcpy(data, (char *)pIcmpHeader + sizeof(ICMP_HEADER) + sizeof(int) , 512 );
- printf("%s -->%s : %s\n", srcIp, dstIp, data);
- }
- int main()
- {
- char data[] = "hello world";
- ICMP_HEADER icmpHeader;
- memset(&icmpHeader, 0x00, sizeof icmpHeader );
- icmpHeader.code = 0x00;
- icmpHeader.type = 0x08;
- //memcpy(icmpHeader.other, data, sizeof data );
- byte flagAndIndex[4];
- *(unsigned short *)flagAndIndex = htons(0x01);
- *(unsigned short *)(flagAndIndex + 2 ) = htons(0x11);
- byte icmpPacket[512];
- memset(icmpPacket, 0x00, sizeof icmpPacket );
- memcpy(icmpPacket, &icmpHeader, sizeof icmpHeader );
- memcpy(icmpPacket + sizeof icmpHeader, flagAndIndex, sizeof flagAndIndex );
- memcpy(icmpPacket + sizeof icmpHeader + sizeof flagAndIndex, data, sizeof data );
- int icmpSize = sizeof icmpHeader + sizeof flagAndIndex + sizeof data;
- *(unsigned short *)(((ICMP_HEADER *)icmpPacket)->checkSum) = CheckSum((unsigned short *)icmpPacket, icmpSize );
- IP_HEADER ipHeader;
- memset( &ipHeader, 0, sizeof ipHeader );
- unsigned char versionAndLen = 0x04;
- versionAndLen <<= 4;
- versionAndLen |= sizeof ipHeader / 4; //版本 + 头长度
- ipHeader.versionAndHeader = versionAndLen;
- *(unsigned short *)ipHeader.totalLen = htons( sizeof(IP_HEADER) + icmpSize );
- ipHeader.ttl = 0xFF;
- ipHeader.hiProtovolType = 0x01;
- *(unsigned int *)(ipHeader.srcIpAddr) = inet_addr("10.126.72.37");
- *(unsigned int *)(ipHeader.dstIpAddr) = inet_addr("10.126.72.36");
- *(unsigned short *)(ipHeader.headerCheckSum) = CheckSum( (unsigned short *)&ipHeader, sizeof ipHeader );
- //90-2B-34-9A-C2-BB
- //00-e0-b6-04-4e-b2
- byte srcMac[] = {0x90, 0x2B, 0x34, 0x9A, 0xC2, 0xBB };
- byte dstMac[] = {0x00, 0xE0, 0xB6, 0x04, 0x4E, 0xB2 }; //目标mac地址,如果是外网机器,这儿要写本地网关的mac地址
- ETHERNET_HEADER ethHeader;
- memset(ðHeader, 0, sizeof ethHeader);
- memcpy(ethHeader.dstMacAddr, dstMac, 6);
- memcpy(ethHeader.srcMacAddr, srcMac, 6);
- *(unsigned short *)ethHeader.ethernetType = htons(0x0800);
- byte packet[1024];
- memset(packet, 0x00, sizeof packet );
- memcpy( packet, ðHeader, sizeof ethHeader );
- memcpy( packet + sizeof ethHeader, &ipHeader, sizeof ipHeader );
- memcpy( packet + sizeof ethHeader + sizeof ipHeader, icmpPacket, icmpSize);
- const char *lpszAdapterName = "\\Device\\NPF_{1DDB19E0-EC33-46E2-ACB5-085E87EF6489}";
- char szError[PCAP_ERRBUF_SIZE];
- pcap_t *handle = pcap_open_live(lpszAdapterName, 65536, 1, 1000, szError );
- //system("pause");
- int size = sizeof ethHeader + sizeof ipHeader + sizeof icmpHeader + sizeof flagAndIndex + sizeof data ;
- pcap_sendpacket(handle, packet, size );
- pcap_loop( handle, -1, HandlePacketCallBack, NULL );
- }
由于在抓包中没有过滤请求包,所以这个地方抓到了两个,一个是请求,一个是回答。