强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

iptables 完全指南 / 第 11 章:端口转发与代理

第 11 章:端口转发与代理

本章目标:掌握使用 iptables 实现端口转发、反向代理、简单负载均衡和透明代理的方法,能够解决常见的内网服务暴露和流量调度问题。


11.1 端口转发基础

11.1.1 什么是端口转发

端口转发(Port Forwarding)是将发送到某个 IP:端口 的流量重新定向到另一个 IP:端口的过程。它是 DNAT 的一种典型应用。

外部用户                  NAT 网关                    内网服务器
         ──────────→     eth0: 203.0.113.1            10.0.0.10:80
请求 203.0.113.1:80       ──── DNAT ────→    请求 10.0.0.10:80
         ←──────────                     ←──────────
响应                      ←── 反向 NAT ──   响应

11.1.2 基本端口转发配置

#!/bin/bash
# ═══════════════════════════════════════════════════
# 基本端口转发:公网 80 → 内网 10.0.0.10:80
# ═══════════════════════════════════════════════════

# 启用 IP 转发
sysctl -w net.ipv4.ip_forward=1

# DNAT:将入站 HTTP 流量转发到内网 Web 服务器
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 \
  -j DNAT --to-destination 10.0.0.10:80

# 允许转发该流量
iptables -A FORWARD -i eth0 -o eth1 -p tcp --dport 80 \
  -d 10.0.0.10 -j ACCEPT

# SNAT:确保内网服务器的回复经过网关返回
iptables -t nat -A POSTROUTING -o eth1 -p tcp --dport 80 \
  -d 10.0.0.10 -j SNAT --to-source 10.0.0.1

11.1.3 跨端口转发

# 将公网 8080 端口转发到内网 80 端口
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 8080 \
  -j DNAT --to-destination 10.0.0.10:80

# 将公网 8443 端口转发到内网 443 端口
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 8443 \
  -j DNAT --to-destination 10.0.0.10:443

# FORWARD 链允许
iptables -A FORWARD -i eth0 -o eth1 -p tcp -m multiport \
  --dports 80,443 -d 10.0.0.10 -j ACCEPT

11.1.4 多端口转发脚本

#!/bin/bash
# ═══════════════════════════════════════════════════
# 多服务端口转发脚本
# ═══════════════════════════════════════════════════

WAN_IF="eth0"
LAN_IF="eth1"
GATEWAY_IP="10.0.0.1"

# 定义端口映射规则(公网端口:内网IP:内网端口)
declare -A PORT_MAP=(
    ["80"]="10.0.0.10:80"        # Web HTTP
    ["443"]="10.0.0.10:443"      # Web HTTPS
    ["2222"]="10.0.0.5:22"       # SSH 跳板
    ["3306"]="10.0.0.200:3306"   # MySQL
    ["5432"]="10.0.0.200:5432"   # PostgreSQL
    ["6379"]="10.0.0.200:6379"   # Redis
    ["8080"]="10.0.0.11:8080"    # Tomcat
    ["9090"]="10.0.0.12:9090"    # Prometheus
)

# 启用转发
sysctl -w net.ipv4.ip_forward=1

# 清空 NAT 和 FORWARD 链
iptables -t nat -F PREROUTING
iptables -t nat -F POSTROUTING
iptables -F FORWARD

# 允许已建立的连接
iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# 应用端口映射
for PUB_PORT in "${!PORT_MAP[@]}"; do
    TARGET="${PORT_MAP[$PUB_PORT]}"
    INTERNAL_IP=$(echo $TARGET | cut -d: -f1)
    INTERNAL_PORT=$(echo $TARGET | cut -d: -f2)

    echo "映射: $PUB_PORT$INTERNAL_IP:$INTERNAL_PORT"

    # DNAT
    iptables -t nat -A PREROUTING -i $WAN_IF -p tcp --dport $PUB_PORT \
      -j DNAT --to-destination $INTERNAL_IP:$INTERNAL_PORT

    # FORWARD
    iptables -A FORWARD -i $WAN_IF -o $LAN_IF -p tcp \
      --dport $INTERNAL_PORT -d $INTERNAL_IP -j ACCEPT
done

# SNAT
iptables -t nat -A POSTROUTING -o $LAN_IF -s 10.0.0.0/24 \
  -j SNAT --to-source $GATEWAY_IP

# 默认策略
iptables -P FORWARD DROP

echo "Port forwarding configured."

11.2 本机端口转发

11.2.1 使用 REDIRECT

