PF_RING使用BPF过滤器

来源:互联网 发布:淘宝商品视频广告制作 编辑:程序博客网 时间:2024/05/29 12:47
 转载:http://blog.chinaunix.net/uid-10540984-id-3240755.html

PF_RING是支持BPF过滤器的,这个在PF_RING的UserGuide中也有相应的函数原型说明。
当编译创建配置的时候,也可以关闭BPF的支持。
./userland/lib/configure --disable-bpf
默认是支持开启BPF过滤器的,在./userland/lib/pfring_mod.c源码中,会有一个宏定义:
#ifdef ENABLE_BPF
#include <pcap/pcap.h>
#include <pcap/bpf.h>
#include <linux/filter.h>
#endif
所以默认没有关闭BPF支持的情况下gcc编译时需要加入pcap的动态库。

PF_RING自己也有过滤器,确实功能功能比较少,习惯了pcap的过滤器书写,当然能使用它的过滤器是再好不过了。

代码中使用了PF_RING过滤器方式和BPF过滤器方式,用gcc编译时加"-D PRINT_ARG"则捕捉arp包,否则捕捉tcp包(其中排除了ssh和samba)

  1. #define _GNU_SOURCE
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <pfring.h>
  5. #include <string.h>
  6. #include <errno.h>
  7. #include <netinet/in.h>
  8. #include <arpa/inet.h>
  9. #include <linux/if_ether.h>
  10. #include <linux/ip.h>
  11. #include <linux/tcp.h>
  12. #include <getopt.h>

  13. #define SNAP_LEN 1518
  14. #define MIN_LEN (sizeof(struct ethhdr) + sizeof(struct iphdr) \
  15.                     + sizeof(struct tcphdr))

  16. #ifdef ARP_SWICTH
  17.     #define PRINT_ARG "arp"
  18. #else
  19.     #define PRINT_ARG "tcp and not (dst port (22 or 445) or src port (22 or 445))"
  20. #endif

  21. static pfring *pd;
  22. static char *in_dev = NULL;
  23. static struct option opts[] = {
  24.     {.name = "interface", .has_arg = 1, .val = 'i'},
  25.     {.name = "help", .has_arg = 0, .val = 'h'},
  26.     {NULL}
  27. };

  28. static void printHelp(void) {
  29.     printf("-h Print this help\n");
  30.     printf("-i <device> Device name. Use device\n");
  31.     exit(EXIT_FAILURE);
  32. }

  33. static int process_packet(const struct pfring_pkthdr *header,
  34.                             const u_char *packet) {
  35.     struct ethhdr *ethh;
  36.     struct arphdr *arph;
  37.     struct iphdr *iph;
  38.     struct tcphdr *tcph;
  39.     struct in_addr src, dst;

  40.     /* 判断长度避免访问到空指针 */
  41.     if (header->caplen < MIN_LEN) return; 

  42.     ethh = (struct ethhdr *)packet;
  43.     printf("Eth_type:");
  44.     switch(ntohs(ethh->h_proto)) {
  45.         case 0x0800:
  46.             printf("IP | ");
  47.             /* 打印IP协议的目的地址和源地址 */
  48.             packet += sizeof(struct ethhdr);
  49.             iph = (struct iphdr *)packet;
  50.             src.s_addr = iph->saddr;
  51.             dst.s_addr = iph->daddr;
  52.             printf("%s->", inet_ntoa(src));
  53.             printf("%s | ", inet_ntoa(dst));
  54.             
  55.             switch (iph->protocol) {
  56.                 case 6:
  57.                     packet += sizeof(struct iphdr);
  58.                     tcph = (struct tcphdr *)packet;
  59.                     printf("Protocol:TCP sport:%d->", ntohs(tcph->source));
  60.                     printf("dport:%d", ntohs(tcph->dest));
  61.                     break;
  62.                 case 1:
  63.                     printf("Protocol:ICMP");
  64.                     break;
  65.             }
  66.             break;
  67.         case 0x0806:
  68.             printf("ARP_request ");
  69.             struct in_addr *src_in_addr, *dst_in_addr;
  70.             struct macaddr { 
  71.                    u_char MAC[6];
  72.             };
  73.             struct macaddr *src_mac, *dst_mac;

  74.             packet += sizeof(struct ethhdr) + 8;
  75.             src_mac = (struct macaddr *)packet;
  76.             
  77.             packet += 6;
  78.             src_in_addr = (struct in_addr *)packet;
  79.             printf("%s", inet_ntoa(*src_in_addr));
  80.             
  81.             packet += 4;
  82.             dst_mac = (struct macaddr *)packet;

  83.             packet += 6;
  84.             dst_in_addr = (struct in_addr *)packet;
  85.             printf(" -> %s", inet_ntoa(*dst_in_addr));

  86.             printf(" %02x:%02x:%02x:%02x:%02x:%02x",
  87.                     src_mac->MAC[0], src_mac->MAC[1], src_mac->MAC[2],
  88.                     src_mac->MAC[3], src_mac->MAC[4], src_mac->MAC[5]
  89.             );
  90.             printf(" -> %02x:%02x:%02x:%02x:%02x:%02x",
  91.                     dst_mac->MAC[0], dst_mac->MAC[1], dst_mac->MAC[2],
  92.                     dst_mac->MAC[3], dst_mac->MAC[4], dst_mac->MAC[5]
  93.             );
  94.             break;
  95.         case 0x8035:
  96.             printf("ARP_response ");
  97.             break;
  98.         }
  99.     printf("\n");
  100. }

  101. int main(int argc, char *argv[]) {
  102.     char c;
  103.     while((= getopt_long(argc, argv, "hi:", opts, NULL)) != -1) {
  104.         switch(c) {
  105.         case 'h':
  106.             printHelp(); 
  107.             break;
  108.         case 'i':
  109.             in_dev = strdup(optarg);
  110.             break;
  111.         }
  112.     }

  113.     if(in_dev == NULL) printHelp();

  114.     printf("Capturing from %s\n", in_dev);

  115.     /* 打开pf设备 */
  116.     pd = pfring_open(in_dev, SNAP_LEN, PF_RING_PROMISC);
  117.     if(pd == NULL) {
  118.         printf("pfring_open %s error [%s]\n", in_dev, strerror(errno));
  119.         exit(EXIT_FAILURE);
  120.     } else {
  121.         u_int32_t version;
  122.         /* 获取版本号 */
  123.         pfring_version(pd, &version);
  124.         printf("Using PF_RING v%u.%u.%u\n",
  125.             (version & 0xFFFF0000) >> 16, 
  126.             (version & 0x0000FF00) >> 8,
  127.             version & 0x000000FF);
  128.     }

  129.     /* 
  130.     设定捕获方向
  131.     rx_and_tx_direction 双向捕获
  132.     rx_only_direction 只捕获接收
  133.     tx_only_direction 只捕获发送
  134.     */
  135.     if (pfring_set_direction(pd, rx_only_direction) != 0) {
  136.         printf("pfring_set_direction is failure error [%s]\n", strerror(errno));
  137.         exit(EXIT_FAILURE);
  138.     }

  139. #if 0 /* PF_RING过滤器 */
  140.     int rc;
  141.     filtering_rule rule;
  142.     memset(&rule, 0, sizeof(rule));
  143.     rule.rule_id = 1; /* 设置规则运行优先级,数值越小优先级越高 */
  144.     /* 匹配哪些情况 */
  145.     rule.rule_action = forward_packet_and_stop_rule_evaluation;
  146. // rule.core_fields.proto = 6 /* 设置需要过滤的传输层协议 6 TCP*/;
  147.     rule.core_fields.dhost.v4 = inet_addr("8.8.8.8"); /* 过滤出的IP地址*/
  148.     rule.core_fields.dhost_mask.v4= inet_addr("255.255.255.255"); /* 主机子网 */
  149.     /* 编译规则 */
  150.     if((rc = pfring_add_filtering_rule(pd, &rule)) < 0)
  151.         fprintf(stderr, "pfring_add_filtering_rule(2) failed\n");
  152.         exit(EXIT_FAILURE);
  153.     else
  154.         printf("Rule added successfully...\n");
  155.     /* 开启过滤器,第二个参数0表示drop,非零则为accept*/
  156.     pfring_toggle_filtering_policy(pd, 0); 
  157. #endif

  158. #if 1 /* 使用BPF过滤器 */
  159.     /* 过滤掉目标端口为22或455的数据包,也可以在前面加协议 */
  160.     char filter_buffer[] = {PRINT_ARG};
  161.     if (pfring_set_bpf_filter(pd, filter_buffer) != 0) {
  162.         printf("set_BPF is failure!\n");
  163.         exit(EXIT_FAILURE);
  164.     }
  165. #endif

  166.     /* 开启pfring */
  167.     if (pfring_enable_ring(pd) != 0) {
  168.         printf("pfring_enable is failure error [%s]\n", strerror(errno));
  169.         exit(EXIT_FAILURE);
  170.     }

  171.     while(1) {
  172.         struct pfring_pkthdr hdr;
  173.         u_char *buffer;
  174.         int rc;

  175.         /* 接收处理数据报文,最后一个参数非0则为阻塞*/
  176.         if((rc = pfring_recv(pd, &buffer, 0, &hdr, 1) > 0)) {
  177.             /* 调用函数处理捕获的数据包 */
  178.             process_packet(&hdr, buffer);
  179.         } else{
  180.             /* 稍等PF_RING就绪 */
  181.             usleep(10);
  182.         }
  183.     }

  184.     pfring_close(pd);

  185.     return(0);
  186. }
0 0
原创粉丝点击