收发ICMP封包,实现ping

  1 #include "stdafx.h"
  2 
  3 #include <WINSOCK2.H>
  4 #pragma comment(lib, "Ws2_32.lib")
  5 
  6 #define ECHO_REPLY   0  //回应
  7 #define ECHO_REQUEST 8  //请求回应
  8 
  9 struct ip_hdr
 10 {
 11     unsigned char h_len:4;         //length of header
 12     unsigned char version:4;       //Version of IP
 13     unsigned char tos;             //Type of service
 14     unsigned short total_len;      //total length of the packet
 15     
 16     unsigned short ident;          //unique identifier
 17     unsigned short frag_and_flags; //flags
 18     
 19     unsigned char ttl;             //ttl
 20     unsigned char proto;           //protocol(TCP ,UDP etc)
 21     unsigned short checksum;       //IP checksum
 22     
 23     unsigned int sourceIP;
 24     unsigned int destIP;
 25 };
 26 
 27 struct icmp_hdr 
 28 {
 29     BYTE icmp_type;     //类型
 30     BYTE icmp_code;     //代码
 31     USHORT icmp_cksum;  //效验和
 32     USHORT icmp_id;     //n
 33     USHORT icmp_seq;    //n
 34     ULONG  icmp_data;   //GetTickout()
 35 };
 36 
 37 //计算ICMP封包校验和
 38 WORD CalcCheckSum(IN unsigned short* addr,IN int len)
 39 {
 40     int        nleft = len;
 41     int        sum = 0;
 42     unsigned short* w = addr;
 43     unsigned short answer = 0;
 44     
 45     while(nleft > 1) 
 46     {
 47         sum += *w++;
 48         nleft -= 2;
 49     }
 50     
 51     if(nleft == 1) 
 52     {
 53         *(unsigned char*)(&answer) = *(unsigned char*)w;
 54         sum += answer;
 55     }
 56     
 57     sum = (sum >> 16) + (sum & 0xffff); //高16位 + 低16位
 58     sum += (sum >> 16);                 //+进位
 59     answer = ~sum;                      //取反
 60     
 61     return (answer);
 62 }
 63 
 64 int main(int argc, char* argv[])
 65 {
 66     //socket初始化
 67     WSADATA wsaData;
 68     WSAStartup(MAKEWORD(2, 2), &wsaData);
 69 
 70     //没有域名,返回
 71     if (argc < 2)
 72     {
 73         puts("Get Domain Error");
 74         return 0;
 75     }
 76 
 77     //域名转IP地址
 78     HOSTENT *pHost = gethostbyname(argv[1]);
 79     if (pHost == NULL)
 80     {
 81         puts("Get Domain Error");
 82         return 0;
 83     }
 84 
 85     unsigned long nAddress = ((long**)pHost->h_addr_list)[0][0];
 86     sockaddr_in addrSend;
 87     addrSend.sin_family = AF_INET;
 88     addrSend.sin_port = htons(0);
 89     addrSend.sin_addr.s_addr = nAddress;
 90     
 91     //创建原始套接字
 92     SOCKET sRaw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
 93     if (sRaw == INVALID_SOCKET)
 94     {
 95         puts("socket error");
 96         return 0;
 97     }
 98 
 99     printf("Pinging [ %s ] with 32 bytes of data:\r\n\r\n", argv[1]);
100 
101     char szSend[32] = {0};
102     for (int i = 0; i < 4; i++)
103     {
104         icmp_hdr *pICMP = (icmp_hdr *)szSend;
105         pICMP->icmp_code = 0;
106         pICMP->icmp_cksum = 0;
107         pICMP->icmp_data = ::GetTickCount();
108         pICMP->icmp_id = (unsigned short)GetCurrentProcessId();
109         pICMP->icmp_seq = i;
110         pICMP->icmp_type = ECHO_REQUEST;
111 
112         pICMP->icmp_cksum = CalcCheckSum((unsigned short *)pICMP, sizeof(icmp_hdr));
113 
114         //发送封包
115         sendto(sRaw, szSend, sizeof(szSend), 0, (sockaddr *)&addrSend, sizeof(addrSend));
116 
117         //通过选择模型,设置等待时间
118         fd_set fd;
119         FD_ZERO(&fd);
120         FD_SET(sRaw, &fd);
121         timeval tv = {1, 0};
122         int nResult = select(0, &fd, NULL, NULL, &tv);
123         if (nResult == 0)
124         {
125             puts("Time Out");
126             continue;
127         }
128 
129         //接收封包
130         char szRecv[MAXBYTE];
131         sockaddr_in addrRecv;
132         int nLen = sizeof(addrRecv);
133         recvfrom(sRaw, szRecv, sizeof(szRecv), 0, (sockaddr *)&addrRecv, &nLen);
134 
135         //检验校验和
136         ip_hdr * pIPRecv = (ip_hdr *)szRecv;
137         icmp_hdr *pICMPRecv = (icmp_hdr *)(pIPRecv + 1);
138 
139         //校验和为0,表示封包正确
140         if (!CalcCheckSum((unsigned short *)pICMPRecv, sizeof(icmp_hdr)))
141         {
142             //计算时间间隔
143             DWORD dwTime = ::GetTickCount() - pICMPRecv->icmp_data;
144             
145             printf("Reply from %s: bytes=%d time=%dms TTL=%d\n", 
146                 inet_ntoa(addrRecv.sin_addr), 
147                 sizeof(szRecv), 
148                 dwTime, 
149                 pIPRecv->ttl);
150         }
151     }
152 
153 
154     //格式控制
155     puts("");
156 
157     //socket释放资源
158     WSACleanup( );
159     return 0;
160 }

 

posted @ 2014-08-19 21:23  luzhiyuan  阅读(5331)  评论(0编辑  收藏  举报