# 将本机 8080 端口的流量重定向到 80 端口
iptables -t nat -A PREROUTING -p tcp --dport 8080 \
  -j REDIRECT --to-port 80

# 将本机 8443 端口的流量重定向到 443 端口
iptables -t nat -A PREROUTING -p tcp --dport 8443 \
  -j REDIRECT --to-port 443

# 也影响本机进程发出的请求
iptables -t nat -A OUTPUT -p tcp --dport 8080 \
  -j REDIRECT --to-port 80

11.2.2 使用 socat 实现端口转发

# socat 可以实现更灵活的端口转发
# 安装:apt install socat

# 将本地 8080 转发到远程 10.0.0.10:80
socat TCP-LISTEN:8080,fork,reuseaddr TCP:10.0.0.10:80 &

# 将本地 8443 转发到远程 10.0.0.10:443
socat TCP-LISTEN:8443,fork,reuseaddr TCP:10.0.0.10:443 &

11.3 内网穿透

11.3.1 场景说明

内网穿透用于让外部网络能够访问位于 NAT 后面的内网服务。

外部用户            公网服务器 (跳板)           内网服务器
                        203.0.113.1              10.0.0.10
                            │                         │
     ───→ 端口 2222    ─────┤                         │
                            ├── DNAT ──→ 端口 22  ────┤
                            │                         │
     ←─── 响应         ←────┤←── 反向 NAT ──────────←─┤

11.3.2 使用 iptables + SSH 隧道

# ─── 步骤 1:在内网服务器上建立 SSH 反向隧道 ───
# 在内网服务器上执行:
ssh -R 2222:localhost:22 [email protected] -N

# ─── 步骤 2:在公网服务器上配置 DNAT ───
# 在公网服务器上执行:
iptables -t nat -A PREROUTING -p tcp --dport 2222 \
  -j DNAT --to-destination 127.0.0.1:2222

# ─── 步骤 3:外部用户通过公网服务器访问内网 SSH ───
ssh -p 2222 [email protected]

11.3.3 使用 iptables 实现固定端口映射

#!/bin/bash
# 公网服务器:将多个高端口映射到不同内网服务器

# 内网服务器 1 的 SSH
iptables -t nat -A PREROUTING -p tcp --dport 2201 \
  -j DNAT --to-destination 10.0.0.10:22

# 内网服务器 2 的 SSH
iptables -t nat -A PREROUTING -p tcp --dport 2202 \
  -j DNAT --to-destination 10.0.0.11:22

# 内网服务器 1 的 Web
iptables -t nat -A PREROUTING -p tcp --dport 8001 \
  -j DNAT --to-destination 10.0.0.10:80

# 内网服务器 2 的 Web
iptables -t nat -A PREROUTING -p tcp --dport 8002 \
  -j DNAT --to-destination 10.0.0.11:80

# FORWARD 规则
iptables -A FORWARD -i eth0 -o eth1 -p tcp \
  -m multiport --dports 22,80 -d 10.0.0.0/24 -j ACCEPT

11.4 简单负载均衡

11.4.1 基于 statistic 模块的随机负载均衡

#!/bin/bash
# ═══════════════════════════════════════════════════
# iptables 简单负载均衡
# 将 HTTP 流量分发到 3 台后端 Web 服务器
# ═══════════════════════════════════════════════════

