Linux网络编程---ICMP协议分析及ping程序实现Word文档下载推荐.docx

上传人:wj 文档编号:228966 上传时间:2023-04-28 格式:DOCX 页数:18 大小:294.20KB
下载 相关 举报
Linux网络编程---ICMP协议分析及ping程序实现Word文档下载推荐.docx_第1页
第1页 / 共18页
Linux网络编程---ICMP协议分析及ping程序实现Word文档下载推荐.docx_第2页
第2页 / 共18页
Linux网络编程---ICMP协议分析及ping程序实现Word文档下载推荐.docx_第3页
第3页 / 共18页
Linux网络编程---ICMP协议分析及ping程序实现Word文档下载推荐.docx_第4页
第4页 / 共18页
Linux网络编程---ICMP协议分析及ping程序实现Word文档下载推荐.docx_第5页
第5页 / 共18页
Linux网络编程---ICMP协议分析及ping程序实现Word文档下载推荐.docx_第6页
第6页 / 共18页
Linux网络编程---ICMP协议分析及ping程序实现Word文档下载推荐.docx_第7页
第7页 / 共18页
Linux网络编程---ICMP协议分析及ping程序实现Word文档下载推荐.docx_第8页
第8页 / 共18页
Linux网络编程---ICMP协议分析及ping程序实现Word文档下载推荐.docx_第9页
第9页 / 共18页
Linux网络编程---ICMP协议分析及ping程序实现Word文档下载推荐.docx_第10页
第10页 / 共18页
Linux网络编程---ICMP协议分析及ping程序实现Word文档下载推荐.docx_第11页
第11页 / 共18页
Linux网络编程---ICMP协议分析及ping程序实现Word文档下载推荐.docx_第12页
第12页 / 共18页
Linux网络编程---ICMP协议分析及ping程序实现Word文档下载推荐.docx_第13页
第13页 / 共18页
Linux网络编程---ICMP协议分析及ping程序实现Word文档下载推荐.docx_第14页
第14页 / 共18页
Linux网络编程---ICMP协议分析及ping程序实现Word文档下载推荐.docx_第15页
第15页 / 共18页
Linux网络编程---ICMP协议分析及ping程序实现Word文档下载推荐.docx_第16页
第16页 / 共18页
Linux网络编程---ICMP协议分析及ping程序实现Word文档下载推荐.docx_第17页
第17页 / 共18页
Linux网络编程---ICMP协议分析及ping程序实现Word文档下载推荐.docx_第18页
第18页 / 共18页
亲,该文档总共18页,全部预览完了,如果喜欢就下载吧!
下载资源
资源描述

Linux网络编程---ICMP协议分析及ping程序实现Word文档下载推荐.docx

《Linux网络编程---ICMP协议分析及ping程序实现Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《Linux网络编程---ICMP协议分析及ping程序实现Word文档下载推荐.docx(18页珍藏版)》请在冰点文库上搜索。

Linux网络编程---ICMP协议分析及ping程序实现Word文档下载推荐.docx

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_INET;

//PF_INET为IPV4,internet协议,在<

中,地址族dest.sin_port=ntohs(0);

//端⼝号,ntohs()返回⼀个以主机字节顺序表达的数。

dest.sin_addr=*(structin_addr*)host->

h_addr_list[0];

//host->

h_addr_list[0]是地址的指针.返回IP地址,初始化

if((sockfd=socket(PF_INET,SOCK_RAW,IPPROTO_ICMP))<

0)

