擎创技术流 |如何使用eBPF监控NAT转换

一、NAT简介

Linux NAT(Network Address Translation)转换是一种网络技术,用于将一个或多个私有网络内的IP地址转换为一个公共的IP地址,以便与互联网通信。

图源于网络

在k8s业务场景中,业务组件之间的关系十分复杂.

由于 Kubernetes 的网络模型假设 Pod 之间访问时使用的是对方 Pod 的实际地址,所以一个 Pod 内部的应用程序看到的自己的IP地址和端口与集群内其他 Pod看到的一样 。它们都是Pod实际分配的IP地址 。将IP地址和端口在Pod内部和外部都保待一致,也就不需要使用 NAT 进行地址转换了。

一些场景如cilium 并没有使用Netfilter的NAT转换。

二、Linux中的NAT转换

linux的NAT转换是基于 Netfilter 网络框架实现的。

Netfilter 是 Linux 内核中一个对数据 包进行控制、修改和过滤(manipulation and filtering)的框架。它在内核协议 栈中设置了若干hook 点,以此对数据包进行拦截、过滤或其他处理。Netfilter 是最古老的内核框架之一,1998 年开始开发,2000 年合并到 2.4.x 内 核主线版本 [5]。

图源于网络

Netfilter 官方文档:

https://www.netfilter.org/documentation/index.html

netfilter是Linux内核的包过滤框架,它提供了一系列的钩子(Hook)供其他模块控制包的流动。这些钩子包括:

  • NF_IP_PRE_ROUTING:刚刚通过数据链路层解包进入网络层的数据包通过此钩子,它在路由之前处理

  • NF_IP_LOCAL_IN:经过路由查找后,送往本机(目的地址在本地)的包会通过此钩子

  • NF_IP_FORWARD:不是本地产生的并且目的地不是本地的包(即转发的包)会通过此钩子

  • NF_IP_LOCAL_OUT:所有本地生成的发往其他机器的包会通过该钩子

  • NF_IP_POST_ROUTING:在包就要离开本机之前会通过该钩子,它在路由之后处理。

三、使用Conntrack读取NAT转换

conntrack 是 netfilter一个模块。

NAT是在连接跟踪的基础上实现的,所以conntrack肯定是在NAT之前建立的。

conntrack注册的优先级:

enum nf_ip_hook_priorities {
  NF_IP_PRI_FIRST = INT_MIN,
  NF_IP_PRI_RAW_BEFORE_DEFRAG = -450,
  NF_IP_PRI_CONNTRACK_DEFRAG = -400,
  NF_IP_PRI_RAW = -300,
  NF_IP_PRI_SELINUX_FIRST = -225,
  NF_IP_PRI_CONNTRACK = -200,
  NF_IP_PRI_MANGLE = -150,
  NF_IP_PRI_NAT_DST = -100,
  NF_IP_PRI_FILTER = 0,
  NF_IP_PRI_SECURITY = 50,
  NF_IP_PRI_NAT_SRC = 100,
  NF_IP_PRI_SELINUX_LAST = 225,
  NF_IP_PRI_CONNTRACK_HELPER = 300,
  NF_IP_PRI_CONNTRACK_CONFIRM = INT_MAX,
  NF_IP_PRI_LAST = INT_MAX,
};

我们可以看到,NAT是在连接跟踪的基础上实现的,所以连接跟踪肯定是在NAT之前建立的。在上面的优先级中,优先级越小,越容易被先调用。

使用conntrack 查看当前节点NAT 转换情况

sudo conntrack -L -j

tcp 6 82 SYN_SENT src=172.19.0.2 dst=192.168.101.98 sport=55628 dport=443 [UNREPLIED] src=192.168.101.98 dst=192.168.1.3 sport=443 dport=55628 mark=0 use=1 conntrack v1.4.6 (conntrack-tools): 1 flow entries have been shown.

所以我们使用ebpf hook conntrack 就可以查看当前节点NAT转换情况。

四、使用eBPF hook conntrack

使用ebpf 拦截conntrack,我们主要拦截:

SEC("kprobe/__nf_conntrack_hash_insert")
SEC("kprobe/ctnetlink_fill_info")

SEC("kprobe/__nf_conntrack_hash_insert") SEC("kprobe/ctnetlink_fill_info")

实现主流程

hook住 __nf_conntrack_hash_insert:

