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

news2024/11/20 9:22:19

一、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标杆供应商

下期我们不见不散~

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

uni-app 前后端调用实例 基于Springboot 上拉分页实现

锋哥原创的uni-app视频教程: 2023版uniapp从入门到上天视频教程(Java后端无废话版),火爆更新中..._哔哩哔哩_bilibili2023版uniapp从入门到上天视频教程(Java后端无废话版),火爆更新中...共计23条视频,包括:第1讲 uni…

音视频通信

文章目录 一、音视频通信流程二、流媒体协议1、RTSP2、RTMP3、HLS4、WebRTC 一、音视频通信流程 音视频通信完整流程有如下几个环节:采集、编码、前后处理、传输、解码、缓冲、渲染等。 每一个细分环节,还有更细分的技术模块。比如,前后处…

【数据结构】二叉搜索(查找/排序)树

一、二叉搜索树基本概念 1、定义 二叉搜索树,又称为二叉排序树,二叉查找树,它满足如下四点性质: 1)空树是二叉搜索树; 2)若它的左子树不为空,则左子树上所有结点的值均小于它根结…

使用宝塔在Linux面板搭建网站,并实现公网远程访问

文章目录 前言1. 环境安装2. 安装cpolar内网穿透3. 内网穿透4. 固定http地址5. 配置二级子域名6. 创建一个测试页面 前言 宝塔面板作为简单好用的服务器运维管理面板,它支持Linux/Windows系统,我们可用它来一键配置LAMP/LNMP环境、网站、数据库、FTP等&…

STL map容器与pair类模板(解决扫雷问题)

CSTL之Map容器 - 数据结构教程 - C语言网 (dotcpp.com)https://www.dotcpp.com/course/118CSTL之Pair类模板 - 数据结构教程 - C语言网 (dotcpp.com)https://www.dotcpp.com/course/119 刷到一个扫雷的题目,之前没有玩怎么过扫雷,于是我就去玩了玩…

【计算机设计大赛作品】豆瓣电影数据挖掘可视化—信息可视化赛道获奖项目深入剖析【可视化项目案例-22】

文章目录 一.【计算机设计大赛作品】豆瓣电影数据挖掘可视化—信息可视化赛道获奖项目深入剖析【可视化项目案例-22】1.1 项目主题:豆瓣电影二.代码剖析2.1 项目效果展示2.2 服务端代码剖析2.3 数据分析2.4 数据评分三.寄语四.本案例完整源码下载一.【计算机设计大赛作品】豆瓣…

Go后端开发 -- main函数 变量 常量 函数

Go后端开发 – main函数 & 变量 & 常量 & 函数 文章目录 Go后端开发 -- main函数 & 变量 & 常量 & 函数一、第一个main函数1.创建工程2.main函数解析 二、变量声明1.单变量声明2.多变量声明 三、常量1.常量的定义2.优雅的常量 iota 四、函数1.函数返回…

2024.1.2 安装JDK和Eclipse,并配置java编译环境

2024.1.2 安装JDK和Eclipse,并配置java编译环境 一直对java一知半解,利用春节前一个月时间补补课。 一、安装jdk 首先在oracle官网上下载jdk,这里选jdk17,选择第二项直接安装,第一项是压缩文件,带有一些…

Noisy DQN 跑 CartPole-v1

gym 0.26.1 CartPole-v1 NoisyNet DQN NoisyNet 就是把原来Linear里的w/b 换成 mu sigma * epsilon, 这是一种非常简单的方法,但是可以显著提升DQN的表现。 和之前最原始的DQN相比就是改了两个地方,一个是Linear改成了NoisyLinear,另外一个是在agent在t…

第二十七章 正则表达式

第二十七章 正则表达式 1.正则快速入门2.正则需求问题3.正则底层实现14.正则底层实现25.正则底层实现36.正则转义符7.正则字符匹配8.字符匹配案例19.字符匹配案例211.选择匹配符(|)12.正则限定符{n}{n,m}(1个或者多个)*(0个或者多…

创建x11vnc系统进程

为方便使用vnc,所以寻找到一个比较好用的vnc服务端那就是x11vnc,索性就创建了一个系统进程 一、环境 系统:银河麒麟v4-sp2-server 软件:x11vnc【linux下】、VNCviewer【win下】 二、安装x11vnc 1、挂载光盘源并修改apt源 mou…

生态系统服务构建生态安全格局中的实践技术应用

生态安全是指生态系统的健康和完整情况。生态安全的内涵可以归纳为:一,保持生态系统活力和内外部组分、结构的稳定与持续性;二,维持生态系统生态功能的完整性;三,面临外来不利因素时,生态系统具…

Linux用shell脚本执行乘法口诀表的两种方式

#!/bin/bash # *********************************************************# # # # * Author : 藻头男 # # * QQ邮箱 : 2322944912qq.com # …

【SpringBoot3】1.SpringBoot入门的第一个完整小项目(新手保姆版+教会打包)

目录 1 SpringBoot简单介绍1.1 SpringBoot是什么1.2 主要优点1.3 术语1.3.1 starter(场景启动器) 1.4 官方文档 2 环境说明3 实现代码3.1 新建工程与模块3.2 加入依赖3.3 主程序文件3.4 业务代码3.5 运行测试3.6 部署打包3.7 命令行运行 1 SpringBoot简单…

[足式机器人]Part2 Dr. CAN学习笔记-自动控制原理Ch1-8Lag Compensator滞后补偿器

本文仅供学习使用 本文参考: B站:DR_CAN Dr. CAN学习笔记-自动控制原理Ch1-8Lag Compensator滞后补偿器 从稳态误差入手(steady state Error) 误差 Error : E ( s ) R ( s ) − X ( s ) R ( s ) − E ( s ) ⋅ K G …

再见2023,你好2024!

大家好,我是老三,本来今天晚上打算出去转一转,陆家嘴打车实在太艰难了,一公里多的路,司机走了四十分钟,还没到,再加上身体不适,咳嗽地比较厉害,所以还是宅在酒店里&#…

.NET Core SkiaSharp 替代 System.Drawing.Common 的一些用法

在.NET 6中,微软官方建议把 System.Drawing.Common 迁移到 SkiaSharp 库。因为System.Drawing.Common 被设计为 Window 技术的精简包装器,因此其跨平台实现欠佳。 SkiaSharp是一个基于谷歌的Skia图形库(Skia.org)的用于.NET平台的…

机器学习与深度学习——使用paddle实现随机梯度下降算法SGD对波士顿房价数据进行线性回归和预测

文章目录 机器学习与深度学习——使用paddle实现随机梯度下降算法SGD对波士顿房价数据进行线性回归和预测一、任务二、流程三、完整代码四、代码解析五、效果截图 机器学习与深度学习——使用paddle实现随机梯度下降算法SGD对波士顿房价数据进行线性回归和预测 随机梯度下降&a…

深度学习 Day23——J3DenseNet算法实战与解析

🍨 本文为🔗365天深度学习训练营 中的学习记录博客🍖 原作者:K同学啊 | 接辅导、项目定制🚀 文章来源:K同学的学习圈子 文章目录 前言1 我的环境2 pytorch实现DenseNet算法2.1 前期准备2.1.1 引入库2.1.2 设…

GitHub Copilot 最佳免费平替:阿里通义灵码

之前分享了不少关于 GitHub Copilot 的文章,不少粉丝都评论让我试试阿里的通义灵码,这让我对通义灵码有了不少的兴趣。 今天,阿七就带大家了解一下阿里的通义灵码,我们按照之前 GitHub Copilot 的顺序分享通义灵码在相同场景下的…