通过上一篇的介绍,我们会发现当SSH隧道建立好以后还需要很多配置工作。为了能让隧道在断开后自动恢复,就需要找到一种方法在建立SSH隧道的同时自动完成这些工作。接下来我们将用两个小章节来分别介绍在服务器端和客户端所使用的方法。
自动配置隧道的服务器端
众所周知,在Unix的世界里一项工作有不止一种方法可以完成。这里仅仅给出一种我自己比较喜欢的做法,使用SSH公私钥认证文件~/.ssh/authorized_key来帮助我们完成服务器端的配置工作。接下来的讨论需要你对SSH公私钥认证体系有基本的了解,如果你对这个概念还不清楚,可以参考我的 如何实现安全的免密码ssh登录 。
首先,我们来看一个配置好的~/.ssh/authorized_key:
no-port-forwarding,no-pty,command=”/root/.ssh/tap-setup” ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA2389WXZZmIIArz6GGyNu/O3TLURtnMgYtsRwTB+VRyN0+RSPhGxIsEPcBI56Wt5DWWInFL711k1m3JCSIZbpagpPCsjWUKvBWHsWfi+JOJBk8aZKvK4rHMkxAVmyAZPSjhR93CiLLnqhIftog/Wb1P2AJSIkpRSKW1oe0CWpH7YiIOYA/9bloHPzOe1yUXp5bmqOOmOPopT26QpuhdAlFAvisEHKTBvpoiRsmhI2Aj7pP2kPQZhqZhGQ5ba/iUw2jMvSyS9FBkoZZbLdtch9wCghnRMPdiuZDvLJ9jwhZIjS+LGhzgGFIyIg4QAkeetHT1k7IxE2JCQDRPPIaZUCyQ== jianingy@nby
与普通的公钥串相比,上面的公钥串在ssh-rsa前面多出了一些参数。它们可以对使用这个公钥验证的用户做出一些限制,这里的几个参数含义如下:
- no-port-forwarding 对于使用该公钥认证的用户,不允许做端口转发。
- no-pty 对于使用该公钥认证的用户,不分配伪终端(PTY)。
- command=”/root/.ssh/tap-setup” (最关键)对于使用该公钥登陆的用户,强制执行脚本/root/.ssh/tap-setup。而用户在登陆时给出的执行命令,将被保存在环境变量SSH_ORIGINAL_COMMAND中。
下面,我们来实现tap-setup脚本。这个脚本需要两类参数。第一,我们需要知道服务器端的tap设备的名字。第二,我们需要知道服务器端tap设备的IP信息。这两类参数都会通过SSH客户端,借助SSH_ORIGINAL_COMMAND环境变量传递给tap-setup脚本。
#!/bin/bash
# author: jianingy.yang (AT) gmail.com
set $SSH_ORIGINAL_COMMAND
device=$1
ipaddr=$2
netmask=${3:-255.255.255.0}
if [ -z "$device" -o -z "$ipaddr" ]; then
echo "not enough arugments" 2>&1
exit 255
fi
retries=3
while ! ifconfig $device $ipaddr netmask $netmask
do
[ $retries -lt 0 ] && break
((--retries))
sleep 5
done
有了tap-setup脚本之后,我们就可以通过如下命令发起SSH连接了。tap-setup会在连接建立好以后帮我们做好服务器端的设置
ssh -w 1:100 -o Tunnel=Ethernet root@server "tap100 192.168.1.250 255.255.255.0"
在客户端自动配置隧道
谈到客户端自动重连SSH的方法,我个人比较喜欢用djb的daemontools。这个工具简单、方便并且还很易于管理多个隧道连接。当然,如果需要一切从简,也可以将一个带有while循环的脚本放在后台去执行。但无论如何我们都要能够在隧道建立成功后进行本地虚拟设备的配置。这里,介绍一个使用SSH客户端LocalCommand参数来进行配置的方法。
LocalCommand用来指定一个在SSH连接建立好以后在本地执行的命令。我们可以将所需的配置包裹在一个脚本中,然后通过LocalCommand来适时地调用我们的脚本。例如,采用如下SSH连接命令可以在连接成功后调用tap-up脚本。
ssh -o PermitLocalCommand=yes -o LocalCommand="./tap-up" -o Tunnel=Ethernet -w 100:1 hostname
tap-up则可以是类似下面的实现。
retries=3 while ! ifconfig tap1 192.168.1.10 netmask 255.255.255.0 do [ $retries -lt 0 ] && break ((--retires)) sleep 5 done
最后,结合我在 SSH隧道技术简介 里面“检查隧道状态”的部分,我们可以让隧道在检测出异常状态时中断并重新连接。
通过bonding模块进行隧道热备份
虽然SSH隧道在意外中断后可以自动重连,但连接终究还是会中断。为了实现“不间断服务”,让我们来借力于Linux的Bonding模块吧。Bonding模块用来将多个二层设备绑定在一起协同工作。它支持很多种工作模式,其中active-backup模式用来在多个二层设备之间进行热备份。举例来说,如果我们将eth0和eth1的物理接口连接在同一个交换机上。然后通过bonding模块将eth0和eth1绑定在一个称作bond0的虚拟设备上。默认情况下,eth0会做为bond0的主设备(Primary)工作。而一旦eth0设备出现问题bonding模块可以在毫秒级别上检测到设备失败并切换到eth1上工作。在这期间已经建立好的TCP链接并不会断开,而只是承受少量的TCP重传。
另人庆幸的是bonding模块只要求被绑定的设备是一个二层设备。因此,SSH创建的二层隧道也可以通过Bonding模块进行绑定从而享受热备份带来的好处。
假设,我们已经创建了两个机器间的两个相同的隧道设备tap100和tap101。我们可以用如下命令在隧道两端制作Bonding虚拟设备。
在客户端:
sudo modprobe bonding mode=active-backup arp_interval=100 arp_ip_target=192.168.1.250 ifenslave bond0 tap100 ifenslave bond0 tap101 ifconfig bond0 192.168.1.10 netmask 0xffffff00
服务器端:
sudo modprobe bonding mode=active-backup arp_interval=100 arp_ip_target=192.168.1.10 ifenslave bond0 tap100 ifenslave bond0 tap101 ifconfig bond0 192.168.1.250 netmask 0xffffff00
modprobe执行的时候向bonding模块传递了3个参数,他们的含义如下:
- mode bonding设备工作模式,这里使用active-backup也就是热备份模式
- arp_ip_interval 通过ARP包检测设备联通状态的检测间隔,单位是毫秒。
- arp_ip_target 通过ARP包检测设备联通状态时,用以发送ARP查询的地址。
模块加载好以后,便可以使用ifenslave命令(该命令一般需要单独安装)来将参与热备的设备加入到bond0中。最后,再为bond0设置好IP地址,整个配置过程就完成了。
模块加载的部分和bond设备IP地址的配置都可以被放到系统启动时完成。对于ifenslave操作,则可以被我们分别放到服务器端和客户端的重连脚本里。这样一来即使隧道处于断开重连状态中,只要还有可工作的隧道存在bond0设备就会一直有效,其上的TCP连接也都能继续保持。
到此为止?
当然不是:)。通过这两篇对SSH隧道的介绍,你应该已经掌握了建立稳定SSH隧道的方法。但仍有很多细节问题需要进一步考察。也许你已经发现了bonding设备的balance-rr模式可以提高SSH隧道的吞吐量,也许你在思考如何在一台服务起上建立多个bonding设备等等。有关SSH隧道及其相关的更多问题我会争取在以后的博文中再逐一解释。
整理自: EmacsWiki EightyColumnRule
;; 高亮结尾白空格
;; 设置颜色
(custom-set-faces
'(my-tab-face ((((class color)) (:background "grey10"))) t)
'(my-trailing-space-face ((((class color)) (:background "gray10"))) t)
'(my-long-line-face ((((class color)) (:background "gray10"))) t))
;; 辅助函数,用来给指定模式添加超过80列的高亮功能
(defun cc-mode-add-keywords (mode)
(font-lock-add-keywords
mode
'(("\t+" (0 'my-tab-face append))
("^.\\{81\\}\\(.+\\)$" (1 'my-long-line-face append)))))
;; 对指定模式使用"超过80列高亮"功能
(cc-mode-add-keywords 'c-mode)
(cc-mode-add-keywords 'cc-mode)
(cc-mode-add-keywords 'c++-mode)
(cc-mode-add-keywords 'perl-mode)
(cc-mode-add-keywords 'python-mode)
介绍一下这两天写的几个处理IP地址相关的工具(PS:只能在Linux上使用哦)。大家可以在 我的BitBucket 查看到源代码。也可以直接下载。
下载地址:
下面分别介绍一下这几个工具。
compress-ip-space
用来将一组IP地址转换成CIDR表示形式。例如,我们有一张IP地址列表
192.168.1.0
192.168.1.1
192.168.1.2
…
192.168.1.63
192.168.1.65
192.168.1.66
…
192.168.1.255
使用compress-ip-space来获得这个列表的CIDR表示形式:
$ compress-ip-space /tmp/iplist
192.168.1.0/26
192.168.1.65/32
192.168.1.66/31
192.168.1.68/30
192.168.1.72/29
192.168.1.80/28
192.168.1.96/27
192.168.1.128/25
expand-ip-space
用来将一个CIDR表示的IP地址展开为IP地址列表,例如
$ expand-ip-space 192.168.1.0/29
192.168.1.0
192.168.1.1
192.168.1.2
192.168.1.3
192.168.1.4
192.168.1.5
192.168.1.6
192.168.1.7
find-subnet-space-open & find-subnet-space-used
分别用来查找当前局域网里可以使用的IP地址和已经被使用的IP地址。他们的原理十分简单,仅仅依靠先发送PING包,之后检查本地ARP表是否追加了目标地址的MAC地址。
find-ip-range
给出一个CIDR表示方式的IP地址,通过find-ip-range可以找出这个地址所在IP段的范围。例如:
$ find-ip-range 192.168.1.27/29
192.168.1.24-192.168.1.31
find-my-ip & find-my-nic
分别用来显示本机的出口IP地址,以及出口网络接口设备名称。例如:
$ find-my-ip
192.168.0.2/24
$ find-my-nic
eth0
cidr2mask & mask2cidr
用来在CIDR表示形式和子网掩码表示形式之间进行转换。mask2cidr是cidr2mask的一个符号链接。使用方法如下:
$ mask2cidr 192.168.2.4/255.255.255.252
192.168.2.4/30
$ cidr2mask 192.168.3.7/29
192.168.3.7/255.255.255.248
最新评论
1 周 4 天之前
6 周 2 天之前
10 周 1 天之前