Linux网络编程---ICMP协议分析及ping程序实现Word格式文档下载.docx
《Linux网络编程---ICMP协议分析及ping程序实现Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《Linux网络编程---ICMP协议分析及ping程序实现Word格式文档下载.docx(18页珍藏版)》请在冰豆网上搜索。
(7)分段偏移(offset)13⽐特,标识⼀个IP分段的数据在原始IP报⽂中的偏移值,注意该值,必须是8的整数倍。
(8)⽣存时间(ttl)8⽐特,⼀个IP报⽂在⽹上所允许的最⼤⽣存时间,该值实际为最⼤跳数,当源主机产⽣⼀个IP报⽂后,该字段将填写⼀个初始值,随后该报⽂每经过⼀个路由器则路由器将对该字段值进⾏减⼀操作,当该字段值变成0后,路由器将丢弃此报⽂。
(9)协议(protocol)8⽐特,⽤于标识IP报⽂承载的上层数据的协议类型,例如可以是TCP,UDP,ICMP和IGMP等。
(10)头部校验和(check)16⽐特,IP头部数据的检验和。
(11)源地址(saddr)32⽐特,报⽂的源IP地址。
(12)⽬的地址(daddr)32⽐特,报⽂的⽬的IP地址。
(13)选项(option)变长且最⼤不超过40字节。
2.IP协议头的c语⾔定义
structiphdr
{
#ifdefined_LITTLE_ENDIAN_BITFIELD//⼩端机u8hlen:
4,
ver:
4;
#elifdefined_BIG_ENFIAN_BITFELD//⼤端机u8ver:
hlen:
4;
#endif
u8tos;
u16tot_len;
u16id;
u16frag_off;
u8ttl;
u8protocol;
u16check;
u32saddr;
u32daddr;
};
⼆、ICMP协议
(1)ICMP消息类型
ICMP消息分为两⼤类,错误报告消息和查询消息,这⾥仅介绍查询消息,每个查询消息类型均包括⼀对请求和应答消息。
(2)ICMP消息通⽤格式
ICMP消息包括8字节的头部和变长数据两个部分,其中所有消息类型头部的前4个字节均相同,头部其余4个字节随消息的不同⽽不同。
如图所⽰:
ICMP消息头部的头4个字节分别是消息类型tye,消息代码code和校验和checksum,其中checksum字段包括头部和数据两部分,⽽并⾮仅头部,查询消息的数据部分data包含了⽤于查询所需要的额外数据。
(3)ICMP查询请求和应答消息格式
ICMP回应请求(echo-request)和应答消息(echo-reply)⽤于诊断两个系统(主机或路由器)之间是否能够进⾏通信,当其中⼀⽅发送回应请求消息给另⼀⽅时,接收到回应请求消息的主机或者路由器将以应答消息进⾏应答,常⽤的⽹络ping命令就是基于此消息类型的,如下图所⽰其中type字段为8表⽰回应请求,0表⽰应答,code字段暂未是要你管,为0.
(4)ICMP消息格式的C语⾔定义
structicmphdr
u8type;
u8code;
u16checksum;
union
struct
u16id;
u16sequence;
}echo;
u32gateway;
struct
u16unused;
u16mtu;
}frag;
//pmtu发现
}un;
//u32icmp_timestamp[2];
//时间戳
//ICMP数据占位符
u8data[0];
#defineicmp_idun.echo.id
#defineicmp_sequn.echo.sequence
ping程序实现:
#include<
stdio.h>
stdlib.h>
#include<
sys/time.h>
unistd.h>
string.h>
sys/socket.h>
sys/types.h>
netdb.h>
errno.h>
arpa/inet.h>
signal.h>
netinet/in.h>
#ifndef_LITTLE_ENDIAN_BITFIELD#define_LITTLE_ENDIAN_BITFIELD#endif
#defineIP_HSIZEsizeof(structiphdr)//定义IP_HSIZE为ip头部长度#defineIPVERSION4//定义IPVERSION为4,指出⽤ipv4
#defineICMP_ECHOREPLY0//Echo应答
#defineICMP_ECHO 8//Echo请求
#defineBUFSIZE1500 //发送缓存最⼤值
#defineDEFAULT_LEN56//ping消息数据默认⼤⼩
//数据类型别名
typedefunsignedcharu8;
typedefunsignedshortu16;
typedefunsignedintu32;
//ICMP消息头部structicmphdr
u32icmp_timestamp[2];
#defineICMP_HSIZEsizeof(structicmphdr)structiphdr
#ifdefined_LITTLE_ENDIAN_BITFIELDu8hlen:
#elifdefined_BIG_ENFIAN_BITFELDu8ver:
charhello[]="
hellothisisapingtest."
;
char*hostname;
//被ping的主机
intdatalen=DEFAULT_LEN;
//ICMP消息携带的数据长度
charsendbuf[BUFSIZE];
charrecvbuf[BUFSIZE];
intnsent;
//发送的ICMP消息序号
intnrecv;
pid_tpid;
//ping程序的进程pid
structtimevalrecvtime;
//收到ICMP应答的时间戳intsockfd;
//发送和接收原始套接字
structsockaddr_indest;
//被ping主机的ip
structsockaddr_infrom;
//发送ping应答消息的主机ip
structsigactionact_alarm;
structsigactionact_int;
//设置的时间是⼀个结构体,倒计时设置,重复倒时,超时值设为1秒structitimervalval_alarm;
//函数原型
voidalarm_handler(int);
//SIGALRM处理程序voidint_handler(int);
//SIGINT处理程序
voidset_sighandler();
//设置信号处理程序voidsend_ping();
//发送ping消息
voidrecv_reply();
//接收ping应答
u16checksum(u8*buf,intlen);
//计算校验和inthandle_pkt();
//ICMP应答消息处理
voidget_statistics(int,int);
//统计ping命令的检测结果voidbail(constchar*);
//错误报告
intmain(intargc,char**argv)//argc表⽰隐形程序命令⾏中参数的数⽬,argv是⼀个指向字符串数组指针,其中每⼀个字符对应⼀个参数
val_alarm.it_interval.tv_sec=1;
val_alarm.it_interval.tv_usec=0;
val_alarm.it_value.tv_sec=0;
val_alarm.it_value.tv_usec=1;
structhostent*host;
//该结构体属于include<
inton=1;
if((host=gethostbyname(argv[1]))==NULL)
{//gethostbyname()返回对应于给定主机名的包含主机名字和地址信息的结构指针,perror("
cannotunderstandthehostname"
);
//理解不了输⼊的地址
exit
(1);
}
hostname=argv[1];
//取出地址名
memset(&
dest,0,sizeofdest);
//将dest中前sizeof(dest)个字节替换为0并返回s,此处为初始化,给最⼤内存清零dest.sin_family=PF_IN