- //
- // Ping.h
- //
- #pragma pack(1)
- #define ICMP_ECHOREPLY 0
- #define ICMP_ECHOREQ 8
- // IP Header -- RFC 791
- typedef struct tagIPHDR
- {
- u_char VIHL; // Version and IHL
- u_char TOS; // Type Of Service
- short TotLen; // Total Length
- short ID; // Identification
- short FlagOff; // Flags and Fragment Offset
- u_char TTL; // Time To Live
- u_char Protocol; // Protocol
- u_short Checksum; // Checksum
- struct in_addr iaSrc; // Internet Address - Source
- struct in_addr iaDst; // Internet Address - Destination
- }IPHDR, *PIPHDR;
- // ICMP Header - RFC 792
- typedef struct tagICMPHDR
- {
- u_char Type; // Type
- u_char Code; // Code
- u_short Checksum; // Checksum
- u_short ID; // Identification
- u_short Seq; // Sequence
- //char Data; // Data
- }ICMPHDR, *PICMPHDR;
- #define REQ_DATASIZE 36
- #define REQ_datasize2 30
- #define Renum 66
- // ICMP Echo Request
- typedef struct tagECHOREQUEST
- {
- ICMPHDR icmpHdr;
- DWORD dwTime;
- char cData[REQ_DATASIZE];
- }ECHOREQUEST, *PECHOREQUEST;
- typedef struct tempECHREQUEST{
- ICMPHDR icmpHdr;
- DWORD dwTime;
- char cData[Renum];
- }tempECHREQUEST,*PtempECHOREQUEST;
- typedef struct tempECHREQUEST2{
- ICMPHDR icmpHdr;
- DWORD dwTime;
- char cData[Renum+8];
- }tempecho,*Ptempecho;
- // ICMP Echo Reply
- typedef struct tagECHOREPLY
- {
- IPHDR ipHdr;
- ECHOREQUEST echoRequest;
- char cFiller[256];
- }ECHOREPLY, *PECHOREPLY;
- //IP echo request
- typedef struct tagIPEchorequest{
- IPHDR ipHeader;
- ECHOREQUEST icmp_data;
- }IPECHOREQUET,*PIPECHOREQUEST;
- typedef struct tagIPEchoTwo{
- IPHDR ipHeader;
- char cData[REQ_datasize2];
- }IPEchoTwo,*PIPEchoTwo;
- typedef struct tagIPechoTwo2{
- IPHDR ipHeader;
- char cData[REQ_datasize2+8];
- }IPechotwo2,*PIPechotwo2;
- //ip echo reply
- typedef struct tagIPREPLY{
- IPHDR ipHdr;
- ECHOREQUEST echoRequest;
- char cFiller[256];
- }IPECHOREPLY,*PIPECHOREPLY;
- #pragma pack()
- // PING.C -- Ping program using ICMP and RAW Sockets
- //
- #include <stdio.h>
- #include <stdlib.h>
- #include <winsock2.h>
- #include "ws2tcpip.h"
- #include <iostream>
- #pragma comment(lib,"WS2_32.lib")
- #include "ping.h"
- // Internal Functions
- void Ping(LPCSTR pstrHost);
- void ReportError(LPCSTR pstrFrom);
- int WaitForEchoReply(SOCKET s);
- u_short in_cksum(u_short *addr, int len);
- // ICMP Echo Request/Reply functions
- int SendEchoRequest(SOCKET, LPSOCKADDR_IN);
- DWORD RecvEchoReply(SOCKET, LPSOCKADDR_IN, u_char *);
- //IP internal function
- void sendIP(LPCSTR pstrHost);
- int SendIPEchoRequestFragmentTwo(SOCKET s,LPSOCKADDR_IN lpstToAddr);
- int SendIPEchoRequest(SOCKET, LPSOCKADDR_IN);
- static short nId = 1;
- static short nSeq = 1;
- static short ip_id = rand()%256;
- static char DataToSend[Renum];
- static short flag1 = 0; //标记,0标识不重复,1标识有重复
- static short flag2 = 0; //标记,0标识顺序,1标识逆序
- char sourseIP[16];
- // main()
- void main(int argc, char **argv)
- {
- WSADATA wsaData;
- WORD wVersionRequested = MAKEWORD(2,1);
- int nRet;
- // Check arguments
- if (argc != 2)
- {
- fprintf(stderr,"nUsage: ping hostnamen");
- return;
- }
- // Init WinSock如果成功,则返回0
- nRet = WSAStartup(wVersionRequested, &wsaData);
- if (nRet)
- {
- fprintf(stderr,"nError initializing WinSockn");
- return;
- }
- // Check version
- if (wsaData.wVersion != wVersionRequested)
- {
- fprintf(stderr,"nWinSock version not supportedn");
- return;
- }
- printf(" n输入目的主机IP地址:n");
- gets(argv[1]);
- sendIP(argv[1]);
- system("pause");
- // Free WinSock
- WSACleanup();
- }
- // Ping()
- // Calls SendEchoRequest() and
- // RecvEchoReply() and prints results
- void Ping(LPCSTR pstrHost)
- {
- SOCKET rawSocket; //原始套接字
- LPHOSTENT lpHost; //保存目的主机信息
- struct sockaddr_in saDest; //目的主机
- struct sockaddr_in saSrc; //源主机
- DWORD dwTimeSent; //发送时间
- DWORD dwElapsed; //时间间隔
- u_char cTTL; //ttl
- int nLoop; //发送循环的ping的次数
- int nRet;
- // Create a Raw socket
- rawSocket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
- if (rawSocket == SOCKET_ERROR)
- {
- ReportError("socket()");
- return;
- }
- // Lookup host
- lpHost = gethostbyname(pstrHost);
- if (lpHost == NULL)
- {
- fprintf(stderr,"nHost not found: %sn", pstrHost);
- return;
- }
- // Setup destination socket address
- saDest.sin_addr.s_addr = *((u_long FAR *) (lpHost->h_addr));
- saDest.sin_family = AF_INET;
- saDest.sin_port = 0;
- // Tell the user what we're doing
- printf("nPinging %s [%s] with %d bytes of data:n",
- pstrHost,
- inet_ntoa(saDest.sin_addr),
- REQ_DATASIZE);
- // Ping multiple times
- for (nLoop = 0; nLoop < 4; nLoop++)
- {
- // Send ICMP echo request
- SendEchoRequest(rawSocket, &saDest);
- // Use select() to wait for data to be received
- nRet = WaitForEchoReply(rawSocket);
- if (nRet == SOCKET_ERROR)
- {
- ReportError("select()");
- break;
- }
- if (!nRet)
- {
- printf("nTimeOut");
- break;
- }
- // Receive reply
- dwTimeSent = RecvEchoReply(rawSocket, &saSrc, &cTTL);
- // Calculate elapsed time
- dwElapsed = GetTickCount() - dwTimeSent;
- printf("nReply from: %s: bytes=%d time=%ldms TTL=%d",
- inet_ntoa(saSrc.sin_addr),
- REQ_DATASIZE,
- dwElapsed,
- cTTL);
- }
- printf("n");
- nRet = closesocket(rawSocket);
- if (nRet == SOCKET_ERROR)
- ReportError("closesocket()");
- }
- /*
- 使用原始套接字编程,实现分片IP数据包的构造,能够用两个IP分片
- 构成ICMP ECHO请求,并接收另一方协议栈返回的ICMP应答。
- */
- void sendIP(LPCSTR pstrHost){
- SOCKET rawSocket; //原始套接字
- LPHOSTENT lpHost; //保存目的主机信息
- struct sockaddr_in saDest; //目的主机
- struct sockaddr_in saSrc; //源主机
- DWORD dwTimeSent; //发送时间
- DWORD dwElapsed; //时间间隔
- u_char cTTL; //ttl
- //int nLoop; //发送循环的ping的次数,这里是需要分片的片数目
- int nRet;
- // Create a Raw socket创建IP数据包的套接字
- rawSocket = socket(AF_INET, SOCK_RAW, IPPROTO_IP);
- if (rawSocket == SOCKET_ERROR)
- {
- ReportError("socket()");
- return;
- }
- //设置套接字选项
- BOOL blflag = true;
- int set_return = setsockopt(rawSocket,
- IPPROTO_IP,
- IP_HDRINCL,
- (char*)&blflag,
- sizeof(blflag));
- if (set_return)
- {
- printf("设置选项失败!%d",set_return);
- return;
- }
- if (set_return == SOCKET_ERROR)
- {
- printf("设置选项错误!");
- return;
- }
- // Lookup host
- lpHost = gethostbyname(pstrHost);
- if (lpHost == NULL)
- {
- fprintf(stderr,"nHost not found: %sn", pstrHost);
- return;
- }
- printf("n输入本机IP地址:n");
- gets(sourseIP);
- // Setup destination socket address
- saDest.sin_addr.s_addr = *((u_long FAR *) (lpHost->h_addr));
- saDest.sin_family = AF_INET;
- saDest.sin_port = 0;
- // Tell the user what we're doing
- printf("n发送数据包(2个分片第一片)到 %s --[%s] 数据大小是%d :n",
- pstrHost,
- inet_ntoa(saDest.sin_addr),
- REQ_DATASIZE);
- // Ping multiple times
- printf("n分片发送,不重叠输入0,重叠输入1:n");
- std::cin>>flag1;
- printf("n分片发送,两片顺序发送输入0,逆序发送输入1:n");
- std::cin>>flag2;
- if (flag2==0)
- {
- SendIPEchoRequest(rawSocket,&saDest);
- SendIPEchoRequestFragmentTwo(rawSocket,&saDest);
- }
- if (flag2==1)
- {
- SendIPEchoRequestFragmentTwo(rawSocket,&saDest);
- SendIPEchoRequest(rawSocket,&saDest);
- }
- // Use select() to wait for data to be received
- nRet = WaitForEchoReply(rawSocket);
- if (nRet == SOCKET_ERROR)
- ReportError("select()");
- if (!nRet)
- printf("nTimeOut");
- // Receive reply//////////////////////////////////////////////
- dwTimeSent = RecvEchoReply(rawSocket, &saSrc, &cTTL);
- printf("n检查收到的时间:%dn",dwTimeSent);
- // Calculate elapsed time
- dwElapsed = GetTickCount() - dwTimeSent;
- printf("n当前的时间 :%dn",GetTickCount());
- printf("nReply from: %s: bytes=%d time=%ldms TTL=%d",
- inet_ntoa(saSrc.sin_addr),
- REQ_DATASIZE,
- dwElapsed,
- cTTL);
- printf("n");
- nRet = closesocket(rawSocket);
- if (nRet == SOCKET_ERROR)
- ReportError("closesocket()");
- }
- // SendEchoRequest()
- // Fill in echo request header
- // and send to destination
- int SendEchoRequest(SOCKET s,LPSOCKADDR_IN lpstToAddr)
- {
- static ECHOREQUEST echoReq;
- static short nId = 1;
- static short nSeq = 1;
- int nRet;
- // Fill in echo request
- echoReq.icmpHdr.Type = ICMP_ECHOREQ;
- echoReq.icmpHdr.Code = 0;
- echoReq.icmpHdr.Checksum = 0;
- echoReq.icmpHdr.ID = nId++;
- echoReq.icmpHdr.Seq = nSeq++;
- // Fill in some data to send
- for (nRet = 0; nRet < REQ_DATASIZE; nRet++)
- echoReq.cData[nRet] = 'a'+nRet;
- // printf("nn%dnn",sizeof(echoReq));
- // Save tick count when sent
- echoReq.dwTime = GetTickCount();
- // Put data in packet and compute checksum
- echoReq.icmpHdr.Checksum = in_cksum((u_short *)&echoReq, sizeof(ECHOREQUEST));
- // Send the echo request
- nRet = sendto(s, /* socket */
- (LPSTR)&echoReq, /* buffer */
- sizeof(ECHOREQUEST),
- 0, /* flags */
- (LPSOCKADDR)lpstToAddr, /* destination */
- sizeof(SOCKADDR_IN)); /* address length */
- if (nRet == SOCKET_ERROR)
- ReportError("sendto()");
- return (nRet);
- }
- /*发送第一片数据*/
- int SendIPEchoRequest(SOCKET s,LPSOCKADDR_IN lpstToAddr){
- static IPECHOREQUET ipechoReq;
- //第一片的IP头部处理过程
- ipechoReq.ipHeader.VIHL = 0x45; //版本是4,首部长度是5
- ipechoReq.ipHeader.TOS = 0x0; //由标准组织分配
- ipechoReq.ipHeader.ID = ip_id; //ip的标识(一唯),这里一定要注意,ip标识不变,同一个数据包的两片
- ipechoReq.ipHeader.TTL = 64; //网络中的最大寿命
- ipechoReq.ipHeader.iaSrc.s_addr = inet_addr(sourseIP); //源主机地址
- ipechoReq.ipHeader.iaDst = lpstToAddr->sin_addr; //
- ipechoReq.ipHeader.Protocol = IPPROTO_ICMP; //协议的类型包含ICMP
- ipechoReq.ipHeader.FlagOff = htons(0x2000); //第一片标志位是001000000000000
- ipechoReq.ipHeader.TotLen = sizeof(IPECHOREQUET); //总产度设置成64,数据部分应该是52
- ipechoReq.ipHeader.Checksum = 0; //
- //IP包头校验和计算
- ipechoReq.ipHeader.Checksum = in_cksum((u_short *)&(ipechoReq.ipHeader), sizeof(IPHDR));
- // Fill in echo request
- ipechoReq.icmp_data.icmpHdr.Type = ICMP_ECHOREQ; //请求数据包类型
- ipechoReq.icmp_data.icmpHdr.Code = 0; //
- ipechoReq.icmp_data.icmpHdr.Checksum = 0; //检验和字段
- ipechoReq.icmp_data.icmpHdr.ID = nId++; //成对出现的
- ipechoReq.icmp_data.icmpHdr.Seq = nSeq++; //成对出现
- // Save tick count when sent
- ipechoReq.icmp_data.dwTime = GetTickCount();
- printf("n发送的时间:%dn",ipechoReq.icmp_data.dwTime);
- memset(DataToSend,0,Renum);
- //ICMP头部填充////////////////////////////////////////////////////////////////////////////
- int nRet;
- for (nRet = 0;nRet < REQ_DATASIZE;nRet++)
- DataToSend[nRet] = 'a';
- for(nRet = REQ_DATASIZE;nRet<Renum;nRet++)
- DataToSend[nRet] = 'b';
- //第一片需要发送的数据
- for (nRet = 0;nRet < REQ_DATASIZE;nRet++)
- ipechoReq.icmp_data.cData[nRet] = DataToSend[nRet];
- //计算校验和的部分构成
- if (flag1 == 0)
- {
- tempECHREQUEST tempecho;
- memset(tempecho.cData,0,Renum);
- tempecho.icmpHdr = ipechoReq.icmp_data.icmpHdr;
- tempecho.dwTime = ipechoReq.icmp_data.dwTime;
- memcpy(tempecho.cData,DataToSend,Renum);
- // Put data in packet and compute checksum
- ipechoReq.icmp_data.icmpHdr.Checksum = in_cksum((u_short *)&tempecho,
- sizeof(tempECHREQUEST));
- }
- if (flag1==1)
- {
- tempecho temp;
- memset(temp.cData,0,Renum+8);
- temp.dwTime = ipechoReq.icmp_data.dwTime;
- temp.icmpHdr = ipechoReq.icmp_data.icmpHdr;
- memcpy(temp.cData,DataToSend,REQ_DATASIZE); //第一片复制
- memcpy(temp.cData+REQ_DATASIZE,DataToSend+REQ_DATASIZE-8,REQ_datasize2);
- ipechoReq.icmp_data.icmpHdr.Checksum = in_cksum((u_short *)&temp,
- sizeof(tempecho));
- }
- //发送echo 请求
- nRet = sendto(s,
- (LPSTR)&ipechoReq,
- sizeof(IPECHOREQUET),
- 0,
- (LPSOCKADDR)lpstToAddr,
- sizeof(SOCKADDR_IN));
- if (nRet == SOCKET_ERROR)
- ReportError("sendto()");
- return nRet;
- }
- /*
- 发送第二片数据
- */
- int SendIPEchoRequestFragmentTwo(SOCKET s,LPSOCKADDR_IN lpstToAddr){
- IPEchoTwo ipechoReq;
- //第二片的IP头部处理过程
- ipechoReq.ipHeader.VIHL = 0x45; //版本是4,首部长度是5
- ipechoReq.ipHeader.TOS = 0x0; //由标准组织分配
- ipechoReq.ipHeader.ID = ip_id; //ip的标识(一唯)
- ipechoReq.ipHeader.TTL = 64; //网络中的最大寿命
- ipechoReq.ipHeader.iaSrc.s_addr = inet_addr(sourseIP); //源主机地址
- ipechoReq.ipHeader.iaDst = lpstToAddr->sin_addr; //
- ipechoReq.ipHeader.Protocol = IPPROTO_ICMP; //协议的类型包含ICMP
- //////////////////////////////////////////////////////////////////////////////////////
- if (flag1 == 0)
- ipechoReq.ipHeader.FlagOff = htons(0x6); //第二片标志位是
- if (flag1 == 1)
- ipechoReq.ipHeader.FlagOff = htons(0x5); //第二片标志位是
- ipechoReq.ipHeader.TotLen = sizeof(IPEchoTwo); //总产度设置成64,数据部分应该是44
- ipechoReq.ipHeader.Checksum = 0; //
- //IP包头校验和计算
- ipechoReq.ipHeader.Checksum = in_cksum((u_short *)&(ipechoReq.ipHeader), sizeof(IPHDR));
- //ICMP头部填充
- int nRet;
- //填充其他的数据部分/////////////////////////////////////////////////////////////////////////////
- if (flag1 == 0){
- memcpy(ipechoReq.cData,DataToSend+REQ_DATASIZE,REQ_datasize2);
- nRet = sendto(s,
- (LPSTR)&ipechoReq,
- sizeof(IPEchoTwo),
- 0,
- (LPSOCKADDR)lpstToAddr,
- sizeof(SOCKADDR_IN));
- }
- if (flag1 == 1){
- IPechotwo2 ipecho;
- ipecho.ipHeader = ipechoReq.ipHeader;
- memset(ipecho.cData,0,REQ_datasize2+8);
- memcpy(ipecho.cData,DataToSend+REQ_DATASIZE-8,REQ_datasize2+8);
- nRet = sendto(s,
- (LPSTR)&ipechoReq,
- sizeof(IPechotwo2),
- 0,
- (LPSOCKADDR)lpstToAddr,
- sizeof(SOCKADDR_IN));
- }
- //发送echo 请求
- if (nRet == SOCKET_ERROR)
- ReportError("sendto()");
- return nRet;
- }
- // RecvEchoReply()
- // Receive incoming data
- // and parse out fields
- DWORD RecvEchoReply(SOCKET s, LPSOCKADDR_IN lpsaFrom, u_char *pTTL)
- {
- IPECHOREPLY ipreply;
- int nRet;
- int nAddrLen = sizeof(struct sockaddr_in);
- // Receive the echo reply
- nRet = recvfrom(s, // socket
- (LPSTR)&ipreply, // buffer
- sizeof(IPECHOREPLY), // size of buffer
- 0, // flags
- (LPSOCKADDR)lpsaFrom, // From address
- &nAddrLen); // pointer to address len
- // Check return value
- if (nRet == SOCKET_ERROR)
- ReportError("recvfrom()");
- // return time sent and IP TTL
- *pTTL = ipreply.ipHdr.TTL;
- return(ipreply.echoRequest.dwTime);
- }
- // What happened?
- void ReportError(LPCSTR pWhere)
- {
- fprintf(stderr,"n%s error: %dn",
- WSAGetLastError());
- }
- // WaitForEchoReply()
- // Use select() to determine when
- // data is waiting to be read
- int WaitForEchoReply(SOCKET s)
- {
- struct timeval Timeout;
- fd_set readfds;
- /*fd_set结构体的定义
- typedef struct fd_set{
- u_int fd_count; //集合中的socket数量
- SOCKET fd_array[FD_SETSIZE]; //集合中包含的Socket数组
- }fd_set;
- */
- readfds.fd_count = 1;
- readfds.fd_array[0] = s;
- Timeout.tv_sec = 5;
- Timeout.tv_usec = 0;
- return(select(1, &readfds, NULL, NULL, &Timeout));
- }
- //
- // Mike Muuss' in_cksum() function
- // and his comments from the original
- // ping program
- //
- // * Author -
- // * Mike Muuss
- // * U. S. Army Ballistic Research Laboratory
- // * December, 1983
- /*
- * I N _ C K S U M
- *
- * Checksum routine for Internet Protocol family headers (C Version)
- *
- */
- u_short in_cksum(u_short *addr, int len)
- {
- register int nleft = len;
- register u_short *w = addr;
- register u_short answer;
- register int sum = 0;
- /*
- * Our algorithm is simple, using a 32 bit accumulator (sum),
- * we add sequential 16 bit words to it, and at the end, fold
- * back all the carry bits from the top 16 bits into the lower
- * 16 bits.
- */
- while( nleft > 1 ) {
- sum += *w++;
- nleft -= 2;
- }
- /* mop up an odd byte, if necessary */
- if( nleft == 1 ) {
- u_short u = 0;
- *(u_char *)(&u) = *(u_char *)w ;
- sum += u;
- }
- /*
- * add back carry outs from top 16 bits to low 16 bits
- */
- sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
- sum += (sum >> 16); /* add carry */
- answer = ~sum; /* truncate to 16 bits */
- return (answer);
- }
来源: http://www.phpxs.com/code/1004152/