计算机网络课程设计网络嗅探器

一、题目

网络嗅探器

二、环境

Win10    codeblocks

三、代码实现

WinPcap的安装教程

winpcap要在CB中使用,还需配置一些.h文件,请自行百度,百度上有。

请熟悉教材IP数据包的格式,以及头部协议部分。
代码如下:

#define HAVE_REMOTE//宏定义
#define LINE_LEN 16
#include "winsock.h"
#include <string.h>
#include "pcap.h"
#pragma comment(lib, "Ws2_32.lib")
typedef struct ip_address
{
    
     //ip地址
    u_char b1;//u_char无符号char
    u_char b2;
    u_char b3;
    u_char b4;
} ip_address;

typedef struct mac_address
{
    
    //mac地址
	u_char b1;
	u_char b2;
	u_char b3;
	u_char b4;
	u_char b5;
	u_char b6;
} mac_address;

typedef struct ethe_header
{
    
     //mac帧首部
	mac_address mac_dest_address;//目的地址
	mac_address mac_source_address;//源地址
	u_short ether_type;//长度或类型
} ethe_header;

typedef struct ip_header
{
    
     //ip地址首部
    u_char  ver_ihl;//版本号和头长度各占4位
    u_char  tos;//服务类型
    u_short tlen;//分组长度
    u_short identification;//分组标识,唯一标识发送的每一个数据报
    u_short flags_fo;//标志
    u_char  ttl;//生存时间,TTL
    u_char  proto;//协议可以是TCP,UDP,ICMP等
    u_short crc;//校验和
    ip_address  saddr;//源IP地址
    ip_address  daddr;//目的IP地址
    u_int   op_pad;// 选项与填充
} ip_header;

typedef struct udp_header
{
    
     //UPD首部
    u_short sport;//源端口号
    u_short dport;//目的端口号
    u_short len;//包长度
    u_short crc;//校验和
} udp_header;

typedef struct tcp_header
{
    
     //TCP首部
	u_short sport;//16位源端口号
                u_short dport;//16位目的端口号
    	u_int num;//32位序列号
	u_int ack;//32位确认号
	u_short sum;//可能是包长度
	u_short windonw;//16位窗口大小
	u_short crc;//16位校验和
	u_short ugr;//16位紧急数据偏移量
} tcp_header;

void packet_handler(u_char * param, const struct pcap_pkthdr * header, const  u_char *pkt_data);
char judge;
int length;
int main()
{
    
    
    pcap_if_t * alldevs, *device;//pcap_if是winpcap这个抓包框架中自带的函数库中的主要函数之一,用来描述一个网络设备结构,
	int i = 0;
	int iNum;
	u_int netmask;
	struct bpf_program fcode;//使用于pcap_compile,格式过滤
	pcap_t * adhandle;//libpcap函数库中pcap_t及pcap_dumper_t类型的数据结构
	char errbuf[PCAP_ERRBUF_SIZE];
	//修改这里可以更改捕获的数据包使用的协议类型
    char packet_filter[] = "(ip and udp) or (ip and tcp) or (ip and icmp)";

	if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)
	{
    
     //获取设备列表
		fprintf(stderr,"无法打开网络设备:%s\n", errbuf);
		return 1;
	}
	for (device = alldevs; device  != NULL; device = device->next)
	{
    
     //打印列表
		if (i == 0)
		{
    
    
			printf("请按CTRL + C退出!\n\n");
			printf("网络设备如下:\n");
		}
		printf("%d. %s\n", ++i, device -> name);
		if (device->description)
			printf(" (%s)\n", device->description);
		else
			printf("没有设备描述信息!");
	}
	if (i == 0)
	{
    
    
		printf("\n请先安装WinPcap!");
		return -1;
	}
	printf("请选择网络设备接口:(1 - %d):", i);
	scanf("%d", &iNum);
	getchar();
	if (iNum < 1 || iNum > i)
	{
    
    
		printf("设备不存在!\n");
		pcap_freealldevs(alldevs);//不需要网卡列表时,释放设备列表
		return -1;
	}
	//跳转到已选设备
    for (device = alldevs, i = 0;i < iNum -1 ; device = device -> next,i++);

    // 打开适配器
    if ( (adhandle= pcap_open(device->name,  // 设备名
                             65536,     // 要捕捉的数据包的部分
                                        // 65535保证能捕获到不同数据链路层上的每个数据包的全部内容
                             PCAP_OPENFLAG_PROMISCUOUS,         // 混杂模式
                             1000,      // 读取超时时间
                             NULL,      // 远程机器验证
                             errbuf     // 错误缓冲池
                             ) ) == NULL)
    {
    
    
        fprintf(stderr,"\n不能打开适配器!\n");
        /* 释放设备列表 */
        pcap_freealldevs(alldevs);
        return -1;
    }

    if (pcap_datalink(adhandle) != DLT_EN10MB)
	{
    
     //检查数据链路层,为了简单,只考虑以太网
		fprintf(stderr, "\n系统网卡链路出错!\n");
		pcap_freealldevs(alldevs); //释放设备列表
		return -1;
	}

	if (device->addresses != NULL) //获得接口第一个地址的掩码
		netmask = ((struct sockaddr_in *)(device->addresses->netmask))->sin_addr.S_un.S_addr;
	else //如果接口没有地址,那么我们假设一个C类的掩码
		netmask = 0xffff00;
	if (pcap_compile(adhandle, &fcode, packet_filter, 1, netmask) < 0)
	{
    
     //编译过滤器
		fprintf(stderr, "不能监听过滤该数据报!\n");
		pcap_freealldevs(alldevs);
		return -1;
	}

	if (pcap_setfilter(adhandle, &fcode) < 0)
	{
    
     //设置过滤器
		fprintf(stderr, "过滤设置错误!\n");
		pcap_freealldevs(alldevs);
		return -1;
	}
	printf("请输入是否要输出捕捉到的报文信息(y/n) : ");
	scanf("%c",&judge);
	if (judge!='n')
	{
    
    
		printf("请输入要限制要输出报文信息长度(-1不限制) : ");
		scanf("%d",&length);
	}
	printf("\n正在监听通过%s的数据报...\n", device->description);
	pcap_freealldevs(alldevs); //释放设备列表
	pcap_loop(adhandle, 0, packet_handler, NULL); //开始捕捉

	return 0 ;
}

