《编程实现发送ICMP协议数据包》由会员分享,可在线阅读,更多相关《编程实现发送ICMP协议数据包(8页珍藏版)》请在金锄头文库上搜索。
1、ICMP 原理与代码及分析专业:班级:学号:姓名:一、ICMP 协议简介ICMP 全称 Internet Control Message Protocol,中文名为因特网控制报文协议。它工作在OSI 的网络层,向数据通讯中的源主机报告错误。ICMP 可以实现故障隔离和故障恢复。网络本身是不可靠的,在网络传输过程中,可能会发生许多突发事件并导致数据传输失败。网络层的IP 协议是一个无连接的协议,它不会处理网络层传输中的故障,而位于网络层的ICMP 协议却恰好弥补了IP 的缺限,它使用IP 协议进行信息传递,向数据包中的源端节点提供发生在网络层的错误信息反馈。ICMP 的报头长8 字节,结构如图1
2、所示。比特 07815 16比特 31 类型( 0 或 8)代码( 0)检验和首部其余部分(未使用)数据(图 1ICMP 报头结构)类型 :标识生成的错误报文,它是ICMP 报文中的第一个字段;代码 :进一步地限定生成ICMP 报文。该字段用来查找产生错误的原因;校验和 :存储了 ICMP 所使用的校验和值。未使用 :保留字段,供将来使用,起值设为0 数据 :包含了所有接受到的数据报的IP 报头。还包含IP 数据报中前8 个字节的数据;ICMP 协议提供的诊断报文类型如表1 所示。种类类型描述差错报文3 目的端不可达4 源点抑制11 超时12 参数问题5 改变路由查询报文8 或 0 回显请求或
3、应答13 或 14 时间戳请求或应答17 或 18 地址掩码请求或应答10 或 9 路由询问和通告(表 1ICMP 诊断报文类型)ICMP 提供多种类型的消息为源端节点提供网络层的故障信息反馈,它的报文类型可以归纳为以下5 个大类:诊断报文(类型8,代码 0;类型 0,代码 0) ;目的不可达报文(类型3,代码 0-15 ) ;重定向报文(类型5,代码 0-4) ;超时报文(类型11,代码 0-1 ) ;信息报文(类型12-18 ) 。二、编程实现发送ICMP 协议数据包代码功能:实现发送ICMP 协议数据包,从而实现DOS 下 ping 命令功能。1.代码简要分析代码执行步骤:(1)创建协议
4、类型为IPPROTO_ICMP 的原始套接字,设置套接字的属性。(2)创建并初始化ICMP 封包。(3)调用 sendto 函数向远程主机发送ICMP 的请求。(4)调用 recvfrom 函数接受ICMP 响应。初始化 ICMP 头时先初始化消息的类型和代码域,之后应该是回显请求头。程序首先定义了ICMP 头的数据结构ICMP_HDR。typedef struct icmp_hdr unsigned char icmp_type; / 消息类型unsigned char icmp_code; / 代码unsigned short icmp_checksum; / 校验和/ 下面是回显头uns
5、igned short icmp_id; / 用来惟一标识此请求的ID 号,通常设置为进程ID unsigned short icmp_sequence; / 序列号unsigned long icmp_timestamp; / 时间戳 ICMP_HDR, *PICMP_HDR; 2.完整代码及解析#include “./common/initsock.h“ #include “./common/protoinfo.h“ #include “./common/comm.h“ #include CInitSock theSock; typedef struct icmp_hdr unsigned
6、 char icmp_type; / 消息类型unsigned char icmp_code; / 代码unsigned short icmp_checksum; / 校验和/ 下面是回显头unsigned short icmp_id; / 用来惟一标识此请求的ID 号,通常设置为进程ID unsigned short icmp_sequence; / 序列号unsigned long icmp_timestamp; / 时间戳 ICMP_HDR, *PICMP_HDR; int main() / 目的 IP 地址,即要Ping 的 IP 地址char szDestIp = “192.168.
7、1.104“; / 127.0.0.1 / 创建原始套节字SOCKET sRaw = :socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); / 设置接收超时SetTimeout(sRaw, 1000, TRUE); / 设置目的地址SOCKADDR_IN dest; dest.sin_family = AF_INET; dest.sin_port = htons(0); dest.sin_addr .S_un.S_addr = inet_addr(szDestIp); / 创建 ICMP 封包char buffsizeof(ICMP_HDR) + 32; ICMP
8、_HDR* pIcmp = (ICMP_HDR*)buff; / 填写 ICMP 封包数据pIcmp-icmp_type = 8; / 请求一个ICMP 回显pIcmp-icmp_code = 0; pIcmp-icmp_id = (USHORT):GetCurrentProcessId(); pIcmp-icmp_checksum = 0; pIcmp-icmp_sequence = 0; / 填充数据部分,可以为任意memset( / 开始发送和接收ICMP 封包USHORT nSeq = 0; char recvBuf1024; SOCKADDR_IN from; int nLen =
9、sizeof(from); while(TRUE) static int nCount = 0; int nRet; if(nCount+ = 4) break; pIcmp-icmp_checksum = 0; pIcmp-icmp_timestamp = :GetTickCount(); pIcmp-icmp_sequence = nSeq+; pIcmp-icmp_checksum = checksum(USHORT*)buff, sizeof(ICMP_HDR) + 32); nRet = :sendto(sRaw, buff, sizeof(ICMP_HDR) + 32, 0, (S
10、OCKADDR *) if(nRet = SOCKET_ERROR) printf(“ sendto() failed: %d n“, :WSAGetLastError(); return -1; nRet = :recvfrom(sRaw, recvBuf, 1024, 0, (sockaddr*) if(nRet = SOCKET_ERROR) if(:WSAGetLastError() = WSAETIMEDOUT) printf(“ timed outn“); continue; printf(“ recvfrom() failed: %dn“, :WSAGetLastError();
11、 return -1; / 下面开始解析接收到的ICMP 封包int nTick = :GetTickCount(); if(nRet icmp_type != 0) / 回显 printf(“ nonecho type %d recvd n“, pRecvIcmp-icmp_type); return -1; if(pRecvIcmp-icmp_id != :GetCurrentProcessId() printf(“ someone elses packet! n“); return -1; printf(“ %d bytes from %s:“, nRet, inet_ntoa(from
12、.sin_addr); printf(“ icmp_seq = %d. “, pRecvIcmp-icmp_sequence); printf(“ time: %d ms“, nTick - pRecvIcmp-icmp_timestamp); printf(“ n“); :Sleep(1000); return 0; 三、代码结果分析运行代码结果: (源地址: 192.168.1.101 目的地址: 192.168.1.104)DOS 下使用 ping 命令ping 192.168.1.104结果: (源地址: 192.168.1.101 目的地址: 192.168.1.104)由图可以分析
13、出代码实现功能与ping 命令功能类似。 即代码会构建一个固定格式的ICMP 请求数据包,然后由ICMP 协议将这个数据包连同地址“192.168.1.104 ”一起交给IP 层协议, IP 层协议将以地址“ 192.168.1.104”作为目的地址,本机IP 地址 192.168.1.101作为源地址,加上一些其他的控制信息,构建一个IP 数据包,并想办法得到192.168.1.104的 MAC 地址(物理地址,这是数据链路层协议构建数据链路层的传输单元帧所必需的) ,以便交给数据链路层构建一个数据帧。关键就在这里,IP层协议通过机器B 的 IP 地址和自己的子网掩码,发现它跟自己属同一网络
14、,就直接在本网络内查找这台机器的MAC,如果以前两机有过通信,在A 机的 ARP 缓存表应该有B 机 IP 与其 MAC 的映射关系,如果没有,就发一个ARP 请求广播,得到B 机的 MAC,一并交给数据链路层。后者构建一个数据帧,目的地址是IP 层传过来的物理地址,源地址则是本机的物理地址,还要附加上一些控制信息,依据以太网的介质访问规则,将它们传送出去。主机 B 收到这个数据帧后,先检查它的目的地址,并和本机的物理地址对比,如符合,则接收;否则丢弃。接收后检查该数据帧,将IP 数据包从帧中提取出来,交给本机的IP 层协议。同样,IP 层检查后,将有用的信息提取后交给ICMP 协议,后者处理
15、后,马上构建一个ICMP 应答包,发送给主机A,其过程和主机A 发送 ICMP 请求包到主机B 一模一样。由 wireshark 抓包,我们可以更清楚的看到两者的相似处。Wireshark 抓到代码的数据包: (源地址: 192.168.1.101 目的地址: 192.168.1.104)Wireshark 抓到 ping 命令的数据包: (源地址: 192.168.1.101 目的地址: 192.168.1.104 )代码和 ping 命令都使用ICMP 协议,并且都是源地址请求一次,目的地址回应一次。而且wireshark判断两者都实现ping 功能。如果是目的网络与主机网络不通代码结果:Ping 命令结果: