【博客578】LVS NAT配合MASQUERADE实现FULLNAT的场景,及此场景下net.ipv4.vs.conntrack参数的重要作用

news2024/10/6 18:31:58

LVS NAT配合MASQUERADE实现FULLNAT的场景,及此场景下net.ipv4.vs.conntrack参数的重要作用

1、LVS基本原理:

在这里插入图片描述
流程:

  • 当用户向负载均衡调度器(Director Server)发起请求,调度器将请求发往至内核空间
    PREROUTING 链首先会接收到用户请求,判断目标 IP 确定是本机 IP,将数据包发往 INPUT 链
  • IPVS 是工作在 INPUT 链上的,当用户请求到达 INPUT 时,IPVS 会将用户请求和自己已定义好的集群服务进行比对,如果用户请求的就是定义的集群服务,那么此时 IPVS 会强行修改数据包里的目标 IP 地址及端口,并将新的数据包发往 POSTROUTING 链
  • POSTROUTING 链接收数据包后发现目标 IP 地址刚好是自己的后端服务器,那么此时通过选路,将数据包最终发送给后端的服务器

2、LVS NAT模式

上面的步骤中,数据包达到RS后,如何返回,有不同的方式,如果直接沿着RS=>DS=>Client方式返回,那么就是NAT模式:

在这里插入图片描述

NAT模式的数据包请求流程:

  • 1、当用户请求到达 Director Server,此时请求的数据报文会先到内核空间的 PREROUTING 链。 此时报文的源 IP 为 CIP,目标 IP 为 VIP
  • 2、PREROUTING 检查发现数据包的目标 IP 是本机,将数据包送至 INPUT 链
  • 3、IPVS 比对数据包请求的服务是否为集群服务,若是,修改数据包的目标 IP 地址为后端服务器 IP,然后将数据包发至 POSTROUTING 链。 此时报文的源 IP 为 CIP,目标 IP 为 RIP
  • 4、POSTROUTING 链通过选路,将数据包发送给 Real Server
  • 5、Real Server 比对发现目标为自己的 IP,开始构建响应报文发回给 Director Server。 此时报文的源 IP 为 RIP,目标 IP 为 CIP
  • 6、Director Server 在响应客户端前,此时会将源 IP 地址修改为自己的 VIP 地址,然后响应给客户端。 此时报文的源 IP 为 VIP,目标 IP 为 CIP

NAT模式特点:

  • RS 应该使用私有地址,RS 的网关必须指向 DIP
  • DIP 和 RIP 必须在同一个网段内
  • 请求和响应报文都需要经过 Director Server,高负载场景中,Director Server 易成为性能瓶颈
  • 支持端口映射
  • RS 可以使用任意操作系统
  • 缺陷:对 Director Server 压力会比较大,请求和响应都需经过 director server
  • 包对客户端看起来就是 LVS 直接返回给它的。客户端无法感知到后端 RS 的存在。

3、LVS NAT模式下,为什么一般需要设置RS 的网关必须指向 DS

因为RS收到的包的源ip是client ip,如果不设置RS 的网关必须指向 DS,默认将包送回DS,再由DS回复给client的话,那么RS直接回给client就会有问题,因为client发出的时候目的ip是vip,不是RS的ip,那么此时client对RS直接回过来的包会回复RST来终止这个连接,因为在client看来,不认为这个包是自己发出去的请求包的回包

这个原理跟三角流量一样:三角流量问题

4、、LVS NAT模式下需要额外做MASQUERADE的场景

需要额外做MASQUERADE场景:

为了让real service把包送回director server,我们在nat模式下可以采用将rs的网关指向ds,但是并不是所有情况下都可以的,比如:rs还负责处理其它的事情,那么不可以统一将包都送到ds那里去,那么此时我们可以通过做MASQUERADE,让ds将包送给rs时,将源ip换成ds的ip,这样rs就看不到client ip,看到的是包从ds给过来的,处理后就会回复给ds

