这篇文章主要介绍如何使用BPF过滤固定特征报文
参考文章:https://www.freebsd.org/cgi/man.cgi?query=bpf&sektion=4&manpath=FreeBSD | 4.7-RELEASE

前两篇文章分别介绍了BPF在Android中的运用实例,以及BPF规则指令的解析,相信大家对BPF及其规则都有了大致的了解。现在我们来看看如何运用BPF来过滤固定特征的报文,从这个过程中加深对BPF规则的了解和运用。

IP过滤

/*** 构建源ip和目标ip过滤的socket filter,并绑定在创建的socket上* @param socket_fd 已创建的socket fd* @param src_ip 需要过滤的源ip* @param dest_ip 需要过滤的目标ip*/
void attachSocketFilter(int socket_fd, uint32_t src_ip, uint32_t dest_ip) {uint32_t ip_offset = sizeof(ether_header);std::vector<sock_filter> filter_code;// 源ip过滤uint32_t saddr_offset = ip_offset + offsetof(iphdr, saddr);filter_code.push_back(BPF_STMT(BPF_LD  | BPF_W   | BPF_ABS,  saddr_offset));filter_code.push_back(BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, src_ip, 3, 4));// 目标ip过滤uint32_t daddr_offset = ip_offset + offsetof(iphdr, daddr);filter_code.push_back(BPF_STMT(BPF_LD  | BPF_W   | BPF_ABS,  saddr_offset));filter_code.push_back(BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, src_ip, 0, 1));// Fail or Successfilter_code.push_back(BPF_STMT(BPF_RET | BPF_K, 0xffff));filter_code.push_back(BPF_STMT(BPF_RET | BPF_K, 0));struct sock_fprog filter = {(uint16_t) filter_code.size(), filter_code.data()};if (setsockopt(socket_fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) {printf("Attach socket filter failed: %s", strerror(errno));}
}

传输层协议过滤

/*** 构建传输层协议过滤的socket filter,并绑定在创建的socket上* @param socket_fd 已创建的socket fd* @param protocol 传输层协议 IPPROTO_UDP | IPPROTO_TCP | IPPROTO_ICMP*/
void attachSocketFilter(int socket_fd, uint32_t protocol) {uint32_t ip_offset = sizeof(ether_header);std::vector<sock_filter> filter_code;// 传输层协议过滤uint32_t protocol_offset = ip_offset + offsetof(iphdr, protocol);filter_code.push_back(BPF_STMT(BPF_LD  | BPF_B   | BPF_ABS,  protocol_offset ));filter_code.push_back(BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K,  protocol, 0, 1));// Fail or Successfilter_code.push_back(BPF_STMT(BPF_RET | BPF_K, 0xffff));filter_code.push_back(BPF_STMT(BPF_RET | BPF_K, 0));struct sock_fprog filter = {(uint16_t) filter_code.size(), filter_code.data()};if (setsockopt(socket_fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) {printf("Attach socket filter failed: %s", strerror(errno));}
}

端口过滤

/*** 构建源端口和目标端口过滤的socket filter,并绑定在创建的socket上* @param socket_fd 已创建的socket fd* @param src_port  需要过滤的源端口* @param dest_port 需要过滤的目标端口*/
void attachSocketFilter(int socket_fd, uint32_t src_port, uint32_t dest_port) {uint32_t ip_offset = sizeof(ether_header);std::vector<sock_filter> filter_code;... // 需要对传输层协议进行过滤,假设我们这里已经对protocol过滤,且目标是tcp// 源端口过滤uint32_t sport_offset = ip_offset + offsetof(tcphdr, source);filter_code.push_back(BPF_STMT(BPF_LDX | BPF_B    | BPF_MSH, ip_offset));filter_code.push_back(BPF_STMT(BPF_LD  | BPF_H    | BPF_IND, sport_offset));filter_code.push_back(BPF_JUMP(BPF_JMP | BPF_JEQ  | BPF_K,   src_port, 3, 4));// 目标端口过滤uint32_t dport_offset = ip_offset + offsetof(tcphdr, dest);filter_code.push_back(BPF_STMT(BPF_LDX | BPF_B    | BPF_MSH, ip_offset));filter_code.push_back(BPF_STMT(BPF_LD  | BPF_H    | BPF_IND, dport_offset ));filter_code.push_back(BPF_JUMP(BPF_JMP | BPF_JEQ  | BPF_K,   dest_port, 0, 1));// Fail or Successfilter_code.push_back(BPF_STMT(BPF_RET | BPF_K, 0xffff));filter_code.push_back(BPF_STMT(BPF_RET | BPF_K, 0));struct sock_fprog filter = {(uint16_t) filter_code.size(), filter_code.data()};if (setsockopt(socket_fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) {printf("Attach socket filter failed: %s", strerror(errno));}
}

数据内容过滤

/*** 构建数据过滤的socket filter,并绑定在创建的socket上* @param socket_fd 已创建的socket fd* @param idents  需要过滤的数据段* @param ident_offset_in_data 需要过滤的数据在包数据中的偏移* @param ident_len 需要过滤的数据长度*/
void attachSocketFilter(int socket_fd, uint8_t *idents, uint32_t ident_offset_in_data, uint_32 ident_len) {uint32_t ip_offset = sizeof(ether_header);... // 需要对传输层协议进行过滤,假设我们这里已经对protocol过滤,且目标是tcp// 计算到数据的偏移// 计算方式:ether_header + iphdr + tcphdr这三个的长度和// 计算ip头长度并存入X寄存器中filter_code.push_back(BPF_STMT(BPF_LDX  | BPF_B    | BPF_MSH, ip_offset));// tcp头长度定义在ack_seq之后的一个字节中的前四位,由于和其他内容共享一个字节,// 所以不好直接计算其offset,这里通过ack_seq来计算uint32_t tcplen_indirect_offset = ip_offset + offsetof(tcphdr, ack_seq) + 4;// 将tcphdr长度的真实偏移存入A中filter_code.push_back(BPF_STMT(BPF_LD   | BPF_B    | BPF_IND, tcplen_indirect_offset));// 移位计算tcphdr长度,与4*(P[k:1]&0xf)如出一辙filter_code.push_back(BPF_STMT(BPF_ALU  | BPF_RSH | BPF_K, 4));filter_code.push_back(BPF_STMT(BPF_ALU  | BPF_LSH | BPF_K, 2));// 将iphdr长度与tcphdr长度相加存入A中filter_code.push_back(BPF_STMT(BPF_ALU  | BPF_ADD | BPF_X));// ident的非直接偏移,除去iphdr和tcphdr的长度后的偏移uint32_t ident_indirect_offset = ip_offset + ident_offset_in_data;// 将A中值(iphdr+tcphdr)存入X中,方便之后将A用于累加计算filter_code.push_back(BPF_STMT(BPF_MISC | BPF_TXA));for (uint32_t i = 0; i < ident_len; i++) {uint32_t ident= idents[i];// 将ident对应包中的偏移存入A中filter_code.push_back(BPF_STMT(BPF_LD | BPF_B | BPF_IND, ident_indirect_offset + (i + 1)));// 对比ident偏移处字节和ident,true则继续,否则跳到jf指令((ident_len - i - 1) * 2 + 1);filter_code.push_back(BPF_JUMP(BPF_JMP | BPF_JEQ  | BPF_K, ident, 0, (ident_len - i - 1) * 2 + 1));}// Fail or Successfilter_code.push_back(BPF_STMT(BPF_RET | BPF_K, 0xffff));filter_code.push_back(BPF_STMT(BPF_RET | BPF_K, 0));struct sock_fprog filter = {(uint16_t) filter_code.size(), filter_code.data()};if (setsockopt(socket_fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) {printf("Attach socket filter failed: %s", strerror(errno));}
}

