ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Linux连接跟踪表(conntrack)实战指南:从原理到排查技巧

Linux连接跟踪表(conntrack)实战指南:从原理到排查技巧 干这行这么多年排查各种网络问题时我十有八九最后都会落到一个命令上查连接跟踪表。不管你是搞运维的、做安全的还是自己搭服务器玩只要你跟Linux防火墙、NAT打过交道就一定绕不开这玩意儿。简单说它就是内核里的一张大表记录着当前系统上所有正在进行的网络连接的状态和元数据。这张表一旦满或者乱了你就会看到各种诡异的现象网站突然卡死、NAT转发失效、防火墙放行了却还是不通、连接数爆表被攻击却不知道是谁干的。这篇文章我就带你把这个连接跟踪彻底摸透。不仅仅是告诉你看哪个文件、敲哪条命令更重要的是让你明白表里那些字段到底是什么意思、怎么从几百条甚至几万条记录里快速揪出你想要的会话、系统报错的时候怎么定位和调优。整篇内容基于我在实际环境里踩过的坑总结出来的Linux发行版以CentOS/RHEL系为主Debian/Ubuntu系原理完全一致命令通用。1. 连接跟踪是什么它为什么这么重要1.1 从防火墙的状态概念说起绝大多数现代防火墙包括Linux下的iptables/nftables都不是傻乎乎地一条条比对规则的。它们都支持状态防火墙Stateful Firewall机制。什么意思呢就是你第一次发起连接时防火墙会严格检查规则一旦放行它就把这个连接记到一张表里。后续这个连接的所有数据包只要跟表里的记录能对上号就直接放行不用再重新匹配那堆规则了。这张表就是连接跟踪表。Linux内核里它叫conntrack你可以把它理解成快递公司的在途包裹登记簿每个包裹数据包属于哪个订单连接往哪送送到了没有都在簿子上记得清清楚楚。没有这本簿子防火墙就得拆开每一个包裹重新审核那效率得低到什么程度去。所以可以说连接跟踪是现代防火墙高效工作的基石。1.2 为什么排查问题必须先看它我碰到过太多类似的情况业务方说某台服务器连不通了我第一眼不会去翻防火墙规则而是先看连接跟踪表有没有异常。因为规则是静态的写在那里就那么几条错没错一眼能看出来。但连接状态是动态的可能昨晚一个大并发把表撑爆了可能某个IP发了一大堆畸形包把表刷满了也可能NAT会话老化时间太长导致表项堆积。这些问题光看规则是看不出来的必须看连接跟踪。它能告诉你三件事系统当前有多少活跃连接、这些连接是什么状态的、有没有异常来源在疯狂建连。基本上网络故障的排查思路三分之二都要从这张表开始。你要是能熟练地查表、过滤、统计、清表那排查效率直接上一个台阶不用再靠瞎猜重启防火墙碰运气。2. 查看连接跟踪的两种核心路径2.1 直接读内核文件/proc/net/nf_conntrack先说说最原始、最通用的方式。Linux内核会把连接跟踪表暴露在/proc/net/nf_conntrack这个虚拟文件里你不需要装任何额外工具直接就能读。这个文件是纯文本的一行就是一条连接记录。执行cat /proc/net/nf_conntrack你看到的每一行大概长这样ipv4 2 tcp 6 431992 ESTABLISHED src192.168.1.10 dst193.32.216.78 sport52034 dport443 packets7 bytes482 src193.32.216.78 dst192.168.1.10 sport443 dport52034 packets5 bytes1053 [ASSURED] mark0 zone0 use2乍一看有点头大但拆开就清楚了。前面几段是协议基本信息ipv4是地址族2是地址族编号tcp是传输层协议6是协议编号431992是这条连接的超时时间秒。接着是连接状态ESTABLISHED这个很关键后面细说。然后一串src/dst/sport/dport构成了完整的四元组——注意连接跟踪表里同时记录了原始方向和回复方向的两组地址端口。这就是它高明的地方不管数据包是从哪个方向来的只要它能跟其中一组对上就能确认属于这条曾经放行的连接。packets和bytes是这两个方向分别统计的报文数和字节数做流量分析的时候很有用。[ASSURED]标记表示这条连接已经在两个方向都有过通信是确认有效的连接如果表满了要清理会优先删掉没有这个标记的。最后mark是防火墙打上的标记zone是区域隔离用的日常排查不太用管。不过说实话直接cat这个文件在连接数少的时候还行一旦生产环境的连接数上到几万几十万你会看到屏幕上滚出来几千几万行根本看不过来。所以实际使用中我更推荐先用wc -l看看总行数wc -l /proc/net/nf_conntrack这个数字就是当前连接跟踪条目总数对比系统限制值你就能判断表有没有接近打满。2.2 用conntrack工具查得更爽直接读文件虽然零成本但过滤能力太弱了。生产环境我更推荐用conntrack命令行工具这个工具是专门操作和管理连接跟踪表的。Debian/Ubuntu下包名是conntrackCentOS/RHEL系是conntrack-tools# CentOS/RHEL yum install -y conntrack-tools # Debian/Ubuntu apt install -y conntrack装好之后最常用的就是-L参数列出当前所有连接跟踪条目conntrack -L它的输出跟/proc文件格式基本一样。真正的优势在于你能用-p、-s、-d这些参数做过滤不用再费劲去grep。比如我查某台服务器跟外部的所有TCP连接conntrack -L -p tcp -s 192.168.1.10再比如查使用了NAT转换的条目加上-n参数配合src或dst指定NAT前后的地址conntrack -L -n -d 192.168.1.10这些过滤选项组合起来比纯文本grep高效得多而且输出更规范。不过要注意这个工具查的是当前这台机器上的连接跟踪表你要是管理工作在商用的硬件防火墙上那是另一套查看方式这点后面我单独说。3. 连接跟踪表里的关键字段和状态解读3.1 四种连接状态必须刻在脑子里连接跟踪表里每条记录都有状态Linux的conntrack核心状态就四种NEW、ESTABLISHED、RELATED、INVALID。我直接用大白话解释一遍NEW刚看到第一个包这条连接是全新的还没确认对端是否回应。典型的比如TCP三次握手的SYN包UDP的头一个包都会先标成NEW。防火墙规则里-m state --state NEW放行的就是这些首包。ESTABLISHED连接已经建立起来了。TCP就是握手完成UDP只要看到对端回包也会升级成这个状态。绝大多数正常流量都是这个状态。如果你数连接数数这个状态的最实在。RELATED这条连接跟某条已经存在的ESTABLISHED连接有关系。最典型的例子就是FTP的数据连接。FTP控制连接在21端口传输数据时服务器会反连客户端的随机端口这条新连接如果没有RELATED机制防火墙会当成全新连接给拦了。所以在实际配置中RELATED通常要跟ESTABLISHED一起放行。INVALID这个包找不到任何对应的连接或者本身就不合法。比如TCP的RST乱飞、伪造的包、报文状态对不上的。如果你的日志里INVALID连接很多那基本可以断定有人在扫你或者你NAT配置有毛病导致公网包内网乱窜。我实际排查时最关注的就是INVALID和NEW这两个状态。INVALID多了说明有攻击或配置错误NEW数量飙升说明可能在被SYN Flood或者某个业务在疯狂建立连接。3.2 学会用awk统计和过滤光会看单条记录还不够生产环境最重要的是统计。最常用的场景我要看当前所有连接里有多少条是TCP有多少条是UDP各占多少。一条awk就搞定cat /proc/net/nf_conntrack | awk {print $3} | sort | uniq -c | sort -nr这里$3是协议名在ipv4那一段里第三个字段是协议统计出来效果就是52395 tcp 12031 udp 387 icmp 120 dccp ...看到TCP占了绝大部分这是正常的因为HTTP/HTTPS/SSH全是TCP。但如果UDP或者ICMP异常多就要留个心眼了多半是DNS放大攻击或者异常隧道、P2P流量。再比如我想统计某个客户端IP一共发起了多少连接、都连到哪些端口可以这样grep src192.168.1.10 /proc/net/nf_conntrack | awk {print $5} | sort | uniq -c这个$5是dst字段统计出来就能看出这个客户端到底在访问哪些目标。如果是你自己的服务器被外部IP大量连进来就反过来看src等于对方IP的行数快速判断是不是被刷了连接。统计完之后比较有意思的是用sort -n对连接数做一下归一化比如统计外部IP往你服务器80端口发起连接TOP 10cat /proc/net/nf_conntrack | grep dport80 | awk {print $6} | sort | uniq -c | sort -nr | head -10输出前三列分别是连接数、源IP一眼就能锁定是不是某个IP恶意刷连接。这个命令组合我几乎天天用比瞪着防火墙日志刷效率高得多。4. 实战用连接跟踪排查三类典型故障4.1 场景一连接表被撑爆系统疯狂丢包这是一个非常经典的故障我相信很多运维都遇到过。现象是业务突然大面积超时dmesg里刷出这句话nf_conntrack: table full, dropping packet翻译成人话就是连接跟踪表满了新的数据包直接丢根本进不了协议栈。这事儿在NAT网关、Docker宿主机、K8s节点上尤其常见。排查第一步确认表占用情况sysctl net.netfilter.nf_conntrack_max cat /proc/sys/net/netfilter/nf_conntrack_count前者是表的上限后者是当前条目数。如果你看到当前条目数贴近上限甚至相差不到几百那基本实锤了。接下来要搞清楚什么连接占满了表conntrack -L | awk {print $3} | sort | uniq -c | sort -nr如果发现TIME_WAIT状态的TCP连接堆积如山说明大量短连接没有被正常回收。常规做法是调整两个参数一个是net.netfilter.nf_conntrack_tcp_timeout_time_wait默认120秒业务是大量短连接的话可以降到30秒甚至20秒另一个是net.netfilter.nf_conntrack_max直接把表调大。但注意别脑子一热就设一个天文数字因为每个表项大概占几百字节内存几百万个表项吃掉的物理内存可不是小数目。8G内存的机器建议最大值别超过50万不然内存会被吃掉一大片得不偿失。临时生效用sysctl -w永久生效写入/etc/sysctl.confsysctl -w net.netfilter.nf_conntrack_max262144 sysctl -w net.netfilter.nf_conntrack_tcp_timeout_time_wait30调完之后最好再清理一下已经没用的表项。比如手动回收所有TIME_WAIT状态的连接注意这会同时影响正常连接非紧急情况少用conntrack -D -p tcp --state TIME_WAIT总的来说优先从超时时间下手而不是一味加表容量。表大只能说是治标把连接的生命周期缩短才能治本该关的连接早点关了表自然就空了。4.2 场景二定位某个IP的高并发连接是否正常网站被爬虫狂刷的时候你会发现一个问题用户访问正常但服务器的负载居高不下。光看access log还不好判断因为日志太分散了。这时候看连接跟踪表就特别直观直接查80端口上连接数最多的IPconntrack -L -p tcp --dport 80 | awk {print $6} | sort | uniq -c | sort -nr | head -20解释一下$6在conntrack输出里是原始方向的src字段也就是发起连接的源IP。输出出来以后4821 203.0.113.55 1300 198.51.100.23 987 192.168.1.20 155 192.168.1.31第一行那个IP明显是异常的四千多条连接全挂在80端口正常用户不可能这样。顺着往下查看看它到底在干什么conntrack -L -p tcp -s 203.0.113.55 | head如果看到一堆SYN_SENT或者ESTABLISHED但几乎没字节数的状态基本就是爬虫或者CC攻击了。处理手段就有很多种了防火墙封IP、限速、扔到蜜罐。不过这里先不展开重点是思路——通过连接跟踪表你直接把谁在疯狂建连这个事实抓了出来而不是靠猜。4.3 场景三排查NAT端口映射不生效这个场景跟前面不太一样不是看连接数而是看NAT映射有没有正确生成表项。你配置了端口映射把公网IP的80端口映射到内网某台服务器的8080端口但外网访问死活不通。先别急着改防火墙规则看看连接跟踪表里有没有映射条目的影子。conntrack -L -n -d 203.0.113.10-n是显示NAT转换后的地址-d指定目的地址。如果这条命令输出为空说明根本没有流量到达NAT阶段问题出在前面的路由或者防火墙拦截。如果有输出仔细看输出里两个方向的转换关系原始方向src内网IP dst公网IP sport端口 dport80应答方向src公网IP dst内网IP sport80 dport端口。正常情况下应该是双向都有的。如果你只看到原始方向、没有对应的应答方向那说明数据包去了但回不来多半是路由回程没走这台NAT网关或者内网服务器访问外网时绕过了网关。这个排查思路在很多跨网段通信的故障里同样适用原理一致先确认连接跟踪层面有没有建立映射再往上下游找问题。4.4 场景四Linux主机作为NAT网关时的整体观测很多公司内部用Linux服务器做软路由、NAT网关后面挂着一堆虚拟机或者容器。这种场景下查看连接跟踪表等于是在看整个内网的出入流量总账。我会写一个简单的监控脚本定期把表项数量、按协议分布、确认的会话数记录下来#!/bin/bash echo $(date %Y-%m-%d %H:%M:%S) cat /proc/sys/net/netfilter/nf_conntrack_count cat /proc/net/nf_conntrack | awk {print $3} | sort | uniq -c | sort -nr conntrack -L -p tcp --state ESTABLISHED | wc -l跑一段时间之后你就能掌握这个网关的正常水位。以后一旦超过这个水位就知道有异常了。这种基于连接跟踪的监控思路比单纯看流量带宽要精准得多因为连接数是业务活跃度最直接的度量。5. 进阶技巧定时清理、超时调优与常见问题速查5.1 连接跟踪表相关的内核参数怎么调连接跟踪不是无限大的内核里一堆参数管着它的行为。我最常调的就几个net.netfilter.nf_conntrack_max表的最大条目数默认值在不同内核版本和内存大小下不一样生产环境一般按内存计算保守一点每1G内存给2万条左右8G内存给16万到20万比较稳。net.netfilter.nf_conntrack_tcp_timeout_established已建立TCP连接的空闲超时默认432000秒5天。这个值对服务器来说太长了一个TCP连接5天没数据包还挂着纯占坑。Web业务调到600或900秒就够了。不过调整之前得想清楚如果业务里有长连接、WebSocket、数据库连接池超时设太短会造成频繁断连。net.netfilter.nf_conntrack_udp_timeoutUDP的超时默认30秒一般不用动。net.netfilter.nf_conntrack_tcp_timeout_syn_recv三次握手收到SYN但没完成握手的超时默认60秒。如果SYN Flood攻击这里就会堆积大量SYN_RECV状态的半连接调小这个值可以让半连接快速老化减轻表压力。这些参数都没有绝对的标准值完全看业务模型。我个人的习惯是先把现状记录下来跑几天看连接数曲线再决定怎么调千万别上来就乱改。5.2 手动清理连接表项的适用时机和方法连接跟踪表有个自愈机制超时自动老化表满了也优先丢新的。但有些场景下你需要手动清。比如你刚改了一批防火墙规则想让所有已有连接全部重新匹配规则或者你怀疑表里有一批脏连接卡着不放导致新连接进不来。这时候可以手动删除# 删除某个来源IP的所有连接 conntrack -D -s 192.168.1.100 # 删除所有UDP连接慎用 conntrack -D -p udp # 删除所有连接全清空影响所有在线会话 conntrack -Fconntrack -F这个命令一定要慎用因为它会把当前所有活跃连接全干掉。你人还在SSH里一执行自己就掉线了因为SSH连接也被清了。我一般只在深夜或者维护窗口才敢用全清平时最多按IP、按状态删特定的条目。另外提一嘴如果你用iptables的-j CT --notrack给某些流量开了不跟踪的免检通道那么这些流量就不会出现在连接跟踪表里。很多人查不到某条连接以为是丢了其实是没跟踪排查的时候脑子里要有这根弦。5.3 常见疑难问题速查表问题现象可能原因快速排查方法解决方向nf_conntrack: table full表项数量达到上限cat /proc/sys/net/netfilter/nf_conntrack_count调大nf_conntrack_max、缩短超时时间、清理失效表项能看到SYN_SENT但迟迟不ESTABLISHED对端无响应或被丢包conntrack -L -p tcp --state SYN_SENT查路由和防火墙规则看对端有没有回包内网能访问外网但外网访问不了内网服务器NAT映射没有同时生成双向条目conntrack -L -n -d 公网IP检查回程路由是否走NAT网关cat /proc/net/nf_conntrack输出为空内核没加载连接跟踪模块lsmod | grep nf_conntrack加载模块比如modprobe nf_conntrackconntrack命令不存在没装工具which conntrack安装conntrack-tools删除连接后马上又出现现有流量还在属于正常现象再次conntrack -D先确认流量到底来自哪里治本而不是反复清表连接数暴涨但流量不大可能存在空连接攻击conntrack -L -p tcp查看状态分布抓包确认防火墙做限速和IP封禁这个表里的问题大部分我都亲身遇到过。尤其是第一条和最后一条已经在好几个环境里反复出现过有时候是业务代码写得不讲究每次请求都新建一条连接然后不释放活活把表堆满有时候是被人拿了肉鸡打空连接。遇到连接数暴涨我现在的第一反应就是先抓一个时间点的快照保存现场再动手清理这样后面复盘才有的依据。5.4 定时监控连接跟踪水位的小建议最后分享一个我自己的习惯。连接跟踪表这东西跟磁盘空间一样你不管它它总会在某个深夜给你搞出个大新闻。所以我现在在所有重要的Linux主机上都会挂一个最简单的Cron任务每隔5分钟记录一下表项数*/5 * * * * echo $(date %s) $(cat /proc/sys/net/netfilter/nf_conntrack_count) /var/log/conntrack_count.log时间长了你把这个日志导出来画个曲线就能清楚地看到业务的潮汐规律高峰在什么时候、基线是多少、有没有哪个时间段出现异常尖峰。这比任何监控告警都来得直观。等下次再有人说内网卡、连不上你先打开这个log看一眼心里基本上就有数了不用再手忙脚乱地现场抓数据。连接跟踪表这个东西说到底就是Linux网络协议栈里一张普通的内核表但它的意义远不止记录连接这么简单。它是状态防火墙的决策基础是NAT转发的数据依据更是你排查网络问题时最快能看清全局的窗口。我从入行到现在不知道在这张表上排查过多少稀奇古怪的网络故障从莫名其妙的丢包到诡异的连接数超限基本都靠它破的案。希望你把今天说的这些命令和思路用到自己的机器上跑一遍看一看下次遇到网络故障的时候你会感谢自己曾经花这十分钟读过这篇文章。
返回列表