默认情况下直接通过iptables来做MASQUERADE产生的问题:

一般通过以下方法做MASQUERADE:

iptables -t nat -A POSTROUTING -m ipvs --vaddr xxxx --vport xxxxx -j MASQUERADE

做完之后出现的问题:

做完会网络不通,抓包看会发现MASQUERADE没生效,因为nat 是依赖 conntrack 的,而 IPVS 默认不会记录 conntrack,我们需要开启 IPVS 的 conntrack 才可以让 MASQUERADE 生效。

设置方法:

启用内核参数:net.ipv4.vs.conntrack=1,在kube-proxy ipvs源码中也可以发现开启了这个
启动方法:echo 1 > /proc/sys/net/ipv4/vs/conntrack

5、为什么LVS NAT模式下要开启net.ipv4.vs.conntrack才能做MASQUERADE

查看ipvs手册: https://www.kernel.org/doc/Documentation/networking/ipvs-sysctl.txt

conntrack - BOOLEAN
	0 - disabled (default)
	not 0 - enabled

	If set, maintain connection tracking entries for
	connections handled by IPVS.

	This should be enabled if connections handled by IPVS are to be
	also handled by stateful firewall rules. That is, iptables rules
	that make use of connection tracking.  It is a performance
	optimisation to disable this setting otherwise.

	Connections handled by the IPVS FTP application module
	will have connection tracking entries regardless of this setting.

	Only available when IPVS is compiled with CONFIG_IP_VS_NFCT enabled.

查看ipvs模块帮助: https://github.com/torvalds/linux/blob/master/net/netfilter/ipvs/Kconfig

config	IP_VS_NFCT
	bool "Netfilter connection tracking"
	depends on NF_CONNTRACK
	---help---
	  The Netfilter connection tracking support allows the IPVS
	  connection state to be exported to the Netfilter framework
	  for filtering purposes.

总结下来:

让Netfilter的状态管理功能也能应用于IPVS模块,反过来也就是说默认nf_conntract没法作用于ipvs

原因剖析:

LVS(Linux Virtual Server)能实现负载均衡主要依靠内核IPVS (IP Virtual Server)模块,而IPVS是基于内核Netfilter实现。IPVS利用了Netfilter的Hook机制,主要在三个Hook点放置了钩子函数,分别是:NF_INET_LOCAL_IN、NF_INET_LOCAL_OUT和NF_INET_FORWARD

钩子源码如下:

static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
	/* After packet filtering, change source only for VS/NAT */
	// @xnile RIP->DIP修改为VIP->DIP,用于本机请求VIP后的回包
	{
		.hook		= ip_vs_reply4,
		.owner		= THIS_MODULE,
		.pf		= NFPROTO_IPV4,
		.hooknum	= NF_INET_LOCAL_IN,
		.priority	= NF_IP_PRI_NAT_SRC - 2,
	},
	/* After packet filtering, forward packet through VS/DR, VS/TUN,
	 * or VS/NAT(change destination), so that filtering rules can be
	 * applied to IPVS. */
	// @xnile CIP->VIP修改为CIP->RIP
	{
		.hook		= ip_vs_remote_request4,
		.owner		= THIS_MODULE,
		.pf		= NFPROTO_IPV4,
		.hooknum	= NF_INET_LOCAL_IN,
		.priority	= NF_IP_PRI_NAT_SRC - 1,
	},
	/* Before ip_vs_in, change source only for VS/NAT */
	// @xnile  NF_INET_LOCAL_OUT 本机应用层发出去的包
	// @xnile  DIP->DIP 修改为DIR->VIP
	{
		.hook		= ip_vs_local_reply4,
		.owner		= THIS_MODULE,
		.pf		= NFPROTO_IPV4,
		.hooknum	= NF_INET_LOCAL_OUT,
		.priority	= NF_IP_PRI_NAT_DST + 1,
	},
	/* After mangle, schedule and forward local requests */
	// @xnile  NF_INET_LOCAL_OUT 本机应用层发出去的包
	// @xnile DIP->VIP修改为DIP->RIP
	{
		.hook		= ip_vs_local_request4,
		.owner		= THIS_MODULE,
		.pf		= NFPROTO_IPV4,
		.hooknum	= NF_INET_LOCAL_OUT,
		.priority	= NF_IP_PRI_NAT_DST + 2,
	},
	/* After packet filtering (but before ip_vs_out_icmp), catch icmp
	 * destined for 0.0.0.0/0, which is for incoming IPVS connections */
	{
		.hook		= ip_vs_forward_icmp,
		.owner		= THIS_MODULE,
		.pf		= NFPROTO_IPV4,
		.hooknum	= NF_INET_FORWARD,
		.priority	= 99,
	},
	/* After packet filtering, change source only for VS/NAT */
	//@xnile RIP->CIP to src为VIP
	{
		.hook		= ip_vs_reply4,
		.owner		= THIS_MODULE,
		.pf		= NFPROTO_IPV4,
		.hooknum	= NF_INET_FORWARD,
		.priority	= 100,
	}

