Files
NE_YuR/network/start/lib/xnet/pcap_device.c
2025-11-19 09:02:51 +08:00

299 lines
8.9 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <memory.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include "pcap_device.h"
#include <netinet/in.h>
#include <arpa/inet.h>
#define PCAP_MAC_ADDR_LEN 6
static int mac_is_zero(const uint8_t* mac_addr) {
if (mac_addr == NULL) {
return 1;
}
for (int i = 0; i < PCAP_MAC_ADDR_LEN; i++) {
if (mac_addr[i]) {
return 0;
}
}
return 1;
}
static int read_interface_mac(const char* if_name, uint8_t* mac_addr) {
if ((if_name == NULL) || (mac_addr == NULL)) {
return -1;
}
int fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0) {
return -1;
}
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, if_name, IFNAMSIZ - 1);
if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
close(fd);
return -1;
}
memcpy(mac_addr, (uint8_t*)ifr.ifr_hwaddr.sa_data, PCAP_MAC_ADDR_LEN);
close(fd);
return 0;
}
static int load_pcap_lib() {
return 0;
}
/**
* 找到指定IP地址的网卡名
* @param ip 物理网卡或者由虚拟软件生成的虚拟刚卡, 字符串形式,如"192.168.1.1"
* @param name_buf 找到的对应网卡名称
*/
static int pcap_find_device(const char* ip, char* name_buf) {
char err_buf[PCAP_ERRBUF_SIZE];
pcap_if_t* pcap_if_list = NULL;
struct in_addr dest_ip;
pcap_if_t* item;
inet_pton(AF_INET, ip, &dest_ip);
int err = pcap_findalldevs(&pcap_if_list, err_buf);
if (err < 0) {
pcap_freealldevs(pcap_if_list);
return -1;
}
for (item = pcap_if_list; item != NULL; item = item->next) {
if (item->addresses == NULL) {
continue;
}
for (struct pcap_addr* pcap_addr = item->addresses; pcap_addr != NULL; pcap_addr = pcap_addr->next) {
struct sockaddr_in* curr_addr;
struct sockaddr* sock_addr = pcap_addr->addr;
if (sock_addr->sa_family != AF_INET) {
continue;
}
curr_addr = ((struct sockaddr_in*)sock_addr);
if (curr_addr->sin_addr.s_addr == dest_ip.s_addr) {
strcpy(name_buf, item->name);
pcap_freealldevs(pcap_if_list);
return 0;
}
}
}
pcap_freealldevs(pcap_if_list);
return -1;
}
/*
* 显示所有的网络接口列表
*/
static int pcap_show_list(void) {
char err_buf[PCAP_ERRBUF_SIZE];
pcap_if_t* pcapif_list = NULL;
int count = 0;
// 查找所有的网络接口
int err = pcap_findalldevs(&pcapif_list, err_buf);
if (err < 0) {
fprintf(stderr, "pcap_show_list: find all net list failed:%s\n", err_buf);
pcap_freealldevs(pcapif_list);
return -1;
}
printf("pcap_show_list: card list\n");
// 遍历所有的可用接口,输出其信息
for (pcap_if_t* item = pcapif_list; item != NULL; item = item->next) {
if (item->addresses == NULL) {
continue;
}
for (struct pcap_addr* pcap_addr = item->addresses; pcap_addr != NULL; pcap_addr = pcap_addr->next) {
char str[INET_ADDRSTRLEN];
struct sockaddr_in* ip_addr;
struct sockaddr* sockaddr = pcap_addr->addr;
if (sockaddr->sa_family != AF_INET) {
continue;
}
ip_addr = (struct sockaddr_in*)sockaddr;
printf("card %d: IP:%s name: %s, \n\n",
count++,
item->description == NULL ? "" : item->description,
inet_ntop(AF_INET, &ip_addr->sin_addr, str, sizeof(str))
);
break;
}
}
pcap_freealldevs(pcapif_list);
if ((pcapif_list == NULL) || (count == 0)) {
fprintf(stderr, "pcap_show_list: no available card!\n");
return -1;
}
return 0;
}
/**
* 打开pcap设备接口
* @param ip 打开网卡的指定ip
* @param 给网卡设置mac
*/
pcap_t* pcap_device_open(const char* ip, uint8_t * mac_addr, uint8_t poll_mode) {
char err_buf[PCAP_ERRBUF_SIZE];
struct bpf_program fp;
bpf_u_int32 mask;
bpf_u_int32 net;
char filter_exp[256];
char name_buf[256];
pcap_t* pcap;
if (load_pcap_lib() < 0) {
fprintf(stderr, "pcap_open: load pcap dll failed! install it first\n");
return (pcap_t*)0;
}
if (pcap_find_device(ip, name_buf) < 0) {
fprintf(stderr, "pcap_open: no net card has ip: %s, use the following:\n", ip);
pcap_show_list();
return (pcap_t*)0;
}
if (mac_addr == NULL) {
fprintf(stderr, "pcap_open: mac address buffer is null\n");
return (pcap_t*)0;
}
if (mac_is_zero(mac_addr)) {
if (read_interface_mac(name_buf, mac_addr) < 0) {
fprintf(stderr, "pcap_open: failed to query mac address of %s, please configure it manually.\n", name_buf);
return (pcap_t*)0;
}
printf("pcap_open: detected mac %02x:%02x:%02x:%02x:%02x:%02x on %s\n",
mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5],
name_buf);
fflush(stdout);
} else {
if (read_interface_mac(name_buf, mac_addr) < 0) {
printf("pcap_open: failed to query mac, using configured value %02x:%02x:%02x:%02x:%02x:%02x\n",
mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
fflush(stdout);
} else {
printf("pcap_open: overriding configured mac with detected value %02x:%02x:%02x:%02x:%02x:%02x\n",
mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
fflush(stdout);
}
}
if (pcap_lookupnet(name_buf, &net, &mask, err_buf) == -1) {
printf("pcap_open: can't find use net card: %s\n", name_buf);
net = 0;
mask = 0;
}
pcap = pcap_open_live(name_buf, // 设置字符串
65536, // 要捕获的最大字节数
1, // 混杂模式
1, // 读取超时(以毫秒为单位)
err_buf);
if (pcap == NULL) {
fprintf(stderr, "pcap_open: create pcap failed %s\n net card name: %s\n", err_buf, name_buf);
fprintf(stderr, "Use the following:\n");
pcap_show_list();
return (pcap_t*)0;
}
// 非阻塞模式读取,程序中使用查询的方式读
if (pcap_setnonblock(pcap, 1, err_buf) != 0) {
fprintf(stderr, "pcap_open: set none block failed: %s\n", pcap_geterr(pcap));
return (pcap_t*)0;
}
// 只捕获输入,不要捕获自己发出去的
// 注win平台似乎不支持这个选项
if (pcap_setdirection(pcap, PCAP_D_IN) != 0) {
// fprintf(stderr, "pcap_open: set direction not suppor: %s\n", pcap_geterr(pcap));
}
// 只捕获发往本接口与广播的数据帧。相当于只处理发往这张网卡的包
sprintf(filter_exp,
"(ether dst %02x:%02x:%02x:%02x:%02x:%02x or ether broadcast) and (not ether src %02x:%02x:%02x:%02x:%02x:%02x)",
mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5],
mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
printf("pcap_open: BPF filter: %s\n", filter_exp);
fflush(stdout);
if (pcap_compile(pcap, &fp, filter_exp, 0, net) == -1) {
printf("pcap_open: couldn't parse filter %s: %s\n", filter_exp, pcap_geterr(pcap));
return (pcap_t*)0;
}
if (pcap_setfilter(pcap, &fp) == -1) {
printf("pcap_open: couldn't install filter %s: %s\n", filter_exp, pcap_geterr(pcap));
return (pcap_t*)0;
}
printf("pcap_open: Filter installed successfully\n");
fflush(stdout);
return pcap;
}
/**
* 关闭Pcapif接口
*/
void pcap_device_close(pcap_t* pcap) {
if (pcap == (pcap_t *)0) {
fprintf(stderr, "pcap = 0");
pcap_show_list();
return;
}
pcap_close(pcap);
}
/**
* 向网络接口发送数据包
*/
uint32_t pcap_device_send(pcap_t* pcap, const uint8_t* buffer, uint32_t length) {
if (pcap_sendpacket(pcap, buffer, length) == -1) {
fprintf(stderr, "pcap send: send packet failed!:%s\n", pcap_geterr(pcap));
fprintf(stderr, "pcap send: pcaket size %d\n", length);
return 0;
}
return 0;
}
/**
* 从网络接口读取数据包
*/
uint32_t pcap_device_read(pcap_t* pcap, uint8_t* buffer, uint32_t length) {
int err;
struct pcap_pkthdr* pkthdr;
const uint8_t* pkt_data;
err = pcap_next_ex(pcap, &pkthdr, &pkt_data);
if (err == 0) {
return 0;
} else if (err == 1) { // 1 - 成功读取数据包, 0 - 没有数据包,其它值-出错
memcpy(buffer, pkt_data, pkthdr->len);
return pkthdr->len;
}
fprintf(stderr, "pcap_read: reading packet failed!:%s", pcap_geterr(pcap));
return 0;
}