计算机网络课程设计编程实现简单的TCP协议分析器_计算机网络课程设计
计算机网络课程设计编程实现简单的TCP协议分析器由刀豆文库小编整理,希望给你工作、学习、生活带来方便,猜你可能喜欢“计算机网络课程设计”。
编程实现简单的TCP协议分析器
编程实现简单的TCP协议分析器
一、问题描述
编程实现简单的TCP协议分析器,TCP协议分析器是一种用于监督和跟踪网络活动的诊断工具,它从局域网中抓取IP数据包,并对它进行分析得到相应的头部信息,过滤TCP包进行分析,得到TCP包的相应信息。
二、基本要求
1.利用原始套接字实现简单的TCP协议分析器。2.系统功能包括:
2.1 原始套接字与网卡绑定,并接收流经网卡的所有数据包; 2.2 对数据包进行分析以获得源IP地址和目的IP地址; 2.3 对TCP Segment进行分析以获得其首部详细信息; 2.4 显示分析结果。3 建议使用VC++。
三、设计思想
TCP协议的数据传送程序是由二个子程序组成的。也可以看成是服务器端程序和客户端程序,其中:服务器端程序的功能是侦听端口号,接收远 程主要的TCP连接申请,并接收远程主机传送来的文字数据。另外一个子程序,也就是所谓的客户端程序,主要实现向网络的远程主机提出TCP连接申请。
程序利用原始套接字抓取局域网中的IP包。
TCP协议分析器实现了sniffer的一部分功能。而sniffer的工作原理是:1.把网卡置于混杂模式;2.捕获数据包;3.分析数据包。
Raw Socket: 原始套接字可以用它来发送和接收 IP 层以上的原始数据包, 如 ICMP,TCP, UDP等。
四、系统结构
(1)Pcap_addr描述网络接口地址;
(2)pcap_pkthdr用来描述每个捕获到的数据包的基本信息;(3)int_pcaplookupnet获取网络地址和网络掩码;
(4)int_pcaploop循环捕获网络数据包,直到遇到错误或满足退出条件;(5)pcap_t* pcap_open_dead构造一个libpcap句柄。
五、程序流程(或模块划分)
编程实现简单的TCP协议分析器
六、源程序
#include “pcap.h” struct ether_header {
u_int8_t ether_dhost[6];
/* 目的以太网地址 */
u_int8_t ether_shost[6];
/* 源以太网地址 */
u_int16_t ether_type;
/* 以太网类型 */ };struct arp_header
编程实现简单的TCP协议分析器
{
u_int16_t arp_hardware_type;
/* 硬件类型 */
u_int16_t arp_protocol_type;
/* 协议类型 */
u_int8_t arp_hardware_length;
/* 硬件地址长度 */
u_int8_t arp_protocol_length;
/* 协议地址长度 */
u_int16_t arp_operation_code;
/* 操作码 */
u_int8_t arp_source_ethernet_addre[6];
/* 源以太网地址 */
u_int8_t arp_source_ip_addre[4];
/* 源IP地址 */
u_int8_t arp_destination_ethernet_addre[6];
/* 目的以太网地址 */
u_int8_t arp_destination_ip_addre[4];
/* 目的IP地址 */ };struct ip_header {
#if defined(WORDS_BIGENDIAN)
u_int8_t ip_version: 4,/* 版本 */
ip_header_length: 4;
/* 首部长度 */
#else
u_int8_t ip_header_length: 4, ip_version: 4;
#endif
u_int8_t ip_tos;
/* 服务质量 */
u_int16_t ip_length;
/* 长度 */
u_int16_t ip_id;
/* 标识 */
u_int16_t ip_off;
编程实现简单的TCP协议分析器
/* 偏移 */
u_int8_t ip_ttl;
/* 生存时间 */
u_int8_t ip_protocol;
/* 协议类型 */
u_int16_t ip_checksum;
/* 校验和 */
struct in_addr ip_souce_addre;
/* 源IP地址 */
struct in_addr ip_destination_addre;
/* 目的IP地址 */ };struct udp_header {
u_int16_t udp_source_port;
/* 源端口号 */
u_int16_t udp_destination_port;
/* 目的端口号 */
u_int16_t udp_length;
/* 长度 */
u_int16_t udp_checksum;
/* 校验和 */ };struct tcp_header {
u_int16_t tcp_source_port;
/* 源端口号 */
u_int16_t tcp_destination_port;
/* 目的端口号 */
u_int32_t tcp_sequence_liuzhen;
/* 序列号 */
u_int32_t tcp_acknowledgement;
/* 确认序列号 */
#ifdef WORDS_BIGENDIAN
u_int8_t tcp_offset: 4,/* 偏移 */
编程实现简单的TCP协议分析器
tcp_reserved: 4;
/* 未用 */
#else
u_int8_t tcp_reserved: 4,/* 未用 */
tcp_offset: 4;
/* 偏移 */
#endif
u_int8_t tcp_flags;
/* 标记 */
u_int16_t tcp_windows;
/* 窗口大小 */
u_int16_t tcp_checksum;
/* 校验和 */
u_int16_t tcp_urgent_pointer;
/* 紧急指针 */ };struct icmp_header {
u_int8_t icmp_type;
/* ICMP类型 */
u_int8_t icmp_code;
/* ICMP代码 */
u_int16_t icmp_checksum;
/* 校验和 */
u_int16_t icmp_id;
/* 标识符 */
u_int16_t icmp_sequence;
/* 序列码 */ };void tcp_protocol_packet_callback(u_char *argument, const struct pcap_pkthdr *packet_header, const u_char *packet_content){
struct tcp_header *tcp_protocol;
/* TCP协议变量 */
u_char flags;
编程实现简单的TCP协议分析器
/* 标记 */
int header_length;
/* 长度 */
u_short source_port;
/* 源端口 */
u_short destination_port;
/* 目的端口 */
u_short windows;
/* 窗口大小 */
u_short urgent_pointer;
/* 紧急指针 */
u_int sequence;
/* 序列号 */
u_int acknowledgement;
/* 确认号 */
u_int16_t checksum;
/* 校验和 */
tcp_protocol =(struct tcp_header*)(packet_content + 14+20);
/* 获得TCP协议内容 */
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_liuzhen);
/* 序列码 */
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);
编程实现简单的TCP协议分析器
/* 校验和 */
printf(“-------TCP协议
-------n”);
printf(“源端口号:%dn”, source_port);
printf(“目的端口号:%dn”, 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(“序列码:%un”, sequence);
printf(“确认号:%un”, acknowledgement);
printf(“首部长度:%dn”, header_length);
printf(“保留:%dn”, tcp_protocol->tcp_reserved);
printf(“标记:”);
if(flags &0x08)
printf(“PSH ”);
if(flags &0x10)
printf(“ACK ”);
if(flags &0x02)
printf(“SYN ”);
if(flags &0x20)
编程实现简单的TCP协议分析器
printf(“URG ”);
if(flags &0x01)
printf(“FIN ”);
if(flags &0x04)
printf(“RST ”);
printf(“n”);
printf(“窗口大小:%dn”, windows);
printf(“校验和:%dn”, checksum);
printf(“紧急指针:%dn”, urgent_pointer);} void ip_protocol_packet_callback(u_char *argument, const struct pcap_pkthdr *packet_header, const u_char *packet_content){
struct ip_header *ip_protocol;
/* IP协议变量 */
u_int header_length;
/* 长度 */
u_int offset;
/* 偏移 */
u_char tos;
/* 服务质量 */
u_int16_t checksum;
/* 校验和 */
ip_protocol =(struct ip_header*)(packet_content + 14);
/* 获得IP协议内容 */
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);
/* 获得偏移 */ if(ip_protocol->ip_protocol==6)
{
printf(“-----------IP协议
-----------n”);
编程实现简单的TCP协议分析器
printf(“版本号:%dn”, ip_protocol->ip_version);
printf(“首部长度:%dn”, header_length);
printf(“服务质量:%dn”, tos);
printf(“总长度:%dn”, ntohs(ip_protocol->ip_length));
printf(“标识:%dn”, ntohs(ip_protocol->ip_id));
printf(“偏移:%dn”,(offset &0x1fff)*8);
printf(“生存时间:%dn”, ip_protocol->ip_ttl);
printf(“协议类型:%dn”, ip_protocol->ip_protocol);
printf(“上层协议为TCP协议n”);
printf(“校验和:%dn”, checksum);
printf(“源IP地址:%sn”, inet_ntoa(ip_protocol->ip_souce_addre));
/* 获得源IP地址 */
printf(“目的IP地址:%sn”, inet_ntoa(ip_protocol->ip_destination_addre));
/* 获得目的IP地址 */
} } void ethernet_protocol_packet_callback(u_char *packet_header, const u_char *packet_content){ static int packet_number = 1;
/* 数据包个数,静态变量 */ u_short ethernet_type;
/* 以太网类型 */
struct ether_header *ethernet_protocol;struct ip_header *ip_protocol;
/* IP协议变量 */
u_int header_length;
/* 长度 */
u_int offset;
/* 偏移 */
u_char tos;
/* 服务质量 */
u_int16_t checksum;
/* 校验和 */
ip_protocol =(struct ip_header*)(packet_content + 14);
/* 获得IP协议内容 */
checksum = ntohs(ip_protocol->ip_checksum);
*argument, const struct pcap_pkthdr 编程实现简单的TCP协议分析器
/* 获得校验和 */
header_length = ip_protocol->ip_header_length *4;
/* 获得长度 */
tos = ip_protocol->ip_tos;
/* 获得服务质量 */
offset = ntohs(ip_protocol->ip_off);
/* 获得偏移 */
/* 以太网协议变量 */ ethernet_protocol =(struct ether_header*)packet_content;ethernet_type = ntohs(ethernet_protocol->ether_type);/* 获得以太网类型 */ if(ethernet_type==0x0800 && ip_protocol->ip_protocol==6){ u_char *mac_string;
/* 以太网地址 */
printf(“**************************************************n”);
printf(“捕获第%d个TCP网络数据包n”, packet_number);
printf(“捕获时间:n”);
printf(“%s”, ctime((const time_t*)&packet_header->ts.tv_sec));
/* 获得捕获数据包的时间 */
printf(“数据包长度:n”);
printf(“%dn”, packet_header->len);
printf(“--------
以太网协议
--------n”);
/* 获得以太网协议内容 */
printf(“类型:n”);
printf(“%04xn”, ethernet_type);
printf(“源以太网地址: n”);
mac_string = ethernet_protocol->ether_shost;
printf(“%02x:%02x:%02x:%02x:%02x:%02xn”,*mac_string, *(mac_string *(mac_string + 2), *(mac_string + 3), *(mac_string + 4), *(mac_string + 5));
/* 获得源以太网地址 */
printf(“目的以太网地址: n”);
mac_string = ethernet_protocol->ether_dhost;
printf(“%02x:%02x:%02x:%02x:%02x:%02xn”, *mac_string, *(mac_string *(mac_string + 2), *(mac_string + 3), *(mac_string + 4), *(mac_string + 5));
/* 获得目的以太网地址 */
ip_protocol_packet_callback(argument, packet_header, packet_content);
+ 1),+ 1), 编程实现简单的TCP协议分析器
packet_number++;
printf(“**************************************************n”);
} } void main(){
pcap_t *pcap_handle;
/* Winpcap句柄 */
char error_content[PCAP_ERRBUF_SIZE];
/* 存储错误信息 */
char *net_interface;
/* 网络接口 */
struct bpf_program bpf_filter;
/* BPF过滤规则 */
char bpf_filter_string[] = “”;
/* 过滤规则字符串 */
bpf_u_int32 net_mask;
/* 掩码 */
bpf_u_int32 net_ip;
/* 网路地址 */
net_interface = pcap_lookupdev(error_content);
/* 获得可用的网络接口 */
pcap_lookupnet(net_interface, &net_ip, &net_mask, error_content);
/* 获得网络地址和掩码地址 */
pcap_handle = pcap_open_live(net_interface, BUFSIZ, 1, 1, error_content);
/* 打开网路接口 */
pcap_compile(pcap_handle, &bpf_filter, bpf_filter_string, 0, net_ip);
/* 编译BPF过滤规则 */
pcap_setfilter(pcap_handle, &bpf_filter);
/* 设置过滤规则 */
if(pcap_datalink(pcap_handle)!= DLT_EN10MB)
return;
pcap_loop(pcap_handle,-1, ethernet_protocol_packet_callback, NULL);
/* 注册回调函数,循环捕获网络数据包,利用回调函数来处理每个数据包 */
pcap_close(pcap_handle);
/* 关闭Winpcap操作 */ }
编程实现简单的TCP协议分析器
七、测试数据
本地局域网IP数据包
八、测试情况
程序运行结果图:
编程实现简单的TCP协议分析器
编程实现简单的TCP协议分析器
结 论
通过两周的课程设计,增强了我的实际动手能力,通过实际的编程整合串联了我所学到的知识。另外我还学到了作为编程人员的一些基本素质,这为我毕业后找工作奠定了基础。
通过做TCP协议分析器学习的很多网络编程知识: 1.学会了winpcap网络数据报捕获开发包的使用; 2.绑定网卡函数bind(); 3.数据接受函数recv(); 4.Windows套接字编程;
5.学习了原始套接字编程的基本机制; 6.学习对数据包进行协议分析的基本方法。
通过做TCP协议分析器学习的很多Visual C++ Windows编程知识:
1.学会了Windows常用数据结构的使用;
2.学到了一些用Visual C++ Windows编程的技巧。
编程实现简单的TCP协议分析器
参考文献
[1] 甘玲 邱劲 《面向对象技术与Visual C++ 》 清华大学出版社 [2] 任哲 《MFC Windows 应用程序设计》清华大学出版社 [3] 《计算机网络》 北京:机械工业出版社
[4] 《Visual C++网络通信编程实用案例精选》 人民邮电出版社 [5] 《windows程序设计》 北京大学出版社