基于ICMP的一个ping程序

本文介绍了一个使用C语言实现的自定义Ping程序,该程序详细展示了如何构造和发送ICMP请求包,以及如何解析和处理回应。通过创建原始套接字并设置超时,程序能够向指定的目标IP地址发送ICMP回显请求,并接收回显应答。

typedef struct icmp_hdr
{
 unsigned char  icmp_type;  //消息类型
 unsigned char  icmp_code;  //代码
 unsigned short icmp_checksum;

 unsigned short icmp_id;
 unsigned short icmp_sequence;

 unsigned long icmp_timestamp;
}ICMP_HDR,*PICMP_HDR;

typedef struct _IPHeader
{
 UCHAR  iphVerLen;
 UCHAR  ipTOS;
 USHORT ipLength;
 USHORT ipID;
 USHORT ipFlags;
 UCHAR  ipTTL;
 UCHAR  ipProtocol;
 USHORT ipChecksum;
 ULONG  ipSource;
 ULONG  ipDestination;
}IPHeader,*PIPHeader;

 

void Ping()

{

char szDestIp[] = "127.0.0.1";
 CString sLog,stemp;
 WSADATA wsaData;
 WORD sockVersion = MAKEWORD(2,2);

 if(WSAStartup(sockVersion,&wsaData) != 0)
 {
  return ;
 }

 SOCKET sRaw = socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);

 SetTimeout(sRaw,1000,TRUE);

 SOCKADDR_IN dest;
 dest.sin_family = AF_INET;
 dest.sin_port = htons(0);
 dest.sin_addr.S_un.S_addr = inet_addr(szDestIp);

 char buff[sizeof(ICMP_HDR)+32];
 ICMP_HDR *pIcmp = (ICMP_HDR*)buff;

 pIcmp->icmp_type = 8;
 pIcmp->icmp_code = 0;
 pIcmp->icmp_id = (USHORT)GetCurrentProcessId();
 pIcmp->icmp_checksum = 0;
 pIcmp->icmp_sequence = 0;
 memset(&buff[sizeof(ICMP_HDR)],'E',32);

 USHORT nSeq = 0;
 char recvBuf[1024];
 SOCKADDR_IN from;
 int nLen = sizeof(from);

 BOOL ret = FALSE;

 while(TRUE)
 {
  static int nCount = 0;
  int nRet;
  if( nCount++ ==4)
   break;

  pIcmp->icmp_checksum = 0;
  pIcmp->icmp_timestamp = GetTickCount();
  pIcmp->icmp_sequence = nSeq;
  pIcmp->icmp_checksum = checksum((USHORT*)buff,sizeof(ICMP_HDR)+32);
  nRet = sendto(sRaw,buff,sizeof(ICMP_HDR)+32,0,(SOCKADDR*)&dest,sizeof(dest));
  if(nRet == SOCKET_ERROR)
  {
   break;
  }

  nRet = recvfrom(sRaw,recvBuf,1024,0,(sockaddr*)&from,&nLen);

  if(nRet == SOCKET_ERROR)
  {
   if(WSAGetLastError() == WSAETIMEDOUT)
   {
    //time out
    sLog.Format("Request timed out/n");
    GetDlgItemText(IDC_EDIT_TEST,stemp);
    SetDlgItemText(IDC_EDIT_TEST,stemp + sLog);
    continue;
   }
   // failed
   return ;
  }

  int nTick = ::GetTickCount();
  if(nRet < sizeof(IPHeader)+sizeof(ICMP_HDR))
  {
   sLog.Format("Too few bytes from  %s /n",::inet_ntoa(from.sin_addr));
   GetDlgItemText(IDC_EDIT_TEST,stemp);
   SetDlgItemText(IDC_EDIT_TEST,stemp + sLog);
  }

  ICMP_HDR* pRecvIcmp = (ICMP_HDR*)(recvBuf + 20); // (ICMP_HDR*)(recvBuf + sizeof(IPHeader));
        if(pRecvIcmp->icmp_type != 0)    // 回显
        {
            sLog.Format("nonecho type %d recvd /n",pRecvIcmp->icmp_type);
            GetDlgItemText(IDC_EDIT_TEST,stemp);
            SetDlgItemText(IDC_EDIT_TEST,stemp + sLog);
            return ;
        }

        if(pRecvIcmp->icmp_id != ::GetCurrentProcessId())
        {
            sLog.Format("someone else's packet! /n");
            GetDlgItemText(IDC_EDIT_TEST,stemp);
            SetDlgItemText(IDC_EDIT_TEST,stemp + sLog);
            return ;
        }
        sLog.Format("%d bytes from %s: /r/n   icmp_seq = %d. time: %d ms /r/n",
   nRet, inet_ntoa(from.sin_addr), pRecvIcmp->icmp_sequence,
   nTick - pRecvIcmp->icmp_timestamp);
  GetDlgItemText(IDC_EDIT_TEST,stemp);
  SetDlgItemText(IDC_EDIT_TEST,stemp + sLog);

  ret |= TRUE;

  ::Sleep(1000); 
 }

}

 

USHORT checksum(USHORT* buff,int size)
{
 unsigned long cksum = 0;
 while(size>1)
 {
  cksum += *buff++;
  size -= sizeof(USHORT);
 }
 if(size)
 {
  cksum += *(UCHAR*)buff;
 }
 cksum = (cksum>>16)+(cksum & 0xffff);
 cksum += (cksum>>16);
 return (USHORT)(~cksum);
}

BOOL SetTimeout(SOCKET s,int nTime,BOOL bRecv)
{
 int ret = setsockopt(s,SOL_SOCKET,bRecv ? SO_RCVTIMEO : SO_SNDTIMEO,(char*)&nTime,sizeof(nTime));
 return ret != SOCKET_ERROR;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值