简介:应对第三方白名单限制或本地开发环境无法直接访问目标IP的场景,Linux端口映射转发是一项关键网络技能。该PDF围绕1.1.1.1与2.2.2.2的典型实例,对比跳板服务、Nginx代理转发与iptables底层映射三种方案,既给出具体配置命令,也说明各自适用边界。对于HTTP接口可通过Nginx快速实现路径级转发,而SSH、SFTP等非HTTP协议则更适合启用内核ip_forward并配合DNAT/SNAT规则完成透明映射,内容贴近真实联调需求,适合后端开发者、运维人员及网络调试初学者阅读。文档共1个PDF文件,体积仅50KB,却覆盖从场景分析到命令落地的完整思路,可作为随查随用的速查手册。目前已有2492人学习下载,简短篇幅适合碎片时间快速掌握端口映射要点。
1. Linux端口映射转发是什么:一次数据包的目标改写旅程
Linux端口映射转发是网络运维里特别高频的一件事。最常见的场景是:内网一台机器跑着Web服务,你想从另一台设备访问;或者本机某个服务为了安全只监听了127.0.0.1,现在想暴露给局域网。转发一旦不通,大家第一反应都是查规则,但实际上九成是内核的ip_forward开关没开。这是Linux端口映射转发的第一个门槛。它解决的问题本质是:把到达Linux主机某个网卡、某个端口的数据包,在内核的Netfilter框架里改写目标地址与端口后,重新掷向另一张网卡或另一个后端进程。适合把所有入口集中在网关机上的linux运维场景,也适合临时调试和搭建测试环境。做运维的、做容器网络的、甚至写嵌入式Linux应用的人,迟早都要和它打交道。
2. 工具选型与转发原理:iptables、firewalld、socat各管什么
2.1 Netfilter挂载点与DNAT/SNAT的本质
端口映射不是“转发文件”,而是“改写数据包”。Linux的内核网络协议栈里有一套名为Netfilter的钩子框架,在数据包经过几个固定位置时,允许用户态规则参与修改。对于端口映射来说,只需要记住这三个位置。
第一个位置叫PREROUTING,数据包刚进入主机、还没做路由决定时经过这里。把目标IP和端口改写掉的动作叫DNAT,就挂在这里。第二个位置是FORWARD,当一个数据包的目标地址不是本机、且内核允许转发时,它会从一张网卡走到另一张网卡,这个动作叫转发。第三个位置叫POSTROUTING,数据包即将离开网卡前经过这里。把源IP改写掉的动作叫SNAT,如果出口IP不固定,就写MASQUERADE自动适配。
端口映射其实就是“DNAT + SNAT”的组合动作。目标地址被改成后端服务器,源地址被改成网关自己。这样内网服务器收到包时,看到的是一个来自网关的请求,于是回包也交给网关,网关再沿原路送回给客户端。整个过程对两端来说,都是和网关在通信,后端服务器完全不知道客户端的存在。
2.2 iptables、firewalld、socat、rinetd怎么选
同一个“端口映射”,工具选了不下四种。常见做法是在选型阶段就按表对号入座:
| 工具 | 工作位置 | 性能特征 | 适用场景 |
|---|---|---|---|
| iptables | 内核态 Netfilter | 高,接近线性转发 | 长期运行的网关、NAT、端口转发 |
| nftables | 内核态 Netfilter | 高,iptables的下一代 | 新版RHEL/Debian/Kali默认方案 |
| firewalld | 封装 nftables/iptables | 高,多一层策略管理 | 不想手写命令、要按zone管理 |
| socat | 用户态进程 | 中,有拷贝和调度开销 | 临时调试、串口转网络、非root环境 |
| rinetd | 用户态进程 | 中,配置极简 | 纯TCP简单转发,不碰系统防火墙 |
端口映射这种长期稳定跑的流量,我一般优先用内核态的iptables或nftables,因为数据包不经过用户态拷贝,延迟低、吞吐高。socat适合“今天上午临时把8080转到另一台机器上看个现象”这种场景,用完就杀,不需要留一堆规则在系统里。firewalld在桌面Linux或需要按区管理的服务器上很顺手,但它在底层生成的规则比较复杂,排查时要多看一层间接层。
2.3 回包路径与MASQUERADE:为什么只配DNAT会翻车
新手最容易翻车的点,不是忘了写规则,而是没有理解“回包怎么走”。假设客户端访问网关公网IP的8080端口,DNAT把目标改成内网服务器192.168.1.50:80。如果只做了DNAT,内网服务器的回包会直接尝试发给客户端——因为数据包里的源地址还是192.168.1.50,目标地址是客户端的IP,而客户端和192.168.1.50不在一个网段,要么被路由器丢弃,要么被客户端拒收。
正确的做法是在POSTROUTING链里做MASQUERADE或SNAT,把源地址改成网关自己的IP。这样内网服务器看到的请求来自网关,回包先还给网关,网关再根据连接跟踪表把包送回客户端。所以“DNAT负责进门,SNAT负责出门”,缺一不可。为什么用MASQUERADE而不是SNAT?因为SNAT要求你写死一个源IP,而出口IP是动态获取的情况下,MASQUERADE会自动取当前出口网卡的主IP。代价是每次连接都要额外查一次地址,性能略低一点点,但对绝大多数场景没有感知。
2.4 连接跟踪:你的规则能跑多快全靠它
Netfilter里还有一张连接跟踪表nf_conntrack,端口映射双向转发能成立,全靠它记录每一个连接的状态。当DNAT改写了一个新连接的请求后,内核会记住“这个连接是经过改写的”,之后同一连接的回包会自动做逆变换,不需要每条包都去匹配两条NAT规则。这也是为什么FORWARD链里要放行ESTABLISHED,RELATED状态的包,而不是只放行80端口。
连接跟踪表的容量是转发性能的瓶颈之一。默认的nf_conntrack_max在内存充足的机器上通常够用,但如果你转发的是海量短连接,比如一个被频繁扫描的端口,表满了之后新连接会被直接丢弃。这个故障很隐蔽,因为流量不多时一切正常,一旦短连接打进来就“随机失败”。后面避坑章节会再提到这个,这里先记住一条排查路径:cat /proc/sys/net/netfilter/nf_conntrack_count,如果数字接近nf_conntrack_max,优先调大而不是加规则。
3. iptables实现端口映射:DNAT、SNAT与MASQUERADE的完整配置
3.1 开启ip_forward:转发的地基
iptables规则只负责“改包”,包能不能从一张网卡走到另一张网卡,由内核的转发开关决定。net.ipv4.ip_forward为0时,内核会直接丢弃所有目标不是本机的数据包,规则再多也无济于事。我见过不少人花几个小时调规则,最后发现罪魁祸首是大意没开转发。
# 临时打开:立即生效,重启失效 sysctl -w net.ipv4.ip_forward=1 # 持久化写入配置文件:重启后依然有效 echo 'net.ipv4.ip_forward=1' >> /etc/sysctl.conf # 重新加载sysctl配置,使刚才写入的配置生效 sysctl -psysctl -w是即时生效的改动,适合先验证思路;/etc/sysctl.conf里的配置会在开机时被sysctl --system加载。验证是否已经生效,执行sysctl net.ipv4.ip_forward看输出,1就是开,0就是关。开完转发后顺手执行sysctl net.ipv4.conf.all.forwarding,二者的语义几乎一致,但有些发行版会把all单独管理,最好两个都确认。
3.2 把127.0.0.1服务暴露到局域网:同机端口映射的两条规则
开发机上跑了一个MySQL,配置文件只监听了127.0.0.1:3306,现在另一台机器要连。你不想改MySQL配置,因为改完要重启服务;也不想把它绑到0.0.0.0,因为安全上有顾虑。这种同机端口映射,用PREROUTING加OUTPUT各一条规则就可以解决。
# 外部进入本机3306的TCP包,目标地址改写成回环地址 iptables -t nat -A PREROUTING -p tcp --dport 3306 -j DNAT --to-destination 127.0.0.1:3306 # 本机自己连接本机3306时,同样做目标改写 iptables -t nat -A OUTPUT -p tcp --dport 3306 -j DNAT --to-destination 127.0.0.1:3306逻辑说明:第一条规则解决“其他机器访问本机IP的3306端口”。数据包到达本机网卡后,在路由决策前被改写成目标127.0.0.1,内核最终把它交给本地监听的MySQL进程。第二条规则解决“本机自己访问自己IP的3306”。本机产生的流量不经过PREROUTING链,只走OUTPUT链,所以必须单独补一条。如果不加第二条,你在本机执行mysql -h 192.168.1.100 -P 3306会超时,但其他机器连却正常,这种不对称现象经常让新手误以为是防火墙拦了本机流量。
这个方案不限于MySQL。Redis、非容器化的数据库、只监听回环的开发服务都可以这样暴露。风险也很明确:所有改写都依赖内核连接跟踪,如果有程序绕过网络栈直接连本机端口,规则不会生效。
3.3 跨网段端口映射:外网端口转到内网主机
更常见的场景是门卫机器(网关)把某个端口让给内网的一台服务器。假设网关有eth0和eth1两张网卡,eth0接外部网络,IP为203.0.113.10,eth1接内网网段192.168.1.0/24。要把网关的8080端口转发到192.168.1.50这个内网主机的80端口,标准配置如下:
# 1. 进入eth0且目标是8080的TCP包,目标地址改写为内网服务器的80端口 iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 8080 -j DNAT --to-destination 192.168.1.50:80 # 2. 离开eth1、且目标为内网服务器80端口的包,源地址改写为网关自身 iptables -t nat -A POSTROUTING -o eth1 -p tcp -d 192.168.1.50 --dport 80 -j MASQUERADE # 3. 放行从eth0向eth1方向的新连接 iptables -I FORWARD -i eth0 -o eth1 -p tcp --dport 80 -j ACCEPT # 4. 放行从eth1回到eth0方向的回包 iptables -I FORWARD -i eth1 -o eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT这样做的逻辑:第一条DNAT是“进门”改写,第三条是允许数据包跨越两张网卡,第二条MASQUERADE是“出门”改写,第四条是放行回包。四条规则在Netfilter里各管一站,缺一条就会表现为“从外部连不上”或“连上后刷不出数据”。如果内网服务器不只192.168.1.50一台,还可以把-d 192.168.1.50改成-d 192.168.1.0/24,配合多目标DNAT实现负载均衡,那是iptables的扩展玩法。
如果出口IP是固定的,比如网关IP永远不会变,把MASQUERADE换成SNAT更高效:
iptables -t nat -A POSTROUTING -o eth1 -p tcp -d 192.168.1.50 --dport 80 -j SNAT --to-source 203.0.113.10注意SNAT的语义是“把源地址改成我指定的IP”,如果出口IP不固定,每次IP变化这条规则就失效,所以动态出口地址用MASQUERADE是常识。固定出口IP用SNAT能省掉每连接查出口IP的损耗,虽然量级很小,但用作生产网关时可以多留一点余量。
3.4 限端口范围与限源IP:转发规则的两个常用修饰
真实生产环境里很少无条件转发。要么只允许某个来源IP访问,要么只转发一段连续端口。iptables的匹配条件可以叠加在DNAT规则上,不需要拆成多条。
# 只允许192.168.5.0/24网段的机器访问网关8080端口,其他来源一概不转 iptables -t nat -A PREROUTING -i eth0 -s 192.168.5.0/24 -p tcp --dport 8080 -j DNAT --to-destination 192.168.1.50:80 # 把TCP的9000-9100端口整段映射到内网同一段端口 iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 9000:9100 -j DNAT --to-destination 192.168.1.50:9000-9100 # 如果后端端口与入口端口不一致,逐一对应需要逐条写,端口段只能段对段-s 192.168.5.0/24是源IP限定,写在--dport之前,语义是“只有来自这个网段的请求才属于我的转发范围”。--dport 9000:9100是端口段写法,iptables会把这个范围内的所有端口逐一匹配。注意DNAT的--to-destination里9000-9100是段映射,不会自动做偏移换算,如果入口是9000:9100,目标写成9000:9100,那么入口9001对应后端9001,而不是偏移到9001+1。这是很多人的误解点,配的时候要反复确认。
3.5 保存规则与开机恢复:不持久化的转发等于白配
iptables规则默认保存在内存里,重启就没了。重新敲一遍很容易出错,尤其是FORWARD规则顺序错了,会导致完全不同的匹配结果。保存规则的标准做法是把当前规则集导出来。
# Debian/Ubuntu 使用 iptables-persistent 实现开机自动加载 apt install iptables-persistent systemctl enable netfilter-persistent # 手动保存当前规则到文件 iptables-save > /etc/iptables/rules.v4 ip6tables-save > /etc/iptables/rules.v6 # RHEL/CentOS 直接覆盖默认规则文件 iptables-save > /etc/sysconfig/iptables提示:如果系统里装了firewalld,尽量别同时开启iptables-persistent。两套工具都在启动时往iptables里写规则,先后顺序不可控,经常造成“重启后规则丢了”的假象。后面避坑章节会展开说这个冲突。
4. firewalld与socat场景化落地:从Web转发到docker端口映射
4.1 firewalld端口转发:先masquerade再forward-port
对不想逐条敲iptables的运维来说,firewalld把端口转发包装成了一条完整的命令。但它有一个前提:必须先开启masquerade,也就是伪装,否则底层不会产生源地址改写,转发依然不通。这个前提让很多人踩坑,因为某些发行版的firewalld配置里默认没开这个选项。
# 开启伪装,这是整个转发能回包的前提 firewall-cmd --permanent --add-masquerade # 把本机8080端口转发到192.168.1.50的80端口 firewall-cmd --permanent --add-forward-port=port=8080:proto=tcp:toport=80:toaddr=192.168.1.50 # 重新加载配置使其生效 firewall-cmd --reload # 查看当前已配置的转发规则 firewall-cmd --list-forward-ports参数拆解:port=8080是监听入口端口,proto=tcp指定协议,toport=80是后端目标端口,toaddr是后端目标IP。注意如果后端端口就是入口端口,toport可以省略,但写上更明确。--permanent加不加的区别是:不加立刻生效但重启失效,加了重启保留但需要--reload才生效。我一般习惯先不加--permanent做联调,通了再补上。
想限定来源网段,用rich rule替代冒号语法更直观:
firewall-cmd --permanent --add-rich-rule='rule family=ipv4 source address=192.168.5.0/24 forward-port port=8080 protocol=tcp to-port=80 to-addr=192.168.1.50' firewall-cmd --reloadrich rule的语义是“在空格分隔的每个条件都满足时执行forward-port动作”。source address限定来源网段,family=ipv4限定协议族。和iptables的-s参数思路一致,只是语法更贴近口语。查看rich rule用firewall-cmd --list-rich-rules。
4.2 socat用户态转发:非root、临时调试、串口转网络
socat是用户态转发工具,不需要改内核参数,不需要root权限,也不会污染系统的iptables。它的工作方式是一个进程监听本地端口,把收到的字节流原样搬到另一个目标。因为走了用户态,性能上限远低于内核态的NAT,但胜在灵活轻巧。
# 本机8080端口转发到192.168.1.50:80,fork支持多个并发连接 socat TCP-LISTEN:8080,fork,reuseaddr TCP:192.168.1.50:80 # UDP端口转发,常用于DNS或日志采集场景 socat UDP-LISTEN:5353,reuseaddr,fork UDP:192.168.1.50:5353 # 串口转网络:把TCP端口4000收到的数据全部送入串口设备 socat TCP-LISTEN:4000,reuseaddr,fork /dev/ttyUSB0,raw,echo=0参数说明:fork让每个新连接都派生一个子进程来处理,否则一个连接关闭后进程就退出;reuseaddr允许端口在TIME_WAIT状态下被重新监听,不加它重启会大概率报“Address already in use”。串口场景里raw表示不对字节流做换行处理,echo=0关闭回显,这两个是嵌入式工程师做linux网口转串口时最常调的关键项。
socat还有一种少有人用的能力,就是监听Unix socket并转发到TCP。Linux主机上的容器运行时不直接暴露TCP端口时,你可以把/var/run/docker.sock通过socat转发出去,这在调试远程连接时很方便。
socat TCP-LISTEN:2375,fork,reuseaddr UNIX-CONNECT:/var/run/docker.sock注意这个动作等于把Docker的控制接口暴露到了网络上,生产环境绝对禁止这么干。我自己的习惯是:只在内网开发机、确认没有敏感容器运行时临时用,用完立刻杀掉进程。
4.3 docker端口映射与防火墙的配合:DOCKER链与firewalld冲突
docker的-p参数本质上是帮你往iptables里插Docker规则,而不是什么独立机制。docker run -p 8080:80 nginx实际做的是:在NAT表的DOCKER链中加一条DNAT规则,把目标端口8080改写为容器IP的80,同时往FORWARD链里插入允许转发到该容器IP的规则。所以docker端口映射和手工iptables端口映射共享同一套内核机制,区别只在于管理入口不同。
# 把容器的80端口映射到主机的8080端口 docker run -d -p 8080:80 --name web nginx # 只绑定到指定网卡指定端口:避免在主机所有IP上暴露 docker run -d -p 192.168.1.5:8081:80 --name web2 nginx # 查看当前容器的端口映射情况 docker port web问题出在同时启用firewalld的机器上。docker启动时会操作iptables的FORWARD链,firewalld启动时也会重置并重建它的规则集。如果firewalld先启动、docker后启动,docker的DOCKER链会插在FORWARD链的前面,可以正常工作;反过来,firewalld在docker之后执行--reload,可能把docker的规则冲掉,表现为“容器端口外部访问不了”。
解决思路按优先级排序:生产环境建议把宿主机的docker网卡加入firewalld的trusted zone,让所有发往容器的流量放行。具体命令如下:
# 把docker0网卡加入trusted zone,firewalld不再拦截容器流量 firewall-cmd --permanent --zone=trusted --add-interface=docker0 firewall-cmd --reload这个操作能消解链条顺序问题的大多数场景。再有就是:firewalld的zone规则的匹配优先级高于iptables规则,所以容器端口还需要在publiczone里显式放行:
firewall-cmd --permanent --zone=public --add-port=8080/tcp firewall-cmd --reload也就是说,docker映射做到两件事:内核NAT规则由docker生成,防火墙放行由firewalld负责。两者缺一,端口就进不来。
4.4 转发规则写完之后如何验证
规则配完了,建议按三层验证法去确认不是“看起来通了”。
# 第一层:查端口监听状态,确认主机端口确实有人监听或被NAT接管 ss -tlnp | grep -E '8080|80' # 第二层:本机回环探活,确认服务本身是活的 curl -I http://127.0.0.1:8080 # 第三层:抓包看真实走向,确认数据包的目标地址已经被改写 tcpdump -i any -nn port 8080 or port 80ss -tlnp如果显示8080没有任何进程监听,但又没有报错,因为NAT规则接管后,端口对应用程序是透明的。本机回环能通,说明服务没问题。抓包最关键:如果tcpdump在eth0抓到目标为192.168.1.50:80的包,说明DNAT已生效;如果看到的目标还是网关IP:8080,说明PREROUTING规则没匹配到,优先检查网卡名是不是写对了。
5. 端口映射转发避坑指南:五个常见故障的排查与解决
5.1 规则明明加了,内网还是不通:ip_forward没开
现象:iptables规则都写完了,iptables -t nat -L -n也能看到DNAT和SNAT规则,外部访问依旧不通,内网服务器上抓包什么都收不到。
原因:内核net.ipv4.ip_forward为0。数据包在PREROUTING阶段做了DNAT,路由决策时发现目标不是本机,而内核又不允许转发,直接把包丢弃。NAT规则本身没有生效机会。
解决:
sysctl -w net.ipv4.ip_forward=1 echo 'net.ipv4.ip_forward=1' >> /etc/sysctl.conf sysctl -p这个坑排第一,因为排查成本极低但最长被忽视。检查命令先于查规则执行,形成肌肉记忆就再也不会翻车。
5.2 转发后回包丢失:忘记SNAT与反向路径过滤双风险
现象:外部客户端能连上、能发出请求,但一直拿不到响应。服务器上看到SYN请求已到,回包也发了,但客户端那边就是卡在连接中。
原因:只配置了DNAT而遗漏了POSTROUTING的SNAT/MASQUERADE。内网服务器看到请求的源IP是外部客户端,于是把回包直接发给客户端,不走网关。客户端收到一个来自未知网段的包,且这个包的源地址自己根本没见过,丢弃掉。另一种可能性是rp_filter反向路径过滤生效:内核检查回包入口是否与连接跟踪记录一致,发现不对称就直接丢。
解决:
# 在POSTROUTING链补一条源地址改写,让回包先回网关 iptables -t nat -A POSTROUTING -o eth1 -p tcp -d 192.168.1.50 --dport 80 -j MASQUERADE # 调试时临时放宽rp_filter,确认现象后修正路由 sysctl -w net.ipv4.conf.all.rp_filter=0 sysctl -w net.ipv4.conf.eth1.rp_filter=0提示:生产环境不要长期关rp_filter,它是对抗IP欺骗的有效机制。正确做法是检查路由表,确保从内网侧进入的包能从同一个网卡原路返回,否则就算放开过滤也只是把问题掩盖掉。
5.3 本机访问本机映射的端口不通:DNAT不作用于本地发起的流量
现象:配好了PREROUTING的DNAT规则,外部机器能正常访问映射端口,但网关自己执行curl http://127.0.0.1:8080或者curl http://<网关IP>:8080一直超时。
原因:本机发起的流量不经过PREROUTING链,它从OUTPUT链直接进入路由。DNAT规则挂在PREROUTING上,对本机流量来说根本不存在。
解决:给OUTPUT链也加一条DNAT规则。
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 8080 -j DNAT --to-destination 192.168.1.50:80 iptables -t nat -A OUTPUT -p tcp --dport 8080 -j DNAT --to-destination 192.168.1.50:80如果觉得不优雅,也可以让PREROUTING去匹配那个通过eth0进来的流量,同时在本机访问时把请求地址写成内网后端IP。但大多数情况下补一条OUTPUT规则是最不疼的方案。注意这条规则会让本机所有发往8080端口的流量都转向内网,包括wget下载一个本地8080端口的文件,行为上要提前想清楚。
5.4 firewalld重启后规则丢失:多套iptables管理工具的冲突
现象:写好的iptables规则重启后全部消失,或者firewalld执行--reload之后docker映射的端口外部访问不了,原以为是规则又被清掉了。
原因:系统里同时存在firewalld、iptables原生服务和docker三套工具,它们都往内核的iptables里写东西。firewalld每次--reload都会重建它管理的规则链,docker启动时也会把它的DOCKER链插到FORWARD链前面。谁先谁后全看启动顺序,于是出现“上次还能用,这次重启就没了”的诡异现场。
解决:选择一套作为持久化管理工具,其他作为临时手段。
# 禁用firewalld,改用原生iptables持久化 systemctl disable firewalld --now systemctl enable iptables --now iptables-save > /etc/iptables/rules.v4 # 或者保留firewalld,把需要持久化的转发全部转写成firewall-cmd语法 firewall-cmd --runtime-to-permanent额外的注意事项:即便禁用了firewalld,docker还是会自己管理iptables。所以生产环境里更稳妥的做法是把docker0加入trusted zone,让firewalld不碰容器流量,docker只管自身的NAT规则,两不干扰。
5.5 socat端口被占用或进程退出:reuseaddr与systemd守护缺失
现象:重启socat时报“Address already in use”,或者socat进程在后台跑了一天后莫名消失,转发随之中断。
原因:第一条是没加reuseaddr,TCP端口在连接关闭后进入TIME_WAIT状态,新监听进程无法绑定。第二条是socat被以普通方式放进后台运行,终端崩溃或SSH断开后进程被杀掉。
解决:临时使用时把reuseaddr加上;常驻服务一律用systemd管理。
socat TCP-LISTEN:8080,fork,reuseaddr TCP:192.168.1.50:80systemd守护配置会在第6章给出完整unit文件。这里先记住原则:socat这种用户态转发工具,凡是期望长期在线的,就不要裸跑在shell里。
6. 进阶技巧:压测、nftables迁移与systemd守护转发
6.1 用iperf3验证转发吞吐
配完转发后很多人只测“通不通”,不测“快不快”。转发链路经过内核Netfilter,理论上可以达到线速,但实际受网卡驱动、连接跟踪表和FORWARD链规则条数影响。用iperf3实测是你的后悔药。
# 在网关机器上启动iperf3服务端 iperf3 -s -p 5201 # 在客户端机器上测试通过端口映射后的实际带宽 iperf3 -c 192.168.1.5 -p 8080 -t 30 -P 4注意细节:-p 8080指的是让iperf3客户端去连网关的映射端口,而不是直接连网关的5201端口。如果客户端连的是映射端口但iperf3报告速率很低,优先怀疑连接跟踪表是否被打满——cat /proc/sys/net/netfilter/nf_conntrack_count接近上限时,新连接会被丢弃,短连接叠加场景尤其严重。调大上限的路径是/etc/sysctl.conf里的net.netfilter.nf_conntrack_max,改完sysctl -p生效。
6.2 从iptables迁移到nftables:关键变化
新版RHEL、Debian和Kali默认用nftables作为防火墙后端。用户名下如果在这些发行版上按旧习惯写iptables命令,会发现工具还在,但规则集的底层结构变成了nftables。迁移的关键变化有两个:链名和匹配语法。
# nftables实现同机端口映射:定义表、链,再写DNAT规则 nft add table ip nat nft add chain ip nat prerouting { type nat hook prerouting priority -100 \; } nft add rule ip nat prerouting tcp dport 8080 dnat to 192.168.1.50:80nft命令把表和链显式分开,hook prerouting对应iptables时代的PREROUTING链,priority -100表示优先级数值。条件写在规则里,tcp dport 8080等价于iptables的-p tcp --dport 8080。反过来,想把现有iptables规则迁移到nftables,可以用iptables-translate查看对应写法。大多数系统迁移的根本原因不是功能差异,而是iptables后端已不再是内核唯一的管理入口。
6.3 用systemd守护socat:开机自启与崩溃拉起
[Unit] Description=socat port forward 8080 to 80 After=network-online.target [Service] ExecStart=/usr/bin/socat TCP-LISTEN:8080,fork,reuseaddr TCP:192.168.1.50:80 Restart=always RestartSec=5 User=nobody [Install] WantedBy=multi-user.target把这段写入/etc/systemd/system/socat-forward.service,执行systemctl daemon-reload && systemctl enable --now socat-forward。Restart=always让进程崩溃后自动拉起,RestartSec=5防止因为端口被占用而疯狂重启。User=nobody把进程权限降到最低,降低被利用后的风险。
我现在配端口映射的第一件事,是先看ip_forward和route -n,最后才碰iptables。这套排查顺序在物理机、虚拟机、容器网络里都一样好用。希望帮到你。
本文还有配套的精品资源,点击获取