PF_RING是支持BPF过滤器的,这个在PF_RING的UserGuide中也有相应的函数原型说明。
当编译创建配置的时候,也可以关闭BPF的支持。
./userland/lib/configure --disable-bpf
默认是支持开启BPF过滤器的,在./userland/lib/pfring_mod.c源码中,会有一个宏定义:
#ifdef ENABLE_BPF
#include
#endif
所以默认没有关闭BPF支持的情况下gcc编译时需要加入pcap的动态库。
PF_RING自己也有过滤器,确实功能功能比较少,习惯了pcap的过滤器书写,当然能使用它的过滤器是再好不过了。
代码中使用了PF_RING过滤器方式和BPF过滤器方式,用gcc编译时加"-D PRINT_ARG"则捕捉arp包,否则捕捉tcp包(其中排除了ssh和samba)
-
#define _GNU_SOURCE
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <pfring.h>
-
#include <string.h>
-
#include <errno.h>
-
#include <netinet/in.h>
-
#include <arpa/inet.h>
-
#include <linux/if_ether.h>
-
#include <linux/ip.h>
-
#include <linux/tcp.h>
-
#include <getopt.h>
-
-
#define SNAP_LEN 1518
-
#define MIN_LEN (sizeof(struct ethhdr) + sizeof(struct iphdr) \
-
+ sizeof(struct tcphdr))
-
-
#ifdef ARP_SWICTH
-
#define PRINT_ARG "arp"
-
#else
-
#define PRINT_ARG "tcp and not (dst port (22 or 445) or src port (22 or 445))"
-
#endif
-
-
static pfring *pd;
-
static char *in_dev = NULL;
-
static struct option opts[] = {
-
{.name = "interface", .has_arg = 1, .val = 'i'},
-
{.name = "help", .has_arg = 0, .val = 'h'},
-
{NULL}
-
};
-
-
static void printHelp(void) {
-
printf("-h Print this help\n");
-
printf("-i Device name. Use device\n");
-
exit(EXIT_FAILURE);
-
}
-
-
static int process_packet(const struct pfring_pkthdr *header,
-
const u_char *packet) {
-
struct ethhdr *ethh;
-
struct arphdr *arph;
-
struct iphdr *iph;
-
struct tcphdr *tcph;
-
struct in_addr src, dst;
-
-
/* 判断长度避免访问到空指针 */
-
if (header->caplen < MIN_LEN) return;
-
-
ethh = (struct ethhdr *)packet;
-
printf("Eth_type:");
-
switch(ntohs(ethh->h_proto)) {
-
case 0x0800:
-
printf("IP | ");
-
/* 打印IP协议的目的地址和源地址 */
-
packet += sizeof(struct ethhdr);
-
iph = (struct iphdr *)packet;
-
src.s_addr = iph->saddr;
-
dst.s_addr = iph->daddr;
-
printf("%s->", inet_ntoa(src));
-
printf("%s | ", inet_ntoa(dst));
-
-
switch (iph->protocol) {
-
case 6:
-
packet += sizeof(struct iphdr);
-
tcph = (struct tcphdr *)packet;
-
printf("Protocol:TCP sport:%d->", ntohs(tcph->source));
-
printf("dport:%d", ntohs(tcph->dest));
-
break;
-
case 1:
-
printf("Protocol:ICMP");
-
break;
-
}
-
break;
-
case 0x0806:
-
printf("ARP_request ");
-
struct in_addr *src_in_addr, *dst_in_addr;
-
struct macaddr {
-
u_char MAC[6];
-
};
-
struct macaddr *src_mac, *dst_mac;
-
-
packet += sizeof(struct ethhdr) + 8;
-
src_mac = (struct macaddr *)packet;
-
-
packet += 6;
-
src_in_addr = (struct in_addr *)packet;
-
printf("%s", inet_ntoa(*src_in_addr));
-
-
packet += 4;
-
dst_mac = (struct macaddr *)packet;
-
-
packet += 6;
-
dst_in_addr = (struct in_addr *)packet;
-
printf(" -> %s", inet_ntoa(*dst_in_addr));
-
-
printf(" %02x:%02x:%02x:%02x:%02x:%02x",
-
src_mac->MAC[0], src_mac->MAC[1], src_mac->MAC[2],
-
src_mac->MAC[3], src_mac->MAC[4], src_mac->MAC[5]
-
);
-
printf(" -> %02x:%02x:%02x:%02x:%02x:%02x",
-
dst_mac->MAC[0], dst_mac->MAC[1], dst_mac->MAC[2],
-
dst_mac->MAC[3], dst_mac->MAC[4], dst_mac->MAC[5]
-
);
-
break;
-
case 0x8035:
-
printf("ARP_response ");
-
break;
-
}
-
printf("\n");
-
}
-
-
int main(int argc, char *argv[]) {
-
char c;
-
while((c = getopt_long(argc, argv, "hi:", opts, NULL)) != -1) {
-
switch(c) {
-
case 'h':
-
printHelp();
-
break;
-
case 'i':
-
in_dev = strdup(optarg);
-
break;
-
}
-
}
-
-
if(in_dev == NULL) printHelp();
-
-
printf("Capturing from %s\n", in_dev);
-
-
/* 打开pf设备 */
-
pd = pfring_open(in_dev, SNAP_LEN, PF_RING_PROMISC);
-
if(pd == NULL) {
-
printf("pfring_open %s error [%s]\n", in_dev, strerror(errno));
-
exit(EXIT_FAILURE);
-
} else {
-
u_int32_t version;
-
/* 获取版本号 */
-
pfring_version(pd, &version);
-
printf("Using PF_RING v%u.%u.%u\n",
-
(version & 0xFFFF0000) >> 16,
-
(version & 0x0000FF00) >> 8,
-
version & 0x000000FF);
-
}
-
-
/*
-
设定捕获方向
-
rx_and_tx_direction 双向捕获
-
rx_only_direction 只捕获接收
-
tx_only_direction 只捕获发送
-
*/
-
if (pfring_set_direction(pd, rx_only_direction) != 0) {
-
printf("pfring_set_direction is failure error [%s]\n", strerror(errno));
-
exit(EXIT_FAILURE);
-
}
-
-
#if 0 /* PF_RING过滤器 */
-
int rc;
-
filtering_rule rule;
-
memset(&rule, 0, sizeof(rule));
-
rule.rule_id = 1; /* 设置规则运行优先级,数值越小优先级越高 */
-
/* 匹配哪些情况 */
-
rule.rule_action = forward_packet_and_stop_rule_evaluation;
-
// rule.core_fields.proto = 6 /* 设置需要过滤的传输层协议 6 TCP*/;
-
rule.core_fields.dhost.v4 = inet_addr("8.8.8.8"); /* 过滤出的IP地址*/
-
rule.core_fields.dhost_mask.v4= inet_addr("255.255.255.255"); /* 主机子网 */
-
/* 编译规则 */
-
if((rc = pfring_add_filtering_rule(pd, &rule)) < 0)
-
fprintf(stderr, "pfring_add_filtering_rule(2) failed\n");
-
exit(EXIT_FAILURE);
-
else
-
printf("Rule added successfully...\n");
-
/* 开启过滤器,第二个参数0表示drop,非零则为accept*/
-
pfring_toggle_filtering_policy(pd, 0);
-
#endif
-
-
#if 1 /* 使用BPF过滤器 */
-
/* 过滤掉目标端口为22或455的数据包,也可以在前面加协议 */
-
char filter_buffer[] = {PRINT_ARG};
-
if (pfring_set_bpf_filter(pd, filter_buffer) != 0) {
-
printf("set_BPF is failure!\n");
-
exit(EXIT_FAILURE);
-
}
-
#endif
-
-
/* 开启pfring */
-
if (pfring_enable_ring(pd) != 0) {
-
printf("pfring_enable is failure error [%s]\n", strerror(errno));
-
exit(EXIT_FAILURE);
-
}
-
-
while(1) {
-
struct pfring_pkthdr hdr;
-
u_char *buffer;
-
int rc;
-
-
/* 接收处理数据报文,最后一个参数非0则为阻塞*/
-
if((rc = pfring_recv(pd, &buffer, 0, &hdr, 1) > 0)) {
-
/* 调用函数处理捕获的数据包 */
-
process_packet(&hdr, buffer);
-
} else{
-
/* 稍等PF_RING就绪 */
-
usleep(10);
-
}
-
}
-
-
pfring_close(pd);
-
-
return(0);
-
}
阅读(1219) | 评论(0) | 转发(0) |