[原创]分析解决lvs fullnat模式下后端服务器获取真实IP地址异常问题

本文涉及的产品
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
简介: 分析解决lvs fullnat模式下少量的请求记录client IP不是用户真实的IP地址问题.

摘要

分析解决lvs fullnat模式下少量的请求记录client IP不是用户真实的IP地址问题.

原创文章:来自分析lvs fullnat模式下后端服务器获取真实IP地址异常问题

问题背景

lvs fullnat模式下观察后端服务器realserver http/https业务运行系统日志,有时候可以发现有少量的请求记录的client IP不是用户真实的IP地址(存在但出现的概率很小,增加了问题排查的难度),而是属于lvs主机私有的IP地址。关于fullnat的简介可以参考http://www.baokaijian.com/?tag=fullnat, 这里借用一下文中的图片。
1

问题分析

大多数TCP正常建立连接过程
2.png

realserver linux系统属于用户自属管理默认配置MTU=1500、MSS=1460,在TCP建连时可以通过syn+ack报文通告给client,而client端可属于移动端或PC端MTU、MSS的差异性较大,通过syn报文通告给realserver端,从而建立的TCP连接取两者之小值做为链路的MSS。中间的LVS只是做连接与报文转发的负载均衡。

fullnat 模式下获取真实IP地址的原理:
开源的lvs fullnat代码与patch可查阅lvs官方网址http://kb.linuxvirtualserver.org/wiki/IPVS_FULLNAT_and_SYNPROXY

lvs fullnat应用模式通过TCP三次握手的ack,ack+data报文将client端的真实IP地址插入到tcp options中从而带给后端的realserver。而后端realserver toa内核模块中通过hook了tcp_v4_syn_recv_sock()函数,然后调用get_toa_data()从tcp_options中取得客户端的真实IP地址,具体的调用过程下边分析。

非标准的tcp三次握手情况分析

先来看以下几个典型的报文序列是否可以建立三次握手:

  1. 乱序的情况(第三个ack和第四个ack+data报文乱序)
    3.png
  2. 直接使用ack+data报文(或含有push标志)不存在bare ack报文

4.png

3.直接使用fin+ack+data报文( 或含有push标志)

5.png

来点内核TCP代码中深度分析:

看一下建立TCP连接时两次经过的tcp_v4_hnd_req函数流程.

syn报文到来时的处理流程:

tcp_v4_rcv() -->tcp_v4_do_rcv()-->tcp_v4_hnd_req()

查找代表客户端连接的sock结构,如果没有找到则返回代表服务器的sock结构, 然后在tcp_rcv_state_process()函数中调用tcp_v4_conn_request()创建req_sock请求结构并放入半连接队列。

握手阶段收到第三个ack报文或其他携带ACK标志的报文处理,tcp_v4_hnd_req()函数将返回代表连接请求的sock结构.

tcp_v4_rcv() ->tcp_v4_do_rcv()-->tcp_v4_hnd_req()-->tcp_check_req()-->tcp_v4_syn_recv_sock()

tcp_v4_syn_recv_sock()函数中将对报文序列号判断,并完成握手,最后将连接请求从半连接请求移到全连接队列,等待应用层调用accept。

特别注意在tcp_check_req()函数中检查了clinet端到来报文的序列号

