我目前正在处理一个 VPN,其连接端点位于子网内,该子网的前缀应通过该特定 VPN 进行隧道传输。
因此,从本质上讲,该问题可以归结为与一组(较大的)目标地址(/16 掩码)进行匹配,但不包括完全包含的特定目标(小子集)子集,这些目标不应通过该方式进行路由(而是通过默认路由进行路由)。
如果问题是关于过滤的,在 Linux 中可以使用ipset
类似这样的设置来实现
ipset create MyVPN hash:net
ipset add MyVPN $MYVPNNET/$MYVPNMASK
ipset add MyVPN $MYVPNENDPOINT nomatch
然而这种 ipset 只能在 netfilter 内部使用。
ip route
现在我的问题是,如何使用 Linux 高级 IP 路由(即命令系列)设置等效的东西?
答案1
事实证明,在 Linux 中可以使用ipset匹配以选择路由表。额外的成分是使用 netfilter 规则,该规则将匹配传出的数据包并应用福马克然后,它们可用于选择专用路由表。此专用路由表将仅包含通过 VPN 的单个默认路由。
这是以脚本形式描述的总体思路以及设置方法。
# 通过 TUN 路由的子网
DSTNETS=.../.. .../..
# 从 TUN 路由中排除这些目的地
EXCLUDE=... ...
# 用于此连接的 TUN 设备及其参数通常由 VPN 守护进程提供
TUNDEV=...
TUNADDR=.../..
TUNPEER=...
# 用于匹配目的地的 ipset 的名称。基于 TUN 名称
IPSET=${TUNDEV}ipset
# 我们需要一个 netfilter fwmark 和一个 iproute2 表。fwmarks 和表是 32 位值,限制在有符号整数范围内,即 [0, 2³¹-1] fwmarks 可以用作表示多个标志的位掩码,因此根据我们的需要,可以设置单个特定位(或几个),或者设置一个非常具体的值,然后进行比较是否相等。
FWMARK=0x...
TABLE=0x...
# 创建 ipset 并用要匹配和不匹配的 IP 地址范围和子网填充它。
ipset create $IPSET hash:net
for d in $DSTNETS ; do ipset add $IPSET $d ; done
for x in $EXCLUDE ; do ipset add $IPSET $x nomatch ; done
# 创建一个新的 iproute2 规则表,用于查找所有设置了我们选择的 fwmark 的数据包的路由
ip rule add fwmark $FWMARK table $TABLE
# 魔法就在这里:创建一个 netfilter 规则,该规则将匹配来自此主机的数据包,用于匹配我们刚刚创建的 ipset 的目的地,并使用我们选择的 fwmark 标记它们。由于我们之前刚刚创建的规则,这些数据包将使用该特定表而不是全局表进行路由。
iptables -t mangle -A OUTPUT -m set --match-set $IPSET dst -j MARK --set-mark $FWMARK
# 还添加一个 netfilter 规则来覆盖这些数据包的源地址,因为如果它们与用于 VPN 的地址范围不匹配,目标网络可能会拒绝它们
iptables -t nat -A POSTROUTING -m set --match-set $IPSET dst -j SNAT --to-source $INTERNAL_IP4_ADDRESS
# 现在我们可以设置实际的 TUN 设备。严格来说,这些步骤可以提前完成,但在 TUN 启动和建立路由规则之间的短暂时间内,一些数据包可能会陷入困境
ip link set dev $TUNDEV up
ip addr add $TUNADDR peer $TUNPEER dev $TUNDEV
# 最后在我们的专用路由表中建立一条通过 TUN 的默认路由,由于 fwmark 规则,只有与我们的 ipset 匹配的数据包才会命中该路由
ip route add default dev $TUNDEV table $TABLE
要拆除一切,只需按照相反的脚本,删除内容即可;ipset可以destroy
用一个命令来编辑。
答案2
路由是按照最具体优先的方法计算的。因此,如果您的小型子网需要默认路由,请先放置该路由,然后再添加其他路由:
本例中的默认网关是 10.0.0.1 VPN 是 10.0.0.2
ip route add 10.0.1.0/24 via 10.0.0.1
ip route add 10.2.0.0/16 via 10.0.0.2
ip route add default via 10.0.0.1
将通过默认网关将流量路由到子网 (10.0.1.0),通过 10.0.0.2 将流量路由到 VPN,并通过默认网关将其他默认流量路由到子网 (10.0.1.0)。