C语言读取DHCP数据包(pcap文件)内容

目录

设计要求

设计过程

1)定义pcap文件头结构体,时间戳结构体,pcap数据包头结构体

2)数据链路层结构体定义

3)IP数据包头结构体定义

4)UDP数据包头结构体定义

5)DHCP数据包结构体定义

6)计算校验和字段

程序源码


设计要求

C语言编写程序,针对wireshark抓获的DHCP数据包(pcap文件),要求按照数据链路层、网络层、传输层、应用层等顺序显示各主要字段的信息。并计算出传输层(UDP)的校验和字段且显示。要求程序能够通过交互方式输入pcap文件的路径。

需要满足该要求,我们就必须需要了解pcap文件是什么,也要了解DHCP协议是讲什么的:

pcap文件格式_sakura0908的博客-CSDN博客DHCP数据包分析_sakura0908的博客-CSDN博客

通过上面两篇博客深刻的了解pcap文件和DHCP数据包的详细内容,才更好的理解该篇博客的编程思想,一步步地深入学习,更好地掌握这个知识点,结尾附有源码分享。

设计过程

//给数据类型起别名,方便我们使用

typedef unsigned char u_int8;
typedef unsigned short u_int16;
typedef unsigned int u_int32;
typedef unsigned long long u_int64;

1)定义pcap文件头结构体,时间戳结构体,pcap数据包头结构体

//pacp文件头结构体
struct pcap_file_header
{
	u_int32 magic;				//识别文件和字节顺序:小端/大端模式
	u_int16 version_major;		//主版本号
	u_int16 version_minor;		//次版本号
	u_int32 thiszone;			//当地的标准时间
	u_int32 sigfigs;			//时间戳精度
	u_int32 snaplen;			//最大的存储长度
	u_int32 linktype;			//链路类型
};

//时间戳
struct time_val
{
	u_int32 tv_sec;					//时间戳高位,精确到seconds
	u_int32 tv_usec;				//时间戳地位,精确到microseconds
};

//pcap数据包头结构体
struct pcap_pkthdr
{
	struct time_val ts;			//捕获时间
	u_int32 caplen;				//数据帧/区的长度
	u_int32 len;				//离线数据长度
};

2)数据链路层结构体定义

//数据链路层数据
typedef struct DL_Header
{
	u_int8 DstMAC[6];			//源MAC地址
	u_int8 SrcMAC[6];			//目的MAC地址
	u_int8 Type[2];				//帧类型
}DL_Header;

3)IP数据包头结构体定义

//IP数据报头
typedef struct IP_Header
{
	u_int8 Ver_HLen;		//版本+报头长度
	u_int8 TOS;				//服务类型
	u_int8 TotalLen[2];		//总长度
	u_int8 ID[2];			//标识
	u_int8 Flag;			//标志
	u_int8 Flag_Segment;	//片偏移
	u_int8 TTL;				//生存周期
	u_int8 Protocol;		//协议类型
	u_int8 Checksum[2];		//头部校验和
	u_int8 SrcIP[4];		//源IP地址
	u_int8 DstIP[4];		//目的IP地址
} IP_Header;

4)UDP数据包头结构体定义

//UDP数据报头
typedef struct UDP_Header
{
	u_int8 SrcPort[2];			//源端口
	u_int8 DstPort[2];			//目的端口
	u_int8 Length[2];			//数据长度
	u_int8 Checksum[2];			//校验和
}UDP_Header;

5)DHCP数据包结构体定义

//DHCP数据
typedef struct DHCP
{
	u_int8 op;
	u_int8 htype;
	u_int8 hlen;
	u_int8 hops;
	u_int8 xid[4];
	u_int16 secs;
	u_int16 flags;
	u_int8 ciaddr[4];
	u_int8 yiaddr[4];
	u_int8 siaddr[4];
	u_int8 giaddr[4];
	u_int8 chaddr[16];
	u_int8 sname[64];
	u_int8 file[128];
	u_int8 mag[4];
	u_int8 option1[3];
	u_int8 option2[6];
	u_int8 option3[9];
	u_int8 option4;
}Dhcp;

6)计算校验和字段

