VC++分析数据包实现ICMP协议分析
ICMP是(Internet Control Message Protocol)Internet控制报文协议。它是TCP/IP协议族的一个子协议,用于在IP主机、路由器之间传递控制消息。控制消息是指网络通不通、主机是否可达、路由是否可用等网络本身的消息。这些控制消息虽然并不传输用户数据,但是对于用户数据的传递起着重要的作用。
ICMP协议是一种面向非连接的协议,用于传输出错报告控制信息。它是一个非常重要的协议,它对于网络安全具有极其重要的意义。
它是TCP/IP协议族的一个子协议,属于网络层协议,主要用于在主机与路由器之间传递控制信息,包括报告错误、交换受限控制和状态信息等。当遇到IP数据无法访问目标、IP路由器无法按当前的传输速率转发数据包等情况时,会自动发送ICMP消息。
ICMP原理ICMP提供一致易懂的出错报告信息。发送的出错报文返回到发送原数据的设备,因为只有发送设备才是出错报文的逻辑接受者。发送设备随后可根据ICMP报文确定发生错误的类型,并确定如何才能更好地重发失败的数据包。但是ICMP唯一的功能是报告问题而不是纠正错误,纠正错误的任务由发送方完成。
我们在网络中经常会使用到ICMP协议,比如我们经常使用的用于检查网络通不通的Ping命令(Linux和Windows中均有),这个“Ping”的过程实际上就是ICMP协议工作的过程。还有其他的网络命令如跟踪路由的Tracert命令也是基于ICMP协议的。
ICMP的全称是 Internet Control Message Protocol 。从技术角度来说,ICMP就是一个“错误侦测与回报机制”,其目的就是让我们能够检测网路的连线状况﹐也能确保连线的准确性﹐其功能主要有:
· 侦测远端主机是否存在。
· 建立及维护路由资料。
· 重导资料传送路径。
· 资料流量控制。 ICMP常用类型 ICMP常用类型ICMP在沟通之中,主要是透过不同的类别(Type)与代码(Code) 让机器来识别不同的连线状况。常用的类别如下表所列﹕
ICMP 是个非常有用的协议﹐尤其是当我们要对网路连接状况进行判断的时候。下面让我们看看常用的 ICMP 实例,以更好了解 ICMP 的功能与作用。
ICMP协议对于网络安全具有极其重要的意义。ICMP协议本身的特点决定了它非常容易被用于攻击网络上的路由器和主机。例如,在1999年8月海信集团“悬赏”50万元人民币测试防火墙的过程中,其防火墙遭受到的ICMP攻击达334050次之多,占整个攻击总数的90%以上!可见,ICMP的重要性绝不可以忽视!
比如,可以利用操作系统规定的ICMP数据包最大尺寸不超过64KB这一规定,向主机发起“Ping of Death”(死亡之Ping)攻击。“Ping of Death” 攻击的原理是:如果ICMP数据包的尺寸超过64KB上限时,主机就会出现内存分配错误,导致TCP/IP堆栈崩溃,致使主机死机。(现在的操作系统已经取消了发送ICMP数据包的大小的限制,解决了这个漏洞)
ICMP协议是一种面向非连接的协议,用于传输出错报告控制信息。它是一个非常重要的协议,它对于网络安全具有极其重要的意义。
它是TCP/IP协议族的一个子协议,属于网络层协议,主要用于在主机与路由器之间传递控制信息,包括报告错误、交换受限控制和状态信息等。当遇到IP数据无法访问目标、IP路由器无法按当前的传输速率转发数据包等情况时,会自动发送ICMP消息。
ICMP原理ICMP提供一致易懂的出错报告信息。发送的出错报文返回到发送原数据的设备,因为只有发送设备才是出错报文的逻辑接受者。发送设备随后可根据ICMP报文确定发生错误的类型,并确定如何才能更好地重发失败的数据包。但是ICMP唯一的功能是报告问题而不是纠正错误,纠正错误的任务由发送方完成。
我们在网络中经常会使用到ICMP协议,比如我们经常使用的用于检查网络通不通的Ping命令(Linux和Windows中均有),这个“Ping”的过程实际上就是ICMP协议工作的过程。还有其他的网络命令如跟踪路由的Tracert命令也是基于ICMP协议的。
ICMP的全称是 Internet Control Message Protocol 。从技术角度来说,ICMP就是一个“错误侦测与回报机制”,其目的就是让我们能够检测网路的连线状况﹐也能确保连线的准确性﹐其功能主要有:
· 侦测远端主机是否存在。
· 建立及维护路由资料。
· 重导资料传送路径。
· 资料流量控制。 ICMP常用类型 ICMP常用类型ICMP在沟通之中,主要是透过不同的类别(Type)与代码(Code) 让机器来识别不同的连线状况。常用的类别如下表所列﹕
ICMP 是个非常有用的协议﹐尤其是当我们要对网路连接状况进行判断的时候。下面让我们看看常用的 ICMP 实例,以更好了解 ICMP 的功能与作用。
ICMP协议对于网络安全具有极其重要的意义。ICMP协议本身的特点决定了它非常容易被用于攻击网络上的路由器和主机。例如,在1999年8月海信集团“悬赏”50万元人民币测试防火墙的过程中,其防火墙遭受到的ICMP攻击达334050次之多,占整个攻击总数的90%以上!可见,ICMP的重要性绝不可以忽视!
比如,可以利用操作系统规定的ICMP数据包最大尺寸不超过64KB这一规定,向主机发起“Ping of Death”(死亡之Ping)攻击。“Ping of Death” 攻击的原理是:如果ICMP数据包的尺寸超过64KB上限时,主机就会出现内存分配错误,导致TCP/IP堆栈崩溃,致使主机死机。(现在的操作系统已经取消了发送ICMP数据包的大小的限制,解决了这个漏洞)
此外,向目标主机长时间、连续、大量地发送ICMP数据包,也会最终使系统瘫痪。大量的ICMP数据包会形成“ICMP风暴”,使得目标主机耗费大量的CPU资源处理,疲于奔命。
#include "nids.h" /* ----------------------------------------------------------------------------------------------------------------------- UDP协议首部的数据结构 ----------------------------------------------------------------------------------------------------------------------- */ struct udp_header { unsigned short udp_source_port; unsigned short udp_destination_port; unsigned short udp_length; unsigned short udp_checksum; }; /* ----------------------------------------------------------------------------------------------------------------------- ICMP协议首部的数据结构 ----------------------------------------------------------------------------------------------------------------------- */ struct icmp_header { unsigned int icmp_type; unsigned int icmp_code; unsigned char icmp_checksum; unsigned char icmp_id; unsigned char icmp_sequence; }; /* ----------------------------------------------------------------------------------------------------------------------- IP协议首部的数据结构 ----------------------------------------------------------------------------------------------------------------------- */ struct ip_header { #if defined(WORDS_BIGENDIAN) unsigned char ip_version: 4, /* 版本 */ ip_header_length: 4; /* 首部长度 */ #else unsigned char ip_header_length: 4, ip_version: 4; #endif unsigned char ip_tos; /* 服务类型 */ unsigned short ip_length; /* 总长度 */ unsigned short ip_id; /* 标识 */ unsigned short ip_off; /* 标志和偏移 */ unsigned char ip_ttl; /* 生存时间 */ unsigned char ip_protocol; /* 协议类型 */ unsigned short ip_checksum; /* 校验和 */ struct in_addr ip_souce_address; /* 源IP地址 */ struct in_addr ip_destination_address; /* 目的IP地址 */ }; /* ----------------------------------------------------------------------------------------------------------------------- TCP协议首部 ----------------------------------------------------------------------------------------------------------------------- */ struct tcp_header { unsigned char tcp_source_port; /* 源端口号 */ unsigned char tcp_destination_port; /* 目的端口号 */ unsigned short tcp_sequence; /* 学列码 */ unsigned short tcp_acknowledgement; /* 确认号 */ #ifdef WORDS_BIGENDIAN unsigned int tcp_offset: 4, /* 数据偏移 */ tcp_reserved: 4; /* 保留 */ #else unsigned int tcp_reserved: 4, /* 保留 */ tcp_offset: 4; /* 数据偏移 */ #endif unsigned int tcp_flags; /* 标志 */ unsigned char tcp_windows; /* 窗口大小 */ unsigned char tcp_checksum; /* 校验和 */ unsigned char tcp_urgent_pointer; /* 紧急指针 */ }; char ascii_string[10000]; char *char_to_ascii(char ch) { char *string; ascii_string[0] = 0; string = ascii_string; if (isgraph(ch)) *string++ = ch; else if (ch == ' ') *string++ = ch; else if (ch == '\n' || ch == '\r') *string++ = ch; else *string++ = '.'; *string = 0; return ascii_string; } /* ======================================================================================================================= 下面是分析ICMP协议的函数 ======================================================================================================================= */ void icmp_protocol_packet_callback(const u_char *packet_content) { struct icmp_header *icmp_protocol; icmp_protocol = (struct icmp_header*)(packet_content + 14+20); printf("---------- ICMP协议 ----------\n"); printf("ICMP类型:%d\n", icmp_protocol->icmp_type); switch (icmp_protocol->icmp_type) /* ICMP类型 */ { case 8: printf("ICMP回显请求协议\n"); printf("ICMP代码:%d\n", icmp_protocol->icmp_code); printf("标识符:%d\n", icmp_protocol->icmp_id); printf("序列码:%d\n", icmp_protocol->icmp_sequence); break; case 0: printf("ICMP回显应答协议\n"); printf("ICMP代码:%d\n", icmp_protocol->icmp_code); printf("标识符:%d\n", icmp_protocol->icmp_id); printf("序列码:%d\n", icmp_protocol->icmp_sequence); break; default: break; } printf("ICMP校验和:%d\n", ntohs(icmp_protocol->icmp_checksum)); /* 获取校验和 */ return ; } /* ======================================================================================================================= 下面是分析TCP协议的函数 ======================================================================================================================= */ void tcp_protocol_packet_callback(const u_char *packet_content) { struct tcp_header *tcp_protocol; u_char flags; int header_length; u_short source_port; u_short destination_port; u_short windows; u_short urgent_pointer; u_int sequence; u_int acknowledgement; unsigned char checksum; tcp_protocol = (struct tcp_header*)(packet_content + 14+20); source_port = ntohs(tcp_protocol->tcp_source_port); /* 获取源端口号 */ destination_port = ntohs(tcp_protocol->tcp_destination_port); /* 获取目的端口号 */ header_length = tcp_protocol->tcp_offset *4; /* 获取首部长度 */ sequence = ntohl(tcp_protocol->tcp_sequence); /* 获取序列码 */ acknowledgement = ntohl(tcp_protocol->tcp_acknowledgement); /* 获取确认号 */ windows = ntohs(tcp_protocol->tcp_windows); /* 获取窗口大小 */ urgent_pointer = ntohs(tcp_protocol->tcp_urgent_pointer); /* 获取紧急指针 */ flags = tcp_protocol->tcp_flags; checksum = ntohs(tcp_protocol->tcp_checksum); printf("------- TCP协议 -------\n"); printf("源端口号:%d\n", source_port); printf("目的端口号:%d\n", destination_port); switch (destination_port) { case 80: printf("上层协议为HTTP协议\n"); break; case 21: printf("上层协议为FTP协议\n"); break; case 23: printf("上层协议为TELNET协议\n"); break; case 25: printf("上层协议为SMTP协议\n"); break; case 110: printf("上层协议POP3协议\n"); break; default: break; } printf("序列码:%u\n", sequence); printf("确认号:%u\n", acknowledgement); printf("首部长度:%d\n", header_length); printf("保留:%d\n", tcp_protocol->tcp_reserved); printf("标记:"); if (flags &0x08) printf("PSH "); if (flags &0x10) printf("ACK "); if (flags &0x02) printf("SYN "); if (flags &0x20) printf("URG "); if (flags &0x01) printf("FIN "); if (flags &0x04) printf("RST "); printf("\n"); printf("窗口大小:%d\n", windows); printf("校验和:%d\n", checksum); printf("紧急指针:%d\n", urgent_pointer); } /* ======================================================================================================================= 下面是分析UPD协议的函数 ======================================================================================================================= */ void udp_protocol_packet_callback(u_char *packet_content) { struct udp_header *udp_protocol; u_short source_port; u_short destination_port; u_short length; udp_protocol = (struct udp_header*)(packet_content + 20); source_port = ntohs(udp_protocol->udp_source_port); /* 获取源端口号 */ destination_port = ntohs(udp_protocol->udp_destination_port); /* 获取目的端口号 */ length = ntohs(udp_protocol->udp_length); printf("---------- UDP协议首部 ----------\n"); printf("源端口:%d\n", source_port); printf("目的端口:%d\n", destination_port); switch (destination_port) { case 138: printf("NETBIOS Datagram Service\n"); break; case 137: printf("NETBIOS Name Service\n"); break; case 139: printf("NETBIOS session service\n"); break; case 53: printf("name-domain server \n"); break; default: break; } printf("长度:%d\n", length); printf("校验和:%d\n", ntohs(udp_protocol->udp_checksum)); } /* ======================================================================================================================= 下面是分析IP协议的函数 ======================================================================================================================= */ void ip_protocol_packet_callback(u_char *packet_content) { struct ip_header *ip_protocol; u_int header_length; u_int offset; u_char tos; unsigned short checksum; printf("---------- IP协议首部 ----------\n"); ip_protocol = (struct ip_header*)(packet_content); checksum = ntohs(ip_protocol->ip_checksum); /* 获取校验和 */ header_length = ip_protocol->ip_header_length *4; /* 获取首部长度 */ tos = ip_protocol->ip_tos; offset = ntohs(ip_protocol->ip_off); printf("IP版本:%d\n", ip_protocol->ip_version); printf("首部长度:%d\n", header_length); printf("TOS:%d\n", tos); printf("总长度:%d\n", ntohs(ip_protocol->ip_length)); printf("标识:%d\n", ntohs(ip_protocol->ip_id)); printf("偏移:%d\n", (offset &0x1fff) *8); printf("生存时间:%d\n", ip_protocol->ip_ttl); printf("协议:%d\n", ip_protocol->ip_protocol); switch (ip_protocol->ip_protocol) /* 判断上层协议类型 */ { case 6: printf("上层协议为TCP\n"); break; case 17: printf("上层协议为UDP\n"); break; case 1: printf("上层协议为ICMP\n"); break; default: break; } printf("校验和:%d\n", checksum); printf("源IP地址:%s\n", inet_ntoa(ip_protocol->ip_souce_address)); printf("目的IP地址:%s\n", inet_ntoa(ip_protocol->ip_destination_address)); switch (ip_protocol->ip_protocol) { case 17: udp_protocol_packet_callback(packet_content); break; /* 上层协议为UDP协议,调用分析UDP协议的函数 */ case 6: tcp_protocol_packet_callback(packet_content); break; /* 上层协议为TCP协议,调用分析TCP协议的函数 */ case 1: icmp_protocol_packet_callback(packet_content); break; /* 上层协议为ICMP协议,调用分析ICMP协议的函数 */ default: break; } } /* ======================================================================================================================= 下面是回调函数 ======================================================================================================================= */ void ip_callback(struct ip *a_packet, int len) { ip_protocol_packet_callback(a_packet); /* 调用分析IP协议的函数 */ } /* ======================================================================================================================= 主函数 ======================================================================================================================= */ void main() { if (!nids_init()) /* Libnids初始化 */ { printf("出现错误:%s\n", nids_errbuf); exit(1); } nids_register_ip_frag(ip_callback); /* 注册分析IP协议的回调函数 */ nids_run(); /* 进入循环捕获数据包的状态 */ }