Administrator
发布于 2025-10-28 / 3 阅读
0
0

内网 IP 映射(GRE 终端互访)

前言

有两台服务器,服务器 A 是移动的机房,服务器 B 是我们的阿里云服务器。‘

这两台服务器已经通过 GRE 隧道连接实现了数据互通。

移动侧内网内每个 IP 都代表了一张物联卡,此处用 A1、A2 ... An 表示。

经测试,发现:

  • An <-> B

  • A1 <-> A2

原因是移动侧做了限制 —— 不允许【终端互访】。也就是即使卡都是同一个内网内,互相之间仍然是隔离的。

PING 抓包发现 ICMP 数据包并没有发送到服务器 B。突发奇想,移动会拦截卡内网 IP 互访,那如果 B 划分一块内网网段和卡 IP 网段做映射,是不是可以绕过拦截呢?

IP 网段映射:A1 <=> C1,A2 <=> C2 ... An <=> Cn。

设计思路:

A1 (10.6.0.x) --[移动限制]--> A2 (10.6.0.y) ❌ 被阻断

改为:

A1 (10.6.0.x) --> 172.20.0.y (映射IP) --> GRE --> B --> DNAT回 10.6.0.y --> A2 ✅

基本参数

gre:gre-pgw1

卡 IP 网段:10.6.0.0/22

B 内网 IP:172.18.141.168

DNAT 映射网段(虚拟 IP 网段):172.20.0.0/22(后续扩展可以考虑 172.20.0.0/14)

少量固定映射

直接写 iptables 规则:

iptables -t nat -A PREROUTING -d 172.20.0.1 -j DNAT --to-destination 10.6.0.1
iptables -t nat -A PREROUTING -d 172.20.0.2 -j DNAT --to-destination 10.6.0.2

一、NETMAP(推荐)

Netmap 是 iptables 的 NAT 扩展,能够实现整个网段的一对一映射转换。

# 1. 添加路由,映射网段指定 gre(IP 不真实存在,只是 NAT 用)
# 如果设置为指向 eth0 设备的路由,要到阿里云 VPC 路由表配置跳回本ECS
# ip route add 172.20.0.0/22 dev gre-pgw1

# 上述 ip route add 非必须, 看情况添加:
# (1)如果有多个 gre 用同一个内网网段或者网段重叠, 才用指定 dev 挂载网卡
# gre1: 10.6.x.x, gre2: 10.6.x.x
# (2)如果 10.6.x.x 唯一归属于 gre1,则不需要这条路由。
# gre1: 10.6.x.x, gre2: 10.7.x.x

# 2. OUTPUT DNAT(用于本机发出的流量, 不经过 PREROUTING 链)
# 服务器 B ping 172.20.0.5
iptables -t nat -A OUTPUT -d 172.20.0.0/22 -j NETMAP --to 10.6.0.0/22

# 3. PREROUTING DNAT(用于转发流量)
# 10.6.0.1 ping 172.20.0.5
iptables -t nat -A PREROUTING -d 172.20.0.0/22 -j NETMAP --to 10.6.0.0/22

# tcpdump gre-pgw1, 会看见两条收发:
# 1、10.6.0.1 ping 172.20.0.5(10.6.0.1 ping => GRE 对端发送到服务器 B)
# 2、10.6.0.10 ping 10.6.0.5 (服务器 B gre 10.6.0.5)

二、nftables

nftables 作为 Linux 内核网络栈 的官方接班人,深度集成在内核中。它在内核网络的协议栈中预定义了几个关键的 Hook(钩子)点,当一个数据包从网卡进入内核后,它会依次流经这些钩子点。内核发现有 nftables 规则挂载(nft add rule ip nat prerouting...)时会做相应的处理。

Linux 内核 3.13(部分支持) 或 3.15(完整支持) 及以上使用。

我的阿里云 CentOS 7 通过 uname -r 看到内核是 3.10,使用不了 nftables。因此,下面命令也未曾验证,风险自行甄别。

# 创建 nftables 表、链和映射
# 1、创建表, 协议是IP, 表名为nat
nft add table ip nat

# 2、链名为 prerouting, type为 nat, hook点是 prerouting, 优先级为 -100                 
nft add chain ip nat prerouting { type nat hook prerouting priority -100 \; }   

# 3、计算动态映射: 172.20.0.0/22 -> 10.6.0.0/22
nft add rule ip nat prerouting ip daddr 172.20.0.0/22 \
    dnat to ip daddr & 0.0.255.255 | 10.6.0.0

# 16进制写法
nft add rule ip nat prerouting ip daddr 172.20.0.0/22 \
    dnat to ip daddr & 0x0000ffff | 0x0a060000

规则持久化:

通过命令行添加的 nftables 规则在重启后不会保留。若要永久生效,请将当前规则集导出到配置文件:

nft list ruleset > /etc/nftables.conf

三、ipset(不满足需求)

ipset 网段类型 hast:net,iptables 不是按照网段对应关系映射的,而是从指定的 IP 范围内随机或轮询一个IP。访问 172.20.0.1 期望是 DNAT 到 10.6.0.1,结果 DNAT 到了 10.6.0.35,不满足业务要求。

# 1、创建一个 hash:net 类型的 ipset, net表示网段
ipset create vnets hash:net
# 2、添加网段
ipset add vnets 172.20.0.0/22
# 3、映射
iptables -t nat -A PREROUTING -m set --match-set vnets dst -j DNAT --to-destination 10.6.0.1-10.6.0.254


评论