// ping.cpp : 定义控制台应用程序的入口点。
//#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h> #define ICMP_ECHO 8
#define ICMP_ECHOREPLY 0 /* The IP header */
typedef struct iphdr
{ unsigned char h_len:4; // length of the header unsigned char version:4; // Version of IP unsigned char tos; // Type of service unsigned short total_len; // total length of the packet unsigned short ident; // unique identifier unsigned short frag_and_flags; // flags unsigned char ttl; unsigned char proto; // protocol (TCP, UDP etc) unsigned short checksum; // IP checksum unsigned int sourceIP; unsigned int destIP;
}IpHeader; /* ICMP header */
typedef struct _ihdr
{ BYTE i_type; BYTE i_code; /* type sub code */USHORT i_cksum; USHORT i_id; USHORT i_seq; /* This is not the std header, but we reserve space for time */ ULONG timestamp;
}IcmpHeader; #define STATUS_FAILED 0xFFFF
#define DEF_PACKET_SIZE 32
#define MAX_PACKET 1024 /* The response is an IP packet. We must decode the IP header to locate the ICMP data */
void decode_resp(char *buf, int bytes,struct sockaddr_in *from)
{IpHeader *iphdr; IcmpHeader *icmphdr; unsigned short iphdrlen; iphdr=(IpHeader*)buf; iphdrlen=sizeof(IpHeader)+sizeof(IcmpHeader);if(bytes<iphdrlen) { printf("Too few bytes from %s\n",inet_ntoa(from->sin_addr)); } icmphdr=(IcmpHeader*)(buf+sizeof(IpHeader)); if(icmphdr->i_type!=ICMP_ECHOREPLY) { fprintf(stderr,"non-echo type %d recvd\n",icmphdr->i_type); return; }if(icmphdr->i_id!=(USHORT)GetCurrentProcessId()) { fprintf(stderr,"someone else's packet!\n"); return ; }int correct=0;for(int k=0;k<bytes-iphdrlen;k++){if(*(buf+iphdrlen+k)=='E'){correct++;}}printf("来自 %s 的回复: 字节=%d 时间=%dms TTL=%d\n",\inet_ntoa(from->sin_addr),correct,GetTickCount()-icmphdr->timestamp,iphdr->ttl);
} USHORT checksum(USHORT *buffer, int size)
{ unsigned long cksum=0; while(size>1) { cksum+=*buffer++; size-=sizeof(USHORT); } if(size) { cksum+=*(UCHAR*)buffer; } cksum=(cksum>>16)+(cksum&0xffff); cksum+=(cksum>>16); return (USHORT)(~cksum);
} /* Helper function to fill in various stuff in our ICMP request. */
void fill_icmp_data(char *icmp_data, int datasize)
{ char *datapart=NULL; IcmpHeader *icmp_hdr=NULL; icmp_hdr=(IcmpHeader*)icmp_data; icmp_hdr->i_type=ICMP_ECHO; icmp_hdr->i_code=0; icmp_hdr->i_id=(USHORT)GetCurrentProcessId(); icmp_hdr->i_cksum=0; icmp_hdr->i_seq++; icmp_hdr->timestamp=GetTickCount(); datapart=icmp_data+sizeof(IcmpHeader); // Place some junk in the buffer. memset(datapart,'E',datasize-sizeof(IcmpHeader)); icmp_hdr->i_cksum=checksum((USHORT*)icmp_data,datasize);
} int main(int argc, char *argv[])
{ int count=1;int error=-1;int datasize=0; int timeout=3000; struct sockaddr_in addrServer; struct hostent *phostent=NULL; int destlen=sizeof(addrServer); char *dest_ip=NULL; char icmp_data[MAX_PACKET]; char recvbuf[MAX_PACKET]; unsigned int addr=0; char srcIP[MAX_PATH]="0.0.0.0";char dstIP[MAX_PATH]="127.0.0.1";for(int n=1;n<argc;){if(!strcmp(argv[n],"-S")){ n++;strcpy_s(srcIP,argv[n++]);}else if(!strcmp(argv[n],"-n")){n++;count=atoi(argv[n++]);}else{strcpy_s(dstIP,argv[n++]);}}WSADATA wsaData={0}; if(WSAStartup(MAKEWORD(1,1),&wsaData)!=0){ printf("WSA startup error\n"); ExitProcess(STATUS_FAILED); } SOCKET sockClient=WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0,0); if(sockClient==INVALID_SOCKET) { printf("WSA socket error\n"); ExitProcess(STATUS_FAILED); } sockaddr_in addrClient;addrClient.sin_addr.S_un.S_addr=inet_addr(srcIP);addrClient.sin_family=AF_INET;addrClient.sin_port=htons(0);error=bind(sockClient,(SOCKADDR *)&addrClient,sizeof(addrClient));if(error){closesocket(sockClient);printf("bind client error\n");return WSACleanup();}unsigned long ul=true;error=ioctlsocket(sockClient,FIONBIO,(unsigned long*)&ul);if(error){closesocket(sockClient);printf("set ioctlsocket error\n");return WSACleanup();}error=setsockopt(sockClient,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout, sizeof(timeout)); if(error==SOCKET_ERROR) { fprintf(stderr,"failed to set recv timeout: %d\n",WSAGetLastError()); ExitProcess(STATUS_FAILED); } error=setsockopt(sockClient,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout, sizeof(timeout)); if(error==SOCKET_ERROR) { fprintf(stderr,"failed to set send timeout: %d\n",WSAGetLastError()); ExitProcess(STATUS_FAILED); } memset(&addrServer,0,sizeof(addrServer)); phostent=gethostbyname(dstIP); if(!phostent){ addr=inet_addr(dstIP); } if((!phostent)&&(addr==INADDR_NONE)) { fprintf(stderr,"Unable to resolve host %s\n",dstIP); ExitProcess(STATUS_FAILED); } if(phostent!=NULL) {memcpy(&(addrServer.sin_addr),phostent->h_addr,phostent->h_length);}else{addrServer.sin_addr.s_addr=addr; }if(phostent) {addrServer.sin_family=phostent->h_addrtype;}else{addrServer.sin_family=AF_INET; dest_ip=inet_ntoa(addrServer.sin_addr);} datasize=DEF_PACKET_SIZE; datasize+=sizeof(IcmpHeader); memset(icmp_data,0,MAX_PACKET);for(int i=0;i<count;i++) { fill_icmp_data(icmp_data,datasize); int num=sendto(sockClient,icmp_data,datasize,0,(struct sockaddr*)&addrServer, sizeof(addrServer)); if(num==SOCKET_ERROR){ error=WSAGetLastError();if(error==WSAETIMEDOUT) { fprintf(stderr,"errorcode=%d\n",error); continue; }} if(num<datasize) { fprintf(stdout,"Write %d bytes\n",num); }timeval tm;int len=sizeof(int);fd_set set;for(int k=0;k<3;k++){num=recvfrom(sockClient,recvbuf,MAX_PACKET,0,(struct sockaddr*)&addrServer, &destlen); if(num!=SOCKET_ERROR){break;}if(num==SOCKET_ERROR){ Sleep(1);tm.tv_sec=0; tm.tv_usec=1; FD_ZERO(&set); FD_SET(sockClient,&set); if(select(sockClient,NULL,&set,NULL,&tm)>0) { getsockopt(sockClient,SOL_SOCKET,SO_ERROR,(char*)&error,&len); } }}if(num!=SOCKET_ERROR){decode_resp(recvbuf,num,&addrServer); }else{printf("Can not find host %s\n",dstIP); }if(i>0){Sleep(1000);}} closesocket(sockClient);WSACleanup();return 0;
}
编译命令如下:
g++ -std=c++2a -o ping.exe ping.cpp -lws2_32