计算机网络课程设计-网络嗅探器的设计与实现

目录

前言

1 实验题目

2 实验目的

3 实验内容

3.1 步骤

3.2 关键代码

3.2.1 初始化socket,监听数据

3.2.2 对捕获到的数据包进行解析

4 实验结果与分析

5 代码


前言

        本实验为计算机网络课程设计内容,基本上所有代码都是根据指导书给的附录写出来的。有些实验需要实现图形界面,但是出于期末考试压力,我所有实验均是在控制台输入输出的,没有花额外时间去学习qt了,有精力的同学可以自学一下qt实现简单的图形界面。同时,该博客内容为部分报告内容,仅为大家提供参考,请勿直接抄袭。另外,本次实验所用平台是centos7,代码均是在终端进行编译的,不会的可以先了解怎么用终端编程,或者利用其他较为智能的开发环境进行编程

1 实验题目

        实验七 网络嗅探器的设计与实现

2 实验目的

        设计一个可以监视网络的状态、数据流动情况以及网络上传输 的信息的网络嗅探器。

3 实验内容

3.1 步骤

        (1)创建原始套接字以捕获数据包。

        (2)解析捕获到的数据包,提取其中的数据链路层和网络层信息。

        (3)输出所提取到的数据包信息。

3.2 关键代码

3.2.1 初始化socket,监听数据

if((sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP))) < 0) {
		fprintf(stdout, "create socket error\n");
		exit(0);
	}

3.2.2 对捕获到的数据包进行解析

while(1) {
		n_read = recvfrom(sock, buffer, 2048, 0, NULL, NULL);
		if(n_read < 42) {
			fprintf(stdout, "Incomplete header, packet corrupt\n");
			continue;
		}
		ethhead = buffer;
		p = ethhead;
		int n = 0XFF;
		printf("数据链路层---源MAC地址: %.2X:%02X:%02X:%02X:%02X:%02X ==> 目的MAC地址: ""%.2X:%.2X:%.2X:%.2X:%.2X:%.2X\n",
			 p[6]&n, p[7]&n, p[8]&n, p[9]&n, p[10]&n, p[11]&n,
			 p[0]&n, p[1]&n, p[2]&n,p[3]&n, p[4]&n, p[5]&n);
		iphead = ethhead + 14;
		p = iphead + 12;
		printf("网络层---源IP地址: %d.%d.%d.%d => 目的IP地址: %d.%d.%d.%d\n",
		       p[0]&n, p[1]&n, p[2]&n, p[3]&n,p[4]&n, p[5]&n, p[6]&n, p[7]&n);
		memset(srcIp,'\0',strlen(srcIp));
		memset(destIp,'\0',strlen(destIp));
		sprintf(srcIp,"%d.%d.%d.%d",p[0]&n, p[1]&n, p[2]&n, p[3]&n);
		sprintf(destIp,"%d.%d.%d.%d",p[4]&n, p[5]&n, p[6]&n, p[7]&n);
		proto = (iphead + 9)[0];
		ipHeaderLen =  (iphead)[0]&0x0f;
		ipTotalLen = ((iphead + 2)[0]<<8)&0xff00 | (iphead + 3)[0]&0x00ff;
		ipDataLen = ipTotalLen - ipHeaderLen*4;
		p = iphead + 20;
		printf("IP数据报头部长度: %d,总长度: %u,数据部分长度: %d\n",
		       ipHeaderLen*4,ipTotalLen,ipDataLen);
		printf("Protocol: ");
		switch(proto) {
			case IPPROTO_ICMP:
				printf("ICMP\n");
				break;
			case IPPROTO_IGMP:
				printf("IGMP\n");
				break;
			case IPPROTO_IPIP:
				printf("IPIP\n");
				break;
			case IPPROTO_TCP :
				printf("TCP,source port: %u,",(p[0]<<8)&0XFF00 | p[1]&0XFF);
				printf("dest port: %u\n", (p[2]<<8)&0XFF00 | p[3]&0XFF);
				printf("\n\n");
				break;
			case IPPROTO_UDP :
				printf("UDP,source port: %u,",(p[0]<<8)&0XFF00 | p[1]&0XFF);
				printf("dest port: %u\n", (p[2]<<8)&0XFF00 | p[3]&0XFF);
				printf("\n\n");
				break;
			case IPPROTO_RAW :
				printf("RAW\n");
				break;
			default:
				printf("Unkown, please query in include/linux/in.h\n");
		}
	}

4 实验结果与分析

