分享
 
 
 

透析ICMP协议(五): 应用篇路由追踪

王朝other·作者佚名  2008-05-31
窄屏简体版  字體: |||超大  

原理简介:

--------

通过前四节的介绍, 可能大家对ICMP的应用有了初步的了解. 不过开始本节之前我对ICMP协议再从宏观上做些介绍. 大家都知道ICMP是为于ISO的第三层---网络层。 既是它同IP协议为于同一层, 然而大家可能也只到,ICMP协议要用到IP协议, 所以有一些书上说ICMP位ISO的第四层, 那是错误的。 同样这样那些书上这样画的的例子也是错误的, 我就发现某外资通讯公司的资料上有这样两种错误的画法

--------------------------

ICMP TCP(SCTP)

--------------------------

IP

--------------------------

---------------------------

... TCP(SCTP)

---------------------------

ICMP IP

----------------------------

其实如上的画法是错误的, 正确地画法应为:

---------------------

... TCP(SCTP)

---------------------

ICMP

----------

IP

---------------------

接下来,让我们来说明怎样实现追踪路由的功能, 大家通过我的第一节的阅读可能已经了解了超时报文的具体内容(参见透析ICMP协议(一): 协议原理), 它在假如网关在处理数据报时发现生存周期域(ttl)为零,此数据报必须抛弃。网关同时必须通过超时信息通知源主机。这是它的报文的具体结构:

0 1 2 3

0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Type(11) Code(0/1) Checksum

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

unused

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Internet Header + 64 bits of Original Data Datagram

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

通过利用setsockopt()函数设置ICMP包的IP包头中的ttl字段便可以达到这种效果。 具体过程如下, 假设你的IP到达目标地址需要过n个路由器(n>1)。 则

1. 初始化第一个ICMP包,并设置IP包头中的TTL为1, 则得到第一个数据路由器发回的超时报文

2. 一般情况下:初始化第i(i<n)个ICMP包,并设置IP包头中的TTL为i, 则得到第一个数据路由器发回的超时报文

剩下的问题为如何确定超时ICMP报文的路由器IP地址得到它的机器名的信息。 这个问题可能很多读者都会求, 用gethostbyaddr()可以得到答案。

经过理论的论证后, 让我们看看如何实现。

具体实现:(具体如何初试化ICMP的数据包上节已有具体的介绍,这里只是补充路由追踪的代码)

--------

主要代码如下:

unsigned long ipback = 0; //超时报文的IP的初试值

unsigned long ms = 0; //超时值

strUCt hostent *hHost;

char m_address[256];

//直到找到目标主机, 或达到最大跳数(HOPS)

while (ipback != ipfinal){

hHost = 0;

//对到目标主机中间的某个路由器发放ping的报文(ttl为1~N-1之间)

if (Ping(m_address,ttl,ipback,ms))

{

sin.sin_family = AF_INET;

sin.sin_addr.S_un.S_addr = ipback; // 由函数返回的IP地址

// 查找主机名

hHost = gethostbyaddr((char*)&sin.sin_addr, 4, PF_INET);

//这里可以输出hHost的内容

}

ttl++;

if (ttl > MAX_HOPS) //达到最大跳数

{

break;

}

}

==================

ping函数的代码

==================

int Ping(const char * host, int ttl, unsigned long& ipback, unsigned long& ms)

{

SOCKET sockRaw;

struct sockaddr_in dest,from;

struct hostent * hp;

int bread,datasize;

int fromlen = sizeof(from);

int timeout = 100;

char *dest_ip;

char *icmp_data;

char *recvbuf;

unsigned int addr=0;

const int MAX_PACKET = 1024;

//初始化Socket

sockRaw = WSASocket (AF_INET,

SOCK_RAW,

IPPROTO_ICMP,

NULL, 0, WSA_FLAG_OVERLAPPED);

if (sockRaw == INVALID_SOCKET)

{

// 错误

}

// 设置IP包头的ttl字段

bread = setsockopt(sockRaw, IPPROTO_IP, IP_TTL, (char *)&ttl, sizeof(int));

if(bread == SOCKET_ERROR)

{

// 错误

}

// 设置接受超时为100ms

bread = setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout,sizeof(timeout));