BPF高阶 - 使用BPF过滤固定特征报文相关推荐

  1. py函数式编程(高阶函数map/reduce/filter/sorted、闭包函数/返回函数、匿名函数lamber、@装饰器decorator、偏函数functool.partial())

    #py函数式编程.py #高阶函数map/reduce/filter/sorted.闭包函数/返回函数.匿名函数lamber.@装饰器decorator.偏函数functool.partial()# ...

  2. 【廖雪峰Python学习笔记】高阶函数

    Higher-order function 高阶函数 映射 过滤算法 排序算法 高阶函数 变量可指向函数 >>> abs # 函数 <built-in function abs ...

  3. 聊聊推荐系统的高阶特征交叉问题

    文 | 水哥 源 | 知乎 Saying 1. DCN看起来给了我们很好的允诺,但是细细想来是有一些问题的,这里也可以参考大佬的意见 2. 高阶FM的核心设计是先element-wise乘,再对emb ...

  4. paper survey(2019.06.11)——卷积网络高阶特征表示

    类似于博文< paper survey(2019.06.05)--卷积网络feature map的传递与利用> 本博文也是系列论文的阅读笔记(基本都是CVPR和ICCV的论文). 对于跟本 ...

  5. 真正的高阶特征交叉:xDeepFM与DCN-V2

    文 | 水哥 源 | 知乎 Saying 1. xDeepFM和DCN-V2是真正的高阶交叉,和前面讲的High Order Factorization Machine(HOFM)又有着千丝万缕的联系 ...

  6. 深度学习中的高阶特征

    由于自己研究方向为基于高阶的图像分类,故在这里对相关论文做一个简单的划分和总结. 按照计算高阶的层,位于卷积神经网络的位置划分,可以分为: 网络末端 网络中部 2022-05-24 update (C ...

  7. 闭包和高阶函数-函数式编程的基本特征

    函数编程支持函数作为第一类对象,有时称为闭包或者仿函数(functor)对象.实质上,闭包是起函数的作用并可以像对象一样操作的对象.与此类似,FP 语言支持高阶函数.高阶函数可以用另一个函数(间接地, ...

  8. NLP高阶:一文走遍完整自然语言处理流程

    NLP进阶之路上,你是否也遇到过这些疑问? 为什么在这个问题上使用Adam,而不是GD或者Adagrad? 对于特定的业务场景,我应该如何把领域知识考虑进去, 用先验,还是用限制条件? 对于拼车场景, ...

  9. NLP高阶实战必读:一文走遍完整自然语言处理流程

    NLP进阶之路上,你是否也遇到过这些疑问? 为什么在这个问题上使用Adam,而不是GD或者Adagrad? 对于特定的业务场景,我应该如何把领域知识考虑进去, 用先验,还是用限制条件? 对于拼车场景, ...

最新文章

  1. 1微秒等于多少皮秒_注册汽油贸易公司分享1升汽油等于多少公斤?
  2. OKR管理和绩效考核有什么不一样呢?
  3. MyBatis 环境搭建
  4. tensorflow安装后在 pychram中 使用测试 找不到 tensorflow 模块的问题解决
  5. 笔记-信息系统开发基础-架构设计-软件架构风格
  6. Sublime Text 2 中运行 PHP
  7. boost windows编译
  8. 复古风格海报设计欣赏|蒸汽波了解下
  9. 根据类名找jar包findjar.com
  10. 3款强大的BootStrap的可视化制作工具推荐
  11. 1. Magento2 --- (1) theme ---create a theme
  12. Java编程--如何突破程序员思维
  13. yolov5s 目标检测模型实战——火点烟雾检测实战
  14. python制作课程表_创建课程表设计
  15. Can‘t Update No tracked branch configured for branch
  16. 复杂性思维中文第二版 八、自组织临界
  17. python 操作excel 表格
  18. 数据化建设知识图谱(文末附PDF下载)
  19. HTML5+CSS3小实例:篮球弹跳动画
  20. 简单画图程序(windows程序设计)

热门文章

  1. vscode配置并运行swift
  2. java赛马游戏,用JAVA语言实现赛马游戏
  3. 工作岗位必备技能总结
  4. commons-codec使用简介
  5. linux 笔记实录(1)
  6. mysql 查询上一周每一天的数据(含跨年问题)
  7. VC界面程序中文字乱码问题
  8. condition_variable的使用以及与锁的关系
  9. 什么是mysql时间戳_什么是mysql 的时间戳
  10. 【软件推荐】synctoy 本机同步的最好的软件 本机不同目录 本机硬盘与移动硬盘同步