使用libpcap对抓到的数据报进行拆分
安装:sudo apt-get install libpcap-dev
1、打开网络设备
获取可用的网络设备名指针
char *pcap_lookupdev(char *errbuf)
打开一个用于捕获数据的网络接口
pcap_t *pcap_open_live(const char *device,
int snaplen,
int promise,
int to_ms,
char *ebuf)
捕获一个网络数据
const u_char *pcap_next(pcap_t *p, struct pcap_pkthdr *h)
2、设置过滤规则
1)先编译过滤规则
int pcap_compile(pcap_t *p,
struct bpf_program *program,
char *buf,
int optimize,
bpf_u_int32 mask) 2)
设置过滤规则
int pcap_setfilter(pcap *p, struct bpf_program *fp)
3、捕获数据 【重要】
4、关闭网络设备
void pcap_close(pcap_t *p)
代码示例:
#include <pcap/pcap.h>
#include <stdio.h>
#include <stdint.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char const *argv[])
{
char error[128]="";
char *device_name = pcap_lookupdev(error); // 自动查询网卡设备
if(device_name == NULL){
printf("error: %s\n", error);
return -1;
}
uint32_t ip, netmask; // 网络ID和子网掩码
int n = pcap_lookupnet(device_name,&ip, &netmask,error);
if(n == -1){
printf("error: %s\n", error);
return -1;
}
uint8_t ip_[INET_ADDRSTRLEN] = "";
inet_ntop(AF_INET, &ip, ip_, INET_ADDRSTRLEN);
printf("网卡名: %s, %s\n", device_name, ip_);
// 打开网络接口 (混杂模式、打开网络接口可以等待 1s ,可以接收最大1518的数据报)
pcap_t *cap = pcap_open_live(device_name, 1518, 0, 0, error);
if(cap == NULL){
printf("error: %s\n", error);
return -1;
}
// 获取数据报
while(1){
struct pcap_pkthdr hdr; // 抓包的时间, 数据长度,实际数据长度(报文长度)
const u_char *data = pcap_next(cap, &hdr);
// 从data中获取源/目标ip和源/目标端口号
// data: 14 mac报文
uint16_t type = ntohs( *((uint16_t *)(data + 12))) ; // 获取mac报文的type
if(type == 0x0800){ // 是IP报文
uint32_t sip = *((uint32_t *)(data+26));
uint32_t dip = *((uint32_t *)(data+30));
uint8_t protocal = *(data+23); // 14+8+1
uint8_t srcip[16]= "", dstip[16]="";
inet_ntop(AF_INET, &sip, srcip, 16);
inet_ntop(AF_INET, &dip, dstip, 16);
if(protocal == 17){
const uint8_t *udp_data = data+14+20+8;
if(strncmp(udp_data, "hi",2) == 0)
printf("%s -> %s protocol(%d): %s\n", srcip, dstip, protocal, data+14+20+8);
else if(strncmp(udp_data, "bye",3) == 0) break;
}
}
}
pcap_close(cap); // 关闭网络接口
return 0;
}
代码示例 2:
#include <pcap/pcap.h>
#include <stdio.h>
#include <stdint.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
// 获取数据的回调函数
void capdata_callback(u_char *usrarg, const struct pcap_pkthdr *hdr, const u_char *data){
if(hdr->caplen <= 0 || data == NULL) return;
printf("datalen : %d ", hdr->caplen);
// 获取mac报文中的类型
uint16_t type = ntohs(*( (uint16_t *)(data+12) ));
printf("\ntype : %x", type);
if(type == 0x0800){ // IP 报文
// 获取IP报文的协议类型
uint8_t protocol = *(data+14+9);
printf("\nprotocl : %d\n", protocol);
if(protocol == 17){
// 获取UDP的端口号
uint16_t srcport = ntohs( *(uint16_t *)(data+14+20) );
uint16_t dstport = ntohs( *(uint16_t *)(data+14+20+2) );
const uint8_t *udp_data = data+14+20+8;
printf("udp %d -> %d: %s\n", srcport, dstport, udp_data);
}
}
}
int main(int argc, char const *argv[])
{
char error[128]="";
char *device_name = pcap_lookupdev(error); // 自动查询网卡设备
if(device_name == NULL){
printf("error: %s\n", error);
return -1;
}
// 打开网络接口 (非混杂模式、打开网络接口可以不等待 ,可以接收最大1518的数据报)
pcap_t *cap = pcap_open_live(device_name, 1518, 0, 0, error);
if(cap == NULL){
printf("error: %s\n", error);
return -1;
}
// 获取网络掩码
bpf_u_int32 netmask, netip;
pcap_lookupnet(device_name, &netip, &netmask, NULL);
// 设置过滤条件
struct bpf_program program; // bpf的规则程序
if(pcap_compile(cap, &program, "host 10.35.184.190 and src port 8000", 0, netmask) != 0){
perror("pcap_compile");
return -1;
}
pcap_setfilter(cap, &program); // 设置bpf过滤规则程序
// 获取数据报
int n = pcap_loop(cap, 10, capdata_callback, NULL); // 内部循环获取数据,并调用回调函数将数据传入
printf("pcap_loop ->%d \n", n);
pcap_close(cap); // 关闭网络接口
return 0;
}