ICMP Ping Tracert

以下材料摘抄自:

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程序当中,我们主要关系的是生存时间TTLIHL

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;

}

版权所有,禁止转载. 如需转载,请先征得博主的同意,并且表明文章出处,否则按侵权处理.

    分享到:

Leave a Reply

Your email address will not be published. Required fields are marked *