已阅读5页,还剩26页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
透析ICMP协议透析ICMP协议(一): 协议原理 对于熟悉网络的人来说, ICMP是再熟悉不过了. 它同IP协议一样工作在ISO模型的网络层, 它的全称是: Internet Control Message Protocal.其在网络中的主要作用是:- 主机探测- 路由维护- 路由选择- 流量控制 对于主机探测来说有很多方法,主机某些服务的BANNER,一些使用的应用程序,或者使用工具来检测主机,如NMAP,在WEB上有来简单的估测主机。下面所讲的是使用ICMP协议来探测主机,主要也是可以了解ICMP这个协议,这里最主要的也是将这个ICMP协议,首先我来讲一下主机探测用到的ICMP报文我没有一一讲全部报文,详细请参见RFC792协议)1. 回送或回送响应我们使用一个ICMPECHO数据包来探测主机地址是否存活(当然在主机没有被配置为过滤ICMP形式),通过简单的发送一个ICMPECHO(Type 8)数据包到目标主机,如果ICMPECHOReply(ICMPtype0)数据包接受到,说明主机是存活状态。如果没有就可以初步判断主机没有在线或者使用了某些过滤设备过滤了ICMP的REPLY。这种机制就是我们通常所用的ping命令来检测目标主机是否可以ping到.回送消息的源地址是回送响应消息的目的地址。若要形成一个回送响应消息,应该将源和目的地址交换,将类型代码更改为0,重新计算机校验码。下面是这个报文的格式: 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 | Code | Checksum | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Identifier | Sequence Number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Data . +-+-+-+-+-类型:8代表回送消息;0代表回送响应消息。代码:0校验码:16位数据(从ICMP类型开始)的反码和再取反而得。为计算校验码,校验码域应该为零。这些零在 以后会被校验码取代。标识符:如果代码=0,帮助匹配回送和回送响应的代码可以为0。序列码:如果代码=0,帮助匹配回送和回送响应的序列码可以为0。说明:回送消息中接收到的消息应该在回送响应消息中返回。标识符和序列码由回送发送者使用帮助匹配回送请求的响应。代码: 从主机或网关接收02. 超时报文 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 | Code | Checksum | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | unused | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Internet Header + 64 bits of Original Data Datagram | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 类型:11代码:0 = 传送超时;1 = 分段级装超时。校验码:16位数据(从ICMP类型开始)的反码和再取反而得。为计算校验码,校验码域应该为零。这些零在以后会被校验码取代。Internet包头+64位源数据报数据:Internet包头加上源数据的头64位而得。此数据用于主机匹配信息到相应的进程。如果高层协议使用端口号,应该假设其在源数据的头64个字节之中。说明:如果网关在处理数据报时发现生存周期域为零,此数据报必须抛弃。网关同时必须通过超时信息通知源主机。如果主机在组装分段的数据报时因为丢失段未能在规定时间内组装数据,此数据报必须抛弃。网关发送超时信息。如果段零不可用则不用发送超时信息。代码0由网关发送,代码1由主机发送。3. 目标主机不可达报文 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 | Code | Checksum | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | unused | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Internet Header + 64 bits of Original Data Datagram | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 类型:3代码:0 = 网络不可达;1 = 主机不可达;2 = 协议不可用;3 = 端口不可达;4 = 需要段和DF设置;5 = 源路由失败;校验码:16位数据(从ICMP类型开始)的反码和再取反而得。为计算校验码,校验码域应该为零。这些零在以后会被校验码取代。Internet包头+源数据报:Internet包头加上源数据的头64位而得。此数据用于主机匹配信息到相应的进程。如果高层协议使用端口号,应该假设其在源数据的头64个字节之中。说明:相应于网关的路由表,如果在目的域中指定的网络不可达,如网络距离为无限远,网关会向发送源数据的主机发送目的不可达消息。而且,在一些网络中,网关有能力决定目的主机是否可达。如果目的地不可达,它将向发送源数据的主机发送不可达信息。在目的主机,如果IP模块因为指定的协议模块和进程端口不可用而不能提交数据报,目的主机将向发送源数据的主机发送不可达信息。另外一种情况是当数据报必须被分段传送,而“不可分段”位打开,在这种情况下,网关必须抛弃此数据报,并向向发送源数据的主机发送不可达信息。代码0,1,4和5由网关发送,而代码2和3由主机发送。Windows Socket简介Windows 的Socket函数有许多, 我没有做详细介绍, 这里的函数都是简要说明其用途, 详细用法请参考MSDN.这里的主要目的是为了后面的三个应用服务.函数说明:- WSAStartup函数初始化Winsock声明int WSAStarup(WORD wVersionRequested,LPWSADATA lpWSAData);参数wVersionRequested - 要求使用Winsock的最低版本号lpWSAData - Winsock的详细资料返回值当函数成功调用时返回0失败时返回非0的值 -socket函数用于生成socket(soket Descriptor)声明SOCKET socket(int af,int type,int protocol);参数af - 地址家族(通常使用:AF_INET)type - socket的种类SOCK_STREAM : 用于TCP协议SOCK_DGRAM : 用于UDP协议protocol - 所使用的协议返回值当函数成功调用时返回一个新的SOCKET(Socket Descriptor)失败时返回INVALID_SOCKET.-inet_addr函数地址转换, 把A.B.C.D的IP地址转换为32位长整数声明unsigned long inet_addr ( const char FAR *cp );参数cp - 指向IP地址字符串的指针返回值当函数成功调用时返回用32位整数表示的IP地址失败时返回INADDR_NONE.-gethostbyname函数从主机名获取主机信息.声明struct hostent FAR * gethostbyname ( const char FAR *name );参数name - 指向主机名字符串的指针返回值当函数成功调用时返回主机信息失败时返回NULL(空值)-recv函数利用Socket进行接受数据.声明int recv ( SOCKET s , char FAR *buf , int len , int flags );参数s - 指向用Socket函数生成的Socket Descriptorbuf - 接受数据的缓冲区(数组)的指针len - 缓冲区的大小flag - 调用方式(MSG_PEEK 或 MSG_OOB) 返回值成功时返回收到的字节数.如果连接被中断则返回0失败时返回 SOCKET_ERROR-sendto函数发送数据.声明int sendto ( SOCKET s , const char FAR *buf , int len , int flags , const struct sockaddr FAR *to , int token );参数s - 指向用Socket函数生成的Socket Descriptorbuf - 接受数据的缓冲区(数组)的指针len - 缓冲区的大小flag - 调用方式(MSG_DONTROUTE , MSG_OOB)to - 指向发送方SOCKET地址的指针token - 发送方SOCKET地址的大小 返回值成功时返回已经发送的字节数.失败时返回SOCKET_ERROR 应用篇ping(ICMP.dll)原理简介:-这个例子演示了应用微软的ICMP.DLL怎样ping另一台机器. 这个DLL是没有文档话的发送ICMP回送包API接口, 也称为pings, 就像潜水员对声纳信号的术语一样. 这段代码出自一个被一个名叫MarkG的家伙的GUI程序, 他的网页已经消失了. ICMP.DLL API 现在在Windows平台上与微软的Winsocks工作的很好, 但是微软说更好的产品一出来他们将替换它. 微软说这个自从Windows 95时代就在用, 这些功能在在Windows 2000上仍然存在.For more information on the ICMP.DLL API, check out s ICMP API page.更详细的ICMP.DLL API的信息到的ICMP API网页获取.具体实现:-/ Borland C+ 5.0: bcc32.cpp ping.cpp/ Visual C+ 5.0:cl ping.cpp wsock32.lib/ This sample program is hereby placed in the public domain.#include #include #include #include icmpdefs.h=ping的实现部分=int doit(int argc, char* argv)/bugfree 建议将这个argc和argv的处理拿到main函数中 / 检查命令行参数 if (argc 2) cerr usage: ping endl; return 1; / 装载ICMP.DLL连接库 HINSTANCE hIcmp = LoadLibrary(ICMP.DLL); if (hIcmp = 0) cerr Unable to locate ICMP.DLL! endl; return 2; / 查找给定机器的IP地址信息 struct hostent* phe; if (phe = gethostbyname(argv1) = 0) cerr Could not find IP address for argv1 endl; return 3; / 定义函数三个指针类型 typedef HANDLE (WINAPI* pfnHV)(VOID); typedef BOOL (WINAPI* pfnBH)(HANDLE); typedef DWORD (WINAPI* pfnDHDPWPipPDD)(HANDLE, DWORD, LPVOID, WORD, PIP_OPTION_INFORMATION, LPVOID, DWORD, DWORD); / evil, no? /定义三个指针函数 pfnHV pIcmpCreateFile; pfnBH pIcmpCloseHandle; pfnDHDPWPipPDD pIcmpSendEcho; /从ICMP.DLL中得到函数入口地址 pIcmpCreateFile = (pfnHV)GetProcAddress(hIcmp,IcmpCreateFile); pIcmpCloseHandle = (pfnBH)GetProcAddress(hIcmp, IcmpCloseHandle); pIcmpSendEcho = (pfnDHDPWPipPDD)GetProcAddress(hIcmp, IcmpSendEcho); if (pIcmpCreateFile = 0) | (pIcmpCloseHandle = 0) | (pIcmpSendEcho = 0) cerr Failed to get proc addr for function. endl; return 4; / 打开ping服务 HANDLE hIP = pIcmpCreateFile(); if (hIP = INVALID_HANDLE_VALUE) cerr Unable to open ping service. endl; return 5; / 构造ping数据包 char acPingBuffer64; memset(acPingBuffer, xAA, sizeof(acPingBuffer); PIP_ECHO_REPLY pIpe = (PIP_ECHO_REPLY)GlobalAlloc( GMEM_FIXED | GMEM_ZEROINIT, sizeof(IP_ECHO_REPLY) + sizeof(acPingBuffer); if (pIpe = 0) cerr Failed to allocate global ping packet buffer. Data = acPingBuffer; pIpe-DataSize = sizeof(acPingBuffer); / 发送ping数据包 DWORD dwStatus = pIcmpSendEcho(hIP, *(DWORD*)phe-h_addr_list0), acPingBuffer, sizeof(acPingBuffer), NULL, pIpe, sizeof(IP_ECHO_REPLY) + sizeof(acPingBuffer), 5000); if (dwStatus != 0) cout Addr: Address) . Address) . Address) . Address) , RTT: RoundTripTime) ms, TTL: Options.Ttl) endl; else cerr Error obtaining info from ping packet. endl; / 关闭,回收资源 GlobalFree(pIpe); FreeLibrary(hIcmp); return 0;=主函数=int main(int argc, char* argv) WSAData wsaData; if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) return 255; int retval = doit(argc, argv); WSACleanup(); return retval;=头文件=icmpdefs.h/ICMP.DLL 函数中需要的结构 typedef struct unsigned char Ttl; / Time To Live unsigned char Tos; / Type Of Service unsigned char Flags; / IP header flags unsigned char OptionsSize; / Size in bytes of options data unsigned char *OptionsData; / Pointer to options data IP_OPTION_INFORMATION, * PIP_OPTION_INFORMATION;typedef struct DWORD Address; / Replying address unsigned longStatus; / Reply status unsigned longRoundTripTime; / RTT in milliseconds unsigned short DataSize; / Echo data size unsigned short Reserved; / Reserved for system use void *Data; / Pointer to the echo data IP_OPTION_INFORMATION Options; / Reply options IP_ECHO_REPLY, * PIP_ECHO_REPLY; 应用篇ping(RAW Socket)原理简介:- 用RAW Socket实现的ping可能比上一节的应用ICMP.DLL的程序庞大些, 但是这才是我们需要关注的东西, 我的观点真正想做网络开发的程序员应该静下心来读读这篇文章, 相信你会从中获益颇多. 中间我也会讲解一些东西为后一章的路由追踪做一些铺垫. 另一个重要的要讲的东西, 微软宣布随时不支持上节讲的ping用到的开发接口, 但是本节的讲的是更一般的东西. 所以它不会过时, 甚至做很小的改动就可以移植到别的系统上去. 系统移植不是我们的讲的重点. 但是微软的长期支持足以引起我们充分的重视.如何少作变动来使的这个程序实现追踪路由的功能, 这里只是抛砖引玉. 将ICMP包中IP包的包头该为特定的值就能得到那个路由器的IP(要求到达目的地的跳数大于你设的特定值).这个程序需要windows2k/WindowsXP/WindowsNT平台和系统管理员的权限.具体实现:-这段源代码大部分来自: /wskfaq/examples/rawping.htmlbugfree只做了少量修改,给出了大量的注释, 最后结合经验给出了自己的建议.-/* 程序名: rawping_driver.cpp* 说明: * 驱动程序,也是主函数*/#include #include #include rawping.h#define DEFAULT_PACKET_SIZE 32 / 默认ICMP包字节数#define DEFAULT_TTL 30 / 默认TTL值#define MAX_PING_DATA_SIZE 1024/ 最大数据块 #define MAX_PING_PACKET_SIZE (MAX_PING_DATA_SIZE + sizeof(IPHeader) /最大ICMP包长度/* 为 send_buf 和 recv_buf 分配内存* send_buf大小为 packet_size* recv_buf大小为 MAX_PING_PACKET_SIZE, 保证大于send_buf*/int allocate_buffers(ICMPHeader*& send_buf, IPHeader*& recv_buf, int packet_size); / Program entry pointint main(int argc, char* argv) int seq_no = 0; /用在发送和接受的ICMP包头中 ICMPHeader* send_buf = 0; IPHeader* recv_buf = 0; / 判断命令行是否合法 if (argc 2) cerr usage: argv0 data_size ttl endl; cerr tdata_size can be up to MAX_PING_DATA_SIZE bytes.Default is DEFAULT_PACKET_SIZE . endl; cerr tttl should be 255 or lower.Default is DEFAULT_TTL . 2) int temp = atoi(argv2); if (temp != 0) packet_size = temp; if (argc 3) temp = atoi(argv3); if (temp = 0) & (temp = 255) ttl = temp; packet_size = max(sizeof(ICMPHeader), min(MAX_PING_DATA_SIZE, (unsigned int)packet_size); / 启动 Winsock WSAData wsaData; if (WSAStartup(MAKEWORD(2, 1), &wsaData) != 0) cerr Failed to find Winsock 2.1 or better. endl; return 1; SOCKET sd; / RAW Socket句柄 sockaddr_in dest, source; / 三个任务(创建sd, 设置ttl, 初试dest的值) if (setup_for_ping(argv1, ttl, sd, dest) 0) goto cleanup; /释放资源并退出 / 为send_buf和recv_buf分配内存 if (allocate_buffers(send_buf, recv_buf, packet_size) = 0) while (1) / 接受回应包 if (recv_ping(sd, source, recv_buf, MAX_PING_PACKET_SIZE) h_len * 4; ICMPHeader* icmphdr = (ICMPHeader*) (char*)recv_buf + header_len); if (icmphdr-seq != seq_no) cerr bad sequence number! endl; continue; else break; if (decode_reply(recv_buf, packet_size, &source) != -2) / Success or fatal error (as opposed to a minor error) / so take off. break; cleanup: deletesend_buf;/释放分配的内存 deleterecv_buf; WSACleanup(); / 清理winsock return 0;/ 为send_buf 和 recv_buf的内存分配. 太简单, 我略过int allocate_buffers(ICMPHeader*& send_buf, IPHeader*& recv_buf, int packet_size) / First the send buffer send_buf = (ICMPHeader*)new charpacket_size; if (send_buf = 0) cerr Failed to allocate output buffer. endl; return -1; / And then the receive buffer recv_buf = (IPHeader*)new charMAX_PING_PACKET_SIZE; if (recv_buf = 0) cerr Failed to allocate output buffer. endl; return -1; return 0;/* 程序名: rawping.h* 说明: * 主要函数库头文件*/#define WIN32_LEAN_AND_MEAN#include / ICMP 包类型, 具体参见本文的第一节#define ICMP_ECHO_REPLY 0 #define ICMP_DEST_UNREACH 3#define ICMP_TTL_EXPIRE 11#define ICMP_ECHO_REQUEST 8/ 最小的ICMP包大小#define ICMP_MIN 8/ IP 包头struct IPHeader BYTE h_len:4; / Length of the header in dwords BYTE version:4; / Version of IP BYTE tos; / Type of service USHORT total_len; / Length of the packet in dwords USHORT ident; / unique identifier USHORT flags; / Flags BYTE ttl; / Time to live, 这个字段我在下一节中用来实现Tracert功能 BYTE proto; / Protocol number (TCP, UDP etc) USHORT checksum; / IP checksum ULONG source_ip; ULONG dest_ip;/ ICMP 包头(实际的包不包括timestamp字段, / 作者用来计算包的回应时间,其实完全没有必要这样做)struct ICMPHeader BYTE type; / ICMP packet type BYTE code; / Type sub code USHORT checksum; USHORT id; USHORT seq; ULONG timestamp; / not part of ICMP, but we need it;extern USHORT ip_checksum(USHORT* buffer, int size);extern int setup_for_ping(char* host, int ttl, SOCKET& sd,sockaddr_in& dest);extern int send_ping(SOCKET sd, const sockaddr_in& dest, ICMPHeader* send_buf, int packet_size);extern int recv_ping(SOCKET sd, sockaddr_in& source, IPHeader* recv_buf, int packet_size);extern int decode_reply(IPHeader* reply, int bytes, sockaddr_in* from);extern void init_ping_packet(ICMPHeader* icmp_hdr, int packet_size, int seq_no);/* 程序名: rawping.cpp* 说明: * 主要函数库实现部分*/include #include #include #include rawping.h/ 计算ICMP包的校验和的简单算法, 很多地方都有说明, 这里没有必要详细将/ 只是一点要提, 做校验之前, 务必将ICMP包头的checksum字段置为0USHORT ip_checksum(USHORT* buffer, int size) unsigned long cksum = 0; / Sum all the words together, adding the final byte if size is odd while (size 1) cksum += *buffer+; size -= sizeof(USHORT); if (size) cksum += *(UCHAR*)buffer; / Do a little shuffling cksum = (cksum 16) + (cksum & 0xffff); cksum += (cksum 16); / Return the bitwise complement of the resulting mishmash return (USHORT)(cksum);/初试化RAW Socket, 设置ttl, 初试化dest/ 返回值 0 表失败int setup_for_ping(char* host, int ttl, SOCKET& sd,
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年安全员B证考试试卷【新题速递】附答案详解
- 2020年初级会计师考试真题经济法
- 国企考试考试训练试卷(含答案及解析)
- 三类人员网上培训考试试题及答案解读
- 公共营养师三级考试题
- 国家公务员考试《行测》卷真题及答案解析18套
- 2025年广东申论真题试卷及答案
- 2025年趣味百科知识竞赛试题库及答案(一)
- 各校自主招生试题
- 2025年监理工程师《工程技术与计量》真题解析
- 新闻职称答辩题库及答案
- 点卡售卖合同范本
- 了解事物的本质课件
- 仓库管理员面试题及答案
- 山西省太原市2025-2026学年高三上学期11月期中考试物理试卷
- 2025高中历史时间轴与大事年表
- 2025宁夏建设投资集团有限公司“集中招聘”524人笔试历年常考点试题专练附带答案详解2套试卷
- 2025浙江嘉兴市体育彩票管理服务中心招聘编外人员4人考试笔试参考题库附答案解析
- 2025广东惠州市博罗县自然资源局招聘编外人员76人考试笔试备考试题及答案解析
- 2025年乌鲁木齐市招聘警务辅助人员(600人)笔试考试备考题库及答案解析
- 动漫分镜美术课件
评论
0/150
提交评论