概述

若已有两台机器 A 和 B 的 root 权限,并且两台机器之间能够建立 ssh 连接(tcp 端口 22 是开放、互通的),那么我们希望能够让 ssh 帮我们把其中一台机器的 IP Packet 嵌进 A 与 B 的 ssh 数据流中,并且放到另外一台机器上才开始转发,也就是说利用 ssh 连接作为一个 IP 隧道。我们在本文讲解具体如何实现。

前置要求

  1. 你能够访问 A, B 两台机器并且拥有 A, B 的 root 权限;
  2. 机器 A 和机器 B 之间能够建立 ssh 连接,哪怕其中一方位于多道 NAT 之内的内网,只要能够建立 ssh 连接,只要你能够在机器 A 上用 ssh 登上机器 B 进行操作,或者在机器 B 用 ssh 登上机器 A 进行操作就可以了;
  3. 你能够修改机器 B(或者机器 A 的) /etc/ssh/sshd_config 配置文件;

步骤

  1. 登录机器 B, 编辑 /etc/ssh/sshd_config. 将 PermitTunnel 选项设为 yes, 登录 A, 也将 PermitTunnel 设为 yes; 运行 systemctl restart sshd 使新的配置生效;
  2. 在机器 A 创建一个 tun 设备:sudo ip tuntap add mode tun tun0 ;
  3. 同样在机器 B 创建一个 tun 设备,激活这两个 tun 设备:sudo ip link set tun0 up ;
  4. 用 ip addr 命令行工具给两个 tun 设备分配 IP 地址和子网掩码,例如 192.168.0.101/24 和 192.168.0.102/24;
  5. 在机器 A 执行
sudo ssh -F /home/ubuntu/.ssh/config -vNT -w 0:0 peer

这里假设 peer 已经保存在了 ssh 的用户配置文件中,0:0 对应两台机器上 tun 网卡的名称 tun0 和 tun0;

  1. 在机器 A ping 机器 B 的虚拟地址 192.168.0.102,在机器 B ping 机器 A 的虚拟地址 192.168.0.102, 如果设置正确无误,应该能 ping 通;

ssh-tunnel.mov

总结和思考

我们主要是利用了 ssh 命令行工具通过 -w 参数提供的功能,以及 Linux 内核提供的 tun 网络虚拟设备功能,具体来说,当运行那一行 ssh 命令时,ssh 程序会打开 (open) tun0 网络设备,对它进行配置,使得它能够将收到的 IP Packet 进行合理的封装并交由 ssh 发送。

192.168.0.0/24 这个子网是这两台机器所处的实际环境所没有的,我们通过建立虚拟网卡,并且为虚拟网卡分配网络地址,人为地将这个子网虚拟了出来,而这对虚拟网卡所依据的仍然是 encapculation, 也就是将一个 packet 塞进另一个 packet 中进行发送的这种处理方式,可见 encapsulation 过程本身就代表了一系列很强大的网络虚拟化技术(包括 IPIP, GRE, VLAN 和 VXLAN 等)。

透过这个由 ssh 建立的 tunnel, 可以使得两台机器具备交换 UDP 数据包的能力,即使它们本来所处的环境不允许他们之间这么做。