SEC("kprobe/__nf_conntrack_hash_insert")
int BPF_KPROBE(kprobe___nf_conntrack_hash_insert, struct nf_conn *ct,unsigned int hash, unsigned int reply_hash) {
    u32 status = ct_status(ct);
    __maybe_unused possible_net_t p_net = BPF_CORE_READ(ct, ct_net);
    if (!(status&IPS_CONFIRMED)) {
        log_debug("kprobe/__nf_conntrack_hash_insert include IPS_CONFIRMED: netns: %u, status: %x\n", get_netns(&p_net), status);
        return 0;
    }
    if (!(status&IPS_NAT_MASK)) {
        return 0;
    }
    if (!(status&IPS_CONFIRMED) || !(status&IPS_NAT_MASK)) {
        log_debug("kprobe/filter: netns: %u, status: %x\n", get_netns(&p_net), status);
        return 0;
    }


    conntrack_tuple_t orig = {}, reply = {};
    if (nf_conn_to_conntrack_tuples(ct, &orig, &reply) != 0) {
        return 0;
    }


    bpf_map_update_with_telemetry(conntrack, &orig, &reply, BPF_ANY);
    bpf_map_update_with_telemetry(conntrack, &reply, &orig, BPF_ANY);
    increment_telemetry_registers_count();
    return 0;
}

hook住ctnetlink_fill_info:

SEC("kprobe/ctnetlink_fill_info")
int BPF_KPROBE(kprobe_ctnetlink_fill_info, struct nf_conn *ct) {


    proc_t proc = {};
    bpf_get_current_comm(&proc.comm, sizeof(proc.comm));


    if (!proc_t_comm_prefix_equals("system-probe", 12, proc)) {
        log_debug("skipping kprobe/ctnetlink_fill_info invocation from non-system-probe process\n");
        return 0;
    }


    u32 status = ct_status(ct);
    if (!(status&IPS_CONFIRMED) || !(status&IPS_NAT_MASK)) {
        return 0;
    }


    __maybe_unused possible_net_t c_net = BPF_CORE_READ(ct, ct_net);
    log_debug("kprobe/ctnetlink_fill_info: netns: %u, status: %x\n", get_netns(&c_net), status);


    conntrack_tuple_t orig = {}, reply = {};
    if (nf_conn_to_conntrack_tuples(ct, &orig, &reply) != 0) {
        return 0;
    }


    bpf_map_update_with_telemetry(conntrack, &orig, &reply, BPF_ANY);
    bpf_map_update_with_telemetry(conntrack, &reply, &orig, BPF_ANY);
    increment_telemetry_registers_count();


    return 0;
}

自此将kernel中NAT的sock五元组采集到了ebpf的map中,上报到用户空间。

擎创科技,Gartner连续推荐的AIOps领域标杆供应商。公司专注于通过提升企业客户对运维数据的洞见能力,为运维降本增效,充分体现科技运维对业务运营的影响力。

行业龙头客户的共同选择

了解更多运维干货与行业前沿动态

可以右上角一键关注

我们是深耕智能运维领域近十年的

连续多年获Gartner推荐的AIOps标杆供应商

下期我们不见不散~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/287483.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【LabVIEW FPGA入门】创建第一个LabVIEW FPGA程序

本教程仅以compactRIO(FPGA-RT)举例 1.系统配置 1.1软件安装 FPGA-RT 1. LabVIEW Development System (Full or Professional) 2. LabVIEW Real-Time Module 3. LabVIEW FPGA Module 4. NI-RIO drivers 1.2硬件配置 1.使用线缆连接CompactRIO至主机…

OpenHarmony之HDF驱动框架

概述 HDF(Hardware Driver Foundation)驱动框架,为驱动开发者提供驱动框架能力,包括驱动加载、驱动服务管理、驱动消息机制和配置管理。并以组件化驱动模型作为核心设计思路,让驱动开发和部署更加规范,旨在…

鸟类识别与分类

Littro 双波段T型云台成像AI一体机是利卓公司结合了红外热成像、可见光相机与边缘计算为一体的整机产品。 产品同时支持双波段成像,基于瞳赋Tofu3智能识别模块的AI算法可以克服因光线不足、背景复杂造成的诸多不利因素,完成目标检测、识别、跟踪等多种功…

RabbitMQ集群的简单说明

1.普通集群(副本集群) 当集群中某一时刻master主节点宕机,可以对master中Queue中的消息进行备份。而就算master宕机了,从节点不会对外提供服务,等到master节点恢复后,系统才会恢复正常。 主从架构的缺点是队列中的消息只是位于主节…

51单片机之LED灯

51单片机之LED灯 🌴前言:🏮点亮LED灯的原理💘点亮你的第一个LED灯💘点亮你的八个LED灯 📌让LED灯闪烁的原理🎽 LED灯的闪烁🏓错误示范1🏓正确的LED闪烁代码应该是这样&am…

玩转数据世界:跨工作空间的安全授权与高效查询

前言 随着数字化时代的来临,数据已经成为了企业和组织的核心资产。如何安全有效地管理和利用这些数据,成为了各行业共同面临的挑战。尤其是在多个工作空间或部门之间,数据的共享、查询和分析往往涉及到复杂的权限管理,影响组织的…

