配置vpnc:不添加默认路由避免影响上网
问题
vpnc
是一个 Linux 下的 Cisco VPN 客户端,它可以让我们连接到 Cisco VPN 服务器。但是,vpnc
会添加一个默认路由,这样我们的所有网络请求都会通过 VPN 服务器转发,这样会导致我们无法正常上网。
例如,以下是普通情况的路由表:
1
2
3
4
5
$ ip route
default via 172.16.170.254 dev enp3s0 proto dhcp metric 100
10.42.0.0/24 dev wlp4s0 proto kernel scope link src 10.42.0.1 metric 600
172.16.170.0/24 dev enp3s0 proto kernel scope link src 172.16.170.159 metric 100
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown
在启动 vpnc 之后,路由表变成了这样:
1
2
3
4
5
6
7
8
$ sudo vpnc
$ ip route
default dev tun0 scope link
default via 172.16.170.254 dev enp3s0 proto dhcp metric 100
10.42.0.0/24 dev wlp4s0 proto kernel scope link src 10.42.0.1 metric 600
172.16.170.0/24 dev enp3s0 proto kernel scope link src 172.16.170.159 metric 100
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown
172.17.72.0/23 dev tun0 scope link
可以看到,多出了一个 default dev tun0 scope link
,这个路由会导致所有网络请求都通过 VPN 服务器转发,从而影响我们正常上网。
解决
vpnc
对路由表的变动实际上是通过一个外部的脚本来实现的,默认情况下这个脚本是 /usr/share/vpnc-scripts/vpnc-script
,而这个脚本是通过调用 ip route
或 route
命令来实现对路由比的修改的。
我们可以通过 --script
选项或修改配置文件中的 Script /path/to/our/script
来指定一个自定义的脚本,例如:
1
2
3
4
5
6
$ sudo vpnc --script /dev/null
$ ip route
default via 172.16.170.254 dev enp3s0 proto dhcp metric 100
10.42.0.0/24 dev wlp4s0 proto kernel scope link src 10.42.0.1 metric 600
172.16.170.0/24 dev enp3s0 proto kernel scope link src 172.16.170.159 metric 100
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown
可以看到,这次路由表就没有发生任何变化,但是这也意味着 VPN 并不能正常工作。我们可以在自定义的脚本中添加一些手动路由规则,来实现 VPN 和正常上网的共存,这个脚本的内容比较复杂,建议复制 /usr/share/vpnc-scripts/vpnc-script
,然后基于它来修改。
我们需要找到它有关默认路由设置的部分,然后将它们改为我们自己需要的路由规则,例如:
1
2
3
4
5
6
7
set_default_route() {
$IPROUTE route | grep '^default' | fix_ip_get_output > "$DEFAULT_ROUTE_FILE"
# $IPROUTE route replace default dev "$TUNDEV"
# 改为
$IPROUTE route add 172.16.0.0/16 dev "$TUNDEV"
$IPROUTE route flush cache 2>/dev/null
}
1
2
3
4
5
6
7
set_ipv6_default_route() {
# We don't save/restore IPv6 default route; just add a higher-priority one.
# $IPROUTE -6 route add default dev "$TUNDEV" metric 1
# 改为
$IPROUTE -6 route add 172.16.0.0/16 dev "$TUNDEV" metric 1
$IPROUTE -6 route flush cache 2>/dev/null
}
这样,就只有 172.16.0.0/16
这个网段的数据包会被发送到 VPN 服务器,其他的数据包会按照原来的路由表进行转发,就能实现 VPN 和正常上网的共存了。
补充学习:ip route
输出的含义
default dev tun0 scope link
这段信息应该这么拆开来看:
default
默认路由,即当没有匹配的路由时,数据包将被发送到这个路由。这个地方也可以是一个 IP 网段,例如下面的
10.42.0.0/24
那样。dev tun0
数据包将通过设备
tun0
发送。这个设备文件一般可能出现在两个地方:/dev/tun0
/sys/class/net/tun0
后者往往是一个到
/sys/devices/pci...
的一个软链接,在系统启动时自动创建。scope link
:表示这是一个直连路由(回想 IP 协议里直接交付和间接交付的概念)。
default via 172.16.170.254 dev enp3s0 proto dhcp metric 100
只介绍和之前不一样的:
via 172.16.170.254
表示数据包将被转发到这个 IP 地址,再在路由表中查询这个 IP 地址,可知数据包会被发送到
enp3s0
这个设备。proto dhcp
这个路由是通过 DHCP 协议获取的。
metric 100
路由的优先级,数值越小,优先级越高。
10.42.0.0/24 dev wlp4s0 proto kernel scope link src 10.42.0.1 metric 600
10.42.0.0/24
和
default
在一样的位置,只是这次表示只有特定网段的数据包会被发送到这个路由了。src 10.42.0.1
这个地址会被填在 IP 数据包的源地址字段里。