299 lines
8.9 KiB
C
299 lines
8.9 KiB
C
#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;
|
||
}
|