ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Linux连接故障排查:SELinux与firewalld双层过滤导致端口不通的完整复盘

2026/10/8 2:34:05 拓冰建站 浏览量
Linux连接故障排查:SELinux与firewalld双层过滤导致端口不通的完整复盘 这两台机器从上周开始就有点不对劲业务方反馈说跨网段调接口偶尔超时严重的时候直接连接被拒绝。我从头到尾把SELinux和防火墙两层都翻了一遍最后发现两边都有问题而且都不是表面看上去那么简单。这篇就当一次完整的问题回顾把排查链路、关键命令和容易踩的坑都写清楚给后来人提个醒。1. 问题现象与初步判断1.1 故障现象描述事情是这样的我们内网有一套CRM系统升级之后部分客户端开始报连接超时还有一部分直接报Connection refused。服务器本身跑得好好的本机curl那个接口一点问题没有日志里也没有任何服务异常。但客户端一跨网关过来就死活不通甚至局域网内非同一网段的机器也连不上。最开始我怀疑是不是程序升级改了什么监听地址或者端口没起来但查了一圈发现进程在跑监听也正常端口也开了。既然进程和端口都没问题那就只剩下系统层面的网络过滤和访问控制也就是SELinux和防火墙这两层。这里有个经验要提前说很多运维一看到连不上就习惯性地systemctl stop firewalld加setenforce 0这种操作虽然能临时速通但往往埋下隐患尤其对于不能随便重启的生产服务器。所以我的原则是先定位到具体原因再考虑怎么改不到万不得已不全局关防火墙。1.2 初步排查思路先看链路再查监听最后查过滤遇到连接问题我会按下面的顺序走一遍不用上来就抓包先排除最底层的网络可达性问题。# 查看网卡和IP配置 ip addr # 查看路由表 ip route # 测试基本连通性 ping -c 3 目标IP # 测试端口是否通 telnet 目标IP 8080 # 查看本机监听端口和进程 ss -lntp | grep 8080ping和telnet的区别很重要ping走的是ICMP协议通与不通只能说明主机之间有没有路而telnet测的是TCP端口是否可达端口能通才代表业务链路没问题。我们这里ping两边都通但telnet只有从本机回环地址测才通一旦用局域网IP去连就卡住这基本可以断定路由和物理链路没问题问题出在中间过滤层。另外提醒一下ss -lntp看到的监听地址很有讲究。如果看到的是127.0.0.1:8080而不是0.0.0.0:8080那服务只监听了回环地址外部怎么都连不上这是程序配置问题不是防火墙的事。我当时排查的服务监听在0.0.0.0所以这种可能性直接排除了。链路、监听、路由这几关都过了那就轮到系统层的主角出场SELinux和firewalld。2. SELinux 到底拦截了什么2.1 SELinux在连接问题里的真实角色很多人觉得SELinux是个反人性的东西设置复杂还看不懂日志。但实际上它是一款内核级强制访问控制机制比普通的文件权限更严格。普通权限看的是进程属主和文件属主是否匹配SELinux关心的是进程的安全上下文是否有权访问这个文件、这个端口、这个网络资源。拿我们这个场景来说业务服务升级后如果可执行文件从旧的路径搬到了新路径SELinux的文件上下文标签会自动匹配吗并不会。比如原本/usr/local/crm/server下是bin_t类型新程序放到/opt/crm/bin下上下文可能变成了usr_t。这时候服务进程如果还想通过特定端口对外监听SELinux策略里没有对应的放行规则就会直接在系统调用层面把这次操作拒掉程序却不会主动崩溃日志里也没有业务异常。SELinux有三种模式模式行为Enforcing强制执行策略违反直接拒绝并记录AVC日志Permissive不实际拒绝只记录警告日志Disabled完全禁用SELinux机制生产环境我建议保持Enforcing然后通过日志精准找问题而不是一刀切关掉。你可以用下面命令快速了解当前状态getenforce sestatus如果输出Enforcing说明SELinux正处于执法状态连接问题完全有可能是它造成的。2.2 用audit日志定位真实拦截原因SELinux有没有拦不是靠猜的去/var/log/audit/audit.log里翻记录就行。最常用的命令是ausearch -m avc -ts recentavc是SELinux访问向量缓存的缩写所有被拒绝的访问都会在这里留下AVC消息。-ts recent表示只看最近一段时间避免日志太多刷屏。我当时执行后看到类似这样的输出typeAVC msgaudit(1711345678.123:456): avc: denied { name_connect } for pid1234 commcrm-server dest8080 scontextsystem_u:system_r:httpd_t:s0 tcontextsystem_u:system_r:port_t:s0 tclasstcp_socket这里的关键词是denied、name_connect、dest8080翻译成人话就是crm-server进程被SELinux拦住了因为它想连接TCP 8080端口但策略里没有放行这个端口给当前进程类型。如果你装了setroubleshoot还能用sealert直接看可读性更强的解释sealert -a /var/log/audit/audit.log它会给出建议命令比如semanage port -a -t http_port_t -p tcp 8080意思是把8080端口关联到http_port_t类型这样运行在httpd上下文下的进程就能合法使用这个端口了。2.3 怎么判断是不是SELinux在干扰判断方法其实很简单临时切换到Permissive模式测试一下就行但千万注意顺序setenforce 0 # 现在试着从外部客户端连接一下 # 如果能通说明SELinux确实在拦截 # 测试完马上恢复 setenforce 1这里有个安全细节必须强调setenforce 0只是临时生效重启机器后还会回到配置文件里的状态。如果改了/etc/selinux/config里的SELINUXdisabled那是永久关闭而且从Disabled切回Enforcing通常需要重启才能生效。我见过不少人在云服务器上调这个结果重启后机器直接起不来了原因就是SELinux上下文对系统文件的影响被忽略。另一个判断办法是看dmesg或者/var/log/messages里有没有SELinux的拦截记录。还有一点值得注意如果程序是运行在自己写的脚本里脚本调用的子进程是否继承SELinux上下文也要考虑。有时候父进程是放行的子进程换了域照样会被拦。3. 防火墙这层也别忽略3.1 firewalld和iptables到底是什么关系再来说防火墙。很多Linux服务器默认用的是firewalld但它并不是独立于iptables的东西。简单理解firewalld是前端管理工具底层通过nftables或iptables来真正应用规则。所以如果你只查看了firewall-cmd --list-all有可能遗漏了直接以iptables/nftables形式存在的规则。这里给一个容易混淆的概念即使你systemctl stop firewalld如果服务器上还跑着独立的iptables服务或者你用云平台自带的安全组连接照样会被拦。所以排查连接问题时一定要把所有能过滤网络的地方都过一遍。我在实际排查时是同时看三样东西systemctl status firewalld iptables -L -n -v --line-numbers nft list ruleset有些服务器换了nftables但命令集合还是不完整的iptables -L可能显示空这时一定要用nft list ruleset看看真实规则。我们这次问题里firewalld的规则倒还好但有个zone配置把新端口漏掉了导致外部访问总是被drop这属于典型的看起来放行了实际上没进对zone。3.2 别把运行时和永久搞混firewalld里面最坑的就是运行时配置和永久配置分离。你得记住一个铁律不加--permanent的规则只对当前运行状态生效防火墙一重启就没了加了--permanent的规则只存在于配置文件里必须执行firewall-cmd --reload才会加载到运行时。# 临时添加端口 firewall-cmd --add-port8080/tcp # 永久添加端口 firewall-cmd --permanent --add-port8080/tcp firewall-cmd --reload # 查看运行时规则 firewall-cmd --list-all # 查看永久规则 firewall-cmd --permanent --list-all我当时犯过一个很经典的错临时加了端口验证通了然后直接关掉终端结果第二天业务又连不上。后来才知道运行时规则在firewalld重启后就会消失必须加--permanent再reload一次才行。另外要特别注意firewall-cmd --list-all默认显示的只是当前zone的规则。如果你的网卡被分到了另一个zone比如public你在默认zone里放行是没用的。3.3 还有这些隐形防火墙nftables、iptables、云安全组除了firewalld还得注意云安全组。现在很多Linux服务器跑在云平台上云控制台上的安全组规则是独立于操作系统之外的。如果你本机firewalld已经放行了8080但云安全组没放行外部照样连不上。我在排查时经常遇到客户说我防火墙都关了怎么还是不通一查安全组压根没开端口。再比如说ping不通的问题很多云服务器默认安全组是不放行ICMP的你在操作系统里把firewalld折腾烂了也没用。所以遇到问题时排查顺序最好是这样先看云安全组如果有再看操作系统firewalld再看iptables/nftables残留规则最后看SELinux这样的顺序能少走不少弯路。我们这个问题在防火墙层面做了两件事一是把业务端口加到正确的zone二是确保--permanent永久生效并且把iptables里残留的旧规则清理掉。4. 完整解决流程与复盘4.1 从SELinux到防火墙的完整操作步骤为了便于大家直接参考我把当时的解决流程完整列一下前面几个步骤是诊断后面是修改。第一步查看SELinux状态和AVC日志getenforce ausearch -m avc -ts recent发现denied消息后查看具体上下文和端口semanage port -l | grep http_port_t这里可以看到当前SELinux放行的端口列表。如果8080不在列表里就要添加semanage port -a -t http_port_t -p tcp 8080如果你的服务进程类型不是httpd_t而是自定义的samba_t、postgresql_t之类就按对应的类型加端口。一次性加多个端口也支持用-p tcp后跟端口范围比如8080-8089。第二步查看firewalld当前状态和zonesystemctl status firewalld firewall-cmd --get-active-zones firewall-cmd --zonepublic --list-all如果网卡在publiczone就在public里放行端口firewall-cmd --zonepublic --add-port8080/tcp firewall-cmd --zonepublic --permanent --add-port8080/tcp firewall-cmd --reload注意第一条临时规则其实可以省掉直接永久添加再reload就行。但为了快速测试我先用临时规则验证确认能连后再做永久配置这样避免误写永久规则。第三步查看iptables和nftables里有没有残留规则iptables -L -n -v --line-numbers nft list ruleset如果有旧的DROP规则正好匹配业务端口需要删除。比如iptables里有一条DROP tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:8080对应规则编号如果是5可以用iptables -D INPUT 5但请注意直接用iptables -D删除的规则在重启后也可能因为服务恢复而回来所以最好找到规则来源比如/etc/sysconfig/iptables或firewalld的direct规则从源头改掉。到这里SELinux和防火墙两层都放行后外部客户端就能正常连接了。但别着急真正的坑在后面。4.2 有些坑必须拿出来说第一个坑SELinux的semanage port添加后旧进程可能还要重启才生效。因为进程在启动时缓存了安全上下文运行时再放行端口部分场景不会立即生效。我当时改完端口后业务依然连不上后来重启了对应服务进程才恢复。你可以用systemctl restart 服务名来重启不要盲目重启整台机器。第二个坑setenforce 0只是临时测试千万别当解决方案。我们这次问题如果用setenforce 0确实也能暂时解决但一旦重启SELinux恢复Enforcing问题又会出现。而且长期Permissive会让系统失去防护能力对生产环境来说很不负责。第三个坑firewalld添加端口后用telnet验证时要注意通和被拒绝的区别。如果端口没放行通常表现是连接超时数据包被drop如果端口放行了但服务没监听表现是立即拒绝。还有一种情况是端口放行了但服务监听在127.0.0.1外部连过去同样拒绝但你在本机测却正常。这个我之前踩过一次后面养成了看ss -lntp的习惯。第四个坑同一台服务器上可能存在多个防火墙管理工具。比如有些发行版预装了firewalld同时还有一个独立的nftables服务或者系统脚本里直接用iptables命令添加规则。你以为只查了一个其实还有另一个在拦。所以iptables -L和nft list ruleset最好都跑一遍。4.3 快速排查清单这里整理成一个速查表以后遇到类似问题可以直接对着看。现象可能原因检查命令解决方法本机正常跨网段连接超时firewalld未放行firewall-cmd --list-all添加端口或服务连接被拒绝拒绝比超时更快服务未监听/监听地址不对ss -lntp修改监听地址到0.0.0.0端口已放行但持续超时云安全组或iptables拦截云控制台/iptables -L -n安全组放行/删除规则服务启动失败但日志无异常SELinux拒绝端口或文件访问ausearch -m avc -ts recentsemanage放行端口或上下文ping不通但端口能通ICMP被拦firewall-cmd --list-all检查icmp服务firewall-cmd添加icmp规则重启防火墙后规则丢失只加了运行时规则firewall-cmd --permanent --list-all永久规则再加reload这套清单其实覆盖了90%的Linux连接故障。所谓连接问题很大程度就是过滤规则和监听配置两层的事情端口开没开、规则对不对、服务听没听够用。5.1 高频坑位提醒整理了三个高频坑尤其是新手特别容易踩。第一关于ping不通。ping走的是ICMP协议firewalld默认情况下是不放行ICMP回显的。如果你需要外部能ping通服务器firewall-cmd --permanent --add-serviceicmp firewall-cmd --reload注意这个操作要小心放行ICMP意味着服务器可以被探测到如果安全要求高建议只在内网网络环境放行。第二关于firewall-cmd --runtime-to-permanent。有时候你已经加了一大堆临时规则一条条重新加永久规则太累可以用这条命令把当前运行时全部规则直接转成永久firewall-cmd --runtime-to-permanent但它也会把临时的不想要规则一起转永久所以执行前最好先--list-all看一眼。第三关于SELinux上下文导致的服务无权限读取文件。连接问题除了端口还有可能是服务进程启动时读不到配置文件或证书文件。这些文件如果被打包搬了位置类型标签可能不对这时候用ls -Z看看ls -Z /opt/crm/config/app.conf如果类型不对可以用restorecon恢复默认上下文或者用chcon手工改类型。最推荐restorecon -Rv /opt/crm简单粗暴又不会改坏。5.2 我的实际操作体会这次问题从定位到解决大概花了两个小时中间很大一部分时间浪费在反复验证SELinux和防火墙的交互上。说几个个人心得。第一日志永远比猜靠谱。不管是SELinux的AVC日志还是防火墙的日志真实记录能告诉你具体被谁拦了。我甚至在/var/log/firewalld里看到过规则命中计数配合iptables -L -v里的计数器一眼就能看出某个规则是否真的有流量命中。第二验证一个修改一定要从外部视角来测。本地curl通、本机telnet通不代表客户端能通。最好从另一台机器telnet 目标IP 端口来验证并且用nc -vz代替telnet效果更好因为telnet在有些环境下没装nc可以单独测试端口是否开放。第三不要害怕SELinux它其实挺讲道理。你把服务该有的访问权限配好它比防火墙还要稳定。我现在的习惯是新装服务优先考虑把SELinux规则配合好而不是直接setenforce 0。这样即使以后重启机器服务也能自动恢复不会出现早上到公司发现业务又挂了这种尴尬。总的来说这个问题回顾下来核心其实就八个字先看监听再看过滤。SELinux和防火墙只是过滤的两层具体实现。只要戴好这个视角遇到连接异常就不会慌了。后面后面如果再遇到类似问题我会想想是不是还有第三层第四层过滤在拦截别让经验变成了惯性。