博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
实验12 ICMP 协议程序设计
阅读量:5810 次
发布时间:2019-06-18

本文共 7820 字,大约阅读时间需要 26 分钟。

实验7 ICMP 协议程序设计

实验要求:

根据ICMP 协议,编写一个类似ping 的程序,具体的要求是:程序发出一个ICMP 包到

目的IP,然后等待接收回应的包(echo

根据ICMP 协议,向一个固定的IP 发出一系列的TTL 逐次增大的ICMP 的包,这些包的

TTL 每通过一个路由器就会减小1,当TTL 的时候,路由器会发回一个ICMP 不可达

的包,通过该包可以获得路由器的IP 地址,通过这个原理编写一个类似tracert 的程序

实验内容:

1ICMP  包的头部结构和IP 包头部结构

struct ICMP

{

unsigned char  type;//类型

unsigned char  code;//代码

unsigned short  checksum;//首部校验和

unsigned short  id;//标识

unsigned short  seq;//序列号

unsigned long  timestamp;//时间戳

};

struct IP

{

unsigned char  VIHL;//版本和首部长度

unsigned char  ToS; //服务类型

unsigned short  TotalLen;//总长度

unsigned short  ID;//标识号

unsigned short  Frag_Flags;//段偏移量

unsigned char  TTL;//生存时间

unsigned char  protocol;//协议

unsigned short  Checksum;//首部校验和

struct in_addr  SrcIP;

struct in_addr  DestIP;

};

2ping 程序的步骤:

Myping()


spacer.gif{

1

设置ICMP 头部,具体为:

ICMP 设置为0

设置type 域为8

设置code 域为0

设置id 为进程号

设置seq 1

计算校验值,设置checksum 为校验值

发送ICMP 包到目的IP

等待回收包,判断id seq 是否对应发出的ICMP 包,若是,则可判断ping 通,否则超

时报错

}

3 tracer 的原理,对一个固定的IP 地址发出一个系列的ICMP 

1 tracer 程序步骤:

For(i=1;i<63;i++)

{

设置ICMP 头部,具体为:

ICMP 设置为0

设置type 域为8

设置code 域为0

设置id 为进程号

设置seq 1

计算校验值,设置checksum 为校验值

设置TTL 的值,setsockopt(sock,IPPROTO_IP,IP_TTL,&i,sizeof(int));

发出ICMP 包,

等待收到回应包,打印出回应包的源IP 地址

}

附录:

Myping 程序:

#include <stdio.h>

#include <stdlib.h>

#include <arpa/inet.h>

#include <string.h>

#include <sys/un.h>

#include <sys/time.h>

#include <sys/ioctl.h>

#include <unistd.h>

#include <netinet/in.h>

#include <netdb.h>

typedef struct sockaddr  SA;


spacer.gif#define ICMP_ECHOREPLY 0

#define ICMP_DESTUNREACH  3

#define ICMP_ECHO  8

#define ICMP_TIMEOUT  11

#define MAX_HOPS  30

#define ICMP_PACKET_MIN  8

#define ICMP_PACKET_SIZE  32

#define MAX_PACKET_SIZE  1024

struct ICMP

{

unsigned char  type;//类型

unsigned char  code;//代码

unsigned short  checksum;//首部校验和

unsigned short  id;//标识

unsigned short  seq;//序列号

unsigned long  timestamp;//时间戳

};

struct IP

{

unsigned char  VIHL;//版本和首部长度

unsigned char  ToS; //服务类型

unsigned short  TotalLen;//总长度

unsigned short  ID;//标识号

unsigned short  Frag_Flags;//段偏移量

unsigned char  TTL;//生存时间

unsigned char  protocol;//协议

unsigned short  Checksum;//首部校验和

struct in_addr  SrcIP;

struct in_addr  DestIP;

};

void show32(char  * buf,int len)

{

//展示整个数据包,其中buf  为首地址,len 为长度

printf("包为:\r\n");

int i=0;

for(;i<len;i++)

printf("%d ",buf[i]);

printf("\r\n");

}

void err_sys(const  char *errmsg)

{

printf("%s\r\n",errmsg);

exit(1);


spacer.gif};

void send_echo_req(int  sockfd, struct sockaddr_in *dstaddr);

uint16_t in_cksum(uint16_t  *addr, int len);

void recv_echo_reply(int  sockfd);

int main(int  argc, char **argv)

{

int sockfd;

struct sockaddr_in dstaddr;

if ((sockfd  = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1)//产生ICMP  

err_sys("socket");

bzero(&dstaddr,  sizeof(dstaddr));

dstaddr.sin_family  = AF_INET;

dstaddr.sin_port  = htons(0);

if (inet_pton(AF_INET,  argv[1], &dstaddr.sin_addr) <= 0)

err_sys("inet_pton");

send_echo_req(sockfd,  &dstaddr);

recv_echo_reply(sockfd);

exit(0);

}

void send_echo_req(int  sockfd, struct sockaddr_in *dstaddr)

{

char buf[100];

size_t len = sizeof(struct ICMP);

struct ICMP *icmp;

socklen_t dstlen = sizeof(struct sockaddr_in);

bzero(buf, sizeof(buf));

//下面设置icmp  头部信息

icmp = (struct  icmp *)buf;

icmp->type  = ICMP_ECHO; //类型设置为8

icmp->code  = 0;//代码设置为0

icmp->id  = getpid();//id 设置为进程号

icmp->seq  = 1;//序号随机找的一个整数

icmp->checksum  = in_cksum((uint16_t *) icmp, sizeof(struct ICMP));//计算校验和

//ICMP  包发出去

if (sendto(sockfd,  buf, len, 0, (SA *)dstaddr, dstlen) == -1)

err_sys("sendto");

}

void recv_echo_reply(int  sockfd)

{

char buf[100];

ssize_t n;

struct IP  *ip;

struct ICMP  *icmp;

while (1)


spacer.gif{

alarm(5);  /* set timeout 超过秒则退出程序*/

struct sockaddr_in  peer;

int len=sizeof  peer;

int ret=recvfrom(sockfd,buf,sizeof(buf),0,(struct  sockaddr*)&peer,&len);

if(ret<0)err_sys("recvfrom  error!\r\n");

ip = (struct  IP *)buf;

if (ip->protocol  != IPPROTO_ICMP)

{

fprintf(stderr,  "protocol error.");

exit(1);

}

icmp = (struct  ICMP *)(buf + sizeof(struct IP));

if (icmp->type  == ICMP_ECHOREPLY)

{

//判断该ICMP  包是否匹配

if (icmp->id  != getpid())

{

fprintf(stderr,  "not this process.");

exit(1);

}

else

{

printf("destinationhostisalive.from

icmp->type=%d",inet_ntoa(peer.sin_addr),htons(peer.sin_port),icmp->type);

break;

}

}

}

}

uint16_t in_cksum(uint16_t  *addr, int len)

{

//该函数用来计算校验和

int nleft  = len;

uint32_t sum  = 0;

uint16_t *w  = addr;

uint16_t answer  = 0;

while (nleft  > 1)

{

sum += *w++;

nleft -= 2;

}

if (nleft  == 1)

{

%s:%d


spacer.gif*(unsigned char *)(&answer) = *(unsigned  char *)w ;

sum += answer;

}

sum = (sum  >> 16) + (sum & 0xffff);

sum += (sum  >> 16);

answer = ~sum;

return(answer);

}

2 mytracert  程序

#include <stdio.h>

#include <stdlib.h>

#include <arpa/inet.h>

#include <string.h>

#include <sys/un.h>

#include <sys/time.h>

#include <sys/ioctl.h>

#include <unistd.h>

#include <netinet/in.h>

#include <netdb.h>

//定义ICMP  信息类型

#define ICMP_ECHOREPLY  0

#define ICMP_DESTUNREACH  3

#define ICMP_ECHO  8

#define ICMP_TIMEOUT  11

#define MAXHOPS  30

#define BUFSIZE  512

struct IP

{

unsigned char  VIHL;//版本和首部长度

unsigned char  ToS; //服务类型

unsigned short  TotalLen;//总长度

unsigned short  ID;//标识号

unsigned short  Frag_Flags;//段偏移量

unsigned char  TTL;//生存时间

unsigned char  Protocol;//协议

unsigned short  Checksum;//首部校验和

struct in_addr  SrcIP;

struct in_addr  DestIP;

};

struct ICMP

{

unsigned char  Type;//类型


spacer.gifunsigned char Code;//代码

unsigned short  Checksum;//首部校验和

unsigned short  ID;//标识

unsigned short  Seq;//序列号

unsigned long  Timestamp;//时间戳

};

char buf[BUFSIZE];

unsigned short  checksum(u_short *buffer,int len)

{

register int  sum=0;

register int  nleft=len;

register unsigned  short *w=buffer;

register unsigned  short answer;

//使用32  位的累加器,进行16 位的反馈计算

while(nleft>1)

{

sum+=*w++;

nleft-=2;

}

//补全奇数位

if(nleft==1)

{

unsigned short u=0;

*(unsigned char*)(&u)=*(unsigned char*)w;

sum+=u;

}

//将反馈的16bit  从高位移动到低位

sum=(sum>>16)+(sum&0xffff);

sum+=(sum>>16);

answer=~sum;

return (answer);

};

void show32(char  * buf,int s)

{

int i=0;

printf("\r\n 包为:\r\n");

for(;i<s;i++)

{

printf("%d  ",buf[i]);

};

printf("\r\n");

};


spacer.gifvoid err_sys(const char *errmsg)

{

printf("%s\r\n",errmsg);

exit(1);

};

int main(int  argc,char * argv[])

{

int ttl=1;

struct ICMP  *icmp,tagICMP;

icmp=&tagICMP;

if(argc<2)  err_sys("请指定目标机器地址\r\n");

int sock=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);//创建ICMP  类型的原始套接字

int timeout=10000;

//设置接收超时时间为

setsockopt(sock,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout,sizeof(timeout));

setsockopt(sock,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout,sizeof(timeout));

//设置接收端地址

struct sockaddr_in  dest;

dest.sin_family=AF_INET;

struct hostent  *hp=gethostbyname(argv[1]);

if(hp==NULL)err_sys("无法解析地址\r\n");

dest.sin_addr.s_addr=*((int*)hp->h_addr);

//memcpy(&(dest.sin_addr),hp->h_addr,hp->h_length);

dest.sin_port=0;

printf("we  are find %s\r\n",inet_ntoa(dest.sin_addr));

int seq_no=1;

for(ttl=1;ttl<MAXHOPS;ttl++)

{

//设置ICMP  首部数据段

icmp->Type=ICMP_ECHO;//ICMP_ECHO  8

icmp->Code=0;

icmp->Checksum=0;

icmp->ID=getpid();

icmp->Seq=seq_no++;

icmp->Timestamp=0;

icmp->Checksum=checksum((u_short*)icmp,sizeof(struct  ICMP));

//show32(icmp,sizeof(struct  ICMP));

int nTTL=ttl;

setsockopt(sock,IPPROTO_IP,IP_TTL,&nTTL,sizeof(int));//设置TTL


spacer.gifsendto(sock,icmp,sizeof(struct ICMP),0,(struct  sockaddr*)&dest,sizeof(dest));//发送ICMP

到目标主机

struct sockaddr_in  src;

int len=sizeof  src;

int retlen=recvfrom(sock,buf,BUFSIZE,0,(struct  sockaddr*)&src,&len);//接收从目标机或者

路由返回的数据

//show32(buf,retlen);

struct IP  *echoip=(struct IP*)buf;

struct ICMP  *echoicmp=(struct ICMP*)(buf+sizeof(struct IP));

if(echoip->Protocol!=IPPROTO_ICMP)

err_sys("protocol error!\r\n");

if(echoicmp->Type==ICMP_ECHOREPLY)

{

if(echoicmp->ID!=getpid())

err_sys("not same process!\r\n");

else

{

printf("%s  reached ttl=%d\r\n",inet_ntoa(src.sin_addr),ttl);

break;

}

}

if(echoicmp->Type==ICMP_TIMEOUT  )

{

printf("%s reached ttl=%d\r\n",inet_ntoa(src.sin_addr),ttl);

}

if(echoicmp->Type==ICMP_DESTUNREACH)

{

printf("dest  unreach\r\n");

break;

}

sleep(1);//等待秒钟

}

return 0;

}

本文转自陈仲阳0 51CTO博客,原文链接:http://blog.51cto.com/wolfword/1240348

转载地址:http://cfnbx.baihongyu.com/

你可能感兴趣的文章
比特币系统采用的公钥密码学方案和ECDSA签名算法介绍——第二部分:代码实现(C语言)...
查看>>
分享15款很实用的 Sass 和 Compass 工具
查看>>
AMD优势: 与众不同 选择丰富
查看>>
玩转高性能超猛防火墙nf-HiPAC
查看>>
简单按日期查询mysql某张表中的记录数
查看>>
自动化部署之jenkins发布PHP项目
查看>>
C/C++编程可用的Linux自带工具
查看>>
如何判断webview是不是滑到底部
查看>>
海贼王十大悲催人物
查看>>
org.hibernate.MappingException: No Dialect mapping for JDBC type: -1 搞定!
查看>>
热点热词新闻资讯API开放接口(永久免费开放)
查看>>
8.1_Linux习题和作业
查看>>
11.排序算法_6_归并排序
查看>>
Redis redis-cli 命令列表
查看>>
.NET框架设计—常被忽视的框架设计技巧
查看>>
BigDecimal 舍入模式(Rounding mode)介绍
查看>>
开源 免费 java CMS - FreeCMS1.2-标签 infoSign
查看>>
开源 免费 java CMS - FreeCMS1.9 移动APP生成栏目列表数据
查看>>
git reset 三种用法总结
查看>>
hdfs笔记
查看>>