iptables nat勾子函数的定义:

static struct nf_hook_ops nf_nat_ipv4_ops[] __read_mostly = {
	/* Before packet filtering, change destination */
	// @xnile  iptables -t nat -A REROUTING
	{
		.hook		= nf_nat_ipv4_in,
		.owner		= THIS_MODULE,
		.pf		= NFPROTO_IPV4,
		.hooknum	= NF_INET_PRE_ROUTING,
		.priority	= NF_IP_PRI_NAT_DST,
	},
	/* After packet filtering, change source */
	// @xnile iptables -t nat -A POSTROUTING
	{
		.hook		= nf_nat_ipv4_out,
		.owner		= THIS_MODULE,
		.pf		= NFPROTO_IPV4,
		.hooknum	= NF_INET_POST_ROUTING,
		.priority	= NF_IP_PRI_NAT_SRC,
	},
	/* Before packet filtering, change destination */
	// @xnile iptables -t nat -A OUTPUT
	// @xnile DNAT 本机出去的包
	{
		.hook		= nf_nat_ipv4_local_fn,
		.owner		= THIS_MODULE,
		.pf		= NFPROTO_IPV4,
		.hooknum	= NF_INET_LOCAL_OUT,
		.priority	= NF_IP_PRI_NAT_DST,
	},
	/* After packet filtering, change source */
	// @xnile SNAT 
	{
		.hook		= nf_nat_ipv4_fn,
		.owner		= THIS_MODULE,
		.pf		= NFPROTO_IPV4,
		.hooknum	= NF_INET_LOCAL_IN,
		.priority	= NF_IP_PRI_NAT_SRC,
	},
};

优先级图如下: 我将ip_confirm标识出来了,他的优先级比其它hook点,比如lvs的hook点要低
在这里插入图片描述
原因分析:

  • 1、NAT构建于nf_conntrack之上,当数据包进入nf_conntrack后,
    会建立一个tuple以及相应的replay tuple,而应答的数据包,
    会直接查找与之匹配的repaly tuple

    tuple example:
    tuple[ORIGINAL]={10.0.5.119–>10.0.0.254,TCP}
    tuple[REPLY]={10.0.0.254–>10.0.5.119,TCP}

  • 2、如果要做SNAT就修改replay tuple中的目的地址,如果要做DNAT就修改replay tuple中的源地址。另外,nf_conntrack有一个confirm的逻辑,就是上图中最上边绿色的部分,只有当数据流的头包离开协议栈的时候才会被confirm,被confirm过的conntrack才会加入到conntrack哈希表。

  • 3、困为LVS钩子函数的优先级要高于confirm,数据流会首先导向到lvs的钩子函数中处理,然而钩子函数处理后会返回NF_STOLEN,也就是数据流不会再往下走了,当然也就不会执行confirm逻辑,因此conntrack表中就不会有对应的tuple和replay tuple,SNAT当然也就不起作用

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

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

