实验3ICMP协议实践ping解析文档格式.docx
《实验3ICMP协议实践ping解析文档格式.docx》由会员分享,可在线阅读,更多相关《实验3ICMP协议实践ping解析文档格式.docx(22页珍藏版)》请在冰豆网上搜索。
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_shortID;
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<
stdio.h>
stdlib.h>
winsock.h>
#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)
\nErrorinitializingWinSock\n"
//Checkversion
if(wsaData.wVersion!
=wVersionRequested)
\nWinSockversionnotsupported\n"
//Godotheping
Ping(argv[1]);
//FreeWinSock
WSACleanup();
}
//Ping()
//CallsSendEchoRequest()and
//RecvEchoReply()andprintsresults
voidPing(LPCSTRpstrHost)
SOCKETrawSocket;
LPHOSTENTlpHost;
structsockaddr_insaDest;
structsockaddr_insaSrc;
DWORDdwTimeSent;
DWORDdwElapsed;
u_charcTTL;
intnLoop;
//CreateaRawsocket
rawSocket=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);
if(rawSocket==SOCKET_ERROR)
ReportError("
socket()"
//Lookuphost
lpHost=gethostbyname(pstrHost);
if(lpHost==NULL)
\nHostnotfound:
%s\n"
pstrHost);
//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"
//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);
nRet=closesocket(rawSocket);
if(nRet==SOCKET_ERROR)
closesocket()"
//SendEchoRequest()
//Fillinechorequestheader
//andsendtodestination
intSendEchoRequest(SOCKETs,LPSOCKADDR_INlpstToAddr)
staticECHOREQUESTechoReq;
staticnId=1;
staticnSeq=1;
//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;
nRet<
REQ_DATASIZE;
nRet++)
echoReq.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)
sendto()"
return(nRet);
//RecvEchoReply()
//Receiveincomingdata
//andparseoutfields
DWORDRecvEchoReply(SOCKETs,LPSOCKADDR_INlpsaFrom,u_char*pTTL)
ECHOREPLYechoReply;
intnAddrLen=sizeof(structsockaddr_in);
//Receivetheechoreply
nRet=recvfrom(s,//socket
(LPSTR)&
echoReply,//buffer
sizeof(ECHOREPLY),//sizeofbuffer
0,//flags
(LPSOCKADDR)lpsaFrom,//Fromaddress
&
nAddrLen);
//pointertoaddresslen
//Checkreturnvalue
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程序*/
signal.h>
arpa/inet.h>
sys/types.h>
sys/socket.h>
unistd.h>
netinet/in.h>
netinet/ip.h>
netinet/ip_icmp.h>
netdb.h>
setjmp.h>
errno.h>
#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"
%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_code=0;
icmp_cksum=0;
icmp_seq=pack_no;
icmp_id=pid;
packsize=8+datalen;
tval=(structtimeval*)icmp->
icmp_data;
gettimeofday(tval,NULL);
/*记录发送时间*/
icmp_cksum=cal_chksum((unsignedshort*)icmp,packsize);
/*校验算法*/
returnpacksize;
/*发送三个ICMP报文*/
voidsend_packet()
{intpacketsize;
while(nsend<
MAX_NO_PACKETS)
{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;
externinterrno;
signal(SIGALR