跳转至内容

VPN over SSH

来自 ArchWiki

有几种方法可以通过 SSH 建立虚拟专用网络 (VPN)。请注意,虽然这在某些时候很有用,但它可能无法完全替代常规的 VPN。例如,请参阅 [1]

使用 badvpn 的 tun2socks

注意 badvpn 项目已于 2022 年 8 月停止维护,最新的稳定版本发布于 2015 年 4 月。目前有一个 Go 语言重写版本可用——tun2socksAUR

badvpn 是一组用于各种 VPN 相关场景的实用工具集合。

启动 SSH 动态 SOCKS 代理

首先,我们将像往常一样设置一个标准的 SSH 动态 socks 代理

$ ssh -TND 4711 <your_user>@<SSH_server>

设置 badvpn 和隧道接口

随后,我们可以继续设置 TUN。

# ip tuntap add dev tun0 mode tun user <your_local_user>
# ip addr replace 10.0.0.1/24 dev tun0
# badvpn-tun2socks --tundev tun0 --netif-ipaddr 10.0.0.2 --netif-netmask 255.255.255.0 --socks-server-addr localhost:4711

现在你拥有一个可用的本地 tun0 接口,它会将所有进入该接口的流量通过你之前设置的 SOCKS 代理进行路由。

将流量引导至隧道

现在剩下的工作就是设置本地路由,以将部分流量引导至其中。让我们设置一个将所有流量都路由到其中的路由。我们需要三条路由:

  1. 一条低度量 (metric) 的路由,指向用于建立隧道的 SSH 服务器。
  2. 一条低度量的 DNS 服务器路由(因为 tun2socks 不支持 UDP,而 DNS 需要 UDP)。
  3. 一条默认路由,用于所有其他流量,其度量值高于上述其他路由。

专门设置度量值的目的是为了确保指向 SSH 服务器的路由始终是直连的,否则流量会再次进入 SSH 隧道,从而导致环路,并导致 SSH 连接断开。除此之外,我们需要设置一个显式的 DNS 路由,因为 tun2socks 不会对 UDP 进行隧道传输(DNS 所需)。我们还需要一个度量值低于原默认路由的新默认路由,这样流量才能进入隧道。话虽如此,让我们开始操作吧。

# ip route add <IP_of_SSH_server> via <IP_of_original_gateway> metric 5
# ip route add <IP_of_DNS_server> via <IP_of_original_gateway> metric 5
# ip route add default via 10.0.0.2 metric 6

现在所有流量(除 DNS 和 SSH 服务器本身外)都应该通过 tun0 传输。

OpenSSH 的内置隧道

OpenSSH 使用 -w<本地-tun-编号>:<远程-tun-编号> 内置支持 TUN/TAP。这里描述的是一个第 3 层/点对点/TUN 隧道。同样也可以创建第 2 层/以太网/TAP 隧道。

为 TUN 设备启用转发

要为 TUN 设备启用转发,请编辑 /etc/ssh/sshd_config 并将 PermitTunnel 设置为 yespoint-to-pointethernet。设置为 yes 将同时启用 point-to-pointethernet 隧道的转发。详情请参阅 sshd_config(5)

/etc/ssh/sshd_config
...
PermitTunnel yes
...

然后 重新加载 sshd.service

使用 systemd-networkd 创建 tun 接口

/etc/systemd/network/vpn.netdev
[NetDev]
Name=tun5
Kind=tun

[Tun]
User=vpn
Group=network
/etc/systemd/network/vpn.network
[Match]
Name=tun5

[Address]
Address=192.168.200.2/24

创建这些文件后,通过 重启 systemd-networkd.service 来启用它们。

此外,你也可以使用 ip tunnel 命令来管理 tun 接口。

在 SSH 命令中创建接口

SSH 会自动创建这两个接口,但在连接建立后应配置 IP 和路由。

ssh \
  -o PermitLocalCommand=yes \
  -o LocalCommand="sudo ifconfig tun5 192.168.244.2 pointopoint 192.168.244.1 netmask 255.255.255.0" \
  -o ServerAliveInterval=60 \
  -w 5:5 vpn@example.com \
  'sudo ifconfig tun5 192.168.244.1 pointopoint 192.168.244.2 netmask 255.255.255.0; echo tun0 ready'

启动 SSH

ssh -f -w5:5 vpn@example.com -i ~/.ssh/key "sleep 1000000000"

如果你处于 NAT 之后,可以添加保持活动 (keep-alive) 选项。

ssh -f -w5:5 vpn@example.com \
        -o ServerAliveInterval=30 \
        -o ServerAliveCountMax=5 \
        -o TCPKeepAlive=yes \
        -i ~/.ssh/key "sleep 1000000000"

故障排除

  • ssh 应当具有访问 tun 接口的权限或创建它的权限。请检查 tun 接口和/或 /dev/net/tun 的所有者。
  • 显然,如果你想访问的是一个网络而非单台机器,你应该在两端正确设置 IP 数据包转发、路由,可能还需要设置 netfilter。
  • 如果你没有启用隧道功能,当你尝试使用 -w 创建 SSH 隧道时,可能会收到以下错误
channel 0: open failed: connect failed: open failed
Tunnel forwarding failed

使用 PPP over SSH

pppd 可以轻松地用于通过 SSH 服务器创建隧道

# pppd updetach noauth silent nodeflate pty "/usr/bin/ssh root@remote-gw /usr/sbin/pppd nodetach notty noauth" ipparam vpn 10.0.8.1:10.0.8.2

VPN 建立后,你可以通过它路由流量。若要访问内部网络:

# ip route add 192.168.0.0/16 via 10.0.8.2

例如,为了在未加密的网络上保护你的通信,将所有互联网流量通过隧道路由,首先通过你的常规网关添加一条到 SSH 服务器的路由

# ip route add <remote-gw> via <current default gateway>

接下来,用隧道替换默认路由

# ip route replace default via 10.0.8.2

辅助脚本

pvpn(软件包 pvpnAUR)是一个围绕 SSH 上的 pppd 编写的封装脚本。

参见

© . This site is unofficial and not affiliated with Arch Linux.

Content is available under GNU Free Documentation License 1.3 or later unless otherwise noted.