if(bread == SOCKET_ERROR)

{

// 错误

}

//禁止用Nagle算法缓存数据

bread = setsockopt(sockRaw, SOL_SOCKET, TCP_NODELAY, (const char*)&killnagle, sizeof(int));

if (bread == SOCKET_ERROR)

{

// 错误

}

timeout = 1000;

// 设置发送超时为100ms

bread = setsockopt(sockRaw,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout,

sizeof(timeout));

if(bread == SOCKET_ERROR)

{

// 错误

}

//下面的代码生成ICMP包

memset(&dest,0,sizeof(dest));

hp = gethostbyname(host);

if (!hp)

{

addr = inet_addr(host);

}

if ((!hp) && (addr == INADDR_NONE) )

{

// 错误

}

if (hp != NULL)

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

else

dest.sin_addr.s_addr = addr;

//初始化dest

if (hp)

dest.sin_family = hp->h_addrtype;

else

dest.sin_family = AF_INET;

dest_ip = inet_ntoa(dest.sin_addr);

// 设置包长度

datasize = DEF_PACKET_SIZE;

// 计算包大小

datasize += sizeof(IcmpHeader);

icmp_data = (char *)new[MAX_PACKET]; //分配内存,可以用new 和 delete

recvbuf = (char *)new[MAX_PACKET];

if (!icmp_data)

{

// 释放内存,退出

}

if (!recvbuf)

{

// 释放内存,退出 }

}

memset(icmp_data,0,MAX_PACKET);

fill_icmp_data(icmp_data,datasize); // 这个函数用来填充ICMP的数据包

int bwrote;

((IcmpHeader*)icmp_data)->i_cksum = 0;

((IcmpHeader*)icmp_data)->timestamp = GetTickCount(); // 存入当前时间值

((IcmpHeader*)icmp_data)->i_seq = seq_no++;

// 计算校验和

((IcmpHeader*)icmp_data)->i_cksum = checksum((USHORT*)icmp_data, datasize);

// 为了最后计算ICMP包回来的总时间

unsigned long tc = GetTickCount();

//发送数据包

bwrote = sendto(sockRaw,icmp_data,datasize,0,(struct sockaddr*)&dest, sizeof(dest));

if (bwrote == SOCKET_ERROR)

{

// 错误

}

if (bwrote < datasize ) //发送字节数对否

{

}

// 接受数据包

bread = recvfrom(sockRaw,recvbuf,MAX_PACKET,0,(struct sockaddr*)&from,

&fromlen);

//计算总时间

ms = GetTickCount() - tc;

if (bread == SOCKET_ERROR)

{

// 错误

}

// 得到返回的路由器

ipback = from.sin_addr.s_addr;

return 1;

}

===============================

函数fill_icmp_data()的源代码

===============================

//这个结构下面将用到

typedef struct _ihdr {

BYTE i_type;

BYTE i_code;

USHORT i_cksum;

USHORT i_id;

USHORT i_seq;

ULONG timestamp; /* 这不是ICMP包的一部分, 只是为了计算时间 */

}IcmpHeader;

void fill_icmp_data(char * icmp_data, int datasize){

IcmpHeader *icmp_hdr;

char *datapart;

icmp_hdr = (IcmpHeader*)icmp_data;

icmp_hdr->i_type = ICMP_ECHO;

icmp_hdr->i_code = 0;

icmp_hdr->i_id = (USHORT)GetCurrentProcessId();

icmp_hdr->i_cksum = 0;

icmp_hdr->i_seq = 0;

datapart = icmp_data + sizeof(IcmpHeader); //计算数据域的开始地址

// 初试化数据域

memset(datapart,'E', datasize - sizeof(IcmpHeader));

}

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有