在项目二中,我们完成了对局域网中数据包的抓取以及对数据包头部信息的解析,接下来我们要从Wireshark已经抓取并保存好的pcapng文件中解析数据包,提取各层的含义,在本例中,我的pcapng文件包含以太网帧、PPPoE头部、PPP头部、IP头部、UDP头部以及RIP头部,最后提取数据可以还原成TS流文件,是一个电视剧片段。
这次我们的任务就是从pcapng文件中抓获一个数据包,然后把它的头部信息解析出来。
之前我们一直在用pcap_opne_live()函数来打开设备,现在我们不需要打开网卡设备去抓取实时的在线数据包了,而是从文件中读取数据包,所以我们使用pcap_open_offline()函数,来打开离线文件,从离线文件中抓取数据包并解析。
函数用法(传送门):https://blog.csdn.net/zjl_1026_2001/article/details/2202436
使用Wireshark观察一下离线文件
数据包中的内容就是我上面分析的内容,我们来看一下PPPoE和PPP协议的PDU头部:
这里我们自定义一个PPPoE的头文件:PPPoE.h
#include <linux/ip.h>
struct PPPoEhdr {
__u8 version:4,
type:4;
__u8 code;
__be16 session_id;
__be16 length;
};
接下来是分析并输出的代码,代码中有较为详细的注释,希望对大家有所帮助。
#include <stdio.h>
#include <stdlib.h>
#include <pcap.h>
#include <time.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/if_ether.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include "PPPoE.h"
//输出以太网帧头部信息
void print_ether_header_info(struct ether_header *eptr){
int i;
u_char *ptr;
printf("Enthernet II:\n");
ptr = eptr->ether_dhost;//目的MAC地址
i = ETHER_ADDR_LEN;
printf("Destination MAC addres: ");
do{
printf ("%s%02x", (i == ETHER_ADDR_LEN)?"":":", *ptr++);
}while(--i>0);
printf ("\n");
ptr = eptr->ether_shost;//源MAC地址
i = ETHER_ADDR_LEN;
printf("Sourse MAC address: ");
do{
printf ("%s%02x", (i == ETHER_ADDR_LEN)?"":":", *ptr++);
}while(--i>0);
printf("\n");
printf("Enthernet type: %#04x ",ntohs(eptr->ether_type));//负载类型
switch(ntohs(eptr->ether_type)){
case ETHERTYPE_IP:
printf("(IPv4)\n");
break;
case ETHERTYPE_ARP:
printf("(ARP)\n");
break;
case ETHERTYPE_REVARP:
printf("(RARP)\n");
break;
case 0X8864:
printf("(PPPoE)\n");
break;
default:
printf("(Other)\n");
break;
}
}
//输出PPPoE头部信息
void print_PPPoE_header_info(struct PPPoEhdr *PPPoEptr){
char *c;
c = (char *)(PPPoEptr);
printf("\nPPP-over-Ethernet Session:\n");
printf("Version: %d\n",PPPoEptr->version);//版本
printf("Type: %d\n",PPPoEptr->type);//类型
printf("Code: Session data(0x%#04x)\n",PPPoEptr