使用 DNATed IP 在与传入相同的接口上进行回复

使用 DNATed IP 在与传入相同的接口上进行回复

一台服务器有3个iface,2个内部(eth1/2)在不同的公网,一个外部(eth0)。

有一个服务 (openvpn) 无法绑定到某些 IP/iface,只能绑定到所有或一个,但我需要它只接受内部 iface 上的连接 (UDP)。默认网关是通过外部网关。

我有一个工作设置,其中包含 2 个服务实例,绑定到每个内部 iface 的 IP 并使用 iproute2 设置路由(ip route add xxx table x, ip rule add from <IP> table x)。

是否可以将第二个内部 iface (eth2) 上的传入连接 DNAT 到第一个内部 iface (eth1) 的 IP,并使其通过同一接口 (eth2) 响应?在这种情况下,无需运行服务的第二个实例并维护 2 个相同的配置,唯一的区别在于要监听的 IP。

问题是,如果我使用 DNAT 将 eth2 上的传入连接的目标 IP 更改为 eth1 的 IP,则基于的 ip 规则from <IP>将不起作用。或者,更确切地说,它将使用 eth1 的默认网关,使服务通过 eth1 而不是 eth2 进行回复。

是否可以有效地为 DNATed“会话”(UDP)的所有传出数据包设置标记,以便我可以在 ip 规则中使用 fwmark?还有其他解决方案可以解决主要问题吗?

答案1

找到了解决方案。此解决方案适用于任何无法侦听特定接口的 Linux 服务,但只能侦听所有 (0.0.0.0) 或某个特定接口,如 MySQL、OpenVPN 和许多其他服务。因此,我们让服务侦听一个 iface,并添加 netfilter/iproute2 规则,以将另一个 iface 上对相同协议和端口的所有请求重定向到第一个 iface 上的服务。

“会话”(尽管在 OpenVPN 的情况下是 UDP)实际上是由 netfilter 维护的,并且有一个模块连接跟踪允许引用来自特定会话的数据包。在这种情况下,我在 mangle 表中为 OUTPUT 添加了一条规则,以使用标记标记来自 DNATed 会话的所有数据包。然后我使用此标记来路由数据包。


因此,命令如下:

定义变量

iface_int2=eth2         # the second internal iface
ip_int2=xx.xx.xx.xx     # the IP of the second internal iface
proto=udp               # the protocol of the connection
service_port=1194       # the incoming service port
ip_int1=yy.yy.yy.yy     # the IP of the first internal iface
ip_gw2=xx.xx.xx.1       # the IP of the default gateway for the second internal iface



此命令指示 netfilter 覆盖第二个 iface 上传入连接的目标 IP。

iptables -t nat -A PREROUTING -i $iface_int2 -d $ip_int2 -p $proto --dport \
$service_port -j DNAT --to $ip_int1



此命令指示 netfilter 为覆盖(DNATed)的传入连接的传出数据包(服务的回复)设置标记。--ctorigdst是传入连接的原始(DNATed 前)目标 IP

iptables -t mangle -A OUTPUT -p $proto --sport $service_port -m conntrack \
--ctstate DNAT --ctorigdst $ip_int2 -j MARK --set-mark 0x75



此命令指示 iproute2 通过表 100 的路由定义路由设置标记的数据包。Prio 是设置此规则的最高优先级所必需的,因为它非常具体并且不会干扰其他规则。如果未指定 prio,则第一个内部 iface 的路由规则可能会获得更高的优先级。

ip rule add prio 10 fwmark 0x75 table 100



此命令将默认网关添加到表 100

ip route add default via $ip_gw2 table 100



为了使这一切发挥作用,有必要减轻返回路径过滤器对第二个内部 iface 的控制。

# rp_filter - INTEGER
#   0 - No source validation.
#   1 - Strict mode as defined in RFC3704 Strict Reverse Path
#       Each incoming packet is tested against the FIB and if the interface
#       is not the best reverse path the packet check will fail.
#       By default failed packets are discarded.
#   2 - Loose mode as defined in RFC3704 Loose Reverse Path
#       Each incoming packet's source address is also tested against the FIB
#       and if the source address is not reachable via any interface
#       the packet check will fail.

echo 2 > /proc/sys/net/ipv4/conf/$iface_int2/rp_filter
# -OR-
sysctl -w "net.ipv4.conf.$iface_int2.rp_filter=2"
# -OR-
echo "net.ipv4.conf.$iface_int2.rp_filter=2" >> /etc/sysctl.conf
sysctl -p /etc/sysctl.conf

相关内容