(1)因为普通用户没有网络权限,所以需要在root用户模式启动程序,刚开始因为没有数据传输,控制台没有输出。

图1.1 利用root用户启动程序

(2)打开火狐浏览器Firefox,可以看到控制台输出了对抓到的数据包解析后的相关信息。

图1.2 打开火狐浏览器Firefox

图1.3 终端输出的数据包相关信息

5 代码

/***************SimpelSniffer.c*************/
/*注意:本代码为 LINUX 操作系统下的源代码*/
//author:duanjigang@2006s
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <linux/if_ether.h>
#include <netinet/in.h>
#define BUFFER_MAX 2048

typedef long long LL;

const int TcpHeaderLen = 20;
const int UdpHeaderLen = 8;

const int MaxLen = 576;
const int TcpCode = 1;
const int UdpCode = 0;

const char *tcpP="tcp.txt";
const char *udpP="udp.txt";

int handleTcpData(char *TcpData,const char *fileName,int dataLen,char *buf) {
	int i;
	LL seq = ((TcpData + 4)[0]<<24)&0xff000000 | ((TcpData + 5)[0]<<16)&0xff0000
	         | ((TcpData + 6)[0]<<8)&0xff00 | ((TcpData + 7)[0]<<16)&0xff;
	LL ack = ((TcpData + 8)[0]<<24)&0xff000000 | ((TcpData + 9)[0]<<16)&0xff0000
	         | ((TcpData + 10)[0]<<8)&0xff00 | ((TcpData + 11)[0]<<16)&0xff;

	TcpData=TcpData+TcpHeaderLen;
	dataLen = dataLen - TcpHeaderLen;

	FILE *fpWrite=fopen(fileName,"a");
	if(fpWrite==NULL) return 0;

	fprintf(fpWrite,"TCP -> %s, seq: %lld, ack: %lld, TcpDataLen: %u\n",buf,seq,ack,dataLen);
	for(i=0; i<dataLen; i++) {
		fprintf(fpWrite,"%02x ",TcpData[i]&0xff);
	}
	fprintf(fpWrite,"\n\n");
	fclose(fpWrite);
	fpWrite=NULL;
	return 1;
}

int handleUdpData(char *UdpData,const char *fileName,char *buf) {
	int i;
	int udpDataLen =  ((UdpData + 4)[0]<<8)&0xff00 | (UdpData + 5)[0]&0x00ff;
	printf("UDP数据长度: %u\n",udpDataLen);

	UdpData = UdpData + 8;

	FILE *fpWrite=fopen(fileName,"a");
	if(fpWrite==NULL) return 0;

	fprintf(fpWrite,"UDP -> %s, UdpDataLen: %u\n",buf,udpDataLen);

	for(i=0; i<udpDataLen; i++) {
		fprintf(fpWrite,"%02x ",UdpData[i]&0xff);
	}


	fprintf(fpWrite,"\n\n");
	fclose(fpWrite);

	fpWrite=NULL;
	return 1;
}

