《网络系统》课程设计报告学院专业班级学号学生姓名指导教师课程成绩完成日期2013年6月28日课程设计成绩评定学院专业班级学号学生姓名指导教师完成日期2013年6月28日指导教师对学生在课程设计中的评价指导教师对课程设计的评定意见课程设计任务书学院专业编程实现简单的TCP协议分析器学生姓名:指导老师:摘要编程实现简单的TCP协议分析器。
TCP协议分析器是一种用于监督和跟踪网络活动的诊断工具。
它从局域网中抓取IP数据包,并对它进行分析得到相对应的头部信息,过滤TCP包进行分析,得到TCP包的相应信息。
运行程序平台为windows7/XP,程序通过调试运行,初步实现了设计目标,并且再经过适当完善后,将可以应用在商业中解决实际问题。
TCP协议的数据传送程序是由二个子程序组成的。
也可以看成是服务器端程序和客户端程序,其中:服务器端程序的功能是侦听端口号,接收远程主要的TCP连接申请,并接收远程主机传送来的文字数据。
关键词程序设计;TCP;局域网;指令;服务器目录1 引言.......................................................................................... 错误!未定义书签。
1.1问题描述........................................................................... 错误!未定义书签。
1.2基本要求........................................................................... 错误!未定义书签。
2系统设计 (1)2.1 设计思想 (1)2.2系统结构 (2)3程序流程 (2)3.1 程序流程图 (2)4 模块设计介绍 (4)4.1 主模块 (4)5 判断 (5)5.1判断IP协议类型字段 (5)5.2判断以太网字协议段类型 (12)6 系统调试 (13)6.1测试情况 (13)7 结束语........................................................................................ 错误!未定义书签。
附录:源程序代码 (16)1 引言TCP协议的数据传送程序是由二个子程序组成的。
也可以看成是服务器端程序和客户端程序,其中:服务器端程序的功能是侦听端口号,接收远程主要的TCP连接申请,并接收远程主机传送来的文字数据。
另外一个子程序,也就是所谓的客户端程序,主要实现向网络的远程主机提出TCP连接申请。
1.1问题描述编程实现简单的TCP协议分析器,TCP协议分析器是一种用于监督和跟踪网络活动的诊断工具,它从局域网中抓取IP数据包,并对它进行分析得到相应的头部信息,过滤TCP包进行分析,得到TCP包的相应信息。
1.2基本要求1.利用原始套接字实现简单的TCP协议分析器。
2.系统功能包括:2.1 原始套接字与网卡绑定,并接收流经网卡的所有数据包;2.2 对数据包进行分析以获得源IP地址和目的IP地址;2.3 对TCP Segment进行分析以获得其首部详细信息;2.4 显示分析结果。
3 使用VC++。
2 系统设计2.1设计思想TCP协议的数据传送程序是由二个子程序组成的,也可以看成是服务器端程序和客户端程序。
其中,服务器端程序的功能是侦听端口号,接收远程主要的TCP连接申请,并接收远程主机传送来的文字数据。
另外一个子程序,也就是所谓的客户端程序,主要实现向网络的远程主机提出TCP连接申请。
程序利用原始套接字抓取局域网中的IP包。
Raw Socket: 原始套接字可以用它来发送和接收IP 层以上的原始数据包, 如ICMP,TCP, UDP等。
TCP协议分析器实现了sniffer的一部分功能。
而sniffer的工作原理是:1. 把网卡置于混杂模式;2. 捕获数据包;3. 分析数据包。
2.2系统结构(1)Pcap_addr描述网络接口地址;(2)pcap_pkthdr用来描述每个捕获到的数据包的基本信息;(3)int_pcaplookupnet获取网络地址和网络掩码;(4)int_pcaploop循环捕获网络数据包,直到遇到错误或满足退出条件;(5)pcap_t* pcap_open_dead构造一个libpcap句柄。
3程序流程3.1程序流程如图1图1数据包的分析流程4 模块设计介绍4.1主模块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操作*/}5 判断5. 1判断IP协议类型字段struct ip_header{#if defined(WORDS_BIGENDIAN)u_int8_t ip_version: 4,/* 版本*/ip_header_length: 4;/* 首部长度*/#elseu_int8_t ip_header_length: 4, ip_version: 4;#endifu_int8_t ip_tos;/* 服务质量*/u_int16_t ip_length;/* 长度*/u_int16_t ip_id;/* 标识*/u_int16_t ip_off;/* 偏移*/u_int8_t ip_ttl;/* 生存时间*/u_int8_t ip_protocol;/* 协议类型*/u_int16_t ip_checksum;/* 校验和*/struct in_addr ip_souce_address;/* 源IP地址*/struct in_addr ip_destination_address;/* 目的IP地址*/};struct udp_header{u_int16_t udp_source_port;t;/* 目的端口号*/u_int32_t tcp_sequence_liuzhen;/* 序列号*/u_int32_t tcp_acknowledgement;/* 确认序列号*/#ifdef WORDS_BIGENDIANu_int8_t tcp_offset: 4,/* 偏移*/tcp_reserved: 4;/* 未用*/#elseu_int8_t tcp_reserved: 4,/* 未用*/tcp_offset: 4;/* 偏移*/#endifu_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;/* 标记*/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);/* 校验和*/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);}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");printf("版本号:%d\n", ip_protocol->ip_version);printf("首部长度:%d\n", header_length);printf("服务质量:%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);printf("上层协议为TCP协议\n");printf("校验和:%d\n", checksum);printf("源IP地址:%s\n", inet_ntoa(ip_protocol->ip_souce_address));/* 获得源IP地址*/printf("目的IP地址:%s\n", inet_ntoa(ip_protocol->ip_destination_address));/* 获得目的IP地址*/}}void ethernet_protocol_packet_callback(u_char *argument, const struct pcap_pkthdr *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);/* 获得校验和*/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->_sec));/* 获得捕获数据包的时间*/printf("数据包长度:\n");printf("%d\n", packet_header->len);printf("-------- 以太网协议--------\n");/* 获得以太网协议内容*/printf("类型:\n");printf("%04x\n", ethernet_type);printf("源以太网地址: \n");mac_string = ethernet_protocol->ether_shost;printf("%02x:%02x:%02x:%02x:%02x:%02x\n", *mac_string, *(mac_string + 1), *(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:%02x\n", *mac_string, *(mac_string + 1), *(mac_string + 2), *(mac_string + 3), *(mac_string + 4), *(mac_string + 5));/* 获得目的以太网地址*/ip_protocol_packet_callback(argument, packet_header, packet_content); packet_number++;printf("**************************************************\n");}}5.2 判断以太网字段类型struct ether_header{u_int8_t ether_dhost[6];/* 目的以太网地址*/u_int8_t ether_shost[6];/* 源以太网地址*/u_int16_t ether_type;/* 以太网类型*/};struct arp_header{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_address[6];/* 源以太网地址*/u_int8_t arp_source_ip_address[4];/* 源IP地址*/u_int8_t arp_destination_ethernet_address[6];/* 目的以太网地址*/u_int8_t arp_destination_ip_address[4];/* 目的IP地址*/};6 系统调试6.1测试情况捕获数据包如图2图2捕获数据包的测试结果判断IP协议类型字段如图3图3判断IP协议类型字段的测试结果判断以太网类型字段如图4图4判断以太网类型字段的测试结果7 结束语通过这两周的课程设计,它增强了我的实际动手能力,让我更加意识到不懂就问的乐趣,问可以是问老师、学长、学姐及度娘。