相关文章

第6章 线程通信

6.2.1 管道 管道是一个线性字节数组,类似文件,使用文件读写进行访问;在程序里面,创建管道需要使用popen()或者pipe(); 管道的一个重要特点是使用管道的两个线程之间必须存在某种关系, 例如,使用popen需要提供另一端进程的文件名,使用pipe的两个线程分别隶属于父子进…

Linux常用命令——fgrep命令

在线Linux命令查询工具 fgrep 为文件搜索文字字符串 补充说明 fgrep命令是用来搜索 file 参数指定的输入文件(缺省为标准输入)中的匹配模式的行。fgrep 命令特别搜索 Pattern 参数,它们是固定的字符串。如果在 File 参数中指定一个以上的…

dp刷题(三)编辑距离(Hard)

编辑距离_牛客题霸_牛客网 描述 给定两个单词word1和word2,请计算将word1转换为word2至少需要多少步操作。 你可以对一个单词执行以下3种操作: a)在单词中插入一个字符 b)删除单词中的一个字符 c)替换单词中的一个字…

C#,图像二值化(14)——全局阈值的最佳迭代算法(Iterate Thresholding)及源代码

1、图像二值化 图像二值化是将彩色图像转换为黑白图像。大多数计算机视觉应用程序将图片转换为二进制表示。图像越是未经处理,计算机就越容易解释其基本特征。 二值化过程 在计算机存储器中,所有文件通常以灰度级的形式存储,灰度级具有从0…

Vue基础入门小demo——记事本

文章目录 📋前言 🎯demo介绍 🎯完整代码 🎯最终效果 🎯案例分析 📋前言 记事本(不是操作系统的那个记事本,是一个简单的网页版本记事本)是一个较全面的Vue指令集合案…

迁移学习简要

什么是迁移学习 迁移学习是一种机器学习方法,就是把任务为A的开发模型作为其的初始点,重新使用在任务为B的开发模型的过程中。迁移学习是通过从已学习的相关任务中转移知识来改进学习的新任务。虽然大多数机器学习的新 算法都是为了解决单个任务而设计的…

Exynos_4412——IIC控制器和MPU6050

目录 一、Exynos_4412下的IIC控制器 二、IIC寄存器 三、MPU6050原理 MPU6050 MPU6050的主要参数 MPU6050通信接口 MPU6050官方芯片手册 MPU6050寄存器 四、MPU6050寄存器读写时序 向MPU6050写一个字节数据 向MPU6050读一个字节数据 五、IIC编程 六、小项目 Exynos…

Linux内核中断子系统

