实验3 ICMP协议实践ping解析资料.docx
《实验3 ICMP协议实践ping解析资料.docx》由会员分享,可在线阅读,更多相关《实验3 ICMP协议实践ping解析资料.docx(22页珍藏版)》请在冰豆网上搜索。
实验3ICMP协议实践ping解析资料
实验3ICMP协议实践ping解析
计算机网络实验上机指导书
专业
班级
学号
姓名
沈阳工程学院信息工程系
实验2ICMP协议实践--ping解析
一.实验目的
掌握ICMP原理,利用其实现网络主机状态测试。
二.实验内容
利用ICMP协议原理编程实现PING命令,测试目标主机是否可到达。
并了解Ping实现原理。
三.实验前的准备
●了解ICMP原理及相关概念。
●掌握相关软件编程知识。
四.实验要求及实验软硬件环境
【基本要求】
●设计程序完成PING命令。
●完成此项实验,完成实验报告。
【实验组织方式】
●个人实验
【实验条件】
●局域网环境下微机两台,编程软件。
五.实验步骤
六..了解ICMP原理以及网络编程
(1)源程序:
Windows
//
//Ping.h
//
#pragmapack
(1)
#defineICMP_ECHOREPLY0
#defineICMP_ECHOREQ8
//IPHeader--RFC791
typedefstructtagIPHDR
{
u_charVIHL;//VersionandIHL
u_charTOS;//TypeOfService
shortTotLen;//TotalLength
shortID;//Identification
shortFlagOff;//FlagsandFragmentOffset
u_charTTL;//TimeToLive
u_charProtocol;//Protocol
u_shortChecksum;//Checksum
structin_addriaSrc;//InternetAddress-Source
structin_addriaDst;//InternetAddress-Destination
}IPHDR,*PIPHDR;
//ICMPHeader-RFC792
typedefstructtagICMPHDR
{
u_charType;//Type
u_charCode;//Code
u_shortChecksum;//Checksum
u_shortID;//Identification
u_shortSeq;//Sequence
charData;//Data
}ICMPHDR,*PICMPHDR;
#defineREQ_DATASIZE32//EchoRequestDatasize
//ICMPEchoRequest
typedefstructtagECHOREQUEST
{
ICMPHDRicmpHdr;
DWORDdwTime;
charcData[REQ_DATASIZE];
}ECHOREQUEST,*PECHOREQUEST;
//ICMPEchoReply
typedefstructtagECHOREPLY
{
IPHDRipHdr;
ECHOREQUESTechoRequest;
charcFiller[256];
}ECHOREPLY,*PECHOREPLY;
#pragmapack()
//
//PING.C--PingprogramusingICMPandRAWSockets
//
#include
#include
#include
#include"ping.h"
//InternalFunctions
voidPing(LPCSTRpstrHost);
voidReportError(LPCSTRpstrFrom);
intWaitForEchoReply(SOCKETs);
u_shortin_cksum(u_short*addr,intlen);
//ICMPEchoRequest/Replyfunctions
intSendEchoRequest(SOCKET,LPSOCKADDR_IN);
DWORDRecvEchoReply(SOCKET,LPSOCKADDR_IN,u_char*);
//main()
voidmain(intargc,char**argv)
{
WSADATAwsaData;
WORDwVersionRequested=MAKEWORD(1,1);
intnRet;
//Checkarguments
if(argc!
=2)
{
fprintf(stderr,"\nUsage:
pinghostname\n");
return;
}
//InitWinSock
nRet=WSAStartup(wVersionRequested,&wsaData);
if(nRet)
{
fprintf(stderr,"\nErrorinitializingWinSock\n");
return;
}
//Checkversion
if(wsaData.wVersion!
=wVersionRequested)
{
fprintf(stderr,"\nWinSockversionnotsupported\n");
return;
}
//Godotheping
Ping(argv[1]);
//FreeWinSock
WSACleanup();
}
//Ping()
//CallsSendEchoRequest()and
//RecvEchoReply()andprintsresults
voidPing(LPCSTRpstrHost)
{
SOCKETrawSocket;
LPHOSTENTlpHost;
structsockaddr_insaDest;
structsockaddr_insaSrc;
DWORDdwTimeSent;
DWORDdwElapsed;
u_charcTTL;
intnLoop;
intnRet;
//CreateaRawsocket
rawSocket=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);
if(rawSocket==SOCKET_ERROR)
{
ReportError("socket()");
return;
}
//Lookuphost
lpHost=gethostbyname(pstrHost);
if(lpHost==NULL)
{
fprintf(stderr,"\nHostnotfound:
%s\n",pstrHost);
return;
}
//Setupdestinationsocketaddress
saDest.sin_addr.s_addr=*((u_longFAR*)(lpHost->h_addr));
saDest.sin_family=AF_INET;
saDest.sin_port=0;
//Telltheuserwhatwe'redoing
printf("\nPinging%s[%s]with%dbytesofdata:
\n",
pstrHost,
inet_ntoa(saDest.sin_addr),
REQ_DATASIZE);
//Pingmultipletimes
for(nLoop=0;nLoop<4;nLoop++)
{
//SendICMPechorequest
SendEchoRequest(rawSocket,&saDest);
//Useselect()towaitfordatatobereceived
nRet=WaitForEchoReply(rawSocket);
if(nRet==SOCKET_ERROR)
{
ReportError("select()");
break;
}
if(!
nRet)
{
printf("\nTimeOut");
break;
}
//Receivereply
dwTimeSent=RecvEchoReply(rawSocket,&saSrc,&cTTL);
//Calculateelapsedtime
dwElapsed=GetTickCount()-dwTimeSent;
printf("\nReplyfrom:
%s:
bytes=%dtime=%ldmsTTL=%d",
inet_ntoa(saSrc.sin_addr),
REQ_DATASIZE,
dwElapsed,
cTTL);
}
printf("\n");
nRet=closesocket(rawSocket);
if(nRet==SOCKET_ERROR)
ReportError("closesocket()");
}
//SendEchoRequest()
//Fillinechorequestheader
//andsendtodestination
intSendEchoRequest(SOCKETs,LPSOCKADDR_INlpstToAddr)
{
staticECHOREQUESTechoReq;
staticnId=1;
staticnSeq=1;
intnRet;
//Fillinechorequest
echoReq.icmpHdr.Type=ICMP_ECHOREQ;
echoReq.icmpHdr.Code=0;
echoReq.icmpHdr.Checksum=0;
echoReq.icmpHdr.ID=nId++;
echoReq.icmpHdr.Seq=nSeq++;
//Fillinsomedatatosend
for(nRet=0;nRetechoReq.cData[nRet]=''+nRet;
//Savetickcountwhensent
echoReq.dwTime=GetTickCount();
//Putdatainpacketandcomputechecksum
echoReq.icmpHdr.Checksum=in_cksum((u_short*)&echoReq,sizeof(ECHOREQUEST));
//Sendtheechorequest
nRet=sendto(s,/*socket*/
(LPSTR)&echoReq,/*buffer*/
sizeof(ECHOREQUEST),
0,/*flags*/
(LPSOCKADDR)lpstToAddr,/*destination*/
sizeof(SOCKADDR_IN));/*addresslength*/
if(nRet==SOCKET_ERROR)
ReportError("sendto()");
return(nRet);
}
//RecvEchoReply()
//Receiveincomingdata
//andparseoutfields
DWORDRecvEchoReply(SOCKETs,LPSOCKADDR_INlpsaFrom,u_char*pTTL)
{
ECHOREPLYechoReply;
intnRet;
intnAddrLen=sizeof(structsockaddr_in);
//Receivetheechoreply
nRet=recvfrom(s,//socket
(LPSTR)&echoReply,//buffer
sizeof(ECHOREPLY),//sizeofbuffer
0,//flags
(LPSOCKADDR)lpsaFrom,//Fromaddress
&nAddrLen);//pointertoaddresslen
//Checkreturnvalue
if(nRet==SOCKET_ERROR)
ReportError("recvfrom()");
//returntimesentandIPTTL
*pTTL=echoReply.ipHdr.TTL;
return(echoReply.echoRequest.dwTime);
}
//Whathappened?
voidReportError(LPCSTRpWhere)
{
fprintf(stderr,"\n%serror:
%d\n",
WSAGetLastError());
}
//WaitForEchoReply()
//Useselect()todeterminewhen
//dataiswaitingtoberead
intWaitForEchoReply(SOCKETs)
{
structtimevalTimeout;
fd_setreadfds;
readfds.fd_count=1;
readfds.fd_array[0]=s;
Timeout.tv_sec=5;
Timeout.tv_usec=0;
return(select(1,&readfds,NULL,NULL,&Timeout));
}
//
//MikeMuuss'in_cksum()function
//andhiscommentsfromtheoriginal
//pingprogram
//
//*Author-
//*MikeMuuss
//*U.S.ArmyBallisticResearchLaboratory
//*December,1983
/*
*IN_CKSUM
*
*ChecksumroutineforInternetProtocolfamilyheaders(CVersion)
*
*/
u_shortin_cksum(u_short*addr,intlen)
{
registerintnleft=len;
registeru_short*w=addr;
registeru_shortanswer;
registerintsum=0;
/*
*Ouralgorithmissimple,usinga32bitaccumulator(sum),
*weaddsequential16bitwordstoit,andattheend,fold
*backallthecarrybitsfromthetop16bitsintothelower
*16bits.
*/
while(nleft>1){
sum+=*w++;
nleft-=2;
}
/*mopupanoddbyte,ifnecessary*/
if(nleft==1){
u_shortu=0;
*(u_char*)(&u)=*(u_char*)w;
sum+=u;
}
/*
*addbackcarryoutsfromtop16bitstolow16bits
*/
sum=(sum>>16)+(sum&0xffff);/*addhi16tolow16*/
sum+=(sum>>16);/*addcarry*/
answer=~sum;/*truncateto16bits*/
return(answer);
}
实验结果如图6-1所示。
图6-1ping程序运行结果
(2)LINUX
/*简单的ping程序*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#definePACKET_SIZE4096
#defineMAX_WAIT_TIME5
#defineMAX_NO_PACKETS3
charsendpacket[PACKET_SIZE];
charrecvpacket[PACKET_SIZE];
intsockfd,datalen=56;
intnsend=0,nreceived=0;
structsockaddr_indest_addr;
pid_tpid;
structsockaddr_infrom;
structtimevaltvrecv;
voidstatistics(intsigno);
unsignedshortcal_chksum(unsignedshort*addr,intlen);
intpack(intpack_no);
voidsend_packet(void);
voidrecv_packet(void);
intunpack(char*buf,intlen);
voidtv_sub(structtimeval*out,structtimeval*in);
voidstatistics(intsigno)
{printf("\n--------------------PINGstatistics-------------------\n");
printf("%dpacketstransmitted,%dreceived,%%%dlost\n",nsend,nreceived,
(nsend-nreceived)/nsend*100);
close(sockfd);
exit
(1);
}
/*校验和算法*/
unsignedshortcal_chksum(unsignedshort*addr,intlen)
{intnleft=len;
intsum=0;
unsignedshort*w=addr;
unsignedshortanswer=0;
/*把ICMP报头二进制数据以2字节为单位累加起来*/
while(nleft>1)
{sum+=*w++;
nleft-=2;
}
/*若ICMP报头为奇数个字节,会剩下最后一字节。
把最后一个字节视为一个2字节数据的高字节,这个2字节数据的低字节为0,继续累加*/
if(nleft==1)
{*(unsignedchar*)(&answer)=*(unsignedchar*)w;
sum+=answer;
}
sum=(sum>>16)+(sum&0xffff);
sum+=(sum>>16);
answer=~sum;
returnanswer;
}
/*设置ICMP报头*/
intpack(intpack_no)
{inti,packsize;
structicmp*icmp;
structtimeval*tval;
icmp=(structicmp*)sendpacket;
icmp->icmp_type=ICMP_ECHO;
icmp->icmp_code=0;
icmp->icmp_cksum=0;
icmp->icmp_seq=pack_no;
icmp->icmp_id=pid;
packsize=8+datalen;
tval=(structtimeval*)icmp->icmp_data;
gettimeofday(tval,NULL);/*记录发送时间*/
icmp->icmp_cksum=cal_chksum((unsignedshort*)icmp,packsize);/*校验算法*/
returnpacksize;
}
/*发送三个ICMP报文*/
voidsend_packet()
{intpacketsize;
while(nsend{nsend++;
packetsize=pack(nsend);/*设置ICMP报头*/
if(sendto(sockfd,sendpacket,packetsize,0,
(structsockaddr*)&dest_addr,sizeof(dest_addr))<0)
{perror("sendtoerror");
continue;
}
sleep
(1);/*每隔一秒发送一个ICMP报文*/
}
}
/*接收所有ICMP报文*/
voidrecv_packet()
{intn,fromlen;
exte