UDP计算校验和的方法和IP数据报首部校验和的方法相似。不同的是:IP数据报校验和只校验IP数据报的首部,但UDP的校验和是把首部和数据部分一起都检验。

UDP的校验和需要计算UDP首部加数据荷载部分,但也需要加上UDP伪首部。这个伪首部指,源地址、目的地址、UDP数据长度、协议类型(0x11),协议类型就一个字节,但需要补一个字节的0x0,构成12个字节。伪首部+UDP首部+数据一起计算校验和。

UDP检验和的计算方法是:

  • 按每16位求和得出一个32位的数;
  • 如果这个32位的数,高16位不为0,则高16位加低16位再得到一个32位的数;
  • 重复第2步直到高16位为0,将低16位取反,得到校验和。
unsigned short checksum(unsigned short* buf, int nword)
{
	unsigned long sum;
	for (sum = 0; nword > 0; nword--)
	{
		sum += *buf++;
		sum = (sum >> 16) + (sum & 0xffff);
	}
	return ~sum;
}

程序源码

int main()
{
	char my_time[1000] = { 0 };
	char file_name[1000] = { 0 };
	struct pcap_file_header* file_header = (struct pcap_file_header*)malloc(sizeof(struct pcap_file_header));
	struct pcap_pkthdr* ptk_header = (struct pcap_pkthdr*)malloc(sizeof(struct pcap_pkthdr));
	DL_Header* dl_header = (struct DL_Header*)malloc(sizeof(struct DL_Header));
	IP_Header* ip_header = (IP_Header*)malloc(sizeof(IP_Header));
	UDP_Header* udp_header = (UDP_Header*)malloc(sizeof(UDP_Header));
	Dhcp* dhcp = (Dhcp*)malloc(sizeof(Dhcp));

	printf("请输入你要抓取的文件名字:");
	scanf("%s", file_name);

	FILE* fp = fopen(file_name, "rb");
	if (fp == NULL)
	{
		printf("打开pcap文件失败,退出!!");
		exit(0);
	}
	else
	{
		fread(file_header, sizeof(struct pcap_file_header), 1, fp);
		fread(ptk_header, sizeof(struct pcap_pkthdr), 1, fp);
		fread(dl_header, sizeof(struct DL_Header), 1, fp);
		fread(ip_header, sizeof(struct IP_Header), 1, fp);
		fread(udp_header, sizeof(UDP_Header), 1, fp);
		fread(dhcp, sizeof(Dhcp), 1, fp);
	}
	fclose(fp);

	struct tm* timeinfo;
	time_t t = (time_t)(ptk_header->ts.tv_sec);
	time(&t);
	timeinfo = localtime(&t);
	strftime(my_time, sizeof(my_time), "%Y-%m-%d %H:%M:%S", timeinfo);

	printf("Frame 1 : % d bytes on wire(% d bits), % d bytes captured(% d bites)\n", ptk_header->caplen, ptk_header->caplen * 8, ptk_header->caplen, ptk_header->caplen * 8);
	printf("Arrival Time:%s\n",my_time);
	printf("Epoch Time: %d.%d\n", ptk_header->ts.tv_sec, ptk_header->ts.tv_usec);
	printf("Frame Number: 1\n");
	printf("Frame Length : %d bytes on wire(% d bits)\n", ptk_header->caplen, ptk_header->caplen * 8);
	printf("Frame 1 : %d bytes on wire(% d bits)\n", ptk_header->caplen, ptk_header->caplen * 8);
	printf("Capture Length: %d bytes (%d bites)\n", ptk_header->caplen, ptk_header->caplen * 8);
	printf("\n");

	printf("Ethernet II, Src :InterCor (%02x:%02x:%02x:%02x:%02x:%02x)", dl_header->SrcMAC[0], dl_header->SrcMAC[1], dl_header->SrcMAC[2], dl_header->SrcMAC[3], dl_header->SrcMAC[4], dl_header->SrcMAC[5]);
	printf("Dst: %02x:%02x:%02x:%02x:%02x:%02x\n", dl_header->DstMAC[0], dl_header->DstMAC[1], dl_header->DstMAC[2], dl_header->DstMAC[3], dl_header->DstMAC[4], dl_header->DstMAC[5]);
	printf("Destination: %02x:%02x:%02x:%02x:%02x:%02x\n", dl_header->DstMAC[0], dl_header->DstMAC[1], dl_header->DstMAC[2], dl_header->DstMAC[3], dl_header->DstMAC[4], dl_header->DstMAC[5]);
	printf("Source: %02x:%02x:%02x:%02x:%02x:%02x\n", dl_header->SrcMAC[0], dl_header->SrcMAC[1], dl_header->SrcMAC[2], dl_header->SrcMAC[3], dl_header->SrcMAC[4], dl_header->SrcMAC[5]);
	printf("Type: IPv4 0x%02x%02x\n", dl_header->Type[0], dl_header->Type[1]);
	printf("\n");

	printf("Internet Protocol Version 4, Src:%d.%d.%d.%d ", ip_header->SrcIP[0], ip_header->SrcIP[1], ip_header->SrcIP[2], ip_header->SrcIP[3]);
	printf("Dst:%d.%d.%d.%d\n", ip_header->DstIP[0], ip_header->DstIP[1], ip_header->DstIP[2], ip_header->DstIP[3]);
	printf("version: 4\n");
	printf("Header length: 20 bytes\n");
	printf("Diffenentiated Services Filed: 0x%02x\n", ip_header->TOS);
	printf("Total Length: %d\n", ip_header->TotalLen[0] * 16 * 16 + ip_header->TotalLen[1]);
	printf("Identination: 0x%02x%02x\n", ip_header->ID[0], ip_header->ID[1]);
	printf("Flag: 0x%04x\n", ip_header->Flag);
	printf("Flagment offset:%d\n", ip_header->Flag_Segment);
	printf("Time to live:%d\n", ip_header->TTL);
	if (ip_header->Protocol == 6)
	{
		printf("Protocol:TCP(%d)\n", ip_header->Protocol);
	}
	else
	{
		printf("Protocol: UDP(%d)\n", ip_header->Protocol);
	}
	printf("Header checksum:0x%2x%2x\n", ip_header->Checksum[0], ip_header->Checksum[1]);
	printf("Source Address: %d.%d.%d.%d\n", ip_header->SrcIP[0], ip_header->SrcIP[1], ip_header->SrcIP[2], ip_header->SrcIP[3]);
	printf("Destination Address: %d.%d.%d.%d\n", ip_header->DstIP[0], ip_header->DstIP[1], ip_header->DstIP[2], ip_header->DstIP[3]);
	printf("\n");

	printf("Source Port:%d\n", udp_header->SrcPort[0] + udp_header->SrcPort[1]);
	printf("DstPort Port:%d\n", udp_header->DstPort[0] + udp_header->DstPort[1]);
	printf("Lengyh:%d\n", udp_header->Length[0] * 16 * 16 + udp_header->Length[1]);
	printf("Checksum:0x%2x%2x\n", udp_header->Checksum[0], udp_header->Checksum[1]);
	printf("\n");

	printf("Message type:Boot Requeest(%d)\n", dhcp->op);
	printf("Hardware type:Ethernet(0x%02x)\n", dhcp->htype);
	printf("Hardware address length: %d\n", dhcp->hlen);
	printf("Hops: %d\n", dhcp->hops);
	printf("Transaction ID:0x%02x%02x%02x%02x\n", dhcp->xid[0], dhcp->xid[1], dhcp->xid[2], dhcp->xid[3]);
	printf("Second elapsed : %d\n", dhcp->secs);
	printf("Bootp flag:0x%04x\n", dhcp->flags);
	printf("Client IP address:%d.%d.%d.%d\n", dhcp->ciaddr[0], dhcp->ciaddr[1], dhcp->ciaddr[2], dhcp->ciaddr[3]);
	printf("Your(client) IP address:%d.%d.%d.%d\n", dhcp->yiaddr[0], dhcp->yiaddr[1], dhcp->yiaddr[2], dhcp->yiaddr[2]);
	printf("Next server IP address:%d.%d.%d.%d\n", dhcp->siaddr[0], dhcp->siaddr[1], dhcp->siaddr[2], dhcp->siaddr[3]);
	printf("Relay agent IP address:%d.%d.%d.%d\n", dhcp->giaddr[0], dhcp->giaddr[1], dhcp->giaddr[2], dhcp->giaddr[3]);
	printf("Client MAC address: chongqin_8f:27:5d(%2x:%2x:%2x:%2x:%2x:%2x)\n", dhcp->chaddr[0], dhcp->chaddr[1], dhcp->chaddr[2], dhcp->chaddr[3],dhcp->chaddr[4],dhcp->chaddr[5]);
	printf("Magic cookie:DHCP(0x%2x%2x 0x%2x%2x)\n", dhcp->mag[0], dhcp->mag[1], dhcp->mag[2], dhcp->mag[3]);
	printf("Option:(%d) DHCP Message Type\n", dhcp->option1[0]);
	printf("Length:%d\n", dhcp->option1[1]);
	printf("DHCP:(%d)\n", dhcp->option1[2]);
	printf("Option:(%d)\n", dhcp->option2[0]);
	printf("Length:%d\n", dhcp->option2[1]);
	printf("DHCP Server Identifer:%d.%d.%d.%d\n", dhcp->option2[2], dhcp->option2[3], dhcp->option2[4], dhcp->option2[5]);
	printf("Option:(%d)\n", dhcp->option3[0]);
	printf("Length:%d\n", dhcp->option3[1]);
	printf("Hardware type:Ethernrt(0x%02x)\n", dhcp->option3[2]);
	printf("CLient MAC address:chonqin_8f:27:5d(%2x:%2x:%2x:%2x:%2x:%2x)\n", dhcp->option3[3], dhcp->option3[4], dhcp->option3[5], dhcp->option3[6], dhcp->option3[7], dhcp->option3[8]);
	printf("Option:(%d)\n", dhcp->option4);
	printf("\n");

	unsigned short buffer[] = {		0x6402,0xdfc4,0x6402,0xfffe,0x0011,0x0044,0x0043,0x0134,0x0101,0x0600,
									0xbc05,0x9194,0x6402,0xdfc4,0x1cbf,0xc08f,0x275d,0x6382,0x5363,0x3501,
									0x0736,0x0464,0x02ff,0xfe3d,0x0701,0x1cbf,0xc08f,0x275d,0xff00,0x0134	};	//pcap报文直接抓取非零数字,两次校验和,一次0x0011
	int n = sizeof(buffer)/sizeof(buffer[0]);
	unsigned short re_checksum = 0;
	re_checksum = checksum(buffer, n);
	printf("%x\n", re_checksum);
	if (re_checksum == 0xb4bc)
	{
		printf("校验和正确!\n");
	}
	else
	{
		printf("校验和不正确!\n");
	}

	return 0;
}
  • 5
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
在使用Scapy读取pcap文件时,有两种常见的方法。第一种方法是使用`rdpcap`函数一次性将整个pcap文件读入内存。例如,使用以下代码可以将pcap文件test.pcap读取到内存中并将其保存在一个名为`pkts`的变量中: ``` from scapy.all import * pkts = rdpcap('test.pcap') ``` 在这种方法中,`pkts`变量是一个包含了所有数据包的列表。你可以通过访问列表的索引来获取特定的包,例如`pkts[n`表示获取第n个包。 另一种方法是使用`PcapReader`类逐行读取pcap文件。每次调用`read_packet()`方法都会读取下一个新的包到内存中。例如,以下代码演示了如何使用逐行读取方法: ``` from scapy.all import * pr = PcapReader('test.pcap') pkt = pr.read_packet() ``` 这样,变量`pkt`将保存读取到的包。 总之,使用Scapy读取pcap文件的两种方法分别是一次性读入内存和逐行读取。你可以根据自己的需求选择适合的方法来读取pcap文件中的数据。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [[Python][Scapy]使用Scapy解析pcap格式数据](https://blog.csdn.net/friend_c/article/details/89214739)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [【scapy】读取pcap](https://blog.csdn.net/weixin_34121304/article/details/85976723)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值