首页 > 代码库 > 收发ICMP封包,实现ping

收发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 =http://www.mamicode.com/ ::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 }