iptables做TCP/UDP端口转发

一、核心原理与前置条件

iptables 端口转发(也称为 DNAT/SNAT)是在 Linux 内核层面进行的网络数据包重定向。它比应用层转发(如 SSH 隧道)效率更高,因为它直接修改数据包的 IP 头和端口信息。

1.1 开启系统路由转发功能

这是实现跨网段端口转发(尤其是转发到其他主机)的必备前提。系统默认禁止转发数据包。

临时开启(重启失效):

1
2
3
echo 1 > /proc/sys/net/ipv4/ip_forward
# 或
sysctl -w net.ipv4.ip_forward=1

永久开启:
编辑 /etc/sysctl.conf 文件,添加或修改以下行:

1
net.ipv4.ip_forward = 1

然后执行 sysctl -p 使配置立即生效。

1.2 理解关键链与表

iptables 的 nat 表是实现端口转发的核心,主要涉及两个链:

  • PREROUTING:数据包进入本机、经过路由判断之前。在此链进行 DNAT(目标地址转换),即修改数据包的“目标IP:端口”。
  • POSTROUTING:数据包经过路由判断、即将发送出网卡之前。在此链进行 SNAT(源地址转换),即修改数据包的“源IP”,确保回包能正确返回。

简单记忆PREROUTING 改“去哪”,POSTROUTING 改“从哪来”。


二、实战场景与配置命令

2.1 场景一:本机端口转发(本地转发)

将发往本机 A 端口的数据,转发到本机的 B 端口。

示例:将本机 7777 端口转发到 6666 端口。

1
2
3
4
5
# 外部访问本机时生效
iptables -t nat -A PREROUTING -p tcp --dport 7777 -j REDIRECT --to-port 6666

# 本机自己访问自己时生效(如 localhost:7777)
iptables -t nat -A OUTPUT -p tcp --dport 7777 -j REDIRECT --to-port 6666

说明

  • -t nat:指定操作 nat 表。
  • -A PREROUTING:在 PREROUTING 链末尾追加规则。
  • -p tcp:匹配 TCP 协议。
  • --dport 7777:匹配目标端口为 7777。
  • -j REDIRECT:执行重定向动作。
  • --to-port 6666:重定向到端口 6666。

2.2 场景二:转发到另一台主机(最常用)

将发往本机(转发机) A 端口的数据,转发到另一台内网/外网主机 BC 端口。

网络拓扑

  • **转发机 (FW)**:IP 192.168.1.168,接收来自客户端的 6666 端口请求。
  • **目标机 (TARGET)**:IP 192.168.1.8,实际提供服务在 7777 端口。

在转发机 (FW) 上执行:

1
2
3
4
5
6
7
8
# 1. 开启路由转发(必须)
sysctl -w net.ipv4.ip_forward=1

# 2. DNAT:修改目标地址 (PREROUTING链)
iptables -t nat -A PREROUTING -p tcp --dport 6666 -j DNAT --to-destination 192.168.1.8:7777

# 3. SNAT:修改源地址,确保回包能经过本机 (POSTROUTING链)
iptables -t nat -A POSTROUTING -p tcp -d 192.168.1.8 --dport 7777 -j SNAT --to-source 192.168.1.168

命令解析

  • -j DNAT --to-destination:执行目标地址转换。
  • -j SNAT --to-source:执行源地址转换,--to-source 通常应设置为转发机的内网IP。如果转发机有公网IP且用于转发公网流量,这里也应填内网IP

2.3 场景三:公网IP主机间的转发

当两台主机都有公网IP时,转发规则与场景二类似,但 SNAT --to-source 必须设置为转发机的内网IP(私网IP),而非公网IP。

错误示例(会导致转发失败):

1
iptables -t nat -A POSTROUTING -p tcp -d <目标机公网IP> --dport XXXX -j SNAT --to-source <转发机公网IP> # 错误!

数据包进入主机后,其目的地址已是内网IP。SNAT 为公网IP会导致回包路径异常。

2.4 场景四:UDP 端口转发

UDP 转发与 TCP 转发命令结构相同,只需将协议 -p tcp 改为 -p udp

UDP 转发完整示例(将本机 100 端口转发到 192.168.1.1:80):