# 后端服务器列表
BACKENDS=("10.0.0.10" "10.0.0.11" "10.0.0.12")
NUM_BACKENDS=${#BACKENDS[@]}

# 第一台:1/3 概率
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 \
  -m statistic --mode random --probability 0.33 \
  -j DNAT --to-destination ${BACKENDS[0]}:80

# 第二台:剩余流量的 1/2(即总体 1/3)
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 \
  -m statistic --mode random --probability 0.50 \
  -j DNAT --to-destination ${BACKENDS[1]}:80

# 第三台:剩余所有流量(即总体 1/3)
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 \
  -j DNAT --to-destination ${BACKENDS[2]}:80

# HTTPS 负载均衡
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 \
  -m statistic --mode random --probability 0.33 \
  -j DNAT --to-destination ${BACKENDS[0]}:443

iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 \
  -m statistic --mode random --probability 0.50 \
  -j DNAT --to-destination ${BACKENDS[1]}:443

iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 \
  -j DNAT --to-destination ${BACKENDS[2]}:443

11.4.2 基于 nth 模式的轮询负载均衡

# 每 3 个包轮询一次
# 第 1 个包 → 服务器 1
iptables -t nat -A PREROUTING -p tcp --dport 80 \
  -m statistic --mode nth --every 3 --packet 0 \
  -j DNAT --to-destination 10.0.0.10:80

# 第 2 个包 → 服务器 2
iptables -t nat -A PREROUTING -p tcp --dport 80 \
  -m statistic --mode nth --every 2 --packet 0 \
  -j DNAT --to-destination 10.0.0.11:80

# 第 3 个包 → 服务器 3
iptables -t nat -A PREROUTING -p tcp --dport 80 \
  -j DNAT --to-destination 10.0.0.12:80

11.4.3 负载均衡注意事项

维度iptables 方案专业方案(Nginx/HAProxy)
算法随机/轮询轮询/最少连接/IP哈希/权重
健康检查不支持支持
会话保持不支持支持(cookie/IP哈希)
SSL 终止不支持支持
性能高(内核态)中(用户态)
适用场景简单场景生产环境

建议:对于简单场景或作为底层流量分发,iptables 负载均衡足够;对于生产环境,建议使用 Nginx、HAProxy 或 LVS。


11.5 透明代理

11.5.1 透明代理原理

透明代理(Transparent Proxy)在客户端无感知的情况下拦截 HTTP 流量并转发给代理服务器处理。

客户端              网关 (iptables)           Squid 代理          互联网
  │                      │                      │                  │
  │── HTTP 请求 ────────→│                      │                  │
  │                      │── REDIRECT ─────────→│                  │
  │                      │  (端口 3128)         │── 转发请求 ─────→│
  │                      │                      │←── 响应 ─────────│
  │←── 响应 ─────────────│←── 代理响应 ─────────│                  │

11.5.2 Squid 透明代理配置

#!/bin/bash
# ═══════════════════════════════════════════════════
# Squid 透明代理配置
# ═══════════════════════════════════════════════════

# ─── Squid 配置(/etc/squid/squid.conf)───
# http_port 3128 transparent
# acl localnet src 10.0.0.0/24
# http_access allow localnet
# http_access deny all

# ─── iptables 配置 ───

# 启用转发
sysctl -w net.ipv4.ip_forward=1

# 将内网的 HTTP 流量重定向到 Squid
iptables -t nat -A PREROUTING -i eth1 -p tcp --dport 80 \
  -j REDIRECT --to-port 3128

# 允许 Squid 发起的出站连接
iptables -A OUTPUT -m owner --uid-owner proxy -j ACCEPT

# 允许已建立的连接
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# 允许回环
iptables -A INPUT -i lo -j ACCEPT

# 允许 Squid 访问 DNS
iptables -A OUTPUT -p udp --dport 53 -j ACCEPT

# 默认策略
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT DROP

11.5.3 HTTPS 透明代理(SSL 拦截)

注意:HTTPS 透明代理需要 SSL 中间人攻击(MITM),在企业环境中使用需遵守相关法规和员工知情同意。

# 将 HTTPS 流量重定向到 Squid 的 SSL 端口
iptables -t nat -A PREROUTING -i eth1 -p tcp --dport 443 \
  -j REDIRECT --to-port 3129

11.5.4 使用 TPROXY 实现透明代理

#!/bin/bash
# TPROXY 方式透明代理(不修改数据包,更高效)

# ─── 步骤 1:在 raw 表跳过连接跟踪 ───
iptables -t raw -A PREROUTING -p tcp --dport 80 -j NOTRACK

# ─── 步骤 2:在 mangle 表使用 TPROXY ───
iptables -t mangle -A PREROUTING -p tcp --dport 80 \
  -j TPROXY --tproxy-mark 0x1/0x1 --on-port 3129

# ─── 步骤 3:策略路由 ───
ip rule add fwmark 1 lookup 100
ip route add local 0.0.0.0/0 dev lo table 100

11.6 端口转发的安全加固

11.6.1 限制来源 IP

# 只允许特定 IP 访问转发的端口
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 3306 \
  -s 192.168.1.100 -j DNAT --to-destination 10.0.0.200:3306

# 只允许特定网段访问
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 22 \
  -s 10.0.0.0/8 -j DNAT --to-destination 10.0.0.5:22

11.6.2 限制连接速率

# 限制转发端口的新连接速率
iptables -A FORWARD -i eth0 -o eth1 -p tcp --dport 80 \
  -d 10.0.0.10 --syn \
  -m hashlimit --hashlimit-above 100/sec \
  --hashlimit-mode srcip --hashlimit-name web_limit \
  -j DROP

11.6.3 隐藏内部拓扑

# MASQUERADE 确保内网服务器看不到外部真实 IP
iptables -t nat -A POSTROUTING -o eth1 -p tcp --dport 80 \
  -d 10.0.0.10 -j MASQUERADE

# 或使用 SNAT
iptables -t nat -A POSTROUTING -o eth1 -p tcp --dport 80 \
  -d 10.0.0.10 -j SNAT --to-source 10.0.0.1

11.7 完整业务场景

11.7.1 企业级端口转发网关

#!/bin/bash
# ═══════════════════════════════════════════════════
# 企业级端口转发网关
# 网络拓扑:
#   eth0: 公网 203.0.113.1
#   eth1: 内网 10.0.0.1/24
#   eth2: DMZ 172.16.0.1/24
# ═══════════════════════════════════════════════════

# 启用转发
sysctl -w net.ipv4.ip_forward=1

# ─── 清空规则 ───
iptables -F
iptables -t nat -F
iptables -X

# ─── 默认策略 ───
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

# ─── 已建立的连接 ───
iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# ─── 回环接口 ───
iptables -A INPUT -i lo -j ACCEPT

# ─── 管理访问 ───
iptables -A INPUT -p tcp --dport 22 -s 192.168.1.0/24 -j ACCEPT

# ─── 端口转发规则 ───

# Web 服务 → DMZ Web 服务器
iptables -t nat -A PREROUTING -i eth0 -p tcp -m multiport \
  --dports 80,443 -j DNAT --to-destination 172.16.0.10
iptables -A FORWARD -i eth0 -o eth2 -p tcp -m multiport \
  --dports 80,443 -d 172.16.0.10 -j ACCEPT

# SSH 跳板 → 内网管理服务器
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 2222 \
  -j DNAT --to-destination 10.0.0.5:22
iptables -A FORWARD -i eth0 -o eth1 -p tcp --dport 22 \
  -d 10.0.0.5 -j ACCEPT

# 邮件服务 → DMZ 邮件服务器
iptables -t nat -A PREROUTING -i eth0 -p tcp -m multiport \
  --dports 25,110,143,465,587,993 -j DNAT --to-destination 172.16.0.20
iptables -A FORWARD -i eth0 -o eth2 -p tcp -m multiport \
  --dports 25,110,143,465,587,993 -d 172.16.0.20 -j ACCEPT

# ─── DMZ 访问内网数据库(仅限 MySQL)───
iptables -A FORWARD -i eth2 -o eth1 -p tcp --dport 3306 \
  -s 172.16.0.10 -d 10.0.0.200 -j ACCEPT

# ─── 内网和 DMZ 出站 ───
iptables -A FORWARD -i eth1 -o eth0 -j ACCEPT
iptables -A FORWARD -i eth2 -o eth0 -j ACCEPT

# ─── SNAT ───
iptables -t nat -A POSTROUTING -o eth0 -s 10.0.0.0/24 \
  -j SNAT --to-source 203.0.113.1
iptables -t nat -A POSTROUTING -o eth0 -s 172.16.0.0/24 \
  -j SNAT --to-source 203.0.113.1

# ─── 日志 ───
iptables -A FORWARD -m limit --limit 5/min \
  -j LOG --log-prefix "IPT-FWD-DROP: "

echo "Enterprise gateway configured."

11.8 注意事项

⚠️ IP 转发必须启用:所有转发场景都需要 net.ipv4.ip_forward = 1

⚠️ FORWARD 链必须允许:DNAT 只改变目的地址,FORWARD 链仍然需要显式允许转发流量。

⚠️ iptables 负载均衡不支持健康检查:如果后端服务器宕机,流量仍会被分发到它。生产环境建议使用 LVS + keepalived 或 Nginx/HAProxy。

⚠️ conntrack 与端口转发:大量短连接会快速填满 conntrack 表。根据并发连接数合理调整 nf_conntrack_max


11.9 扩展阅读

资源说明
LVS(Linux Virtual Server)内核级四层负载均衡
HAProxy高性能七层负载均衡
NginxWeb 服务器和反向代理
SquidHTTP 代理服务器
man sshSSH 隧道和端口转发

本章小结

技术命令/模块用途
端口转发DNAT将流量从公网端口转发到内网
本机重定向REDIRECT将本机端口流量重定向
简单负载均衡statistic + DNAT随机/轮询分发流量
透明代理REDIRECT / TPROXY无感知 HTTP 代理
内网穿透SSH -R + DNAT从外部访问内网服务

下一章第 12 章:安全加固规则,将学习防扫描、防 DDoS 和速率限制等安全规则。