Linux内核协议栈丢弃SYN报文的主要场景剖析

本文分析了Linux内核丢弃TCP SYN报文的两个主要场景:Per-host PAWS检查和Accept Queue满。Per-host PAWS在某些NAT环境可能导致连接时通时不通,而Accept Queue满可能是应用程序处理连接不及时所导致。解决建议包括关闭net.ipv4.tcp_tw_recycle和调整accept queue长度。
摘要由CSDN通过智能技术生成

在排查网络问题的时候,经常会遇见TCP连接建立不成功的场景。如果能获取到两端抓包,两端抓包看起来如下:

  • 客户端在一直按照指数退避重传TCP SYN (因为首包没有获取到RTT及RTO,会在1, 2, 4, 8秒…
    重传,直到完成net.ipv4.tcp_syn_retries次重传)
  • 服务器端能看到TCP SYN报文已经到达网卡,但是TCP协议栈没有任何回包。

因为这样的问题出现的频率不小,本文会从TCP协议栈方面总结常见原因。所谓的TCP协议栈方面的原因,就是TCP SYN报文已经到了内核的TCP处理模块,但在服务器端内核逻辑中不给客户端回SYNACK。客户端一直重传TCP SYN也可能由别的原因造成,比如服务器端有多块网卡造成的出入路径不一致,或者SYN报文被iptables规则阻拦,这些场景都不在本文的讨论范围之内。

Listen状态下处理TCP SYN的代码逻辑

本文以很多用户使用的CentOS 7的内核版本为基础,看看下TCP处理SYN的主要逻辑,结合案例处理的经验来分析主要可能出问题的点。处于listen状态的socket处理第一个TCP SYN报文的逻辑大概如下:

tcp_v4_do_rcv() @net/ipv4/tcp_ipv4.c
        |--> tcp_rcv_state_process() @net/ipv4/tcp_input.c // 这个函数实现了绝大TCP状态下的接受报文的处理过程 (ESTABLISHED和TIME_WAIT除外),当然包括了我们关注的LISTEN状态
                |--> tcp_v4_conn_request() @@net/ipv4/tcp_ipv4.c // 当TCP socket出于LISTEN状态,且接收报文中TCP SYN flag是置位的,就来到这个函数中处理

CentOS中内核代码可能会有些调整,如果你需要跟踪源代码的确切行数,systemtap是一个很好的方法,如下:

# uname -r
3.10.0-693.2.2.el7.x86_64
# stap -l 'kernel.function("tcp_v4_conn_request")'
kernel.function("tcp_v4_conn_request@net/ipv4/tcp_ipv4.c:1303")

来到tcp_v4_conn_request()的逻辑里,函数逻辑的前几行如下:

在这里插入图片描述

进入到这个函数的前提条件是TCP socket出于LISTEN状态,且接收报文中TCP SYN flag是置位的。在进入函数逻辑后,可以发现函数要考虑各种可能发生的异常情况,但在现实中很多并不常见。比如我们在前几行看到的这两种情况:

  • 1482行:拒绝广播和组播报文。
  • 1490行:如果request queue (存放SYN报文的队列)满了,且isn为0,且want_cookie为flase,
    则drop掉SYN报文。

第一种情况意思比较明确,在实际中也没见过,在这里不讨论。第二种情况略为复杂,并且有小概率可能会碰到,下面简单看看:

第一个条件request queue 满实际是很容易发生的事情,syn flood攻击很容易完成这件事情。而isn在函数开始被赋值成TCP_SKB_CB(skb)->when,这个是TCP控制块结构体中用于计算RTT的字段。want_cookie则代表这syn syncookies的使用与否。在tcp_syn_flood_action()中的定义如下,如果ifdef了CONFIG_SYN_COOKIES, 内核参数的net.ipv4.tcp_syncookies也设置成1,则概述的返回是true, want_cookie则为true。
在这里插入图片描述

所以在上面这种drop SYN报文的情况中,真正的前提条件是没有开启net.ipv4.tcp_syncookies这个内核参数。而在实际生产系统中,net.ipv4.tcp_syncookies默认是打开的。Syn syncookies是一种时间(CPU计算)换空间(request queue队列)来抵御syn flood攻击的方式,在实际生产中看不到任何场景需要显示地关闭这个开关。所以总的来讲,1490行中这种请求在实际中也不太常见。

内核drop SYN报文的主要场景

本文的主要目的不是按照代码逻辑依次描述drop SYN报文的所有场景,而是结合之前的实际经验描述两种主要可能丢SYN报文的场景以及如何迅速判断的方

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值