{//PF_INEI套接字协议族,SOCK_RAW套接字类型,IPPROTO_ICMP使⽤协议,调⽤socket函数来创建⼀个能够进⾏⽹络通信的套接字。

这⾥判断是否perror("

rawsocketcreatederror"

setuid(getuid());

//getuid()函数返回⼀个调⽤程序的真实⽤户ID,setuid()是让普通⽤户可以以root⽤户的⾓⾊运⾏只有root帐号才能运⾏的程序或命令。

pid=getpid();

//getpid函数⽤来取得⽬前进程的进程识别码

printf("

PID:

%d\n"

pid);

set_sighandler();

//对信号处理

Ping%s(%s):

%dbytesdatainICMPpackets.\n"

argv[1],inet_ntoa(dest.sin_addr),datalen);

if((setitimer(ITIMER_REAL,&

val_alarm,NULL))==-1)//定时函数bail("

setitimerfails."

recv_reply();

return0;

//发送ping消息voidsend_ping()

structiphdr*ip_hdr;

//iphdr为IP头部结构体

structicmphdr*icmp_hdr;

//icmphdr为ICMP头部结构体

intlen;

intlen1;

icmp_hdr=(structicmphdr*)(sendbuf);

//字符串指针icmp_hdr->

type=ICMP_ECHO;

//初始化ICMP消息类型typeicmp_hdr->

code=0;

//初始化消息代码code

icmp_hdr->

icmp_id=pid;

//把进程标识码初始给icmp_id

icmp_seq=nsent++;

//发送的ICMP消息序号赋值给icmp序号gettimeofday((structtimeval*)icmp_hdr->

icmp_timestamp,NULL);

//获取当前时间

memcpy(icmp_hdr->

data,hello,strlen(hello));

len=ICMP_HSIZE+strlen(hello);

icmp_hdr->

checksum=0;

//初始化

checksum=checksum((u8*)icmp_hdr,len);

//计算校验和

//printf("

Thesendpackchecksumis:

0x%x\n"

icmp_hdr->

checksum);

sendto(sockfd,sendbuf,len,0,(structsockaddr*)&

dest,sizeof(dest));

//经socket传送数据

//接收程序发出的ping命令的应答voidrecv_reply()

intn;

socklen_tlen;

interrno;

n=nrecv=0;

len=sizeof(from);

//发送ping应答消息的主机IP

while(nrecv<

4)

