当前位置:文档之家› 编程实现简单的TCP协议分析器

编程实现简单的TCP协议分析器

《网络系统》课程设计报告

学院专业

班级学号

学生姓名指导教师

课程成绩完成日期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. 懂得了学习对数据包进行协议分析的基本方法。

相关主题