/* RFC793 page 36: "If the connection is in any non-synchronized state ...
 * and the incoming segment acknowledges something not yet
 * sent (the segment carries an unacceptable ACK) ...
 * a reset is sent."
 *
 * Invalid ACK: reset will be sent by listening socket
 */
    if ((flg & TCP_FLAG_ACK) &&// 正常情况下 收包的ack_seq = 初始发送的seq + 1(syn)
        (TCP_SKB_CB(skb)->ack_seq !=    //此报序列号不等于发送初始序列号         tcp_rsk(req)->snt_isn + 1 + tcp_s_data_size(tcp_sk(sk))))
        return sk;

结论: 完成握手最后一个clinet端到来报文ack序号必须是client 端tcp连接ISN初始序号+1(没有检查seq序列号),所以只要符合此规则的都可以通过,然后调用调用tcp_v4_syn_recv_sock()从而调用toa模块取client IP tcp options。再解释明白点: 非bare ack乱序报文即带有数据的ack报文,也可以通过。注:至于seq序列号有效性以及影响能不能真正完成连接建立,这是在后续的tcp_ack()中判断了。

接着tcp_v4_syn_recv_sock()函数中创建代表与client端连接的sock结构(设置此条TCP连接状态是TCP_SYN_RECV),然后在tcp_rcv_state_process()函数中case TCP_SYN_RECV代码段中通过tcp_set_state(sk, TCP_ESTABLISHED); 改状态为ESTABLISHED连接状态。

经过在toa模块中探点调试发现:

  1. 从realserver端看到大量使用FIN+ACK+PUSH的含数据报文完成三次握手,这时也不能插入toa options(用户业务很多用http/https这种post请求推数据,realserver收到后会回复response,但若是反向代理的proxy收到后会FIN掉client,同时向后端realserver再发RST报文)
  2. 上述图中因乱序或直接ack+data报文没超但达到了1444字节(假如toa需要16字节); 使用ack+data报文完成了三次握手, 使lvs层不能插入用户的IP:PORT

改进建议

官方lvs fullnat代码:
http://kb.linuxvirtualserver.org/wiki/IPVS_FULLNAT_and_SYNPROXY
Lvs-fullnat-synproxy.tar.gz 包中包含fullnat 和toa的patch.

1、 lvs代码tcp_fnat_in_handler()函数中去掉!tcph->fin的条件判断,可以解决FIN+PUSH+ACK+数据报文中不能携带client端ip与端口的缺陷

6

2、 后端RS建立监听时直接使用 setsockopt, 将MSS改小(如toa需要16字节则可减小到1444字节), 从而client到来的报文可以有插入clientip:port的空间

3、 (第2条的替代方法但会增加lvs处理的复杂性:
TCP握手阶段lvs收到后端RS发送的syn+ack报文时,将其中的MSS改小(如16字节),传给client, 从而client到来的报文就有了插入clientip:port的空间。
另一种方法虽然client发送来的报文已经达到了client与RS协商的MSS(如1460), 但若lvs与RS之间设置的MTU(如9000)要大于client与LVS之间的值1460, 并且tcp options有足够的空间可以强制在tcp options中插入clientip:port)

4、以上修改后最后还是不行(可能存在非标准的client tcp处理),建议客户端程序(特别是手机APP)建立socket时使用 setsockopt 将MSS改小适当的数值(发现存在有部分终端出现通告给其MSS是1444,但仍然发送1460的报文)

备注:

  1. tcp options满载40字节,如果在握手时用户有插入自己的数据占满则lvs判断没有空间再插入用户IP了。
  2. 发现手机终端的MSS值多种多样,这里列里几个值, 1412 1120 1452 1400 1394 1260 1460
相关实践学习
容器服务Serverless版ACK Serverless 快速入门:在线魔方应用部署和监控
通过本实验,您将了解到容器服务Serverless版ACK Serverless 的基本产品能力,即可以实现快速部署一个在线魔方应用,并借助阿里云容器服务成熟的产品生态,实现在线应用的企业级监控,提升应用稳定性。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
目录
相关文章
若依修改,若依部署在本地运行时的注意事项,后端连接了服务器,本地的vue.config.js要先改成localhost:端口号与后端匹配,部署的时候再改公网IP:端口号
若依修改,若依部署在本地运行时的注意事项,后端连接了服务器,本地的vue.config.js要先改成localhost:端口号与后端匹配,部署的时候再改公网IP:端口号
|
9天前
|
前端开发 NoSQL 数据库
部署常用的流程,可以用后端,连接宝塔,将IP地址修改好,本地只要连接好了,在本地上前后端跑起来,前端能够跑起来,改好了config.js资料,后端修改好数据库和连接redis,本地上跑成功了,再改
部署常用的流程,可以用后端,连接宝塔,将IP地址修改好,本地只要连接好了,在本地上前后端跑起来,前端能够跑起来,改好了config.js资料,后端修改好数据库和连接redis,本地上跑成功了,再改
|
13天前
|
网络协议 安全 Linux
在IntelliJ IDEA中使用固定公网地址远程SSH连接服务器环境进行开发
在IntelliJ IDEA中使用固定公网地址远程SSH连接服务器环境进行开发
18 2
|
21天前
|
负载均衡 监控 搜索推荐
蓝易云 - 多ip站群服务器如何选择?能做什么
这些只是一些基本的考虑和能力,具体的选择和使用方式会根据你的具体需求和目标而变化。
29 3
|
9天前
|
Web App开发
软件开发常见流程之移动端调试方法,利用Chrome(谷歌浏览器)的模拟手机调试,搭建本地Web服务器,手机和服务器在一个局域网,通过手机访问服务器,使用服务器,利用ip实现域名访问
软件开发常见流程之移动端调试方法,利用Chrome(谷歌浏览器)的模拟手机调试,搭建本地Web服务器,手机和服务器在一个局域网,通过手机访问服务器,使用服务器,利用ip实现域名访问
|
11天前
|
前端开发 JavaScript Java
文本----简单编写文章的方法(中),后端接口的编写,自己编写好页面就上传到自己的服务器上,使用富文本编辑器进行编辑,想写好一个项目,先分析一下需求,再理一下实现思路,再搞几层,配好参数校验,lomb
文本----简单编写文章的方法(中),后端接口的编写,自己编写好页面就上传到自己的服务器上,使用富文本编辑器进行编辑,想写好一个项目,先分析一下需求,再理一下实现思路,再搞几层,配好参数校验,lomb
|
11天前
|
安全 网络协议 数据挖掘
游戏盾如何隐藏服务器真实IP
游戏盾采用了智能分布式云接入系统,通过部署接入服务,使得游戏客户端不再直接与源服务器建立连接,而是通过游戏盾连接至分布在各地的高防节点。这一架构不仅实现了网络加速,还巧妙地隐藏了源服务器的真实IP地址,使得攻击者难以直接定位到真实的服务器。
|
4天前
|
存储 关系型数据库 数据库
给阿里云的建议和意见 一个云服务器架构是否可行
摘要(Markdown格式): 在修复阿里云服务器IPv4设置错误时遇到困难,导致服务器远程登录失败及外网访问受阻,耗时三天解决。建议阿里云更新文档,确保设置指导与实际情况一致,例如只需在路由表添加条目关联IPv4。此外,建议优化帮助页面,如采用折叠式设计减少干扰。服务器主要任务是数据分析、存储和分发,文中提出简化服务器框架,消除硬件软件复杂配置,利于初学者和独立开发者快速上手,降低时间成本。该设计旨在减少无用组件,节省资源,同时降低云服务商的人力和支持成本。期望云服务商考虑此类架构创新。目前未知是否有类似产品,期待业界反馈。
206 0
给阿里云的建议和意见 一个云服务器架构是否可行
|
6天前
|
存储 编解码 网络协议
阿里云服务器计算型和通用型四代云服务器实例区别及选择参考
目前阿里云在售的云服务器中,计算型和通用型实例规格都包含了第5代、第6代、第7代和最新第八代倚天云服务器产品,例如计算型实例中有c5、c6、c7、c8y实例,而通用型实例有g5、g6、g7、g8y等实例,有的新手用户并不清楚这四代产品之间的差别,本文为大家展示这四代云服务器实例在规格、CPU(核)、内存(G)、计算、存储、内存以及不同配置的指标数据等方面为大家做个对比,让大家了解一下他们之间的不同,以供参考和选择。
阿里云服务器计算型和通用型四代云服务器实例区别及选择参考
|
2天前
|
弹性计算 运维 安全
阿里云ecs使用体验
整了台服务器部署项目上线

热门文章

最新文章