在CentOS服务器运维中,TCP连接状态异常往往是攻击发生的最早信号。很多运维人员习惯在流量飙升或服务响应变慢后才去查问题,但此时攻击可能已经持续了一段时间。更有效的做法是直接观察TCP连接状态的变化,尤其是SYN_RECV、ESTABLISHED、TIME_WAIT、CLOSE_WAIT这几类关键状态的数值和比例。正常的业务流量会有相对稳定的连接状态分布,而SYN Flood、CC攻击、端口扫描、TCP连接耗尽等行为都会在连接状态上留下非常明显的指纹。下面直接讲如何通过TCP连接状态识别攻击,以及具体的排查和处置方法。

先理解TCP连接状态与攻击的对应关系

TCP连接的状态转换本身是固定的,但攻击会打破正常比例。SYN_RECV状态表示服务器收到了SYN包并回复了SYN+ACK,但还没收到客户端的ACK确认。如果SYN_RECV数量短时间内从几十涨到几万甚至几十万,基本可以判定是SYN Flood攻击。攻击者伪造大量源IP发送SYN包,服务器为每个半开连接分配资源,最终导致内存和连接表耗尽。在CentOS上可以用以下命令查看当前各状态的数量:

netstat -ant | awk '{print $6}' | sort | uniq -c | sort -n

如果SYN_RECV数量异常高,并且源IP分布非常分散,甚至很多IP段在公网上根本不存在,那就可以确认是SYN Flood。另一个关键状态是ESTABLISHED,它代表已经完成三次握手的连接。如果ESTABLISHED数量远超业务正常水平,并且单个源IP或少数几个源IP建立了大量连接,这通常是CC攻击或者慢速连接耗尽攻击。攻击者用真实IP完成握手,然后保持连接不释放,占满服务器的连接数上限,导致正常用户无法建立新连接。

通过源IP聚合快速定位攻击来源

单看状态总数还不够,必须结合源IP聚合分析。对于SYN_RECV状态,可以用以下命令统计每个源IP的半开连接数:

netstat -ant | grep SYN_RECV | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -rn | head -20

如果攻击者使用了真实源IP,这个命令会直接暴露攻击源。但SYN Flood大多数情况下源IP是伪造的,聚合出来的IP数量可能非常庞大且分散,此时需要进一步分析IP的分布特征。对于ESTABLISHED状态的异常,聚合源IP非常有效。比如某个IP建立了超过500个连接,而正常用户通常只有几个到十几个连接,这个IP就非常可疑。命令如下:

netstat -ant | grep ESTABLISHED | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -rn | head -20

如果发现少数IP连接数异常高,可以直接用iptables封禁这些IP。但要注意,如果是NAT出口的IP,比如公司或学校共用一个公网IP,封禁可能会误伤正常用户。所以封禁前最好结合业务日志确认这些IP是否有正常的访问行为。

TIME_WAIT和CLOSE_WAIT的异常同样值得警惕

TIME_WAIT状态是主动关闭连接的一方在等待2MSL时间后进入CLOSED,这是正常的TCP行为。但如果TIME_WAIT数量异常高,比如达到几万甚至十几万,说明服务器在短时间内主动关闭了大量连接。这可能是短连接业务在高并发下的正常表现,也可能是攻击者频繁建立和断开连接,消耗服务器的端口资源。CentOS默认的TIME_WAIT超时时间是60秒,如果连接建立和断开的速度过快,端口会被迅速占满,导致无法建立新的出站连接。可以通过调整内核参数来缓解:

sysctl -w net.ipv4.tcp_tw_reuse=1
sysctl -w net.ipv4.tcp_tw_recycle=0
sysctl -w net.ipv4.tcp_fin_timeout=30

注意tcp_tw_recycle在较新的内核中已经被移除,而且它在NAT环境下会导致问题,所以不建议开启。tcp_tw_reuse可以安全地复用TIME_WAIT状态的端口。CLOSE_WAIT状态则完全不同,它表示对端已经关闭连接,但本地应用程序没有调用close()来关闭socket。如果CLOSE_WAIT数量持续增长,说明应用程序存在bug或者资源泄漏,比如代码中忘记关闭数据库连接或HTTP连接。这不是直接的攻击,但攻击者可以利用这个漏洞,通过发送大量请求并主动断开连接,让服务器端的CLOSE_WAIT不断累积,最终耗尽文件描述符。排查方法是查看哪些进程持有大量CLOSE_WAIT连接:

ss -antp | grep CLOSE_WAIT

然后检查对应进程的代码逻辑,确保在连接异常或请求处理完成后正确关闭socket。

利用ss命令进行更精细的连接分析

netstat在连接数非常大的时候性能会下降,而且输出速度慢。推荐使用ss命令,它直接读取内核socket信息,速度更快,信息更全。比如查看当前所有TCP连接的状态汇总:

ss -s

查看SYN_RECV状态的连接及其源地址:

ss -tan state syn-recv

查看某个进程的所有连接:

ss -tanp | grep nginx

ss命令还支持按状态过滤,state参数可以指定established、syn-sent、syn-recv、fin-wait-1、fin-wait-2、time-wait、closed、close-wait、last-ack、listen、closing等。在排查攻击时,用ss配合awk和sort可以快速得到统计结果。例如统计每个源IP的ESTABLISHED连接数:

ss -tan state established | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -rn | head -20

