最开始接触 Linux ALG 技术,是因为一次特别让人头疼的故障:办公室网络里所有终端都能正常上网,唯独访问公司自建 FTP 服务器时频繁失败。更奇怪的是,从外网访问这台 FTP 反而一切正常。我花了大半天时间排查地址转换规则和防火墙策略,最后在服务器上抓包才发现,客户端发起的 FTP 数据连接总是落在内网网段,压根没有经过正确翻译。这个场景,就是非常典型的 NAT 环境下缺少应用层网关配合的表现。
如果你想做网络设备运维、网关开发,或者只是在家里用软路由跑 Docker 和自建服务,ALG 都是一个绕不开的基础话题。它和传统 NAT 的关系可以这样理解:NAT 负责“翻译地址”,ALG 负责“让翻译连应用层内容一起生效”。下面我会用尽量贴近实操的语言,把 Linux 系统里 ALG 的原理、配置方法、常见故障和现代替代方案一次讲透。
1. 认识 ALG 之前,先看 NAT 的底层短板
1.1 数据包层转换管不到应用层
传统 NAT 做的事情很简单:在设备收到出去的数据包时,把源 IP 和源端口替换成公网 IP 和随机端口;收到回来的数据包时,根据连接跟踪表反向还原。它工作在 TCP/IP 协议栈的三层和四层,也就是只看 IP 头和 TCP/UDP 头。
但问题是,很多应用协议出于设计习惯,会把 IP 地址和端口号直接写进应用数据里。比如 FTP 的 PORT 命令、PASV 应答,SIP 协议里的 Contact 头和 SDP 媒体描述,RTSP 的 DESCRIBE 和 SETUP 报文,H.323 的 Q.931 信令。NAT 翻译完包头之后,数据负载里的旧地址还原封不动躺在那里。
举一个最直观的例子。FTP 主动模式是这样的流程:客户端先连上服务器的 21 端口,然后通过 PORT 命令告诉服务器“请你来连我,我的 IP 是 192.168.1.100,端口是 40000”。如果这个客户端在 NAT 后面,那么服务器从公网收到的 PORT 命令里,写的还是 192.168.1.100。服务器尝试连接这个私网地址,当然连不上。
换句话说,NAT 把“信封”上的地址改好了,但“信纸”里写的地址还是旧的内网地址。应用层对方拿到信纸后,按照里面的地址去回信,自然就找不到人。
1.2 一个生动例子:FTP 主动模式为何天然“迷路”
我们把上面那种情况展开来看,现实中常见的是更让人困惑的被动模式。FTP 被动模式下,客户端连接服务器 21 端口后发送 PASV 命令,服务器返回 227 应答,里面包含一个 IP 地址和一个端口,告诉客户端“你到这个地方来建立数据连接”。如果服务器本身就在 NAT 后面,它返回的可能是自己的内网地址,例如 10.0.0.5:50000。客户端在公网,拿到这个地址后尝试连接 10.0.0.5,自然失败。
Linux 内核如果加载了 FTP 相关的连接跟踪和地址转换辅助模块,就能在处理 227 应答时,把里面的内网 IP 替换成公网 IP,数据端口也做相应的地址转换。这样客户端才能按图索骥找到服务器。
所以 ALG 不是一个独立运行的守护进程,它更像 NAT 在应用层的“外挂翻译官”,负责在连接跟踪引擎处理数据包时,额外解析和改写指定的应用协议负载。
1.3 哪些协议需要 ALG 配合
并不是所有协议都需要 ALG。只有那些具备“动态协商端口”或“负载内嵌入地址”特性的协议才需要。常见的有这么几类:
| 协议 | 主要场景 | 为什么需要 ALG |
|---|---|---|
| FTP | 文件传输 | 控制连接与数据连接分离,动态协商端口 |
| SIP | VoIP 通话 | 信令和媒体流分属不同会话,SDP 负载内嵌入地址和端口 |
| H.323 | 视频会议、老式语音网关 | 与 SIP 类似的信令与媒体分离机制 |
| RTSP | 流媒体点播、摄像头 | SETUP 阶段动态协商 RTP 端口 |
| ICMP | 错误反馈、ping 大包 | ICMP 错误报文内嵌原始数据包头,需要同步翻译 |
ICMP 这个经常被忽略,补一句:当网络里出现分片重组错误或端口不可达时,ICMP 错误消息会把触发错误的数据包头部一并带回,如果不跟着做地址转换,发送方的连接跟踪表会对接不上。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. Linux 内核如何实现 ALG:架构与工作流程
2.1 三层联动:hook 点、连接跟踪与 helper
Linux 的 ALG 功能建立在 netfilter 框架之上,核心是三个部分协同工作:hook 点、连接跟踪模块、helper 辅助模块。
netfilter 在数据包经过协议栈的各个阶段提供了钩子点,比如 PREROUTING、LOCAL_IN、FORWARD、LOCAL_OUT、POSTROUTING。连接跟踪模块在 pre-routing 和 post-routing 阶段建立连接表项,记录五元组和状态。而 ALG 对应的 helper 模块,则注册到特定协议和端口的解析逻辑上,每当连接跟踪引擎处理新报文时,helper 会被调用,检查负载里是否包含需要翻译的信息。
早期实现里,helper 和 NAT 转换是分开的两个模块。例如 FTP 场景,需要同时加载 nf_conntrack_ftp 和 nf_nat_ftp。前者负责识别 PORT 命令、建立预期连接;后者负责在建立地址转换规则时,将负载里的地址一起改写。在现代内核中,这两个模块配合得更加紧密,但理解上仍然可以按“识别跟踪”和“做地址翻译”两个角色来看待。
2.2 连接预期:让“后到的数据流”也能被正确翻译
ALG 最关键也比较难理解的机制是连接预期。FTP 的主动模式中,控制连接是客户端到服务器的 21 端口,数据连接则是服务器主动发起连接到客户端指定端口。连接跟踪引擎怎么知道“这串新来的连接”和之前那个控制连接属于同一个会话?
这就是预期机制做的事情。当 helper 在控制连接里解析到 PORT 命令后,会告诉连接跟踪引擎:稍后可能会有一个来自服务器、目标是客户端指定端口的新连接,这个新连接应该被当作当前会话的附属数据连接。于是连接跟踪引擎预先创建一条预期记录,在之后的数据连接报文第一次出现时,直接把它归入预期会话,并自动应用预先计划好的地址转换规则。
这种方式有两个好处:一是数据连接无需额外维护状态,二是地址转换对两层协议栈透明。实际观察时,也可以从 /proc/net/nf_conntrack_expect 或者 conntrack -L expect 里看到预期表项。
2.3 ALG 内核模块到底做了什么
具体到代码层面,helper 模块的主要工作流程可以简化成下面几步:
- 在连接跟踪的数据包里按协议规则扫描负载。FTP 就扫描 FTP 命令;SIP 就扫描 SIP 请求行、Via 头、Contact 头、SDP 部分。
- 当发现 IP 地址和端口信息时,把它们记录到当前连接表项中。
- 调注册好的 NAT 辅助函数,在地址转换阶段同步替换负载里的旧地址。
- 为后续会建立的关联连接创建预期表项。
- 在双向流量中持续维护地址映射关系,因为有些协议在请求和响应里都含地址信息,例如 SIP 的 Register 和 200 OK。
这个工作机制看似简单,但涉及大量边界情况。例如 FTP 被动模式下服务器应答内容的格式有差异,SIP 消息里地址出现在 Header 和 SDP 多个位置,RTSP 的响应中还可能出现多个端口号。所以 ALG 模块的实现并不轻松。
3. 动手配置 Linux ALG(以 FTP 和 SIP 为例)
3.1 加载对应 helper 模块
现代 Linux 发行版通常把各类协议helper 编译成内核模块,常见的包括:
nf_conntrack_ftp、nf_nat_ftpnf_conntrack_sip、nf_nat_sipnf_conntrack_h323、nf_nat_h323nf_conntrack_rtsp、nf_nat_rtsp(部分厂商发行版有独立补丁)nf_conntrack_irc、nf_nat_irc
在早期内核中,加载 ftp 模块的方式非常简单:
bash复制modprobe nf_conntrack_ftp
modprobe nf_nat_ftp
加载完模块之后,如果系统里有地址转换规则,当 FTP 控制连接经过时,helper 就会自动介入。很多老教程到这里就结束了,新内核可能就行不通。
3.2 从自动关联到显式匹配
内核 4.4 之后,net.netfilter.nf_conntrack_helper 默认值变为 0,意思是连接跟踪引擎不再仅凭端口号自动挂载 helper。这是出于安全考虑,因为盲目解析负载会让攻击面变大。
此时,如果只加载模块但不做显式配置,FTP 和 SIP 的 ALG 并不会生效。需要通过 raw 表把特定流量指定给对应 helper。以 iptables 为例:
bash复制iptables -t raw -A PREROUTING -p tcp --dport 21 -j CT --helper ftp
该命令让所有去往 21 端口的新连接在连接跟踪阶段就被标记为 FTP 类型,之后 helper 才会处理。SIP 的话按端口和协议调整:
bash复制iptables -t raw -A PREROUTING -p udp --dport 5060 -j CT --helper sip
iptables -t raw -A PREROUTING -p tcp --dport 5060 -j CT --helper sip
如果使用 nftables,可以在 prerouting 链里显式设置 helper:
code复制table inet filter {
chain prerouting {
type filter hook prerouting priority -200; policy accept;
meta l4proto tcp tcp dport 21 ct helper set "ftp"
}
}
注意,helper 配置必须和连接跟踪的 hook 点在同一个优先级窗口内,否则标记不生效。如果同时用了多张网卡、多个地址转换规则,最好把 raw 表规则放在最前面。
3.3 实机验证:用 conntrack 工具观察
配置完之后,不能只盯着 iptables 规则看,要直接观察连接跟踪表和预期表。
先用 conntrack 命令确认模块已生效:
bash复制conntrack -L -p tcp --dport 21
正常情况可以看到控制连接。接着在新终端里执行:
bash复制conntrack -E -p tcp --dport 21
然后触发一次 FTP 上传或下载操作,预期能够看到两条连接记录:一条控制连接,一条数据连接。如果只看到控制连接,而数据连接根本没有进入 conntrack 表,那说明 helper 没被识别,或者数据连接走了别的路径。
针对预期表,可以执行:
bash复制conntrack -L expect
在 FTP 主动模式下,这条命令会在数据连接还没建立前就显示出预期记录。平时我验证 SIP 服务也是类似思路:观察 UDP 5060 端口的连接跟踪记录,并确认 INVITE 报文里的 SDP 地址是否已经被替换成公网地址。
这个步骤是一个很好的“体检”方式。如果你发现自己配置了 ALG 却始终不生效,第一步就检查这些运行状态,而不是反复改 iptables 规则或者重启防火墙。
4. 常见故障排查与避坑实录
4.1 数据连接总指向内网 IP
这是最常见的问题,表现是:FTP 客户端登录成功,但列目录或传输文件时卡住。抓包发现 PASV 或 PORT 命令里的地址没有被改写。
排查看三点:
- 是否加载了
nf_nat_ftp模块?在较旧内核里,如果只加载nf_conntrack_ftp而忘记加载nf_nat_ftp,就会出现控制连接正常、数据连接失败的怪现象。 nf_conntrack_helper是不是默认禁用了?在内核 4.4 之后的系统上,如果你没有按照 3.2 节的方法在 raw 表里显式指定 helper,加载模块也白搭。- 是否还有其他防火墙规则把数据连接挡掉了?判断方法是:抓包看数据连接的目标地址和端口是否已经是公网地址。如果已经是公网地址,说明 ALG 工作正常,问题可能在防火墙放行策略上。
有一些老教程会让你直接 sysctl -w net.netfilter.nf_conntrack_helper=1 恢复自动关联,实际上这会带来安全隐患,不建议在生产环境做。
4.2 SIP 注册成功但只有单通
SIP 场景中更经典的坑是:话机能够完成注册,但拨打外线时只有一路能听见声音,另一路静音;甚至两端都显示已接通,却没有音频。
原因是 SIP 信令和媒体流是分开的。ALG 如果只翻译了 Via 和 Contact 头,没有正确翻译 SDP 里的 IP 和端口,媒体流就会发往错误地址。SIP 报文可能出现多次转发,每个转发点都要检查 SDP 地址是否被正确替换,尤其要注意两边都是 NAT 环境的场景。
此外,检查 UDP 的 nf_conntrack_sip 超时参数也很有必要。SIP 的会话保持时间可能很长,如果连接跟踪超时设置太短,通话到一半媒体连接就被清理掉,表现就是过一段时间自动挂断或听不到声音。可以通过 /sys/module/nf_conntrack_sip/parameters/ 下的参数调整对应超时。
4.3 ICMP 错误消息未处理
平时不太容易注意到 ICMP 错误消息,但一旦要在 NAT 后做大流量的探索,例如频繁使用带 DF 标志的大 UDP 报文,ICMP 类型 3 的消息就会变得关键。ICMP 差错报文回包里携带了触发错误的原数据包头部,如果连接跟踪引擎没有对应的 helper,这个回包就找不到原来的连接映射,表现为网络间歇性异常。
Linux 在处理 ICMP 方面有比较完善的内建机制,但如果你开启了非常严格的防火墙,建议确认是否允许必要的 ICMP 回返包。实际排查时可以参考 iptables -t raw -L -v,确认 ICMP 流量没有被丢在 raw 表里。
4.4 关于内核版本与默认参数
不同内核版本对 ALG 的行为差异极大,尤其是内核 4.18、5.4、6.1 之间的默认策略变化。比如早期 Ubuntu 会把 nf_conntrack_ftp 自动加入启动模块列表,而新版系统可能完全不加。
建议在部署前先确认当前环境的内核配置:
bash复制sysctl net.netfilter.nf_conntrack_helper
cat /proc/net/nf_conntrack
lsmod | grep nf_
另外,有些厂家定制内核里带了 RTSP helper,但标准发行版内核没有。如果需要支持 RTSP,就得评估是否能升级内核、换 helper 模块或者干脆用应用层代理方案。
实践过程中我给自己的排查速查表是:
| 现象 | 可能原因 | 优先排查动作 |
|---|---|---|
| FTP 登录成功,列表失败 | 数据连接地址没翻译 | 确认 nf_nat_ftp、raw 表 helper |
| SIP 注册成功,但呼叫单通 | SDP 地址未翻译 | 抓包检查媒体流目的地址 |
| 服务偶尔断流,现象随机 | conntrack 超时过短 | 调整对应协议超时参数 |
| ICMP 大包回包异常 | NAT 后差错报文未映射 | 检查 conntrack 对 ICMP 的支持 |
5. ALG 的演变与架构选型思考
5.1 为什么现代网络越来越“讨厌”ALG
讲完配置和排查,我想聊点更宏观的内容。ALG 本质上是在给 NAT 的缺陷打补丁,但这个补丁有代价:
- 应用负载解析消耗 CPU,高并发场景下对转发性能有影响。
- 兼容性差,客户端和服务器对协议格式稍有变化,ALG 就可能误判。
- 安全风险高,解析器本身成了一大攻击面,历史上出现过通过畸形 FTP 或 SIP 报文攻击内核模块的事件。
- 协议扩展困难,每新增一个协议都要重新实现 helper,跟不上应用迭代速度。
因此,现在很多网关和软路由默认都会建议关闭各类 ALG,尤其是家用设备的 SIP ALG,经常导致 VoIP 语音问题,用户反馈之后,厂商往往改成默认关闭。
5.2 应用层代理、协议改进与 NAT 穿透
替代 ALG 的思路主要有三个方向。
第一个是应用层代理。比如用代理程序终结承载连接,由代理主动发起新的连接,数据流经过代理转发,这个过程中对外只暴露代理自己的地址,自然不存在二次地址翻译问题。FTP 服务端可以部署虚拟主机机制代替 NAT 映射,SIP 网络可以在边界部署会话边界控制器,本质都是应用层代理思路。
第二个是协议本身的改进。FTP 扩展被动模式 EPSV 已经允许客户端只接收端口号,不再依赖 IP 地址;很多现代协议从一开始就设计成“所有数据都在同一连接上跑”,不再像老协议那样动态协商新端口,因此对 ALG 的依赖大幅降低。
第三个是上层应用自己实现 NAT 穿透。比如 STUN、TURN、ICE 这套机制,让通信双方在应用层协商出可用的地址组合,而不是依赖网关去改写负载。这在音视频会议、WebRTC 场景里已经很成熟。
5.3 我的最终推荐实践配置
根据我自己在 Linux 服务器和软路由上的实践经验,最终推荐的做法是:
尽量在内核层面保持最简配置,除非有明确的老旧 FTP 或 H.323 应用需求,否则不主动开启自动 helper。FTP 优先改用 SFTP 或者被动模式加指定端口范围的方式,把端口范围限制在可控范围内,再用防火墙规则做精确放行。SIP 优先采用支持 STUN 的 VoIP 终端,或者部署会话边界控制器做媒体代理,而不是依赖网关的内核 ALG。
如果确实必须在 Linux 网关上支持 ALG,我建议按下面这套组合拳来做:
bash复制# 装载模块
modprobe nf_conntrack_ftp
modprobe nf_nat_ftp
# 显式指定 helper,而不是依赖自动关联
iptables -t raw -A PREROUTING -p tcp --dport 21 -j CT --helper ftp
# 避免在 FORWARD 链上过度放开,只放行建立好的连接和预期的数据连接
iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -p tcp --dport 21 -m conntrack --ctstate NEW -j ACCEPT
注意 RELATED 状态很关键,数据连接正是以预期连接的身份出现的。如果你把 RELATED 丢掉了,即使 helper 工作正常,数据连接也会被防火墙拦截。
最后再分享一个我在实际维护中踩过的坑:有些系统发行版会在开机时预加载了 nf_conntrack_ftp,但没有任何 raw 表规则,也没有把 nf_conntrack_helper 改回来。于是管理员以为 ALG 已经生效,结果故障反复出现。排查这类问题有一个简单有效的习惯,永远不要只看模块加载列表,一定要看连接跟踪表里有没有对应协议的辅助记录。把这个习惯记牢,ALG 相关的大部分疑难问题都能在十分钟内定位到根因。
