《网络系统》课程设计报告
学院专业
班级学号
学生姓名指导教师
课程成绩完成日期2013年6月28日
课程设计成绩评定
学院专业
班级学号
学生姓名指导教师
完成日期2013年6月28日
指导教师对学生在课程设计中的评价
评分项目优良中及格不及格课程设计中的创造性成果
学生掌握课程内容的程度
课程设计完成情况
课程设计动手能力
文字表达
学习态度
规范要求
课程设计论文的质量
指导教师对课程设计的评定意见
综合成绩指导教师签字2013年6月28日
课程设计任务书
学院专业
课程名称网络系统课程设计时间2012~2013学年第二学期17~18周学生姓名指导老师
题目编程实现简单的TCP协议分析器
主要内容:
(1)从局域网中抓取IP数据包;
(2)对它进行分析得到相应的头部信息;
(3)过滤TCP包进行分析,得到TCP包的相应信息
(4)谈谈本次课程设计活动的体会和心得
要求:
(1)利用编程软件
(2)通过课程设计培养学生严谨的科学态度,认真的工作作风和团队协作精神。
(3)学会文献检索的基本方法和综合运用文献的能力。
(4)在老师的指导下,要求每个学生独立完成课程设计的全部内容。
应当提交的文件:
(1)课程设计报告。
(2)课程设计附件(源程序、各类图纸、实验数据、运行截图等)
编程实现简单的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数据包的分析流程
捕获网络数据包
分析以太网协议
判断以太网类型字段
分析ARP 协议 分析IP 协议 分析RARP 协议
判断IP 协议类型字段
分析TCP 协议 分析UDP 协议 分析ICMP 协议
0X086
0X8035
0X0800
6
17
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;
/* 首部长度*/
#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;
/* 偏移*/
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_BIGENDIAN
u_int8_t tcp_offset: 4,
/* 偏移*/
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;
/* 标记*/
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->http://biz.doczj.com/doc/228341396.html,_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 结束语
通过这两周的课程设计,它增强了我的实际动手能力,让我更加意识到不懂就问的乐趣,问可以是问老师、学长、学姐及度娘。通过实际的编程整合串联了我以前和现在所学到的知识,让我懂得了许多以前所不知道得知识,另外我懂得了一些作为编程人员的一些基本素质,如:写程序时要静心,不要一下写不出来就觉得很烦;程序测试出错时,不要心急,慢慢查看,看自己那里出了错或丢失了什么东西;不懂时要善于、敢于去问,不要想不知道就把它丢一边,等下次再做。我想这可以为我毕业后找工作多一些经验基础。
通过做TCP协议分析器学习的很多网络编程知识:
1.我学会了winpcap网络数据报捕获开发包的使用;
2.了解了怎样绑定网卡函数bind();
3.了解了怎样使数据接受函数recv();
4.了解了怎样Windows套接字编程;
5. 懂得了原始套接字编程的一些基本机制;
6. 懂得了学习对数据包进行协议分析的基本方法。