目录
前言
本实验为计算机网络课程设计内容,基本上所有代码都是根据指导书给的附录写出来的。有些实验需要实现图形界面,但是出于期末考试压力,我所有实验均是在控制台输入输出的,没有花额外时间去学习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");
}
}
}