if((n=recvfrom(sockfd,recvbuf,sizeofrecvbuf,0,(structsockaddr*)&

from,&

len))<

{//经socket接收数据,如果正确接收返回接收到的字节数,失败返回0.if(errno==EINTR)//EINTR表⽰信号中断

continue;

bail("

recvfromerror"

gettimeofday(&

recvtime,NULL);

//记录收到应答的时间if(handle_pkt())//接收到错误的ICMP应答信息

nrecv++;

get_statistics(nsent,nrecv);

//统计ping命令的检测结果

//计算校验和

u16checksum(u8*buf,intlen)

u32sum=0;

u16*cbuf;

cbuf=(u16*)buf;

while(len>

1)

sum+=*cbuf++;

len-=2;

if(len)

sum+=*(u8*)cbuf;

sum=(sum>

>

16)+(sum&

0xffff);

sum+=(sum>

16);

return~sum;

//ICMP应答消息处理inthandle_pkt()

structiphdr*ip;

structicmphdr*icmp;

intip_hlen;

u16ip_datalen;

//ip数据长度doublertt;

//往返时间

structtimeval*sendtime;

ip=(structiphdr*)recvbuf;

ip_hlen=ip->

hlen<

<

2;

ip_datalen=ntohs(ip->

tot_len)-ip_hlen;

icmp=(structicmphdr*)(recvbuf+ip_hlen);

u16sum=(u16)checksum((u8*)icmp,ip_datalen);

Therecvpackchecksumis:

sum);

if(sum)//计算校验和

return-1;

if(icmp->

icmp_id!

=pid)return-1;

type!

=ICMP_ECHOREPLY)return-1;

sendtime=(structtimeval*)icmp->

icmp_timestamp;

//发送时间

rtt=((&

recvtime)->

tv_sec-sendtime->

tv_sec)*1000+((&

tv_usec-sendtime->

tv_usec)/1000.0;

//往返时间

//打印结果

%dbytesfrom%s:

icmp_seq=%uttl=%drtt=%.3fms\n"

ip_datalen,//IP数据长度

inet_ntoa(from.sin_addr),//⽬的ip地址

icmp->

icmp_seq,//icmp报⽂序列号ip->

ttl,//⽣存时间

rtt);

//往返时间

//设置信号处理程序voidset_sighandler()

act_alarm.sa_handler=alarm_handler;

if(sigaction(SIGALRM,&

act_alarm,NULL)==-1)//sigaction()会依参数signum指定的信号编号来设置该信号的处理函数。

参数signum指所要捕获信号或忽bail("

SIGALRMhandlersettingfails."

act_int.sa_handler=int_handler;

if(sigaction(SIGINT,&

act_int,NULL)==-1)

bail("

//统计ping命令的检测结果

voidget_statistics(intnsent,intnrecv)

---%spingstatistics---\n"

inet_ntoa(dest.sin_addr));

//将⽹络地址转换成“.”点隔的字符串格式。

%dpacketstransmitted,%dreceived,%0.0f%%"

"

packetloss\n"

nsent,nrecv,1.0*(nsent-nrecv)/nsent*100);

voidbail(constchar*on_what)

fputs(strerror(errno),stderr);

//:

向指定的⽂件写⼊⼀个字符串(不写⼊字符串结束标记符‘\0’)。

成功写⼊⼀个字符串后,⽂件的位置指针会⾃动后移,函

fputs("

:

stderr);

fputs(on_what,stderr);

fputc('

\n'

//送⼀个字符到⼀个流中

//SIGINT(中断信号)处理程序voidint_handler(intsig)

//统计ping命令的检测结果close(sockfd);

//关闭⽹络套接字

//SIGALRM(终⽌进程)处理程序voidalarm_handler(intsigno)

send_ping();

//发送ping消息

程序结果(注意这⾥的PID):

下⾯我们在对我们写的ping程序进⾏抓包分析

这是通过抓包抓到的我们发的ICMP请求包,当然还有ICMP应答报,可以先看看后⾯的id,和seq,后⾯我们会再次提到,⾸先我们对其中⼀个包展开分析:

这⾥显⽰的是IP报⽂字段,可以看到我们前⾯所展⽰的IP报头⾥⾯所包含的东西,⽐较简单,就不⼀⼀分析了。

然后我们在来看看我我们ICMP报⽂:

可以看到,搜下是类型type=8,说明是个ICMP请求,code=0,然后是校验和,接下来是标识符,这⾥怎么有两个呢,其实⼀个是⼤端表

⽰,⼀个是⼩端表⽰的结果,这⾥的标识符是我们的进程ID,可以看我前⾯ping的时候输出了进程ID,然后是序列号,可以对照⼏个包分析,开始序列号(⼤端和⼩端表⽰)是为0,然后⼀次递增,这是我们在程序⾥⾯所设定的。

接下来是时间戳,开始的时候icmp结构⾥⾯我没有放时间戳,这样系统会放在数据位置,我来我单独放了⼀个时间戳结构这样把它和data分开,关于时间戳⼤⼩我也是抓包分析得出来的,是8个字节。

接下来便是我们的数据部分,为了很好的区分数据区域和前⾯的头,特别把数据部分拿出来分析:

可以看到数据部分恰好是从我们⾃⼰定义的数据地⽅开始的,数据前⾯就是时间戳,开始调试的时候,数据总是被覆盖,后来才找出了⾥⾯的时间戳占了8个字节。

所以调整后刚好合适。

当然不同的类型和代码会导致后⾯的结构有些不⼀样,这需要调整。

上⾯的代码中ICMP和IP都是我们⾃⼰定义的。

系统中也有提供相应的结构,我们直接调⽤就可以了,不过必须先查看⾥⾯结构是如何定义的。

在我这⾥,ICMP中的数据是单独定义在外⾯的,不是⼀起放在⾥⾯的,所以,数据部分需要⾃⼰声明⼀个结构,具体名称

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > IT计算机 > 电脑基础知识

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2