OpenVPN 基于策略的路由无法正常工作

OpenVPN 基于策略的路由无法正常工作

我正在尝试使用 PrivateInternetAccess 在 ArchLinux 上设置 OpenVPN 客户端。默认情况下,PIA 会推送以下路由:全部流量通过 VPN。我只想要一些应用程序使用 VPN。

为此,我使用了“基于策略的路由”。我创建了一个名为“vpn”的新路由表,并将有选择地将用户发送到该路由表。

执行这些命令后,“media”用户将被路由到“vpn”路由表:

$ echo 100 vpn >> /etc/iproute2/rt_tables
$ iptables -t mangle -I OUTPUT -m owner --uid-owner media -j MARK --set-mark 0x1
$ ip rule add fwmark 0x1 table vpn

我还修改了我的 OpenVPN 客户端配置,以便我的路由表能够正确填充:

$ cat /etc/openvpn/client.conf
    client
    dev tun
    proto udp
    remote us-newyorkcity.privateinternetaccess.com 1194
    resolv-retry infinite
    nobind
    persist-key
    persist-tun
    ca /etc/openvpn/ca.crt
    tls-client
    remote-cert-tls server
    auth-user-pass /etc/openvpn/login.conf
    comp-lzo
    verb 1
    reneg-sec 0
    crl-verify /etc/openvpn/crl.pem

    # This will override PIA so that traffic will route through our normal gateway
    route 0.0.0.0 192.0.0.0 net_gateway
    route 64.0.0.0 192.0.0.0 net_gateway
    route 128.0.0.0 192.0.0.0 net_gateway
    route 192.0.0.0 192.0.0.0 net_gateway

    # Calling these scripts will add the PIA routes to the vpn table
    script-security 2
    up /etc/openvpn/up.sh
    down /etc/openvpn/down.sh

$ cat /etc/openvpn/up.sh
    #!/bin/sh
    ip route add table vpn default via $ifconfig_remote

$ cat /etc/openvpn/down.sh
    #!/bin/sh
    ip route flush table vpn

运行后的路由表如下openvpn /etc/openvpn/client.conf

$ ip route show table main
    0.0.0.0/2 via 192.168.1.1 dev eth0
    0.0.0.0/1 via 10.197.1.5 dev tun0
    default via 192.168.1.1 dev eth0  src 192.168.1.124  metric 202
    10.197.1.1 via 10.197.1.5 dev tun0
    10.197.1.5 dev tun0  proto kernel  scope link  src 10.197.1.6
    64.0.0.0/2 via 192.168.1.1 dev eth0
    128.0.0.0/2 via 192.168.1.1 dev eth0
    128.0.0.0/1 via 10.197.1.5 dev tun0
    192.0.0.0/2 via 192.168.1.1 dev eth0
    192.168.1.0/24 dev eth0  proto kernel  scope link  src 192.168.1.124  metric 202
    209.95.50.86 via 192.168.1.1 dev eth0

$ ip route show table vpn
    default via 10.197.1.5 dev tun0

作为未被路由到“vpn”表的用户,一切正常运行:

$ whoami
    jordan

$ ping -c 2 8.8.8.8
    PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
    64 bytes from 8.8.8.8: icmp_seq=1 ttl=46 time=38.9 ms
    64 bytes from 8.8.8.8: icmp_seq=2 ttl=46 time=39.0 ms

    --- 8.8.8.8 ping statistics ---
    2 packets transmitted, 2 received, 0% packet loss, time 1001ms
    rtt min/avg/max/mdev = 38.952/38.999/39.047/0.203 ms

但是,对于确实被路由到“vpn”表的用户来说,事情却失败了:

$ whoami
media

$ ping -c 2 8.8.8.8
    PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.

    --- 8.8.8.8 ping statistics ---
    2 packets transmitted, 0 received, 100% packet loss, time 999ms

我查看了一下tcpdump -i tun0发生了什么。看来 icmp 请求是通过 tun0 发出的,但是不会回来

$ tcpdump -i tun0
    listening on tun0, link-type RAW (Raw IP), capture size 262144 bytes
    15:37:30.134399 IP keep > google-public-dns-a.google.com: ICMP echo request, id 10256, seq 1, length 64
    15:37:31.143217 IP keep > google-public-dns-a.google.com: ICMP echo request, id 10256, seq 2, length 64

