以下材料摘抄自:
http://blog.sina.com.cn/s/blog_5cec38f30100b8w0.html
http://hi.baidu.com/five_cent/blog/item/23f4876c76205af042169467.html
http://www.cell–phone-411.com/action-viewnews-itemid-23183.html
创建ICMP封包
2. 发送ICMP封包
3. 接收ICMP封包
4. 解ICMP封包
向网络上的另一个主机系统发送ICMP报文,如果指定系统得到了报文,它将把报文一模一样地传回给发送者。
ICMP封包结构
IP报头 |
ICMP报头 |
ICMP数据报 |
在PING程序当中,我们主要关系的是生存时间TTL和IHL
IP报头格式
版本号VER 4-bit |
IP报头长度IHL 4-bit |
服务类型TOS 8-bit |
数据报长度TL 16-bit |
|
报文标志ID 16-bit |
报文标志F 16-bit |
分段偏移量FO |
||
生存时间TTL 8-bit |
协议号PORT 8-bit |
报头校验和 16-bit |
||
源地址32-bit |
||||
目的地址32-bit |
||||
任选项和填充位 |
||||
ICMP报头格式,绿色部分为必须,其余部分可以随意构造,因为,ICMP报文发送和返回都是一样的,用于判断网络情况
为了计算一份数据报的IP校验和,首先把校验和字段置为0,然后,对首部中每个16bit进行二进制反码求和(整个16进制是由一串16bit的字组成),结果存在校验和字段中。因此,首先将所有的字段都填充完毕,并将校验和字段填充为0,再计算校验和。
类型TYPE 8-bit |
代码CODE 8bit |
校验和CheckSum 16-bit |
|
标识符Identifiers 16-bit |
序列号Sequence.No 16-bit |
||
时间戳TimeStamp 16-bit |
|||
终于写完了代码,很是悲剧,抓了一天的ICMP协议包,后来发现,sendto发送的数据包是自动带IP头部的。 而recvfrom接收的数据包又没有去掉IP头部。 很是奇怪,没有 |
———————————————————————————————-
//———protocolsHeader.h
typedef struct icmp_hdr
{
//ICMP协议报头
unsigned char icmp_type;
unsigned char icmp_code;
unsigned short icmp_checksum;
//ICMP信息
unsigned short icmp_id;
unsigned short icmp_seqno;
unsigned long icmp_timestamp;
}ICMP_HDR,*PICMP_HDR;
typedef struct ip_hdr
{
unsigned char ip_verihl;
unsigned char ip_tos;
unsigned short ip_tl;
unsigned short ip_id;
unsigned short ip_flag;
unsigned char ip_ttl;
unsigned char ip_port;
unsigned short ip_checksum;
unsigned long ip_source;
unsigned long ip_Destination;
}IP_HDR,*PIP_HDR;
//—————–initsock.h
#include <winsock2.h>
#pragma comment(lib,”ws2_32″)
class CInitSock
{
public:
CInitSock(BYTE minorVer=2,BYTE majorVer=2)
{
WSADATA wsaData;
WORD sockVersion=MAKEWORD(minorVer,majorVer);
if(::WSAStartup(sockVersion,&wsaData)!=0)
{
exit(0);
}
}
~CInitSock()
{
::WSACleanup();
}
};
//———-ping.cpp没设定超时,recvfrom是阻塞模式,大概懂意思就行了
#include <stdio.h>
#include “initsock.h”
#include “ProtocolsHeader.h”
#include <windows.h>
USHORT checksum(USHORT* buff, int size)
{
unsigned long cksum = 0;
while(size>1)
{
cksum += *buff++;
size -= sizeof(USHORT);
}
// 是奇数
if(size)
{
cksum += *(UCHAR*)buff;
}
// 将32位的chsum高16位和低16位相加,然后取反
cksum = (cksum >> 16) + (cksum & 0xffff);
cksum += (cksum >> 16); //
return (USHORT)(~cksum);
}
CInitSock sock;
int SendIcmp(char *szDestIp)
{
//创建原始套接字
SOCKET sRaw=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);
SOCKADDR_IN dest;
dest.sin_family=AF_INET;
dest.sin_port =htons(0);
dest.sin_addr.S_un.S_addr=inet_addr(szDestIp);
//创建icmp封包
char icmpBuf[sizeof(ICMP_HDR)+32];
PICMP_HDR pIcmp=(PICMP_HDR)icmpBuf;
//1.填充ICMP的type和code字段
pIcmp->icmp_type=8;
pIcmp->icmp_code=0;
pIcmp->icmp_checksum=0;
pIcmp->icmp_id=(unsigned short)GetCurrentProcessId();
pIcmp->icmp_seqno=0;
memset(&icmpBuf[sizeof(ICMP_HDR)],’A’,32);
//循环
char recvBuf[1024];
int nSeq=0;
int nRet=0;
SOCKADDR_IN from;
int nLen=sizeof(from);
PICMP_HDR pRecvIcmp=NULL;
while(1)
{
//2.填充ICMP的id,seqno,和timestamp字段,并最终计算校验和
static int nCount=0;
if(nCount++==4)
break;
pIcmp->icmp_checksum=0;
pIcmp->icmp_seqno=nSeq++;
pIcmp->icmp_timestamp=GetTickCount();
pIcmp->icmp_checksum=checksum((unsigned short*)icmpBuf,sizeof(ICMP_HDR)+32);
//3.发送ICMP报文
nRet=::sendto(sRaw,icmpBuf,sizeof(ICMP_HDR)+32,0,(SOCKADDR*)&dest,sizeof(dest));
if(nRet==SOCKET_ERROR)
{
printf(“sendto failed: %d n”,::WSAGetLastError());
return -1;
}
//4.接收ICMP报文(超时1000ms)
nRet=::recvfrom(sRaw,recvBuf,1024,0,(sockaddr*)&from,&nLen);
if(nRet==SOCKET_ERROR)
{
if(::WSAGetLastError()==WSAETIMEDOUT)
{
printf(“time outn”);
continue;
}
}
//5.解包,recvfrom接收到的包是IP+ICMP的包
int nTick=::GetTickCount();
if(nRet<sizeof(IP_HDR)+sizeof(ICMP_HDR))
{
printf(“Too few bytes from %s”,::inet_ntoa(from.sin_addr));
}
pRecvIcmp=(PICMP_HDR)&recvBuf[sizeof(IP_HDR)];
//6.type段必须是0,id匹配
if(pRecvIcmp->icmp_type!=0)
{
printf(“nonecho type %d recvedn”,pRecvIcmp->icmp_type);
}
if(pRecvIcmp->icmp_id!=pIcmp->icmp_id)
{
printf(“someone else’s packetn”);
}
//7.输出timestamp,计算时间,输出seqno
printf(“%d bytes from %s”,nRet,::inet_ntoa(from.sin_addr));
printf(“icmp_seq=%d.”,pRecvIcmp->icmp_seqno);
printf(“time:%d ms”,nTick-pRecvIcmp->icmp_timestamp);
printf(“n”);
::Sleep(1000);
}
return 0;
}
int main()
{
char ip[]=”127.0.0.1″;
SendIcmp(ip);
return 0;
}
版权所有,禁止转载. 如需转载,请先征得博主的同意,并且表明文章出处,否则按侵权处理.