移动CRM系统有哪些具体的应用场景?移动CRM好用吗?

大家好我是卡林,最近杭州亚运会盛大举办,外国友人在打卡各地美食景点的同时也体会到了移动支付的乐趣。在智能手机全面普及的今天,移动CRM系统的应用也越来越广泛,移动CRM系统的应用场景有哪些?移动办公、签到打卡、销…

【C语言】Linux socket 编程

一、Socket 通信过程 在 Linux 系统中,socket 是一种特殊的文件描述符,用于在网络中的不同主机间或者同一台主机中的不同进程间进行双向通信。它是通信链路的端点,可以看作是网络通信的接口。Socket 通信过程主要分为以下几个步骤&#xff1a…

【算法】利用分治思想解算法题:快排、归并、快速选择实战(C++)

1. 分治思想 介绍 分治法将问题划分成多个相互独立且相同或类似的子问题,然后递归地解决每个子问题,并将结果合并以得到原始问题的解。 分治思想通常包含以下三个步骤: 分解:将原始问题划分成多个规模较小、相互独立且类似的子…

企业如何利用好数据,让数据真正成为数据资产?数据资产管理应该怎样建设?

数字化时代,数据已经成为了个人、机构、企业乃至国家的重要战略资产。 近日,财政部正式对外发布《企业数据资源相关会计处理暂行规定》,并自 2024 年 1 月 1 日开始施行。数据资产入表政策落地节奏超预期,标志着国家把数据作为生…

如何用python实时监控股票,并且持续扫描大盘?

用 Python 抓取分析股市数据很简单!只用短短几行代码,就能实现策略制定到交易信号生成。 一、数据准备 在分析的最开始,需要获取数据。本文中将以沪深 300 指数为标的进行分析(包含日期、开高低收价、成交量、成交额字段&#xf…

MySQL之四大引擎、账号管理以及建库认识

目录 一、数据库存储引擎(发动机) 1.1、认识引擎 1.2、查看存储引擎 1.3、引擎常识 1.4、support字段说明 1.5、四大引擎 二、数据库管理 2.1、元数据库介绍: 2.2、分类: 2.3、增删改查以及使用操作 2.4、权限 三、数…

【面试高频算法解析】算法练习2 回溯

目录 前言算法解析练习题组合总和全排列II单词搜索 前言 本篇章开放目的是按算法类型学习算法,学习对应算法理论,并通过练习一些经典算法题深入理解这类算法,避免出现刷了很多算法题,还是一知半解的状态 算法解析 回溯&#xff…

UDP通信(服务器-客户端)

一、 UDP服务器-客户端通信 UDP(User Datagram Protocol)是一种面向无连接的传输层协议,它提供了一种简单的、不可靠的数据传输服务。与TCP(Transmission Control Protocol)不同,UDP不建立连接,…

FusionAccess配置Lite AD

1、Lite AD的安装及配置 Lite AD流程: (1)创建一个新的Windows 10,安装tools,再安装ITA组件(安装Lite AD会自动安装VAG/VLB) (2)创建一个新的Windows 10,安…

线性规划中解的关系

写于:2024年1月2日星期二 修改于: 本文从两个角度对线性规划中的解做划分,角度一是将解划为基解、基可行解、可行解;角度二是将解划分为无可行解、无界解、最优解(唯一和无穷多)。同时,详细描述…

【计算机视觉网络训练技巧】你知道你拿什么图片在训练吗?训练图片可视化简易版

以下是一张图片,数据增广之后的示意图: 问题是这样的,当数据增广后,我们怎么知道图片变成什么样了呢,或者说我们输入到网络中的图片长什么样?对,解法很简单,就是在图片输入到网络时…

C++的基础语句

C前奏 1.变量的定义2.键入和输出3.运算符4.sizeof()函数5.判断6.goto语句7.总结 这个专题,我会用简单的语言介绍C的语法,并会适当的对比实现相同或相似功能的C与python代码写法上的不同。 1.变量的定义 对于python来说,我们可以跳过定义直接…

Efficient Classification of Very Large Images with Tiny Objects(CVPR2022补1)

文章目录 Two-stage Hierarchical Attention SamplingsummaryOne-stageTwo-Stage内存需求 Efficient Contrastive Learning with Attention Sampling Two-stage Hierarchical Attention Sampling summary 从一个大图像中按照指定的低分辨率比例和位置提取出一个小图块 一阶段…

web前端——clear可以清除浮动产生的影响

clear可以解决高度塌陷的问题&#xff0c;产生的副作用要小 未使用clear之前 <!DOCTYPE html> <head><meta charset"UTF-8"><title>高度塌陷相关学习</title><style>div{font-size:50px;}.box1{width:200px;height:200px;backg…