ping程序设计.docx
- 文档编号:23797952
- 上传时间:2023-05-20
- 格式:DOCX
- 页数:22
- 大小:230.14KB
ping程序设计.docx
《ping程序设计.docx》由会员分享,可在线阅读,更多相关《ping程序设计.docx(22页珍藏版)》请在冰豆网上搜索。
ping程序设计
ping程序设计
课程名称:
网络安全
老师:
姓名:
班级:
学号:
日期:
1、ping功能简介
Ping是DOS命令,一般用于检测网络通与不通,也叫时延,其值越大,速度越慢
PING(PacketInternetGrope),因特网包探索器,用于测试网络连接量的程序。
Ping发送一个ICMP回声请求消息给目的地并报告是否收到所希望的ICMP回声应答。
它是用来检查网络是否通畅或者网络连接速度的命令。
作为一个生活在网络上的管理员或者黑客来说,ping命令是第一个必须掌握的DOS命令,它所利用的原理是这样的:
网络上的机器都有唯一确定的IP地址,我们给目标IP地址发送一个数据包,对方就要返回一个同样大小的数据包,根据返回的数据包我们可以确定目标主机的存在,可以初步判断目标主机的操作系统等。
Ping是Windows系列自带的一个可执行命令。
利用它可以检查网络是否能够连通,用好它可以很好地帮助我们分析判定网络故障。
应用格式:
PingIP地址。
该命令还可以加许多参数使用,具体是键入Ping按回车即可看到详细说明。
ping指的是端对端连通,通常用来作为可用性的检查,但是某些病毒木马会强行大量远程执行ping命令抢占你的网络资源,导致系统变慢,网速变慢。
2、程序流程图
图1main函数流程图
图1main函数流程图
图1main函数流程图
图1main函数流程图
图1main函数流程图
图2创建套接字流程图
图3建立IP选项头部流程图
图4创建SockRaw套接字的接收/发送时限属性流程图
图5判断终端的主机名获取信息流程图
图6分配堆内存流程图
图7接收/发送ICMP数据包流程图
图8清空Socket库所占内存
图9传参解析函数流程图
图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_family printf("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_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: %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(WSAGetLastError()==WSAETIMEDOUT)//当前错误进程号为超时 { printf("timedout\n"); continue;//结束本次循环 } printf("recvfrom()failed: %d\n",WSAGetLastError()); return-1;退出main函数,并返回值-1 } DecodeICMPHeader(recvbuf,bread,&from);//调用解析ICMP头部函数 Sleep(1000);//暂停1000ms } if(sockRaw! =INVALID_SOCKET)//套接字有效 { closesocket(sockRaw);//关闭套接字 } HeapFree(GetProcessHeap(),0,recvbuf); HeapFree(GetProcessHeap(),0,icmp_data);//释放堆内存 WSACleanup();//应用程序完成对请求的Socket库的使用调用WSACleanup()函数来解除与Socket库的绑定并释放Soc
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- ping 程序设计
![提示](https://static.bdocx.com/images/bang_tan.gif)