工程为名为:pcap_work
该示例可以在win10_x86、麒麟V10_arm_华为擎云9000L、麒麟V10_x86、麒麟V4_arm_飞腾2000上运行。
可以根据过滤器,抓取过滤arp、udp、tcp、icmp数据包。
由于系统限制,包最大每次抓包最大长度为1518字节,建议自定义的基于udp的通信协议包不要超过1450字节,这样的话,通过udp传输数据,就不会分片,可以用libpcap直接抓包,不用后期组包处理数据。
libpcap个人认为主要用于udp高密度数据传输,可以做到零丢包。
pcap_work.pro文件内容如下:
TEMPLATE = app
CONFIG += console
CONFIG -= app_bundle
CONFIG -= qt
# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
packetAnalyze.c \
callback.c
HEADERS += \
callback.h \
head.h
contains(QT_ARCH,arm64){
message("compile linux arm 64-bit")
#引入并行编程模块
QMAKE_CXXFLAGS += -fopenmp
LIBS += -fopenmp
CONFIG(release, debug|release){
LIBS += -L$$PWD/lib/linux/arm -lZLToolKit
} else {
LIBS += -L$$PWD/lib/linux/arm -lZLToolKitd
}
# QMAKE_LFLAGS += "-Wl,-rpath,\'\$$ORIGIN\':\'\$$ORIGIN/lib\'"
QMAKE_LFLAGS += "-Wl,-rpath,\'\$$ORIGIN\':\'\$$ORIGIN/lib/\':\'\$$ORIGIN/lib/linux/arm/\':\'/usr/local/lib/\'"
# QMAKE_LFLAGS += "-Wl,-rpath=/usr/lib -symbolic"
LIBS += -L$$PWD/lib/linux/arm/ -lpcap
INCLUDEPATH += $$PWD/include/pcap_linux_include
DEPENDPATH += $$PWD/include/pcap_linux_include
PRE_TARGETDEPS += $$PWD/lib/linux/arm/libpcap.a
}
contains(QT_ARCH,x86_64)
{
win32: {#判断是否windows,msvc 静态连接zltoolkit
message("compile win x86 64-bit")
#引入并行编程模块
QMAKE_CXXFLAGS+= -openmp
CONFIG(release, debug|release){
LIBS += -L$$PWD/lib/windows -lZLToolKit
} else {
LIBS += -L$$PWD/lib/windows -lZLToolKitd
}
QMAKE_LFLAGS += "-Wl,-rpath,\'\$$ORIGIN\':\'\$$ORIGIN/lib/\':\'\$$ORIGIN/lib/windows/\'"
#pcap捕获网卡数据
INCLUDEPATH += $$PWD/include/pcap_windows_include
DEPENDPATH += $$PWD/include/pcap_windows_include
LIBS += -L$$PWD/lib/windows/pcap/x64 -lPacket
LIBS += -L$$PWD/lib/windows/pcap/x64 -lwpcap
}
unix: {
message("compile linux x86 64-bit")
#引入并行编程模块
QMAKE_CXXFLAGS += -fopenmp
LIBS += -fopenmp
CONFIG(release, debug|release){
LIBS += -L$$PWD/lib/linux/x86 -lZLToolKit
} else {
LIBS += -L$$PWD/lib/linux/x86 -lZLToolKit
PRE_TARGETDEPS += $$PWD/lib/linux/x86/libZLToolKit.a
}
# QMAKE_LFLAGS += "-Wl,-rpath,\'\$$ORIGIN\':\'\$$ORIGIN/lib\'"
QMAKE_LFLAGS += "-Wl,-rpath,\'\$$ORIGIN\':\'\$$ORIGIN/lib/\':\'\$$ORIGIN/lib/linux/x86/\':\'/usr/local/lib/\'"
# QMAKE_LFLAGS += "-Wl,-rpath=/usr/lib -symbolic"
LIBS += -L$$PWD/lib/linux/x86/ -lpcap
INCLUDEPATH += $$PWD/include/pcap_linux_include
DEPENDPATH += $$PWD/include/pcap_linux_include
PRE_TARGETDEPS += $$PWD/lib/linux/x86/libpcap.a
}
}
下面是 头文件 head.h
/******************************************************************************
文 件 名 : head.h
版 本 号 : V1.1
负 责 人 : yz
生成日期 : 2023年9月27日
最近修改 :
文件描述 : 报文头部结构体
函数列表 :
修改历史 :
1.日 期 : 2023年9月27日
作 者 : yz
修改内容 : 创建文件
******************************************************************************/
#ifndef _HEAD_H_
#define _HEAD_H_
#include<sys/types.h>
//#include<netinet/in.h>
typedef unsigned char u_char;
typedef unsigned short u_short;
typedef unsigned int u_int;
typedef unsigned short uint16_t;
/*最大抓包长度 :Ethernet 1500字节 + 以太网帧头部14字节 + 以太网帧尾部4字节*/
#define SNAP_LEN 1518
/*ethernet head are exactly 14 bytes*/
#define ETHERNET_HEAD_SIZE 14
/*ip头部字节数宏 取hlv低四位即头部长度*单位4bytes 然后强转为ip结构体*/
//#define IP_HEAD_SIZE(ipheader) ((ipheader->ip_hlv & 0x0f) * 4)
#define IP_HEAD_SIZE(packet) ((((struct ip *)(packet + ETHERNET_HEAD_SIZE))->ip_hlv & 0x0f) * 4)
/*ethernet address are 6 bytes*/
#define ETHERNET_ADDR_LEN 6
/*ip address are 4 bytes*/
#define IP_ADDR_LEN 4
#define ARP_REQUEST 1
#define ARP_REPLY 2
/*TCP flag*/
#define TCP_FIN 0x01
#define TCP_SYN 0x02
#define TCP_RST 0x04
#define TCP_PUSH 0x08
#define TCP_ACK 0x10
#define TCP_URG 0x20
#define TCP_ECE 0x40
#define TCP_CWR 0x80
/*Ethernet HEADER*/
struct ethernet
{
u_char ether_dhost[ETHERNET_ADDR_LEN];
u_char ether_shost[ETHERNET_ADDR_LEN];
u_short ether_type; //IP?ARP?etc
};
/*IP HEADER*/
struct ip
{
//unsigned int ip_version:4;
//unsigned int ip_hlen:4;
u_char ip_hlv; /*version + headlength 如果分开定义会有大小端问题,会增加额外的判断*/
u_char ip_tos;
u_short ip_len;
u_short ip_id;
u_short ip_off;
u_char ip_ttl;
u_char ip_protocol;
u_short ip_sum;
u_char ip_src[IP_ADDR_LEN];
u_char ip_dst[IP_ADDR_LEN];
};
/*TCP HEADER*/
struct tcp
{
u_short tcp_sport;
u_short tcp_dport;
u_int tcp_seqe;
u_int tcp_ack;
//u_char tcp_off:4;
//u_char tcp_unused:4; //保留位
u_char tcp_hre; //header(4bits) + reserved(4bits)
u_char tcp_flag;
u_short tcp_win;
u_short tcp_sum;
u_short tcp_urp;
};
/*UDP HEADER*/
struct udp
{
u_short udp_sport;
u_short udp_dport;
u_short udp_len;
u_short udp_sum;
};
/*ARP HEADER 8+6+4+6+4*/
struct arp
{
u_short arp_hrd; //hardware
u_short arp_pro; //protocol
u_char arp_hdlen; //hardware address length
u_char arp_prolen; //protocol length
u_short arp_op; //arp operations
u_char arp_shost[ETHERNET_ADDR_LEN];
u_char arp_sip[IP_ADDR_LEN];
u_char arp_dhost[ETHERNET_ADDR_LEN];
u_char arp_dip[IP_ADDR_LEN];
};
/*ICMP HEADER*/
struct icmp
{
u_char icmp_type;
u_char icmp_code;
u_short icmp_sum;
u_short icmp_id;
u_short icmp_seq;
u_int icmp_time;
};
/*PPPOE HEADER*/
struct pppoe
{
u_char pppoe_vtype; //version(0x1) + type(0x1)
u_char pppoe_code;
u_short pppoe_s_id;
u_short pppoe_len;
};
#endif
下面是 头文件 callback.h
#ifndef _CALLBACK_H_
#define _CALLBACK_H_
#include<sys/types.h>
//#include<netinet/in.h>
#include<string.h>
#include<pcap.h>
//#include <winsock.h>
//#pragma comment (lib, "ws2_32.lib")
extern char filter_exp[128];
extern char *dev;
void pppoe_callback(u_char *arg, const struct pcap_pkthdr *pcap_pkt,const u_char *packet);
void ethernet_callback(u_char *arg, const struct pcap_pkthdr *pcap_pkt,const u_char *packet);
void ip_callback(u_char *arg, const struct pcap_pkthdr *pcap_pkt,const u_char *packet);
char *tcp_flag(const u_char tcp_flags);
void pppoe_callback(u_char *arg, const struct pcap_pkthdr *pcap_pkt,const u_char *packet);
void icmp_callback(u_char *arg, const struct pcap_pkthdr *pcap_pkt,const u_char *packet);
void tcp_callback(u_char *arg, const struct pcap_pkthdr *pcap_pkt,const u_char *packet);
void arp_callback(u_char *arg, const struct pcap_pkthdr *pcap_pkt,const u_char *packet);
void udp_callback(u_char *arg, const struct pcap_pkthdr *pcap_pkt,const u_char *packet);
#endif
下面是 头文件 callback.c
/******************************************************************************
文 件 名 : callback.c
版 本 号 : V1.1
负 责 人 : Sophisticated
生成日期 : 2023年9月28日
最近修改 :
文件描述 : 解析数据包的回调函数
函数列表 :
arp_callback
ethernet_callback
icmp_callback
ip_callback
pppoe_callback
tcp_callback
tcp_flag
udp_callback
修改历史 :
1.日 期 : 2023年9月28日
作 者 : yz
修改内容 : 创建文件
******************************************************************************/
#include<stdio.h>
#include<time.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<string.h>
#include<pcap.h>
#include"head.h"
#include"callback.h"
/*过滤条件*/
char filter_exp[128] = "port 8041 || port 8042";
/*抓包设备名称*/
char *dev=NULL;
/*****************************************************************************
函 数 名 : ethernet_callback
功能描述 : 以太网数据包头分析
输入参数 : u_char *arg
const struct pcap_pkthdr *pcap_pkt
const u_char *packet
输出参数 : 无
返 回 值 :
调用函数 :
被调函数 :
修改历史 :
1.日 期 : 2023年9月28日
作 者 : yz
审 核 人 : #
修改内容 : 新生成函数
*****************************************************************************/
void ethernet_callback(u_char *arg, const struct pcap_pkthdr *pcap_pkt,const u_char *packet)
{
struct ethernet *ethheader;
struct ip *ipptr;
u_short protocol;
u_int *id = (u_int *)arg;
u_char *time = ctime((const time_t*)&pcap_pkt->ts.tv_sec);
printf("---------------Device : %s--------------\n",dev);
printf("---------------Filter: %s---------------\n",filter_exp);
printf("-----------------Analyze Info---------------\n");
printf("Id: %d\n",++(*id));
printf("Packet length: %d\n",pcap_pkt->len);
printf("Number of bytes: %d\n",pcap_pkt->caplen);
printf("Receive time: %s\n",time);
int k;
for (k = 0; k < pcap_pkt->len; k++)
{
/*表示以16进制的格式输出整数类型的数值,
输出域宽为2,右对齐,不足的用字符0替代*/
printf(" %02x",packet[k]);
if ((k + 1) % 16 == 0)
{
printf("\n");
}
}
printf("\n\n");
ethheader = (struct ethernet*)packet;
printf("---------------Data Link Layer-----------\n");
printf("Mac Src Address: ");
int i;
for (i = 0; i < ETHERNET_ADDR_LEN; i++)
{
if (ETHERNET_ADDR_LEN - 1 == i)
{
printf("%02x\n",ethheader->ether_shost[i]);
}
else
{
printf("%02x:",ethheader->ether_shost[i]);
}
}
printf("Mac Dst Address: ");
int j;
for (j = 0; j < ETHERNET_ADDR_LEN; j++)
{
if (ETHERNET_ADDR_LEN - 1 == j)
{
printf("%02x\n",ethheader->ether_dhost[j]);
}
else
{
printf("%02x:",ethheader->ether_dhost[j]);
}
}
protocol = ntohs(ethheader->ether_type);
/*对pppoe报文的处理*/
if (0x8863 == protocol)
{
printf("PPPOE Discovery");
pppoe_callback(arg, pcap_pkt, packet);
}
if (0x8864 == protocol)
{
printf("PPPOE Session");
pppoe_callback(arg, pcap_pkt, packet);
}
printf("----------------Network Layer-------------\n");
switch (protocol)
{
case 0x0800:
printf("IPv4 protocol!\n");
ip_callback(arg, pcap_pkt, packet);
break;
case 0x0806:
printf("ARP protocol!\n");
arp_callback(arg, pcap_pkt, packet);
break;
case 0x8035:
printf("RARP protocol!\n");
break;
case 0x86DD:
printf("IPv6 protocol!\n");
break;
case 0x880B:
printf("PPP protocol!\n");
printf("There is no function to process PPP packet!!!");
break;
default:
printf("Other Network Layer protocol is used!\n");
break;
}
printf("---------------------Done--------------------\n\n\n");
}
/*****************************************************************************
函 数 名 : pppoe_callback
功能描述 : pppoe数据包处理函数
输入参数 : u_char *arg
const struct pcap_pkthdr *pcap_pkt
const u_char *packet
输出参数 : 无
返 回 值 :
调用函数 :
被调函数 :
修改历史 :
1.日 期 : 2023年10月8日
作 者 : yz
审 核 人 : #
修改内容 : 新生成函数
*****************************************************************************/
void pppoe_callback(u_char *arg, const struct pcap_pkthdr *pcap_pkt,const u_char *packet)
{
struct pppoe *pppoeheader = (struct pppoe *)(packet + ETHERNET_HEAD_SIZE);
printf("Version: %d\n",(pppoeheader->pppoe_vtype & 0xf0) >> 4);
printf("Type: %d\n",pppoeheader->pppoe_vtype & 0x0f);
printf("Code: %d\n",pppoeheader->pppoe_code);
printf("Session ID: %d\n",ntohs(pppoeheader->pppoe_s_id));
printf("Payload Length: %d\n",ntohs(pppoeheader->pppoe_len));
}
/*****************************************************************************
函 数 名 : ip_callback
功能描述 : ip数据包分析
输入参数 : u_char *arg
const struct pcap_pkthdr *pcap_pkt
const u_char *packet
输出参数 : 无
返 回 值 :
调用函数 :
被调函数 :
修改历史 :
1.日 期 : 2023年9月29日
作 者 : yz
审 核 人 : #
修改内容 : 新生成函数
*****************************************************************************/
void ip_callback(u_char *arg, const struct pcap_pkthdr *pcap_pkt,const u_char *packet)
{
u_char protocol;
struct ip *ipheader;
ipheader = (struct ip *)(packet + ETHERNET_HEAD_SIZE);
printf("Version: %d\n", (ipheader->ip_hlv & 0xf0) >> 4); //取hlv高4位
printf("Header Length: %d\n",ipheader->ip_hlv & 0x0f); //取hlv低4位
printf("Type of Service: %x\n",ipheader->ip_tos);
printf("Total Length: %d\n",ntohs(ipheader->ip_len));
printf("Indentification: %x\n",ntohs(ipheader->ip_id));
printf("Offset: %d\n",ntohs(ipheader->ip_off));
printf("TTL: %d\n",ipheader->ip_ttl);
printf("Protocol: %d\n",ipheader->ip_protocol);
printf("CheckSum: %d\n",ntohs(ipheader->ip_sum));
int i = 0;
printf("IP Src Address: ");
for (i = 0; i < IP_ADDR_LEN; i++)
{
printf("%d.",ipheader->ip_src[i]);
}
printf("\nIP Dst Address: ");
for (i = 0; i < IP_ADDR_LEN; i++)
{
printf("%d.",ipheader->ip_dst[i]);
}
printf("\n");
protocol = ipheader->ip_protocol;
if (0x01 == protocol)
{
printf("ICMP Protocol!\n");
icmp_callback(arg, pcap_pkt, packet);
}
printf("----------------Transport Layer--------------\n");
switch (protocol)
{
case 0x06:
printf("TCP Protocol!\n");
tcp_callback(arg, pcap_pkt, packet);
break;
case 0x11:
printf("UDP Protocol!\n");
udp_callback(arg, pcap_pkt, packet);
break;
case 0x02:
printf("IGMP Protocol!\n");
printf("There is no function to process IGMP packet!!!");
break;
default:
printf("Other Transport Layer protocol is used!\n");
break;
}
}
/*****************************************************************************
函 数 名 : tcp_callback
功能描述 : TCP数据包分析
输入参数 : u_char *arg
const struct pcap_pkthdr *pcap_pkt
const u_char *packet
输出参数 : 无
返 回 值 :
调用函数 :
被调函数 :
修改历史 :
1.日 期 : 2023年9月28日
作 者 : yz
审 核 人 : #
修改内容 : 新生成函数
*****************************************************************************/
void tcp_callback(u_char *arg, const struct pcap_pkthdr *pcap_pkt,const u_char *packet)
{
struct tcp *tcpheader = (struct tcp *)(packet + ETHERNET_HEAD_SIZE + IP_HEAD_SIZE(packet));
printf("Src Port: %d\n",ntohs(tcpheader->tcp_sport));
printf("Dst Port: %d\n",ntohs(tcpheader->tcp_dport));
printf("Squence Number: %d\n",ntohs(tcpheader->tcp_seqe));
printf("ACK Number: %d\n",ntohs(tcpheader->tcp_ack));
printf("Header Length: %d\n",(tcpheader->tcp_hre & 0xf0) >> 4);
printf("FLAG: %d\n",tcpheader->tcp_flag);
printf("Flag: %s\n",tcp_flag(tcpheader->tcp_flag));
printf("Window Size: %d\n",ntohs(tcpheader->tcp_win));
printf("Checksum: %d\n",ntohs(tcpheader->tcp_sum));
printf("Urgent Pointer: %d\n",ntohs(tcpheader->tcp_urp));
}
/*****************************************************************************
函 数 名 : tcpflag
功能描述 : 判断TCP协议的标志位
输入参数 : const u_char tcp_flags
输出参数 : 无
返 回 值 : u_char
调用函数 :
被调函数 :
修改历史 :
1.日 期 : 2023年9月29日
作 者 : yz
审 核 人 : #
修改内容 : 新生成函数
*****************************************************************************/
char *tcp_flag(const u_char tcp_flags)
{
char flags[100] = "-";
if ((TCP_CWR & tcp_flags) == TCP_CWR)
{
strncat(flags, "CWR ", 100);
}
if ((TCP_ECE & tcp_flags) == TCP_ECE)
{
strncat(flags, "ECE ", 100);
}
if ((TCP_URG & tcp_flags) == TCP_URG)
{
strncat(flags, "URG ", 100);
}
if ((TCP_ACK & tcp_flags) == TCP_ACK)
{
strncat(flags, "ACK ", 100);
}
if ((TCP_PUSH & tcp_flags) == TCP_PUSH)
{
strncat(flags, "PUSH ", 100);
}
if ((TCP_RST & tcp_flags) == TCP_RST)
{
strncat(flags, "RST ", 100);
}
if ((TCP_SYN & tcp_flags) == TCP_SYN)
{
strncat(flags, "SYN ", 100);
}
if ((TCP_FIN & tcp_flags) == TCP_FIN)
{
strncat(flags, "FIN ", 100);
}
return flags;
}
/*****************************************************************************
函 数 名 : icmp_callback
功能描述 : ICMP数据包分析
输入参数 : u_char *arg
const struct pcap_pkthdr *pcap_pkt
const u_char *packet
输出参数 : 无
返 回 值 :
调用函数 :
被调函数 :
修改历史 :
1.日 期 : 2023年9月29日
作 者 : yz
审 核 人 : #
修改内容 : 新生成函数
*****************************************************************************/
void icmp_callback(u_char *arg, const struct pcap_pkthdr *pcap_pkt,const u_char *packet)
{
struct icmp *icmpheader = (struct icmp *)(packet + ETHERNET_HEAD_SIZE + IP_HEAD_SIZE(packet));
u_char icmp_type = icmpheader->icmp_type;
printf("ICMP Type: %d ",icmpheader->icmp_type);
switch (icmp_type)
{
case 0x08:
printf("(ICMP Request)\n");
break;
case 0x00:
printf("(ICMP Response)\n");
break;
case 0x11:
printf("(Timeout!!!)\n");
break;
}
printf("ICMP Code: %d\n",icmpheader->icmp_code);
printf("ICMP CheckSum: %d\n",icmpheader->icmp_sum);
}
/*****************************************************************************
函 数 名 : udp_callback
功能描述 : UDP数据包分析
输入参数 : u_char *arg
const struct pcap_pkthdr *pcap_pkt
const u_char *packet
输出参数 : 无
返 回 值 :
调用函数 :
被调函数 :
修改历史 :
1.日 期 : 2023年9月28日
作 者 : yz
审 核 人 : #
修改内容 : 新生成函数
*****************************************************************************/
void udp_callback(u_char *arg, const struct pcap_pkthdr *pcap_pkt,const u_char *packet)
{
struct udp *udpheader = (struct udp *)(packet + ETHERNET_HEAD_SIZE + IP_HEAD_SIZE(packet));
printf("Src Port: %d\n",ntohs(udpheader->udp_sport));
printf("Dst Port: %d\n",ntohs(udpheader->udp_dport));
printf("UDP Length: %d\n",ntohs(udpheader->udp_len));
printf("Checksum: %d\n",ntohs(udpheader->udp_sum));
}
/*****************************************************************************
函 数 名 : arp_callback
功能描述 : arp数据包分析
输入参数 : u_char *arg
const struct pcap_pkthdr *pcap_pkt
const u_char *packet
输出参数 : 无
返 回 值 :
调用函数 :
被调函数 :
修改历史 :
1.日 期 : 2023年9月28日
作 者 : Sophisticated
审 核 人 : #
修改内容 : 新生成函数
*****************************************************************************/
void arp_callback(u_char *arg, const struct pcap_pkthdr *pcap_pkt,const u_char *packet)
{
struct arp *arpheader;
arpheader = (struct arp *)(packet + ETHERNET_HEAD_SIZE);
printf("Hardware type: %s\n",(ntohs(arpheader->arp_hrd) == 0x0001) ? "Ethernet" : "Unknow");
printf("Protocol type: %s\n",(ntohs(arpheader->arp_pro) == 0x0800) ? "IPv4" : "Unknow");
printf("Operation: %s\n",(ntohs(arpheader->arp_op) == ARP_REQUEST) ? "ARP_Request" : "ARP_Reply");
int i = 0;
printf("Sender MAC:");
for (i = 0; i < ETHERNET_ADDR_LEN; i++)
{
printf("%02x:",arpheader->arp_shost[i]);
}
printf("\nSender IP:");
for (i = 0; i < IP_ADDR_LEN; i++)
{
printf("%d.",arpheader->arp_sip[i]);
}
printf("\nTarget Mac:");
for (i = 0; i < ETHERNET_ADDR_LEN; i++)
{
printf("%02x:",arpheader->arp_dhost[i]);
}
printf("\nTarget IP:");
for (i = 0; i < IP_ADDR_LEN; i++)
{
printf("%d.",arpheader->arp_dip[i]);
}
printf("\n\n");
}