ping程序分析报告.docx
《ping程序分析报告.docx》由会员分享,可在线阅读,更多相关《ping程序分析报告.docx(19页珍藏版)》请在冰豆网上搜索。
ping程序分析报告
课程名称:
老师:
姓名:
班级:
学号:
日期:
1、Ping功能简介…………………………………………………1
2、程序流程图
(1)主函数流程图…………………………………………………3
(2)创建套接字流程图……………………………………………3
(3)建立IP选项头部流程图……………………………………4
(4)创建SockRaw套接字的接收/发送时限属性流程图…………4
(5)判断终端的主机名获取信息流程图…………………………5
(6)分配堆内存流程图……………………………………………5
(7)接收/发送ICMP数据包流程图………………………………6
(8)清空Socket库所占内存……………………………………7
(9)传参解析函数流程图…………………………………………7
(10)解析IP选项函数流程图……………………………………8
3、源代码清单……………………………………………………8
4、心得体会………………………………………………………16
1、ping功能简介
Ping是DOS命令,一般用于检测网络通与不通,也叫时延,其值越大,速度越慢
PING(PacketInternetGrope),因特网包探索器,用于测试网络连接量的程序。
Ping发送一个ICMP回声请求消息给目的地并报告是否收到所希望的ICMP回声应答。
它是用来检查网络是否通畅或者网络连接速度的命令。
作为一个生活在网络上的管理员或者黑客来说,ping命令是第一个必须掌握的DOS命令,它所利用的原理是这样的:
网络上的机器都有唯一确定的IP地址,我们给目标IP地址发送一个数据包,对方就要返回一个同样大小的数据包,根据返回的数据包我们可以确定目标主机的存在,可以初步判断目标主机的操作系统等。
Ping是Windows系列自带的一个可执行命令。
利用它可以检查网络是否能够连通,用好它可以很好地帮助我们分析判定网络故障。
应用格式:
PingIP地址。
该命令还可以加许多参数使用,具体是键入Ping按回车即可看到详细说明。
ping指的是端对端连通,通常用来作为可用性的检查,
但是某些病毒木马会强行大量远程执行ping命令抢占你的网络资源,导致系统变慢,网速变慢。
图1main函数流程图
图2创建套接字流程图
图3建立IP选项头部流程图
图4创建SockRaw套接字的接收/发送时限属性流程图
图5判断终端的主机名获取信息流程图
图6分配堆内存流程图
图7接收/发送ICMP数据包流程图
图8清空Socket库所占内存
图9传参解析函数流程图
i=0
计算RR选项中记录的地址个数n
ii!=0NOYES输出空格通过IP地址获得主机信息赋给hosthost真假输出主机名和地址输出地址returni++ 图10解析IP首部函数流程图3、源代码清单//ModuleName:Ping.c#include"windows.h"#include"winsock.h"#include"stdio.h"#defineIP_RECORD_ROUTE0x7//IP记录路由#defineICMP_ECHO8//ICMP回显#defineICMP_ECHOREPLY0//ICMP回显应答#defineICMP_MIN8//ICMP数据包最小长度#defineDEF_PACKET_SIZE32//差错报文长度#defineMAX_PACKET0x10000//ICMP包最大长度#defineMAX_IP_HDR_SIZE60//IP首部最大字节数//IP头文件定义typedefstruct_iphdr{unsignedinth_len:4;//头部长度4字节unsignedintversion:4;//IP版本号IPv4unsignedchartos;//服务类型unsignedshorttotal_len;//数据包总长度unsignedshortident;//ID标识unsignedshortfrag_and_flags;//3位标志,13位片偏移unsignedcharttl;//生存期unsignedcharproto;//协议类型unsignedshortchecksum;//IP头部的检验和unsignedintsourceIP;//源地址unsignedintdestIP;//目的地址}IpHeader;//ICMP头部定义typedefstruct_icmphdr{BYTEi_type;//ICMP类型(8位)BYTEi_code;//代码类型(8位)USHORTi_cksum;//头部及数据检验和(16位)USHORTi_id;ID//标识USHORTi_seq;//序列号ULONGtimestamp;//时间戳}IcmpHeader;//IP选项首部定义typedefstruct_ipoptionhdr{unsignedcharcode;//IP选项的类型unsignedcharlen;//RR选项总字节长度unsignedcharptr;//指针字段unsignedlongaddr[9];//IP地址清单}IpOptionHeader;BOOLbRecordRoute;intdatasize;char*lpdest;//定义3个全局变量//使用信息voidusage(char*progname){printf("usage:ping-r[datasize]\n");printf("-rrecordroute\n");printf("hostremotemachinetoping\n");printf("datasizecanbeupto0x10000Byte\n");ExitProcess(-1);//结束进程}//ICMP首部初始化voidFillICMPData(char*icmp_data,intdatasize){IcmpHeader*icmp_hdr=NULL;char*datapart=NULL;//指针定义及初始化icmp_hdr=(IcmpHeader*)icmp_data;icmp_hdr->i_type=ICMP_ECHO;//ICMP回显请求icmp_hdr->i_code=0;icmp_hdr->i_id=(USHORT)GetCurrentProcessId();//取得当前进程号icmp_hdr->i_cksum=0;//检验和字段置0icmp_hdr->i_seq=0;datapart=icmp_data+sizeof(IcmpHeader);//datapart指针指向数据报文开头memset(datapart,'E',datasize-sizeof(IcmpHeader));//填充数据段}//计算检验和USHORTchecksum(USHORT*buffer,intsize){unsignedlongcksum=0;//检验和字段置0while(size>1){cksum+=*buffer++;size-=sizeof(USHORT);}if(size){cksum+=*(UCHAR*)buffer;}cksum=(cksum>>16)+(cksum&0xffff);//将检验和字段高16位右移16位再与低16位相加cksum+=(cksum>>16);//将所加的检验和再与剩余低16位相加return(USHORT)(~cksum);//检验和取反,并返回}//解析IP选项voidDecodeIPOptions(char*buf,intbytes){IpOptionHeader*ipopt=NULL;IN_ADDRinaddr;//声明结构体inti;HOSTENT*host=NULL;ipopt=(IpOptionHeader*)(buf+20);//去掉IP首部,指针指向数据选项首部printf("RR:");for(i=0;i<(ipopt->ptr/4)-1;i++){inaddr.S_un.S_addr=ipopt->addr[i];if(i!=0){printf("");}host=gethostbyaddr((char*)&inaddr.S_un.S_addr,sizeof(inaddr.S_un.S_addr),AF_INET);//通过IP地址获得主机信息if(host){printf("(%-15s)%s\n",inet_ntoa(inaddr),host->h_name);//打印IP地址和主机名}else{printf("(%-15s)\n",inet_ntoa(inaddr));//打印IP地址}}return;}//解析ICMP首部函数voidDecodeICMPHeader(char*buf,intbytes,structsockaddr_in*from){IpHeader*iphdr=NULL;IcmpHeader*icmphdr=NULL;unsignedshortiphdrlen;DWORDtick;//毫秒级数staticinticmpcount=0;iphdr=(IpHeader*)buf;iphdrlen=iphdr->h_len*4;//IP首部实际长度tick=GetTickCount();//获得毫秒级数if((iphdrlen==MAX_IP_HDR_SIZE)&&(!icmpcount))//判断是否为一个IP数据包{DecodeIPOptions(buf,bytes);//调用IP选项解析函数}if(bytes{printf("Toofewbytesfrom%s\n",inet_ntoa(from->sin_addr));}icmphdr=(IcmpHeader*)(buf+iphdrlen);//指针指向ICMP报文首部if(icmphdr->i_type!=ICMP_ECHOREPLY)//判断ICMP类型是否为ICMP回显应答{printf("nonechotype%drecvd\n",icmphdr->i_type);//输出其类型return;}if(icmphdr->i_id!=(USHORT)GetCurrentProcessId())//获得当前进程的ID,判断是否为ICMP标识{printf("someoneelse'spacket!\n");return;}printf("%dbytesfrom%s:",bytes,inet_ntoa(from->sin_addr));printf("icmp_seq=%d.",icmphdr->i_seq);//输出ICMP序列号printf("time:%dms",tick-icmphdr->timestamp);//打印时间戳printf("\n");icmpcount++;return;}//传参解析函数voidValidateArgs(intargc,char**argv){inti;bRecordRoute=FALSE;赋初值lpdest=NULL;datasize=DEF_PACKET_SIZE;//初始化datasize,使其等于差错报文长度for(i=1;i{if((argv[i][0]=='-')||(argv[i][0]=='/'))//判断数组argv第i行第0列是否为‘-’或‘/’{switch(tolower(argv[i][1]))//将数组argv第i行第1列的字符转化为小写字母{case'r'://记录路由选项bRecordRoute=TRUE;break;default:usage(argv[0]);调用usage函数break;}}elseif(isdigit(argv[i][0]))//判断数组argv第i行第0列是否为数字{datasize=atoi(argv[i]);//将数组argv第i行的字符转化成长整型数}else{lpdest=argv[i];}}}//main函数intmain(intargc,char**argv)//argc代表命令行中的参数个数,**argv是指向字符串的指针{char*icmp_data=NULL;char*recvbuf=NULL;USHORTseq_no=0;//定义及初始化structsockaddr_indest={'\0'};structsockaddr_infrom={'\0'};structhostent*hp=NULL;//声明结构体intbread=0;intret=0;intfromlen=sizeof(from);inttimeout=1000;unsignedintaddr=0;//定义及初始化WSADATAwsaData;//声明数据结构SOCKETsockRaw=INVALID_SOCKET;IpOptionHeaderipopt={'\0'};if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0)//指明程序请求使用的socket版本,返回请求的版本信息{printf("WSAStartup()failed:%d\n",GetLastError());//获得当前的进程错误号,并输出“请求版本信息失败”return2;}ValidateArgs(argc,argv);//调用传参解析函数sockRaw=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);//创建sockRaw套接字if(sockRaw==INVALID_SOCKET)//创建失败{printf("WSASocket()failed:%d\n",WSAGetLastError());return3;//返回值3,并退出main函数}if(bRecordRoute){ZeroMemory(&ipopt,sizeof(ipopt));ipopt.code=IP_RECORD_ROUTE;ipopt.ptr=4;//指向第一个地址列表ipopt.len=39;ret=setsockopt(sockRaw,IPPROTO_IP,IP_OPTIONS,(char*)&ipopt,sizeof(ipopt));//设置sockRaw套接字属性if(ret==SOCKET_ERROR)//设置属性失败{printf("setsockopt(IP_OPTIONS)failed:%d\n",WSAGetLastError());//取得当前错误进程号,并输出“属性设置失败”}}bread=setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout,sizeof(timeout));//设置套接字接收时限属性if(bread==SOCKET_ERROR)//设置失败{printf("setsockopt(SO_RCVTIMEO)failed:%d\n",WSAGetLastError());return-1;返回值-1,并退出main函数}timeout=1000;bread=setsockopt(sockRaw,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout,sizeof(timeout));//设置套接字发送时限属性if(bread==SOCKET_ERROR)//设置发送时限失败{printf("setsockopt(SO_SNDTIMEO)failed:%d\n",WSAGetLastError());return-1;返回值-1,并退出main函数}memset(&dest,0,sizeof(dest));//填充数据段,dest.sin_family=AF_INET;//指定地址族if((dest.sin_addr.s_addr=inet_addr(lpdest))==INADDR_NONE)//网络地址是无效的地址{if((hp=gethostbyname(lpdest))!=NULL){memcpy(&(dest.sin_addr),hp->h_addr,hp->h_length);dest.sin_family=hp->h_addrtype;将hp->h_addrtype的类型赋给dest.sin_familyprintf("dest.sin_addr=%s\n",inet_ntoa(dest.sin_addr));//输出IP地址}else{printf("gethostbyname()failed:%d\n",WSAGetLastError());return-1;退出main函数,并返回值-1}}datasize+=sizeof(IcmpHeader);icmp_data=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,MAX_PACKET);//分配堆内存recvbuf=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,MAX_PACKET);if(!icmp_data)//分配失败{printf("HeapAlloc()failed:%d\n",GetLastError());//获得当前错误进程号,输出“堆内存分配失败”return-1;//退出main函数,并返回值-1}memset(icmp_data,0,MAX_PACKET);//填充数据段FillICMPData(icmp_data,datasize);//调用ICMP初始化函数while(1){staticintnCount=0;//初始化intbwrote;if(nCount++==4){break;结束整个循环}((IcmpHeader*)icmp_data)->i_cksum=0;((IcmpHeader*)icmp_data)->timestamp=GetTickCount();//设定时间戳((IcmpHeader*)icmp_data)->i_seq=seq_no++;//设置ICMP头部序列号((IcmpHeader*)icmp_data)->i_cksum=checksum((USHORT*)icmp_data,datasize);//调用计算检验和函数,将其返回值赋给i_cksumbwrote=sendto(sockRaw,icmp_data,datasize,0,(structsockaddr*)&dest,sizeof(dest));//发送ICMP数据包if(bwrote==SOCKET_ERROR)//发送失败{if(WSAGetLastError()==WSAETIMEDOUT)//当前错误进程号为超时{printf("timedout\n");continue;//结束本次循环}printf("sendto()failed:%d\n",WSAGetLastError());return-1;//退出main函数,并返回值-1}if(bwrote{printf("Wrote%dbytes\n",bwrote);}bread=recvfrom(sockRaw,recvbuf,MAX_PACKET,0,(structsockaddr*)&from,&fromlen);//接收ICMP数据包if(bread==SOCKET_ERROR)//接收失败{if(WSAGetLastEr
i!
=0
NOYES
输出空格
通过IP地址获得主机信息
赋给host
host
真假
输出主机名和地址输出地址
return
i++
图10解析IP首部函数流程图
3、源代码清单
//ModuleName:
Ping.c
#include"windows.h"
#include"winsock.h"
#include"stdio.h"
#defineIP_RECORD_ROUTE0x7//IP记录路由
#defineICMP_ECHO8//ICMP回显
#defineICMP_ECHOREPLY0//ICMP回显应答
#defineICMP_MIN8//ICMP数据包最小长度
#defineDEF_PACKET_SIZE32//差错报文长度
#defineMAX_PACKET0x10000//ICMP包最大长度
#defineMAX_IP_HDR_SIZE60//IP首部最大字节数
//IP头文件定义
typedefstruct_iphdr
{
unsignedinth_len:
4;//头部长度4字节
unsignedintversion:
4;//IP版本号IPv4
unsignedchartos;//服务类型
unsignedshorttotal_len;//数据包总长度
unsignedshortident;//ID标识
unsignedshortfrag_and_flags;//3位标志,13位片偏移
unsignedcharttl;//生存期
unsignedcharproto;//协议类型
unsignedshortchecksum;//IP头部的检验和
unsignedintsourceIP;//源地址
unsignedintdestIP;//目的地址
}IpHeader;
//ICMP头部定义
typedefstruct_icmphdr
BYTEi_type;//ICMP类型(8位)
BYTEi_code;//代码类型(8位)
USHORTi_cksum;//头部及数据检验和(16位)
USHORTi_id;ID//标识
USHORTi_seq;//序列号
ULONGtimestamp;//时间戳
}IcmpHeader;
//IP选项首部定义
typedefstruct_ipoptionhdr
unsignedcharcode;//IP选项的类型
unsignedcharlen;//RR选项总字节长度
unsignedcharptr;//指针字段
unsignedlongaddr[9];//IP地址清单
}IpOptionHeader;
BOOLbRecordRoute;
intdatasize;
char*lpdest;
//定义3个全局变量
//使用信息
voidusage(char*progname)
printf("usage:
ping-r[datasize]\n");
printf("-rrecordroute\n");
printf("hostremotemachinetoping\n");
printf("datasizecanbeupto0x10000Byte\n");
ExitProcess(-1);//结束进程
}
//ICMP首部初始化
voidFillICMPData(char*icmp_data,intdatasize)
IcmpHeader*icmp_hdr=NULL;
char*datapart=NULL;//指针定义及初始化
icmp_hdr=(IcmpHeader*)icmp_data;
icmp_hdr->i_type=ICMP_ECHO;//ICMP回显请求
icmp_hdr->i_code=0;
icmp_hdr->i_id=(USHORT)GetCurrentProcessId();//取得当前进程号
icmp_hdr->i_cksum=0;//检验和字段置0
icmp_hdr->i_seq=0;
datapart=icmp_data+sizeof(IcmpHeader);//datapart指针指向数据报文开头
memset(datapart,'E',datasize-sizeof(IcmpHeader));//填充数据段
//计算检验和
USHORTchecksum(USHORT*buffer,intsize)
unsignedlongcksum=0;//检验和字段置0
while(size>1)
cksum+=*buffer++;
size-=sizeof(USHORT);
if(size)
cksum+=*(UCHAR*)buffer;
cksum=(cksum>>16)+(cksum&0xffff);//将检验和字段高16位右移16位再与低16位相加
cksum+=(cksum>>16);//将所加的检验和再与剩余低16位相加
return(USHORT)(~cksum);//检验和取反,并返回
//解析IP选项
voidDecodeIPOptions(char*buf,intbytes)
IpOptionHeader*ipopt=NULL;
IN_ADDRinaddr;//声明结构体
inti;
HOSTENT*host=NULL;
ipopt=(IpOptionHeader*)(buf+20);//去掉IP首部,指针指向数据选项首部
printf("RR:
");
for(i=0;i<(ipopt->ptr/4)-1;i++)
inaddr.S_un.S_addr=ipopt->addr[i];
if(i!
=0)
printf("");
host=gethostbyaddr((char*)&inaddr.S_un.S_addr,sizeof(inaddr.S_un.S_addr),AF_INET);//通过IP地址获得主机信息
if(host)
printf("(%-15s)%s\n",inet_ntoa(inaddr),host->h_name);
//打印IP地址和主机名
else
printf("(%-15s)\n",inet_ntoa(inaddr));//打印IP地址
return;
//解析ICMP首部函数
voidDecodeICMPHeader(char*buf,intbytes,structsockaddr_in*from)
IpHeader*iphdr=NULL;
IcmpHeader*icmphdr=NULL;
unsignedshortiphdrlen;
DWORDtick;//毫秒级数
staticinticmpcount=0;
iphdr=(IpHeader*)buf;
iphdrlen=iphdr->h_len*4;//IP首部实际长度
tick=GetTickCount();//获得毫秒级数
if((iphdrlen==MAX_IP_HDR_SIZE)&&(!
icmpcount))//判断是否为一个IP数据包
DecodeIPOptions(buf,bytes);//调用IP选项解析函数
if(bytes{printf("Toofewbytesfrom%s\n",inet_ntoa(from->sin_addr));}icmphdr=(IcmpHeader*)(buf+iphdrlen);//指针指向ICMP报文首部if(icmphdr->i_type!=ICMP_ECHOREPLY)//判断ICMP类型是否为ICMP回显应答{printf("nonechotype%drecvd\n",icmphdr->i_type);//输出其类型return;}if(icmphdr->i_id!=(USHORT)GetCurrentProcessId())//获得当前进程的ID,判断是否为ICMP标识{printf("someoneelse'spacket!\n");return;}printf("%dbytesfrom%s:",bytes,inet_ntoa(from->sin_addr));printf("icmp_seq=%d.",icmphdr->i_seq);//输出ICMP序列号printf("time:%dms",tick-icmphdr->timestamp);//打印时间戳printf("\n");icmpcount++;return;}//传参解析函数voidValidateArgs(intargc,char**argv){inti;bRecordRoute=FALSE;赋初值lpdest=NULL;datasize=DEF_PACKET_SIZE;//初始化datasize,使其等于差错报文长度for(i=1;i{if((argv[i][0]=='-')||(argv[i][0]=='/'))//判断数组argv第i行第0列是否为‘-’或‘/’{switch(tolower(argv[i][1]))//将数组argv第i行第1列的字符转化为小写字母{case'r'://记录路由选项bRecordRoute=TRUE;break;default:usage(argv[0]);调用usage函数break;}}elseif(isdigit(argv[i][0]))//判断数组argv第i行第0列是否为数字{datasize=atoi(argv[i]);//将数组argv第i行的字符转化成长整型数}else{lpdest=argv[i];}}}//main函数intmain(intargc,char**argv)//argc代表命令行中的参数个数,**argv是指向字符串的指针{char*icmp_data=NULL;char*recvbuf=NULL;USHORTseq_no=0;//定义及初始化structsockaddr_indest={'\0'};structsockaddr_infrom={'\0'};structhostent*hp=NULL;//声明结构体intbread=0;intret=0;intfromlen=sizeof(from);inttimeout=1000;unsignedintaddr=0;//定义及初始化WSADATAwsaData;//声明数据结构SOCKETsockRaw=INVALID_SOCKET;IpOptionHeaderipopt={'\0'};if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0)//指明程序请求使用的socket版本,返回请求的版本信息{printf("WSAStartup()failed:%d\n",GetLastError());//获得当前的进程错误号,并输出“请求版本信息失败”return2;}ValidateArgs(argc,argv);//调用传参解析函数sockRaw=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);//创建sockRaw套接字if(sockRaw==INVALID_SOCKET)//创建失败{printf("WSASocket()failed:%d\n",WSAGetLastError());return3;//返回值3,并退出main函数}if(bRecordRoute){ZeroMemory(&ipopt,sizeof(ipopt));ipopt.code=IP_RECORD_ROUTE;ipopt.ptr=4;//指向第一个地址列表ipopt.len=39;ret=setsockopt(sockRaw,IPPROTO_IP,IP_OPTIONS,(char*)&ipopt,sizeof(ipopt));//设置sockRaw套接字属性if(ret==SOCKET_ERROR)//设置属性失败{printf("setsockopt(IP_OPTIONS)failed:%d\n",WSAGetLastError());//取得当前错误进程号,并输出“属性设置失败”}}bread=setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout,sizeof(timeout));//设置套接字接收时限属性if(bread==SOCKET_ERROR)//设置失败{printf("setsockopt(SO_RCVTIMEO)failed:%d\n",WSAGetLastError());return-1;返回值-1,并退出main函数}timeout=1000;bread=setsockopt(sockRaw,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout,sizeof(timeout));//设置套接字发送时限属性if(bread==SOCKET_ERROR)//设置发送时限失败{printf("setsockopt(SO_SNDTIMEO)failed:%d\n",WSAGetLastError());return-1;返回值-1,并退出main函数}memset(&dest,0,sizeof(dest));//填充数据段,dest.sin_family=AF_INET;//指定地址族if((dest.sin_addr.s_addr=inet_addr(lpdest))==INADDR_NONE)//网络地址是无效的地址{if((hp=gethostbyname(lpdest))!=NULL){memcpy(&(dest.sin_addr),hp->h_addr,hp->h_length);dest.sin_family=hp->h_addrtype;将hp->h_addrtype的类型赋给dest.sin_familyprintf("dest.sin_addr=%s\n",inet_ntoa(dest.sin_addr));//输出IP地址}else{printf("gethostbyname()failed:%d\n",WSAGetLastError());return-1;退出main函数,并返回值-1}}datasize+=sizeof(IcmpHeader);icmp_data=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,MAX_PACKET);//分配堆内存recvbuf=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,MAX_PACKET);if(!icmp_data)//分配失败{printf("HeapAlloc()failed:%d\n",GetLastError());//获得当前错误进程号,输出“堆内存分配失败”return-1;//退出main函数,并返回值-1}memset(icmp_data,0,MAX_PACKET);//填充数据段FillICMPData(icmp_data,datasize);//调用ICMP初始化函数while(1){staticintnCount=0;//初始化intbwrote;if(nCount++==4){break;结束整个循环}((IcmpHeader*)icmp_data)->i_cksum=0;((IcmpHeader*)icmp_data)->timestamp=GetTickCount();//设定时间戳((IcmpHeader*)icmp_data)->i_seq=seq_no++;//设置ICMP头部序列号((IcmpHeader*)icmp_data)->i_cksum=checksum((USHORT*)icmp_data,datasize);//调用计算检验和函数,将其返回值赋给i_cksumbwrote=sendto(sockRaw,icmp_data,datasize,0,(structsockaddr*)&dest,sizeof(dest));//发送ICMP数据包if(bwrote==SOCKET_ERROR)//发送失败{if(WSAGetLastError()==WSAETIMEDOUT)//当前错误进程号为超时{printf("timedout\n");continue;//结束本次循环}printf("sendto()failed:%d\n",WSAGetLastError());return-1;//退出main函数,并返回值-1}if(bwrote{printf("Wrote%dbytes\n",bwrote);}bread=recvfrom(sockRaw,recvbuf,MAX_PACKET,0,(structsockaddr*)&from,&fromlen);//接收ICMP数据包if(bread==SOCKET_ERROR)//接收失败{if(WSAGetLastEr
printf("Toofewbytesfrom%s\n",
inet_ntoa(from->sin_addr));
icmphdr=(IcmpHeader*)(buf+iphdrlen);//指针指向ICMP报文首部
if(icmphdr->i_type!
=ICMP_ECHOREPLY)//判断ICMP类型是否为ICMP回显应答
printf("nonechotype%drecvd\n",icmphdr->i_type);//输出其类型
if(icmphdr->i_id!
=(USHORT)GetCurrentProcessId())//获得当前进程的ID,判断是否为ICMP标识
printf("someoneelse'spacket!
\n");
printf("%dbytesfrom%s:
",bytes,inet_ntoa(from->sin_addr));
printf("icmp_seq=%d.",icmphdr->i_seq);//输出ICMP序列号
printf("time:
%dms",tick-icmphdr->timestamp);//打印时间戳
printf("\n");
icmpcount++;
//传参解析函数
voidValidateArgs(intargc,char**argv)
bRecordRoute=FALSE;赋初值
lpdest=NULL;
datasize=DEF_PACKET_SIZE;//初始化datasize,使其等于差错报文长度
for(i=1;i{if((argv[i][0]=='-')||(argv[i][0]=='/'))//判断数组argv第i行第0列是否为‘-’或‘/’{switch(tolower(argv[i][1]))//将数组argv第i行第1列的字符转化为小写字母{case'r'://记录路由选项bRecordRoute=TRUE;break;default:usage(argv[0]);调用usage函数break;}}elseif(isdigit(argv[i][0]))//判断数组argv第i行第0列是否为数字{datasize=atoi(argv[i]);//将数组argv第i行的字符转化成长整型数}else{lpdest=argv[i];}}}//main函数intmain(intargc,char**argv)//argc代表命令行中的参数个数,**argv是指向字符串的指针{char*icmp_data=NULL;char*recvbuf=NULL;USHORTseq_no=0;//定义及初始化structsockaddr_indest={'\0'};structsockaddr_infrom={'\0'};structhostent*hp=NULL;//声明结构体intbread=0;intret=0;intfromlen=sizeof(from);inttimeout=1000;unsignedintaddr=0;//定义及初始化WSADATAwsaData;//声明数据结构SOCKETsockRaw=INVALID_SOCKET;IpOptionHeaderipopt={'\0'};if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0)//指明程序请求使用的socket版本,返回请求的版本信息{printf("WSAStartup()failed:%d\n",GetLastError());//获得当前的进程错误号,并输出“请求版本信息失败”return2;}ValidateArgs(argc,argv);//调用传参解析函数sockRaw=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);//创建sockRaw套接字if(sockRaw==INVALID_SOCKET)//创建失败{printf("WSASocket()failed:%d\n",WSAGetLastError());return3;//返回值3,并退出main函数}if(bRecordRoute){ZeroMemory(&ipopt,sizeof(ipopt));ipopt.code=IP_RECORD_ROUTE;ipopt.ptr=4;//指向第一个地址列表ipopt.len=39;ret=setsockopt(sockRaw,IPPROTO_IP,IP_OPTIONS,(char*)&ipopt,sizeof(ipopt));//设置sockRaw套接字属性if(ret==SOCKET_ERROR)//设置属性失败{printf("setsockopt(IP_OPTIONS)failed:%d\n",WSAGetLastError());//取得当前错误进程号,并输出“属性设置失败”}}bread=setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout,sizeof(timeout));//设置套接字接收时限属性if(bread==SOCKET_ERROR)//设置失败{printf("setsockopt(SO_RCVTIMEO)failed:%d\n",WSAGetLastError());return-1;返回值-1,并退出main函数}timeout=1000;bread=setsockopt(sockRaw,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout,sizeof(timeout));//设置套接字发送时限属性if(bread==SOCKET_ERROR)//设置发送时限失败{printf("setsockopt(SO_SNDTIMEO)failed:%d\n",WSAGetLastError());return-1;返回值-1,并退出main函数}memset(&dest,0,sizeof(dest));//填充数据段,dest.sin_family=AF_INET;//指定地址族if((dest.sin_addr.s_addr=inet_addr(lpdest))==INADDR_NONE)//网络地址是无效的地址{if((hp=gethostbyname(lpdest))!=NULL){memcpy(&(dest.sin_addr),hp->h_addr,hp->h_length);dest.sin_family=hp->h_addrtype;将hp->h_addrtype的类型赋给dest.sin_familyprintf("dest.sin_addr=%s\n",inet_ntoa(dest.sin_addr));//输出IP地址}else{printf("gethostbyname()failed:%d\n",WSAGetLastError());return-1;退出main函数,并返回值-1}}datasize+=sizeof(IcmpHeader);icmp_data=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,MAX_PACKET);//分配堆内存recvbuf=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,MAX_PACKET);if(!icmp_data)//分配失败{printf("HeapAlloc()failed:%d\n",GetLastError());//获得当前错误进程号,输出“堆内存分配失败”return-1;//退出main函数,并返回值-1}memset(icmp_data,0,MAX_PACKET);//填充数据段FillICMPData(icmp_data,datasize);//调用ICMP初始化函数while(1){staticintnCount=0;//初始化intbwrote;if(nCount++==4){break;结束整个循环}((IcmpHeader*)icmp_data)->i_cksum=0;((IcmpHeader*)icmp_data)->timestamp=GetTickCount();//设定时间戳((IcmpHeader*)icmp_data)->i_seq=seq_no++;//设置ICMP头部序列号((IcmpHeader*)icmp_data)->i_cksum=checksum((USHORT*)icmp_data,datasize);//调用计算检验和函数,将其返回值赋给i_cksumbwrote=sendto(sockRaw,icmp_data,datasize,0,(structsockaddr*)&dest,sizeof(dest));//发送ICMP数据包if(bwrote==SOCKET_ERROR)//发送失败{if(WSAGetLastError()==WSAETIMEDOUT)//当前错误进程号为超时{printf("timedout\n");continue;//结束本次循环}printf("sendto()failed:%d\n",WSAGetLastError());return-1;//退出main函数,并返回值-1}if(bwrote{printf("Wrote%dbytes\n",bwrote);}bread=recvfrom(sockRaw,recvbuf,MAX_PACKET,0,(structsockaddr*)&from,&fromlen);//接收ICMP数据包if(bread==SOCKET_ERROR)//接收失败{if(WSAGetLastEr
if((argv[i][0]=='-')||(argv[i][0]=='/'))//判断数组argv第i行第0列是否为‘-’或‘/’
switch(tolower(argv[i][1]))//将数组argv第i行第1列的字符转化为小写字母
case'r':
//记录路由选项
bRecordRoute=TRUE;
break;
default:
usage(argv[0]);调用usage函数
elseif(isdigit(argv[i][0]))//判断数组argv第i行第0列是否为数字
datasize=atoi(argv[i]);//将数组argv第i行的字符转化成长整型数
lpdest=argv[i];
//main函数
intmain(intargc,char**argv)//argc代表命令行中的参数个数,**argv是指向字符串的指针
char*icmp_data=NULL;
char*recvbuf=NULL;
USHORTseq_no=0;
//定义及初始化
structsockaddr_indest={'\0'};
structsockaddr_infrom={'\0'};
structhostent*hp=NULL;
//声明结构体
intbread=0;
intret=0;
intfromlen=sizeof(from);
inttimeout=1000;
unsignedintaddr=0;
WSADATAwsaData;//声明数据结构
SOCKETsockRaw=INVALID_SOCKET;
IpOptionHeaderipopt={'\0'};
if(WSAStartup(MAKEWORD(2,2),&wsaData)!
=0)//指明程序请求使用的socket版本,返回请求的版本信息
printf("WSAStartup()failed:
%d\n",GetLastError());//获得当前的进程错误号,并输出“请求版本信息失败”
return2;
ValidateArgs(argc,argv);//调用传参解析函数
sockRaw=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);//创建sockRaw套接字
if(sockRaw==INVALID_SOCKET)//创建失败
printf("WSASocket()failed:
%d\n",WSAGetLastError());
return3;//返回值3,并退出main函数
if(bRecordRoute)
ZeroMemory(&ipopt,sizeof(ipopt));
ipopt.code=IP_RECORD_ROUTE;
ipopt.ptr=4;//指向第一个地址列表
ipopt.len=39;
ret=setsockopt(sockRaw,IPPROTO_IP,IP_OPTIONS,
(char*)&ipopt,sizeof(ipopt));//设置sockRaw套接字属性
if(ret==SOCKET_ERROR)//设置属性失败
printf("setsockopt(IP_OPTIONS)failed:
%d\n",
WSAGetLastError());//取得当前错误进程号,并输出“属性设置失败”
bread=setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,
(char*)&timeout,sizeof(timeout));//设置套接字接收时限属性
if(bread==SOCKET_ERROR)//设置失败
printf("setsockopt(SO_RCVTIMEO)failed:
WSAGetLastError());
return-1;返回值-1,并退出main函数
timeout=1000;
bread=setsockopt(sockRaw,SOL_SOCKET,SO_SNDTIMEO,
(char*)&timeout,sizeof(timeout));//设置套接字发送时限属性
if(bread==SOCKET_ERROR)//设置发送时限失败
printf("setsockopt(SO_SNDTIMEO)failed:
memset(&dest,0,sizeof(dest));//填充数据段,
dest.sin_family=AF_INET;//指定地址族
if((dest.sin_addr.s_addr=inet_addr(lpdest))==INADDR_NONE)
//网络地址是无效的地址
if((hp=gethostbyname(lpdest))!
=NULL)
memcpy(&(dest.sin_addr),hp->h_addr,hp->h_length);
dest.sin_family=hp->h_addrtype;将hp->h_addrtype的类型赋给dest.sin_family
printf("dest.sin_addr=%s\n",inet_ntoa(dest.sin_addr));//输出IP地址
printf("gethostbyname()failed:
return-1;退出main函数,并返回值-1
datasize+=sizeof(IcmpHeader);
icmp_data=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,MAX_PACKET);//分配堆内存
recvbuf=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,MAX_PACKET);
if(!
icmp_data)//分配失败
printf("HeapAlloc()failed:
%d\n",GetLastError());//获得当前错误进程号,输出“堆内存分配失败”
return-1;//退出main函数,并返回值-1
memset(icmp_data,0,MAX_PACKET);//填充数据段
FillICMPData(icmp_data,datasize);//调用ICMP初始化函数
while
(1)
staticintnCount=0;//初始化
intbwrote;
if(nCount++==4)
break;结束整个循环
((IcmpHeader*)icmp_data)->i_cksum=0;
((IcmpHeader*)icmp_data)->timestamp=GetTickCount();//设定时间戳
((IcmpHeader*)icmp_data)->i_seq=seq_no++;//设置ICMP头部序列号
((IcmpHeader*)icmp_data)->i_cksum=
checksum((USHORT*)icmp_data,datasize);//调用计算检验和函数,将其返回值赋给i_cksum
bwrote=sendto(sockRaw,icmp_data,datasize,0,
(structsockaddr*)&dest,sizeof(dest));//发送ICMP数据包
if(bwrote==SOCKET_ERROR)//发送失败
if(WSAGetLastError()==WSAETIMEDOUT)//当前错误进程号为超时
printf("timedout\n");
continue;//结束本次循环
printf("sendto()failed:
if(bwrote{printf("Wrote%dbytes\n",bwrote);}bread=recvfrom(sockRaw,recvbuf,MAX_PACKET,0,(structsockaddr*)&from,&fromlen);//接收ICMP数据包if(bread==SOCKET_ERROR)//接收失败{if(WSAGetLastEr
printf("Wrote%dbytes\n",bwrote);
bread=recvfrom(sockRaw,recvbuf,MAX_PACKET,0,(structsockaddr*)&from,&fromlen);//接收ICMP数据包
if(bread==SOCKET_ERROR)//接收失败
if(WSAGetLastEr
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1