1
2
3
4
5
6
7
# DNAT
iptables -t nat -A PREROUTING -d 10.10.10.1 -p udp --dport 100 -j DNAT --to-destination 192.168.1.1:80
# SNAT (注意参数顺序与TCP示例略有不同,但原理一致)
iptables -t nat -A POSTROUTING -s 192.168.1.1 -p udp --dport 80 -j SNAT --to-source 10.10.10.1:100
# 允许转发 (FORWARD链)
iptables -A FORWARD -o eth0 -d 192.168.1.1 -p udp --dport 80 -j ACCEPT
iptables -A FORWARD -i eth0 -s 192.168.1.1 -p udp --sport 80 -j ACCEPT

三、规则管理与持久化

3.1 查看规则

1
2
3
4
# 查看 nat 表的所有规则(带行号)
iptables -t nat -nL --line-numbers
# 查看 filter 表的 FORWARD 链规则
iptables -L FORWARD --line-numbers

3.2 删除规则

通过规则序号删除是最高效的方式。

1
2
3
4
# 删除 nat 表 PREROUTING 链的第 1 条规则
iptables -t nat -D PREROUTING 1
# 删除 filter 表 FORWARD 链的第 2 条规则
iptables -D FORWARD 2

3.3 保存规则(永久生效)

配置的规则默认在重启后丢失,需要保存。

  • CentOS 6 / RHEL 6
    1
    service iptables save
    规则将保存到 /etc/sysconfig/iptables
  • CentOS 7 / RHEL 7
    首先安装 iptables-services
    1
    2
    3
    yum install iptables-services
    systemctl enable iptables
    systemctl start iptables
    然后使用相同命令保存:service iptables saveiptables-save > /etc/sysconfig/iptables

3.4 清空与重置

1
2
3
4
5
6
7
8
# 清除 nat 表所有链的规则
iptables -t nat -F
# 清除 filter 表所有链的规则
iptables -F
# 清除所有用户自定义链
iptables -X
# 计数器归零
iptables -Z

警告:在生产环境谨慎使用 -F-X,可能导致网络中断。


四、综合示例与排错

4.1 完整示例:实现内网穿透式访问

目标:让客户端能通过转发机 A 访问到后端服务器 B 的 Web 服务。

  • **转发机 (A)**:IP 1.1.1.1(公网),2.2.2.2(转发机内网IP,用于SNAT)
  • **后端服务器 (B)**:IP 192.168.1.100(内网),运行在 80 端口。

在转发机 A 上配置:

1
2
3
4
5
6
7
8
9
# 开启路由转发
echo 1 > /proc/sys/net/ipv4/ip_forward

# 添加转发规则
iptables -t nat -A PREROUTING -p tcp --dport 999 -j DNAT --to-destination 192.168.1.100:80
iptables -t nat -A POSTROUTING -d 192.168.1.100 -p tcp --dport 80 -j SNAT --to-source 2.2.2.2

# 保存规则
service iptables save

结果:客户端访问 http://1.1.1.1:999,实际获取到的是 http://192.168.1.100:80 的内容。

4.2 常见问题与排查

  1. 转发不生效

    • 检查是否已开启 net.ipv4.ip_forward = 1
    • 检查 iptables -t nat -nL 规则是否添加成功。
    • 检查目标服务器的防火墙是否放行了来自转发机 IP 的流量。
    • 使用 tcpdump 在转发机抓包,观察数据包是否被正确修改和转发。
      1
      tcpdump -i any port [源端口] or [目标端口] -nn
  2. 本机无法访问自己的转发端口
    确保添加了 OUTPUT 链的 REDIRECT 规则(见场景一)。

  3. CentOS 7 没有 service iptables save 命令
    安装 iptables-services 包。


五、总结

iptables 端口转发是一项强大而高效的内核级网络功能。掌握其核心步骤:

  1. 开启路由转发 (ip_forward=1)。
  2. 添加 DNAT 规则 (PREROUTING 链),修改“去哪”。
  3. 添加 SNAT 规则 (POSTROUTING 链),修改“从哪来”,确保回包路径正确。
  4. 保存规则,确保重启后生效。

对于简单的本机端口重定向,使用 REDIRECT 动作更为便捷。对于复杂的网络环境,理解 DNAT/SNAT 的原理和 PREROUTING/POSTROUTING 链的工作时机是成功配置的关键。