OpenSSH 可以使用tun/tap设备来创建一个加密隧道,SSH隧道类似mode TCP模式下的OpenVPN,对于有需求快速设置一个基于IP的VPN来说非常方便。使用SSH隧道的优点:

  1. 不需要安装和配置额外的软件
  2. 使用SSH认证并自带加密,不需要使其它VPN软件一样配置共享密钥或者证书
  3. 兼容性强,可以建立二层隧道或三层隧道,所有3/4层协议如:ICMP、TCP/UDP 等都可支持
  4. 配置过程简单

当然也有缺点:

  1. 基于TCP协议,其传输效率较低
  2. 隧道依赖于单个TCP连接,容易中断或假死
  3. 需要ROOT权限

这里还要说明一下二层和三层的区别:

  • layer 2 : 交换单元是帧,只识别MAC地址,只有交换功能,相关协议:Ethernet、VLAN、STP、PPP、FDDI、ARP(OSI模型)、MPLS(介于2层3层之间)等,在Linux中是虚拟点对点设备,显示为tap
  • layer 3 : 交换单元是包,能识别MAC地址和IP,有交换和路由功能,相关协议:IP、ICMP、IGMP、IPsec等,在Linux中是虚拟以太网设备,显示tun

在Linux中tun/tap都可以设置IP,只是模拟的工作层有区别,tun是模拟三层网络设备,收发的是IP包,无法处理以太网数据帧。tap模拟的是二层设备,收发的是以为网数据帧,更接近物理网卡,可以和物理网卡通过网桥绑定。我们日常用的wmware虚拟机中的nat网络,对应的就是tun,桥接网络对应的就是tap。

一、ssh server端配置

首先要使用ssh的二层和三层隧道,尽量保证系统差别不要太大,我这里两边都是oracle linux 8,SSH版本更新到最新。server端需要允许root登录和隧道,编辑/etc/ssh/sshd_config:

PermitRootLogin yes
PermitTunnel yes
#建议添加
TCPKeepAlive yes

PermitTunnel yes代表允许point-to-point (layer 3)和ethernet (layer 2)

二、三层隧道配置

2.1 建立三层隧道

在client端执行:

ssh -w any:any  root@[server_ip] 

如果客户端和服务器端没有其它的tun设备,就会在客户端和服务器端各生成一个名为tun0设备,指定any可以自动分配可用的设备。查看设备:

[root@centos8 ~]# ip addr
3: tun0: <POINTOPOINT,MULTICAST,NOARP> mtu 1500 qdisc noop state DOWN group default qlen 500
    link/none 

可以看到有个tun0 <POINTOPOINT,MULTICAST,NOARP>,这个设备是未激活的状态,如果用ifconfig命令查看,需要加上-a参数才能看到。

为安全起见,建议使用以下命令:

ssh -NTCf -w 5:5 root@[server_ip]
  • “-N”:不执行远程命令
  • “-T”:不分配终端
  • “-C”:压缩传输的流量
  • “-f”:在客户端后台运行

执行完该命令client和server各自会创建一个tun5的点对点设备,下一步就是需要激活设备并分配IP。

2.2 分配IP并激活隧道

分配IP不要与服务器和客户端网段有冲突,这里假设:

客户端IP:10.0.0.2 tun5
服务器IP:10.0.0.1 tun5

服务器激活点对点设备并分配IP和路由:

ip link set tun5 up
ip addr add 10.0.0.1/32 peer 10.0.0.2 dev tun5

客户端同理:

ip link set tun5 up
ip addr add 10.0.0.2/32 peer 10.0.0.1 dev tun5

这时隧道已经建立成功,此时用查看一下状态:

[root@centos8 ~]# ip addr
14: tun5: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN group default qlen 500
    link/none 
    inet 10.0.0.1 peer 10.0.0.2/32 scope global tun5

可以看到比之前多了“UP,LOWER_UP”,说明已经激活。正常情况下客户端和服务器已经可以相互ping。

客户端用一条命令也能搞定:

ssh \
  -o PermitLocalCommand=yes \
  -o LocalCommand="ip link set tun5 up && ip addr add 10.0.0.2/32 peer 10.0.0.1 dev tun5 " \
  -o TCPKeepAlive=yes \
  -w 5:5  root@[server_ip] \
  'ip link set tun5 up && ip addr add 10.0.0.1/32 peer 10.0.0.2 dev tun5'
  

2.3 添加其它网段的路由

如果服务器端有其它内网段,需要继续添加客户端路由才能ping通,例如,客户端想与服务器端网段10.0.12.0/24互通,需在客户端执行:

ip route add  10.0.12.0/24 dev tun5

按需添加即可,更改路由是高风险操作,需要格外小心,同时也要确保ssh连接不要中断。

三、二层隧道配置

由于linux中允许为tap设备设置ip,所以二层隧道和三层隧道也可以完全一样的进行配置。区别是tap设备可以和物理网卡进行绑定,也就是桥接,同时由于工作在二层,允许Arp通过,能支持STP生成树、PPP等协议。

3.1 建立二层隧道

在客户端执行:

ssh  -o Tunnel=ethernet -w 6:6    root@[server_ip] 

这里参数 -o 需要在 -w 前面,查看一下客户端和服务器的网卡:

[root@centos8 ~]# ip addr
20: tap6: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000

在ip命令中 tap6: <BROADCAST,MULTICAST>,和物理网卡显示的一样,说明模拟的是物理网卡。

3.2 创建并配置网桥

二层可以进行网卡桥接,桥接可以多块网卡,也可以一块网卡,这里测试为了省事只用一块网卡,创建网桥有三种工具:

  1. 使用bridge-utils中的brctl命令
  2. 使用oracle linux 8 系列自带的nmcli
  3. 使用ip命令

建议用ip命令建立:

ip link add br0 type bridge

将tap6加入网桥:

ip link set tap6 master br0

配置服务器端网桥IP信息并启动网桥:

ip address add 10.0.0.1/32 dev br0
ip link set tap6 up
ip link set br0 up

客户端流程一样,只是客户端的ip是10.0.0.2

在客户端测试ARP包能不能通过:

[root@oracle8 ~]# arping -I br0 10.0.0.1
ARPING 10.0.0.1 from 10.0.0.2 br0
Unicast reply from 10.0.0.1 [3A:E7:2F:3F:42:24]  193.222ms
Unicast reply from 10.0.0.1 [3A:E7:2F:3F:42:24]  191.903ms

如果是三层隧道,就无法使用arping。

看似很多内容,其实使用很简单,OpenSSH套件功能真强大。

参考文章
https://help.ubuntu.com/community/SSH_VPN
https://www.cyberciti.biz/faq/centos-8-add-network-bridge-br0-with-nmcli-command/
https://gobomb.github.io/post/build-l2-l3-vpn-by-openssh/