有什么想法吗?:(

==== 编辑 #1 ====

作为健全性检查,如果我们发送全部通过 VPN 的流量(通过删除 /etc/openvpn/client.conf 中的“route xxxx 192.0.0.0 net_gateway”行),我们可以正常获得 icmp 响应:

$ tcpdump -i tun0
    listening on tun0, link-type RAW (Raw IP), capture size 262144 bytes
    16:26:54.401732 IP keep > google-public-dns-a.google.com: ICMP echo request, id 10480, seq 1, length 64
    16:26:54.483122 IP google-public-dns-a.google.com > keep: ICMP echo reply, id 10480, seq 1, length 64
    16:26:55.403465 IP keep > google-public-dns-a.google.com: ICMP echo request, id 10480, seq 2, length 64
    16:26:55.485068 IP google-public-dns-a.google.com > keep: ICMP echo reply, id 10480, seq 2, length 64

==== 编辑 #2 ====

根据 MariusMatutiae 的建议,我尝试使用--route-noexec标志在 中手动设置路线/etc/openvpn/up.sh。我们还在 中禁用了反向路径过滤/etc/openvpn/up.sh,并在 中重新启用了它/etc/openvpn/down.sh

$ cat /etc/openvpn/up.sh
    #!/bin/sh
    ip route add table vpn 0.0.0.0/1 via $ifconfig_remote
    ip route add table vpn 128.0.0.0/1 via $ifconfig_remote
    ip route add table vpn $route_network_1 via $ifconfig_remote
    ip route add table vpn $trusted_ip via $route_net_gateway

    ip route add table vpn $ifconfig_remote dev tun0 proto kernel src $ifconfig_local
    ip route add table vpn 192.168.1.0/24 dev eth0 proto kernel src 192.168.1.124 metric 202

    ip route del table main $ifconfig_remote

    # Disable reverse path filtering
    for f in /proc/sys/net/ipv4/conf/*/rp_filter; do
            echo 0 > $f;
    done

$ cat /etc/openvpn/down.sh
    #!/bin/sh
    ip route flush table vpn

    # Re-enable reverse path filtering
    for f in /proc/sys/net/ipv4/conf/*/rp_filter; do
            echo 1 > $f;
    done

之后,我的路由表如下所示:

$ ip route show table main
    default via 192.168.1.1 dev eth0  src 192.168.1.124  metric 202
    192.168.1.0/24 dev eth0  proto kernel  scope link  src 192.168.1.124  metric 202

$ ip route show table vpn
    0.0.0.0/1 via 10.173.1.5 dev tun0
    10.173.1.1 via 10.173.1.5 dev tun0
    10.173.1.5 dev tun0  proto kernel  scope link  src 10.173.1.6
    128.0.0.0/1 via 10.173.1.5 dev tun0
    192.168.1.0/24 dev eth0  proto kernel  scope link  src 192.168.1.124  metric 202
    209.95.50.133 via 192.168.1.1 dev eth0

然而,用户“media”仍然无法ping 8.8.8.8tcpdump -i tun0仍然报告说没有回复:(

答案1

您错误地通过两个路由表划分了路由。main表中出现的以下路由属于该vpn表:

0.0.0.0/1 via 10.197.1.5 dev tun0
128.0.0.0/1 via 10.197.1.5 dev tun0
10.197.1.1 via 10.197.1.5 dev tun0     
10.197.1.5 dev tun0  proto kernel  scope link  src 10.197.1.6
209.95.50.86 via 192.168.1.1 dev eth0

下面的路由属于这两个表:

192.168.1.0/24 dev eth0  proto kernel  scope link  src 192.168.1.124  metric 202

原因在于:前四条规则涉及接口tun0,即 OpenVPN 启动的虚拟 NIC,这显然与main表无关。第五条规则教您的内核如何访问您的 PIA 服务器。最后一条规则允许两个表访问本地 PC、打印机、NAS 等。

至于如何自动设置,由于您的 OpenVPN 服务器tun0每次可能都会为您分配一个不同的 IP 地址,因此这有点复杂:由于您无法控制服务器,因此您可能无法将其配置为为您的tun0接口分配静态地址。

因此,您需要做的是首先学会使用选项--route-no-exec手册状态:

–route-no-exec(路线无执行)

不要自动添加或删除路由。而是使用环境变量将路由传递给 --route-up 脚本。

然后你应该学习如何使用环境变量(上面链接的手册末尾有一整节内容),尤其是那些被称作ifconfig--某物的东西。

此外,你会发现有必要禁用内核的反向路径过滤,

for f in /proc/sys/net/ipv4/conf/*/rp_filter; do echo 0 > $f; done

我会把这个命令放在你的up脚本中,然后反向命令

for f in /proc/sys/net/ipv4/conf/*/rp_filter; do echo 1 > $f; done

在你的down脚本中。这是必要的,因为你在主表上有一个默认网关,这意味着,当内核检查是否存在欺骗时,任何数据包被标记。

另外,更简单的是,您可以考虑切换两个表的角色:让 OpenVPN 自动执行其操作,并设置main路由表的路由,并设置一个名为的新路由表,non-vpn其中包含您通常的配置,

# ip route show
  default via 192.168.0.1 dev eth0  proto static 
  192.168.0.0/24 dev eth0  proto kernel  scope link  src 192.168.0.74  metric 1 

(或类似的东西)对于数据包不是与上面的标记匹配。这更容易设置。

答案2

我放弃了让基于策略的路由发挥作用。相反,我最终使用网络命名空间来实现我的目标。可以在此处找到一个不错的入门指南https://schnouki.net/posts/2014/12/12/openvpn-for-a-single-application-on-linux/

特别感谢 MariusMatutiae 的所有帮助!

相关内容