计算机网络的一个作业:实现ping+ip 不要求其它参数
用到的知识:ip报头结构,icmp报头结构,获取主机ip方法,winsock的简单操作
实现的结果:一般的ip能够ping通,如www.baidu.com, www.sina.com.cn
存在的问题:本机(127.0.0.1)ping不通
1 /* 2 *filename:ping.c 3 *author:ChrisZZ 4 */ 5 #pragma comment(lib, "ws2_32.lib") 6 #include <stdio.h> 7 #include <winsock2.h> 8 #include <ws2tcpip.h> 9 #include <process.h> 10 11 12 struct IPHeader{//IPv4头部结构 13 unsigned char ver_hlen;//头部长度,用4位表示,range[5,15] 14 // unsigned int ver:4;//version 15 unsigned char tos;//type of service 16 unsigned short total_len; 17 unsigned short id; 18 unsigned short frags_and_flags; 19 unsigned char ttl;//time to live 20 unsigned char proto;//protocal 21 unsigned short chksum;//checksum 22 unsigned int srcIp;//source IP 23 unsigned int dstIp;//destination IP 24 }; 25 26 struct ICMPHeader{//ICMP头部结构 27 unsigned char type; 28 unsigned char code; 29 unsigned short chksum; 30 unsigned short id; 31 unsigned short seq;//sequence 32 unsigned int timestamp; 33 }; 34 35 #define ICMP_ECHO 8 36 #define ICMP_ECHO_REPLY 0 37 #define PACKAGE_SIZE sizeof(IPHeader)+sizeof(ICMPHeader) 38 void usage(); 39 unsigned short CheckSum(unsigned short*, int); 40 void HandleError(char *); 41 42 //用法说明函数 43 void usage(){ 44 printf("用法:ping 目标主机\n\n"); 45 system("pause"); 46 } 47 48 //错误处理函数 49 void HandleError(char *str){ 50 int errCode=WSAGetLastError(); 51 52 char info[65]={0}; 53 _snprintf(info, 64, "%s: %d\n", str, errCode); 54 printf(info); 55 } 56 57 unsigned short checksum(unsigned short* buff, int size){ 58 unsigned int chksum=0; 59 while(size>1){ 60 chksum+=*buff++; 61 size-=sizeof(unsigned short); 62 } 63 if(size){ 64 chksum+=*(unsigned char*)(buff); 65 } 66 chksum=(chksum>>16)+(chksum &0xffff); 67 chksum+=(chksum>>16); 68 return (unsigned short)(~chksum); 69 } 70 71 void FillPackage(char *pData, unsigned int dstIP, unsigned short id){ 72 memset(pData, 0, PACKAGE_SIZE); 73 74 IPHeader *pIPHeader=(IPHeader*)pData; 75 76 int nVersion=4; 77 int nHeadSize=sizeof(IPHeader)/4; 78 79 //获得本机IP 80 struct sockaddr_in SrcAddr; 81 struct hostent * hpsrc; 82 char localhost[32]; 83 gethostname(localhost, sizeof(localhost)); 84 hpsrc=gethostbyname(localhost); 85 memset(&SrcAddr, 0, sizeof(SrcAddr)); 86 memcpy(&(SrcAddr.sin_addr), hpsrc->h_addr, hpsrc->h_length); 87 SrcAddr.sin_port=htons(0); 88 SrcAddr.sin_family=AF_INET; 89 90 91 unsigned int srcIP=SrcAddr.sin_addr.s_addr;//本机IP 92 unsigned int destIp=dstIP; 93 pIPHeader->ver_hlen=(nVersion<<4)|nHeadSize; 94 pIPHeader->tos=0; 95 pIPHeader->total_len=htons(PACKAGE_SIZE); 96 pIPHeader->id=htons(1234);//???? 97 pIPHeader->frags_and_flags=0; 98 pIPHeader->ttl=255;//?? 99 pIPHeader->proto=IPPROTO_ICMP; 100 pIPHeader->chksum=0; 101 pIPHeader->srcIp=srcIP; 102 pIPHeader->dstIp=dstIP; 103 104 pIPHeader->chksum=checksum((unsigned short*)pData, sizeof(IPHeader)); 105 ICMPHeader* pICMPHeader=(ICMPHeader*)(pData+sizeof(IPHeader)); 106 pICMPHeader->type=ICMP_ECHO; 107 pICMPHeader->code=0; 108 pICMPHeader->chksum=0; 109 pICMPHeader->id=htons(id); 110 pICMPHeader->seq=htons(id); 111 pICMPHeader->chksum=checksum((unsigned short*)((char*)pData+sizeof(IPHeader)), sizeof(ICMPHeader)); 112 113 } 114 115 int main(int argc, char* argv[]){ 116 117 //初始化 118 WSADATA wsaData; 119 struct sockaddr_in DestAddr,from; 120 IPHeader *ip; 121 ICMPHeader *icmp; 122 ICMPHeader *SendIcmp; 123 int Timeout=1000; 124 char IcmpBuffer[PACKAGE_SIZE]=""; 125 SOCKET IcmpSocket; 126 char RecvBuffer[1024]; 127 sockaddr_in addr; 128 int Len = sizeof(addr); 129 int Result; 130 struct hostent * hpdst; 131 int pid=_getpid(); 132 struct timeval tv; 133 fd_set readSet; 134 BOOL bBroadcast=false; 135 136 //确定参数个数 137 if(argc!=2){ 138 printf("参数不正确\n"); 139 usage(); 140 return -1; 141 } 142 143 144 if ((Result = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0){ 145 printf("WSAStartup failed with error %d\n", Result); 146 return 0; 147 } 148 149 150 //获取目的主机IP 151 hpdst=gethostbyname(argv[1]); 152 if(hpdst==NULL){ 153 HandleError("gethostbyname"); 154 WSACleanup(); 155 return -1; 156 } 157 158 //创建ICMP封包并发送 159 //char buff[sizeof(ICMP_HDR)+32]; 160 IcmpSocket=socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 161 if(IcmpSocket==INVALID_SOCKET){ 162 HandleError("socket"); 163 WSACleanup(); 164 return -1; 165 } 166 BOOL on=TRUE; 167 Result=setsockopt(IcmpSocket,IPPROTO_IP,IP_HDRINCL, (char*)&on, sizeof(on)); 168 if(Result==SOCKET_ERROR){ 169 HandleError("socketopt"); 170 WSACleanup(); 171 return -1; 172 } 173 memset(&DestAddr, 0, sizeof(DestAddr)); 174 memcpy(&(DestAddr.sin_addr), hpdst->h_addr, hpdst->h_length); 175 DestAddr.sin_port=htons(0); 176 /*reference:http://www.cnblogs.com/CBDoctor/archive/2012/10/28/2743109.html*/ 177 DestAddr.sin_family=AF_INET; 178 179 180 181 int i; 182 for(i=0; i<3; i++){ 183 if(i==0) printf("正在Ping %s 具有 %d 字节的数据:\n", inet_ntoa(DestAddr.sin_addr), 32); 184 185 FillPackage(IcmpBuffer, DestAddr.sin_addr.s_addr/*dstIp*/, (unsigned short)pid); 186 187 Result=sendto(IcmpSocket, IcmpBuffer, PACKAGE_SIZE, 0, (struct sockaddr*)&DestAddr, sizeof(DestAddr)); 188 if(Result==SOCKET_ERROR){ 189 HandleError("sendto"); 190 break; 191 } 192 193 while (1){ 194 tv.tv_sec=3; 195 tv.tv_usec=0; 196 FD_ZERO(&readSet); 197 FD_SET(IcmpSocket,&readSet); 198 199 int res=select(IcmpSocket+1,&readSet,NULL,NULL,&tv); 200 if(res==SOCKET_ERROR){ 201 HandleError("select"); 202 break; 203 } 204 if(res==0){ 205 if(!bBroadcast) 206 printf("请求超时。\n"); 207 break; 208 } 209 if(FD_ISSET(IcmpSocket, &readSet)){ 210 memset(IcmpBuffer,0, PACKAGE_SIZE); 211 memset(&from,0,sizeof(from)); 212 int len=sizeof(from); 213 if(recvfrom(IcmpSocket, IcmpBuffer, PACKAGE_SIZE,0,(struct sockaddr*) &from, &len)==SOCKET_ERROR) 214 { 215 HandleError("recvfrom"); 216 break; 217 } 218 219 IPHeader *pIPHdr=(IPHeader *) IcmpBuffer; 220 ICMPHeader *pICMPHdr=(ICMPHeader*)(IcmpBuffer+sizeof(IPHeader)); 221 int nTime = GetTickCount() - pICMPHdr->timestamp; 222 if(pICMPHdr->id==htons((u_short) pid)&&pICMPHdr->seq==htons((u_short) pid) 223 &&pICMPHdr->type==ICMP_ECHO_REPLY){ 224 printf("来自 %s 的回复: 字节=%d time=%dms\n",inet_ntoa(from.sin_addr), Result, pIPHdr->ttl); 225 if (!bBroadcast) break; 226 } 227 } 228 }//end of while 229 Sleep(1000); 230 } 231 232 //关闭套接字 233 closesocket(IcmpSocket); 234 WSACleanup(); 235 system("pause"); 236 return 0; 237 }