VPN over SSH

出自 ArchWiki

有几种方法可以通过 SSH 设置虚拟专用网络。请注意,虽然这可能偶尔有用,但它可能无法完全替代常规 VPN。例如,请参阅 [1]

使用 badvpn 的 tun2socks

注意: badvpn 项目已于 2022 年 8 月停止维护,最新的稳定版本发布于 2015 年 4 月。在 https://github.com/xjasonlyu/tun2socks 有一个 Go 语言的重新实现。

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. 指向我们用于隧道的 SSH 服务器的路由,具有较低的跃点数。
  2. DNS 服务器的路由(因为 tun2socks 不支持 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 数据包转发、路由,并且可能在双方都设置网络过滤器。
  • 如果您不启用隧道,当您想使用 -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

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

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

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

# ip route replace default via 10.0.8.2

辅助脚本

pvpn(软件包 pvpnAUR) 是 pppd over SSH 的包装脚本。

参见