SSH反向隧道链接及Autossh守护进程的使用

1.建立SSH反向隧道链接:

A要控制B

A主机:外网,ip:123.123.123.123,sshd端口:2221
B主机:内网,sshd端口:2223

无论是外网主机A,还是内网主机B都需要跑ssh daemon

1.1.首先在B上执行

1
$ ssh -NfR 1234:localhost:2223 user1@123.123.123.123 -p2221

这句话的意思是将A主机的1234端口和B主机的2223端口绑定,相当于远程端口映射(Remote Port Forwarding)。

这里每次需要输入A主机user1的登陆密码,后面会讲到解决办法。

1.2.这时在A主机上sshd会listen本地1234端口

1
2
3
$ ss -ant
State      Recv-Q Send-Q        Local Address:Port          Peer Address:Port
LISTEN     0      128               127.0.0.1:1234                     *:*

1.3.像平时一样连接到A主机的1234端口就可以控制内网B主机了

1
$ ssh localhost -p1234

2.这种反向连接(Reverse Connection)不稳定,可能随时断开,需要内网主机B再次向外网A发起连接,将自动连接ssh的应用Autossh制作成daemon,每次开机自动运行,并且可以使用service进行开关控制。

在此之前还要解决之前的一个问题,那就是每次内网主机B连接外网主机A时都需要输入密码,这个问题ssh本身是提供另外一种验证方式——通过密钥验证用户身份,实现自动登录。

2.1.在内网B主机上生产公钥和私钥

1
2
3
4
$ ssh-keygen
...(一直按Enter,最后在~/.ssh/下生成密钥)
$ ls ~/.ssh/
id_rsa id_rsa.pub known_hosts

2.2.复制B主机上生成的id_rsa.pub公钥到外网A主机上,并将内容加入到~/.ssh/authorized_keys

ssh-copy-id命令添加到远程主机的自动验证

1
$ ssh-copy-id user1@123.123.123.123

2.3.制作Autossh的daemon

使用vim编辑,如果没有则新建

SysV:/etc/inid.d/autossh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#!/bin/bash  
### BEGIN INIT INFO  
#  
# Provides:  location_server  
# Required-Start:   $local_fs  $remote_fs  
# Required-Stop:    $local_fs  $remote_fs  
# Default-Start:    2 3 4 5  
# Default-Stop:     0 1 6  
# Short-Description:    initscript  
# Description:  This file should be used to construct scripts to be placed in /etc/init.d.  
#  
### END INIT INFO  
 
## Fill in name of program here.  
PROG="autossh"  
PROG_PATH="/usr/bin" ## Not need, but sometimes helpful (if $PROG resides in /opt for example).  
PROG_ARGS="-M 5678 -NR *:2222:127.0.0.1:8080 root@123.123.123.123 -p 22"  
PID_PATH="/var/run/"  
 
start() {  
    if [ -e "$PID_PATH/$PROG.pid" ]; then  
        ## Program is running, exit with error.  
        echo "Error! $PROG is currently running!" 1>&2  
        exit 1  
    else  
        ## Change from /dev/null to something like /var/log/$PROG if you want to save output.  
        $PROG_PATH/$PROG $PROG_ARGS 2>&1 >/var/log/$PROG &  
    $pid=`ps ax | grep -i 'location_server' | sed 's/^[0−9]{1,}.*/\1/g' | head -n 1`  
 
        echo "$PROG started"  
        echo $pid > "$PID_PATH/$PROG.pid"  
    fi  
}  
 
stop() {  
    echo "begin stop"  
    if [ -e "$PID_PATH/$PROG.pid" ]; then  
        ## Program is running, so stop it  
    pid=`ps ax | grep -i 'location_server' | sed 's/^[0−9]{1,}.*/\1/g' | head -n 1`  
    kill $pid  
         
        rm -f  "$PID_PATH/$PROG.pid"  
        echo "$PROG stopped"  
    else  
        ## Program is not running, exit with error.  
        echo "Error! $PROG not started!" 1>&2  
        exit 1  
    fi  
}  
 
## Check to see if we are running as root first.  
## Found at http://www.cyberciti.biz/tips/bash-root-user-check-script.html  
if [ "$(id -u)" != "0" ]; then  
    echo "This script must be run as root" 1>&2  
    exit 1  
fi  
 
case "$1" in  
    start)  
        start  
        exit 0  
    ;;  
    stop)  
        stop  
        exit 0  
    ;;  
    reload|restart|force-reload)  
        stop  
        start  
        exit 0  
    ;;  
    **)  
        echo "Usage: $0 {start|stop|reload}" 1>&2  
        exit 1  
    ;;  
esac