int main(int argc, char *argv[]) {
	char buf[256];
	char srcPort[6],destPort[6];
	char srcMac[18],decMac[18];
	char srcIp[16],destIp[16];
	int sock, n_read, proto,ipTotalLen,ipHeaderLen,ipDataLen;
	char buffer[BUFFER_MAX];
	char *ethhead, *iphead, *tcphead,
	     *udphead, *icmphead, *p;

	if((sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP))) < 0) {
		fprintf(stdout, "create socket error\n");
		exit(0);
	}

	while(1) {
		n_read = recvfrom(sock, buffer, 2048, 0, NULL, NULL);
		/*
		14 6(dest)+6(source)+2(type or length)
		+
		20 ip header
		+
		8 icmp,tcp or udp header
		= 42
		*/
		if(n_read < 42) {
			fprintf(stdout, "Incomplete header, packet corrupt\n");
			continue;
		}

		ethhead = buffer;
		p = ethhead;
		int n = 0XFF;
		printf("数据链路层---源MAC地址: %.2X:%02X:%02X:%02X:%02X:%02X ==> 目的MAC地址: "
		       "%.2X:%.2X:%.2X:%.2X:%.2X:%.2X\n",
		       p[6]&n, p[7]&n, p[8]&n, p[9]&n, p[10]&n, p[11]&n,
		       p[0]&n, p[1]&n, p[2]&n,p[3]&n, p[4]&n, p[5]&n);
//		sprintf(srcMac,"%02X:%02X:%02X:%02X:%02X:%02X",
//		        p[6]&n, p[7]&n, p[8]&n, p[9]&n, p[10]&n, p[11]&n);
//		sprintf(decMac,"%02X:%02X:%02X:%02X:%02X:%02X",
//		        p[0]&n, p[1]&n, p[2]&n,p[3]&n, p[4]&n, p[5]&n);

		iphead = ethhead + 14;
		p = iphead + 12;

		printf("网络层---源IP地址: %d.%d.%d.%d => 目的IP地址: %d.%d.%d.%d\n",
		       p[0]&n, p[1]&n, p[2]&n, p[3]&n,
		       p[4]&n, p[5]&n, p[6]&n, p[7]&n);

		memset(srcIp,'\0',strlen(srcIp));
		memset(destIp,'\0',strlen(destIp));
		sprintf(srcIp,"%d.%d.%d.%d",p[0]&n, p[1]&n, p[2]&n, p[3]&n);
		sprintf(destIp,"%d.%d.%d.%d",p[4]&n, p[5]&n, p[6]&n, p[7]&n);

		proto = (iphead + 9)[0];
		ipHeaderLen =  (iphead)[0]&0x0f;
		ipTotalLen = ((iphead + 2)[0]<<8)&0xff00 | (iphead + 3)[0]&0x00ff;
//		printf("高字节: %u,低字节: %u\n",((iphead + 2)[0]<<8)&0xff00,(iphead + 3)[0]&0x00ff);
		ipDataLen = ipTotalLen - ipHeaderLen*4;
		p = iphead + 20;
		printf("IP数据报头部长度: %d,总长度: %u,数据部分长度: %d\n",
		       ipHeaderLen*4,ipTotalLen,ipDataLen);
		printf("Protocol: ");
		switch(proto) {
			case IPPROTO_ICMP:
				printf("ICMP\n");
				break;
			case IPPROTO_IGMP:
				printf("IGMP\n");
				break;
			case IPPROTO_IPIP:
				printf("IPIP\n");
				break;
			case IPPROTO_TCP :
				printf("TCP,source port: %u,",(p[0]<<8)&0XFF00 | p[1]&0XFF);
				printf("dest port: %u\n", (p[2]<<8)&0XFF00 | p[3]&0XFF);

//				memset(srcPort,'\0',strlen(srcPort));
//				memset(destPort,'\0',strlen(destPort));
//				sprintf(srcPort,"%u",(p[0]<<8)&0XFF00 | p[1]&0XFF);
//				sprintf(destPort,"%u",(p[2]<<8)&0XFF00 | p[3]&0XFF);
//				memset(buf,'\0',strlen(buf));
//				sprintf(buf,"(srcIp: %s---srcPort: %s),(destIp: %s---destPort: %s)",
//				        srcIp,srcPort,destIp,destPort);
//				if(ipDataLen<MaxLen) {
//					if(handleTcpData(p,tcpP,ipDataLen,buf)) {
//						printf("TCP数据部分已写入 tcp.txt 文件\n");
//					} else {
//						printf("TCP数据部分已写入 tcp.txt 文件错误\n");
//					}
//				}
				printf("\n\n");
				break;
			case IPPROTO_UDP :
				printf("UDP,source port: %u,",(p[0]<<8)&0XFF00 | p[1]&0XFF);
				printf("dest port: %u\n", (p[2]<<8)&0XFF00 | p[3]&0XFF);
//				memset(srcPort,'\0',strlen(srcPort));
//				memset(destPort,'\0',strlen(destPort));
//				sprintf(srcPort,"%u",(p[0]<<8)&0XFF00 | p[1]&0XFF);
//				sprintf(destPort,"%u",(p[2]<<8)&0XFF00 | p[3]&0XFF);
//				memset(buf,'\0',strlen(buf));
//				sprintf(buf,"(srcIp: %s---srcPort: %s),(destIp: %s---destPort: %s)",
//				        srcIp,srcPort,destIp,destPort);
//				if(ipDataLen<MaxLen) {
//					if(handleUdpData(p,udpP,buf)) {
//						printf("UDP数据部分已写入 udp.txt 文件\n");
//					} else {
//						printf("UDP数据部分已写入 udp.txt 文件错误\n");
//					}
//				}
				printf("\n\n");
				break;
			case IPPROTO_RAW :
				printf("RAW\n");
				break;
			default:
				printf("Unkown, please query in include/linux/in.h\n");
		}
	}
}

  • 9
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值