问题
在基于 Linux 的路由器上设置了一个 OpenVPN 服务器实例(tun
、udp
、 端口),该路由器还运行一个 OpenVPN 客户端实例( 、、 端口),将其连接到 VPN 提供商。客户端和服务器实例均运行正常1194
tun
udp
1197
单独地。但是,当启用VPN客户端实例时,客户端无法连接到VPN服务器。
我确信这种情况会发生,因为 VPN 客户端实例修改了main
路由表,因此来自 ( OUTPUT
) 和通过 ( FORWARD
) 路由器的所有流量都会路由到 VPN 提供商。这是所需的默认行为,但对于从 Internet 发起的连接则不然。
使用iptables
和/或ip
,如何设置路由策略,以便从 Internet 发起的所有(或至少 VPN)连接都通过标准默认网关(192.168.1.1
)进行路由?
设置
LINUX ROUTER
-----------------------------------------
| LAN if: br-lan, 192.168.2.1/24 |
| VPN client if: tun0, 10.63.10.6/32 |
| VPN server if: tun1, 10.255.0.1/24 |
| DMZ if: eth0, 192.168.1.2/24 |
-----------------------------------------
|
GATEWAY ROUTER |
--------------------------
| DMZ if: 192.168.1.1/24 |
| WAN if: x.x.x.x/x |
--------------------------
|
INTERNET | VPN CLIENT OF LINUX ROUTER (public IP: y.y.y.y/y)
----------------- --------------------------------------
| |----| VPN client if: tun1, 10.255.0.6/24 |
----------------- --------------------------------------
|
|
VPN PROVIDER OF LINUX ROUTER
--------------------------------
| VPN server if: 10.63.10.1/32 |
--------------------------------
你会注意到,我们这里处于双 NAT 的情况。虽然这可能让人不舒服这不是问题,因为客户能当 VPN 客户端实例被禁用时连接。
启用 VPN 客户端和服务器实例后,main
路由表如下ip route list table main
:
0.0.0.0/1 via 10.63.10.5 dev tun0 #added by VPN client instance
default via 192.168.1.1 dev eth0 proto static
10.63.10.1 via 10.63.10.5 dev tun0 #added by VPN client instance
10.63.10.5 dev tun0 proto kernel scope link src 10.63.10.6 #added by VPN client instance
10.255.0.0/24 via 10.255.0.2 dev tun1
10.255.0.2 dev tun1 proto kernel scope link src 10.255.0.1
128.0.0.0/1 via 10.63.10.5 dev tun0 #added by VPN client instance
178.162.199.211 via 192.168.1.1 dev eth0 #added by VPN client instance
192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.2
192.168.2.0/24 dev br-lan proto kernel scope link src 192.168.2.1
这些是 IP 规则,如下所示ip rule list
:
0: from all lookup 128 #a non-existent table
1: from all lookup local
32766: from all lookup main
32767: from all lookup default #empty table
尝试
首先,我构建了一个no_vpn_provider
路由表(echo "2 no_vpn_provider" >> /etc/iproute2/rt_tables
),这是该表的精确副本main
,没有对 VPN 客户端实例进行修改。ip route list table no_vpn_provider
显示
default via 192.168.1.1 dev eth0 proto static
10.255.0.0/24 via 10.255.0.2 dev tun1
10.255.0.2 dev tun1 proto kernel scope link src 10.255.0.1
192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.2
192.168.2.0/24 dev br-lan proto kernel scope link src 192.168.2.1
1)我尝试了这些简单的ip
规则
ip rule add from 192.168.1.2 table no_vpn_provider priority 2
ip rule add from 10.255.0.1 table no_vpn_provider priority 3
其中192.168.1.2
和分别10.255.0.1
是外部接口eth0
和 VPN 服务器接口的IP 地址tun1
。
我也尝试过用from all iif eth0
andfrom all iif tun1
代替from 192.168.1.2
and from 10.255.0.1
。
2)我尝试用0x1
新的标记連接(conntrack
模块安装完毕)到接口eth0
和tun1
iptables -t mangle -A PREROUTING -m conntrack --ctstate NEW -i eth0 -j CONNMARK --set-mark 0x1
iptables -t mangle -A PREROUTING -m conntrack --ctstate NEW -i tun1 -j CONNMARK --set-mark 0x1
并添加此规则以使标记的连接使用新的路由表
ip rule add fwmark 0x1 table no_vpn_provider priority 2
3)我尝试标记外出数据包来自 VPN 服务器端口1194
iptables -t mangle -A OUTPUT -p udp --sport 1194 -j MARK --set-mark 0x1
iptables -t mangle -A OUTPUT -p tcp --sport 1194 -j MARK --set-mark 0x1 # just in case
并使用相同的规则
ip rule add fwmark 0x1 table no_vpn_provider priority 2
我还尝试了 2) 和 3),并使用不同的标记,并插入 ( -I
) 而不是附加 ( -A
)。怀疑我的防火墙根本没有标记,我测试了
iptables -t mangle -A FORWARD -s 192.168.2.0/24 -j MARK --set-mark 0x1
ip rule add fwmark 0x1 table no_vpn_provider priority 2
但正如预期的那样,来自我的 LAN 的数据包没有被转发到 VPN 提供商。
4)唯一的事情是作品到目前为止这个丑陋的规则
ip rule add from all to y.y.y.y/y table no_vpn_provider priority 2
其中 yyyy/y 是尝试连接的客户端的公共 IP 地址:这当然是一个糟糕的解决方案,因为客户端不会总是从同一个网络连接。
答案1
要使具有 IP 地址的接口发送的所有数据包192.168.1.2
使用自定义路由表no_vpn_provider
,您只需使用
ip rule add from 192.168.1.2 table no_vpn_provider priority 2
就像我在尝试 1 中所做的那样)。问题是默认情况下 OpenVPN 服务器不会绑定到任何特定的 IP 地址,因此上述规则不会产生任何效果(https://serverfault.com/a/228258)。
要将你的 OpenVPN 服务器绑定到 IP 地址192.168.1.2
,只需将此行添加到其配置文件中即可
local 192.168.1.2
笔记如果您使用 创建规则和自定义路由表ip
,则每次重新启动路由器时它们都会被删除。根据您的openvpn
配置,每次重新启动时自定义路由表也可能会进行修改openvpn
。您可以编写脚本,在需要时重新创建规则和自定义路由表。