查看中断控制相关的设备树节点 *********************gpiof控制器*************************pinctrl: pin-controller50002000 {#address-cells <1>;#size-cells <1>;compatible "st,stm32mp157-pinctrl";interrupt-parent <&exti>;gpiof…

数据结构与算法三【树】

二叉树性质 满二叉树 深度为k&#xff0c;有2k−12^{k}-12k−1个结点的二叉树&#xff0c;为满二叉树。 完全二叉树 完全二叉树的定义如下&#xff1a;在完全二叉树中&#xff0c;除了最底层节点可能没填满外&#xff0c;其余每层节点数都达到最大值&#xff0c;并且最下面…

【jQuery】常用API——jQuery选择器

一、 jQuery基础选择器原生JS获取元素方式很多&#xff0c;很杂&#xff0c;而且兼容性情况不一致&#xff0c;因此jQuery给我们做了封装&#xff0c;使荻取元素统一标准。$(“选择器”); //里面选择器直接写CSS选择器即可&#xff0c;但是要加号<script src"../jquery…

Ubuntu18.04系统 部署python3.9.0 源码编译安装及pip配置全过程记录

1.Ubuntu系统镜像下载和基本配置 1.1 镜像下载 镜像下载&#xff1a;https://cn.ubuntu.com/download/desktop 1.2 配置静态IP 配置固定IP方式&#xff1a; Ubuntu18之前在/etc/network/interfaces进行配置&#xff0c;Ubuntu18及之后版本在/etc/netplan/*.yaml进行配置&am…

Node.JS(1)

目录 命令行窗口&#xff08;cmd窗口、小黑屏、终端、shell&#xff09; 环境变量 命令行窗口&#xff08;cmd窗口、小黑屏、终端、shell&#xff09; winR快捷键-->cmd 常用指令 dir 列出当前目录下的所有文件 cd 目录名 进入到指定的目录 md 目录名 创建一个文件…

redis安装和使用说明

Redis安装说明大多数企业都是基于Linux服务器来部署项目&#xff0c;而且Redis官方也没有提供Windows版本的安装包。因此课程中我们会基于Linux系统来安装Redis.此处选择的Linux版本为CentOS 7.Redis的官方网站地址&#xff1a;https://redis.io/1.单机安装Redis1.1.安装Redis依…

数字验证学习笔记——SystemVerilog芯片验证23 ——数据采样

一、数据采样 当你coverpoint指定采样一个变量或表达式时&#xff0c;SV会创建很多“仓&#xff08;bin&#xff09;”来记录每个数值被捕捉到的次数。这些bin是衡量功能覆盖率的基本单位。covergroup中可以定义多个coverpoint&#xff0c;coverpoint中可以自定义多个cover bi…

SAP灵活工作流场景模板创建

目录 1. 创建流程对象容器 2. 编辑模板中的灵活块 3. 设置工作流启动事件 4. 设置工作流运行时事件 5. 设置工作流输出结果&#xff08;可选&#xff09; 6. 工作流控制类 7. 创建流程活动 8. 创建流程条件 9. 代理规则 9. 值帮助 10. 参考时间 11. 电子邮件模版 …

[ AWS - SAA ] 解决方案架构师之设计弹性架构 - 选择可靠的弹性存储(如何选择 SSD vs. HDD)

本系列博文会围绕AWS Well-Architected 和六大支柱进行讲解&#xff0c;这些领域的内容对成为AWS亚马逊云科技上的 解决方案架构师&#xff08;SAA&#xff09; 非常重要。 本文主要介绍AWS亚马逊云中&#xff0c;关于弹性架构设计中存储设备的一些讲解。 本文的部分内容适用于…

哈希切割 + 位图 + 布隆过滤器 —— 海量数据面试题

目录 题目一&#xff1a;给一个超过100G大小的log file, log中存着IP地址, 设计算法找到出现次数最多的IP地址&#xff1f; 哈希切割 题目二&#xff1a;给定100亿个整数&#xff0c;设计算法找到只出现一次的整数&#xff1f; 解法一&#xff1a;哈希切割 解法二&#xf…

【论文精读】Guided-MVS

今天读的是一篇发表在IROS2022上的MVS文章&#xff1a;Multi-View Guided Multi-View Stereo&#xff0c;作者是来自于意大利University of Bologna的Matteo Poggi。 论文链接&#xff1a;arxiv 代码链接&#xff1a;https://github.com/andreaconti/multi-view-guided-multi-v…

SpringCloud Netflix复习之OpenFeign

文章目录写作背景Feign核心组件介绍Encoder和DecoderLoggerContractFeign.Builder上手实战开启FeignClient调用请求日志给FeignClient注入自定义拦截器Feign支持文件上传配置Feign开启Gzip压缩Feign配置超时时间Feign整合Ribbon支持负载均衡核心源码部分FeignClient注入到Sprin…

【Qt】通过创建ui界面类成员变量的方式显示窗体

【Qt】通过创建ui界面类成员变量的方式显示窗体1、背景2、实例3、验证1、背景 将.ui 文件转化为.h 头文件参考&#xff1a; 【Qt】将QtDesigner生成的.ui文件转化为.h头文件 https://jn10010537.blog.csdn.net/article/details/128589666其生成的.h头文件的显示&#xff0c;如…