ss输出的第五列是Peer Address:Port,格式与netstat略有不同,但处理方式类似。需要注意的是,IPv6地址的格式包含冒号,用cut -d: -f1可能会截断,如果服务器启用了IPv6,建议先用grep过滤掉IPv6或者使用更精确的awk字段处理。

结合内核日志和连接跟踪表识别攻击类型

TCP连接状态只是表象,要确认攻击类型还需要结合内核日志。CentOS的dmesg或/var/log/messages中如果出现大量“possible SYN flooding”日志,说明内核的SYN队列已经被打满,这是SYN Flood的典型特征。可以通过以下命令查看:

dmesg | grep -i "syn flood"

如果日志中有“nf_conntrack: table full, dropping packet”,说明连接跟踪表被占满,这通常是连接耗尽攻击或者大量短连接导致的。连接跟踪表的大小可以通过sysctl查看和调整:

sysctl net.netfilter.nf_conntrack_max
sysctl net.netfilter.nf_conntrack_count

如果nf_conntrack_count接近nf_conntrack_max,就需要排查是正常业务增长还是攻击。攻击者如果发送大量伪造源IP的包,连接跟踪表会迅速被占满,导致正常连接被丢弃。此时可以临时增大nf_conntrack_max,但根本解决办法是封禁攻击源或启用更严格的防火墙规则。

基于TCP连接状态的自动化监控与告警

人工登录服务器查看连接状态只能用于事后排查,要第一时间发现攻击,必须建立自动化监控。可以在CentOS上写一个简单的shell脚本,每分钟统计一次各状态连接数,如果SYN_RECV或ESTABLISHED超过阈值就触发告警。脚本示例:

#!/bin/bash
SYN_RECV=$(ss -tan state syn-recv | wc -l)
ESTAB=$(ss -tan state established | wc -l)
if [ "$SYN_RECV" -gt 1000 ]; then
    echo "SYN_RECV too high: $SYN_RECV" | mail -s "SYN Flood Alert" admin@example.com
fi
if [ "$ESTAB" -gt 50000 ]; then
    echo "ESTABLISHED too high: $ESTAB" | mail -s "Connection Exhaustion Alert" admin@example.com
fi

将这个脚本加入crontab每分钟执行一次。更完善的做法是结合Prometheus和node_exporter,通过node_netstat_Tcp_CurrEstab等指标进行监控和告警。但无论用哪种方式,核心监控指标都应该是SYN_RECV、ESTABLISHED、CLOSE_WAIT这几个状态的数量和变化趋势。单纯的流量监控无法区分正常高峰和攻击,而连接状态的比例变化能更准确地反映攻击特征。

处置措施:从临时封禁到内核参数加固

确认攻击后,第一步是封禁攻击源IP。对于真实源IP的攻击,直接用iptables封禁:

iptables -I INPUT -s 攻击IP -j DROP

对于伪造源IP的SYN Flood,封禁单个IP没有意义,需要启用SYN Cookie机制。CentOS默认已经开启SYN Cookie,但可以确认一下:

sysctl net.ipv4.tcp_syncookies

如果值为1说明已开启。SYN Cookie可以在SYN队列满时仍然响应新的SYN请求,通过计算一个特殊的Cookie来验证客户端,而不需要为每个半开连接分配资源。同时可以调整SYN队列的大小:

sysctl -w net.ipv4.tcp_max_syn_backlog=8192
sysctl -w net.core.somaxconn=8192

对于连接耗尽攻击,除了封禁源IP,还可以限制单个IP的最大连接数。使用iptables的connlimit模块:

iptables -I INPUT -p tcp --dport 80 -m connlimit --connlimit-above 50 -j DROP

这条规则限制每个IP对80端口最多同时建立50个连接,超过的直接丢弃。对于慢速连接攻击,可以调整TCP超时时间,让空闲连接更快被回收:

sysctl -w net.ipv4.tcp_keepalive_time=600
sysctl -w net.ipv4.tcp_keepalive_intvl=30
sysctl -w net.ipv4.tcp_keepalive_probes=3

这些参数让服务器更快地检测并清理死连接,减少资源占用。

长期策略:基于行为分析的连接状态基线

每次攻击都靠人工临时处理不是长久之计。运维人员应该为每台CentOS服务器建立TCP连接状态的基线。正常业务下,SYN_RECV通常只占总连接数的1%以下,ESTABLISHED占比最高,TIME_WAIT在短连接业务中可能较多但相对稳定,CLOSE_WAIT应该接近零。记录一周内不同时段的连接状态分布,计算出正常波动范围。当某个状态的比例突然偏离基线超过一定幅度,比如SYN_RECV占比超过5%,或者CLOSE_WAIT从零增长到几百,就触发告警。这种基于基线的监控比固定阈值更准确,能适应业务的自然增长和周期性波动。同时,定期分析连接日志,找出哪些源IP、哪些目标端口、哪些时间段的连接行为异常,逐步建立IP信誉库。对于反复出现异常行为的IP段,可以在防火墙层面提前限制。

TCP连接状态是服务器健康度的直接反映,也是攻击识别最原始、最可靠的数据来源。运维人员不需要依赖复杂的商业安全设备,只要熟练掌握ss、netstat、iptables和sysctl这几个工具,就能在攻击发生的早期阶段发现并处置。关键是养成持续观察连接状态的习惯,而不是等到服务不可用了才去查。