我想连接到 Linux 中的第三方 VPN 服务器(例如 Debian Jessie),但默认情况下仍使用我的 eth0 lan 接口作为默认路由,我很好奇如何实现这一点。我将使用策略路由或网络命名空间或规则集来选择何时使用第三方 VPN。
但我不清楚 openvpn 在幕后做了什么,让它引导所有流量通过它。为了解决这个问题,是不是只要在从我的客户端连接时覆盖“redirect-gateway”就行了?
答案1
这是一个使用控制组 (cgroups) 的完整解决方案,它允许每个进程进行资源控制。网络控制组允许隔离 VPN 路由,轻松允许任何进程及其子进程在其中有选择地运行,允许非 root 用户被授予访问 cgroup 内正在运行的进程的权限,并且使用 dnsmasq 的第二个实例也可以隔离 DNS 查询。这假设您已安装 openvpn、dnsmasq、cgroup 和支持 cgroup 的 iptables 1.6+ 版本。这一切都是在 Debian Jessie 上完成的
第一步是创建 cgroup 并相应地设置 iptables。每次重启时都应执行此操作,因此我将以下内容放在/etc/rc.local
# enable ip forwarding
echo 1 > /proc/sys/net/ipv4/ip_forward
# create cgroup for 3rd party VPN (can change 'vpn' to your name of choice)
mkdir -p /sys/fs/cgroup/net_cls/vpn
# give it an arbitrary id
echo 11 > /sys/fs/cgroup/net_cls/vpn/net_cls.classid
# grant a non-root user access (change user:group accordingly)
cgcreate -t user:group -a user:group -g net_cls:vpn
# mangle packets in cgroup with a mark
iptables -t mangle -A OUTPUT -m cgroup --cgroup 11 -j MARK --set-mark 11
# NAT packets in cgroup through VPN tun interface
iptables -t nat -A POSTROUTING -m cgroup --cgroup 11 -o tun0 -j MASQUERADE
# redirect DNS queries to port of second instance, more on this later
iptables -t nat -A OUTPUT -m cgroup --cgroup 11 -p tcp --dport 53 -j REDIRECT --to-ports 5354
iptables -t nat -A OUTPUT -m cgroup --cgroup 11 -p udp --dport 53 -j REDIRECT --to-ports 5354
# create separate routing table
ip rule add fwmark 11 table vpn
# add fallback route that blocks traffic, should the VPN go down
ip route add blackhole default metric 2 table vpn
# disable reverse path filtering for all interfaces
for i in /proc/sys/net/ipv4/conf/*/rp_filter; do echo 0 > $i; done
下一步是编辑第三方 VPN 的客户端配置文件,例如/etc/openvpn/客户端.conf. 保持其余配置不变。
# redirect-gateway def1 <--- comment or remove the redirect-gateway line if it exists
# disable automatically configuring routes and run our own routeup.sh script instead
route-noexec
route-up /etc/openvpn/routeup.sh
# run our own update-dnsmasq-conf script on interface up/down; comment out existing up/down lines
up /etc/openvpn/update-dnsmasq-conf
down /etc/openvpn/update-dnsmasq-conf
我们现在需要创建/etc/openvpn/routeup.sh脚本
#!/bin/bash
# add default route through vpn gateway to our separate routing table
/sbin/ip route add default via $route_vpn_gateway dev $dev metric 1 table vpn
exit 0
现在我们需要创建一个 update-resolv-conf 的修改版本,它通常安装在 /etc/openvpn 中,以创建 dnsmasq 的第二个实例。我称之为/etc/openvpn/更新-dnsmasq-conf
#!/bin/bash
[ "$script_type" ] || exit 0
split_into_parts()
{
part1="$1"
part2="$2"
part3="$3"
}
case "$script_type" in
up)
NMSRVRS=""
for optionvarname in ${!foreign_option_*} ; do
option="${!optionvarname}"
split_into_parts $option
if [ "$part1" = "dhcp-option" ] ; then
if [ "$part2" = "DNS" ] ; then
NMSRVRS="${NMSRVRS:+$NMSRVRS }--server $part3"
fi
fi
done
dnsmasq $NMSRVRS --no-hosts --no-resolv --listen-address=127.0.0.1 \
--port=5354 --bind-interfaces --no-dhcp-interface=* \
--pid-file=/var/run/dnsmasq/dnsmasq2.pid
;;
down)
kill -9 $(cat /var/run/dnsmasq/dnsmasq2.pid)
;;
esac
就是这样。现在您可以启动 vpn 连接并通过该接口有选择地运行进程(--sticky 选项可确保子进程在同一个 cgroup 中运行)。
cgexec -g net_cls:vpn --sticky chromium &
注意:对于 dnsmasq,请确保 /etc/resolv.conf 指向本地主机(名称服务器 127.0.0.1)。您的主 dnsmasq 实例将处理您正常非 VPN 路由上的查询并使用(/var/run/dnsmasq/resolv.conf),它通常由您的默认网关或某些公共 DNS(例如 Google 的 8.8.8.8)组成。第二个实例仅由隔离的 cgroup 使用
答案2
我建议使用路由表。您可以为所有流量指定默认路由,然后根据需要通过 VPN 添加路由。