void packet_handler(u_char *dumpfile, const struct pcap_pkthdr *header, const u_char *pkt_data)
{
    
     //回调函数,当收到每一个数据包时会被libpcap所调用
	if(header->caplen>400) return;
	int len;
    struct tm *ltime;
    char timestr[16];
	ip_header * ip_hd;
	udp_header * udp_hd;
	tcp_header * tcp_hd;
    ethe_header * ethe_hd;
	int ip_len,tcp_len,start;
	u_short sport,dport;

	printf("\n");
    ltime=localtime(&header->ts.tv_sec); //将时间戳转换为可读字符
    strftime( timestr, sizeof timestr, "%H:%M:%S", ltime);
    printf("时间:%s\n",timestr);

    ethe_hd = (ethe_header *)pkt_data;
    ip_hd = (ip_header *)(pkt_data + 14);
	ip_len = (ip_hd ->ver_ihl & 0xf) * 4; //ip首部长度
	udp_hd = (udp_header *)((u_char *)ip_hd + ip_len);
	sport = ntohs(udp_hd->sport);
	dport = ntohs(udp_hd->dport);
	if(ip_hd->proto==17)
	{
    
    
		printf("协议:UDP");
		start=ip_len+8;
	}
	else if(ip_hd->proto==6)
	{
    
    
		printf("协议:TCP");
		tcp_hd = (tcp_header *)((u_char *)ip_hd + ip_len);
		tcp_len=ntohs(tcp_hd->sum)>>12;
		start=ip_len+tcp_len*4;
	}
	else if(ip_hd->proto==1)
	{
    
    
		printf("协议:ICMP");
		start=ip_len+23;
	}
	else printf("协议:其他");
	printf("start=%d\n",start);
	printf("                      数据报的长度:%d\n",header->caplen);

	printf("IP头的长度:%d              IP包存活时间:%d\n",ip_hd->tlen,ip_hd->ttl);

    printf("源IP地址: %d.%d.%d.%d:%d      目的IP地址:%d.%d.%d.%d:%d\n      源端口:%d                     目的端口:%d\n源物理地址: %x-%x-%x-%x-%x-%x   目的物理地址:%x-%x-%x-%x-%x-%x\n",
		  ip_hd->saddr.b1, ip_hd->saddr.b2, ip_hd->saddr.b3, ip_hd->saddr.b4,
		           ip_hd->daddr.b1, ip_hd->daddr.b2, ip_hd->daddr.b3, ip_hd->daddr.b4, sport, dport,
				   ethe_hd->mac_source_address.b1, ethe_hd->mac_source_address.b2, ethe_hd->mac_source_address.b3,
				   ethe_hd->mac_source_address.b4, ethe_hd->mac_source_address.b5, ethe_hd->mac_source_address.b6,
				   ethe_hd->mac_dest_address.b1, ethe_hd->mac_dest_address.b2, ethe_hd->mac_dest_address.b3,
				   ethe_hd->mac_dest_address.b4, ethe_hd->mac_dest_address.b5, ethe_hd->mac_dest_address.b6);
	//输出数据部分
	if (judge=='y')
	{
    
    
	    printf("数据部分内容为:\n");
	    if(length==-1) len=(header->caplen) + 1 ;
	    else len=(length>header->caplen + 1-start)?(header->caplen+1)-start:length;
	    for (int i=start; (i < start + len ) ; i++)
	    {
    
    
	        printf("%.2x ", pkt_data[i-1]); //也可以改为 %c 以 ascii码形式输出。
	        if ( (i % LINE_LEN) == 0) printf("\n");
	    }
	    printf("\n\n");
	}
}



四、实验结果
结果

猜你喜欢

转载自blog.csdn.net/weixin_43752257/article/details/112965606