Linux信号处理及跳板机

*Linux信号处理及跳板机*

场景1:公司新招聘了一个配置管理员,他的工作是负责将公司开发人员写的新代码依次分发到办公室测试环境、roC测试环境和正式线上环境。因此公司需要开发一个程序,当配置管理员登录服务器,只能进入分发的管理界面,无法进行其他操作或直接进入bash界面。

场景2:公司有大量服务器,我们不能让每个人用root用户登录服务器,这样很危险。但我们又不能在每一台服务器为所有人创建登录账号,这样管理起来会很繁琐。于是就有一种叫做跳板机或堡垒机的解决方案。

我们可以用Shell脚本实现上面的功能,但通常的Shell脚本有一个不是bug的bug。平时我们执行脚本时发现什么问题时,就会用Ctrl+C强制终止脚本。但是在上面的类似场景中我们可不希望自己的shell脚本在运行时被用户使用Ctrl+c之类进入到bash界面,做我们不希望做的事情。这里就引出了我们接下来要学习的信号处理

1. *查看系统信号*

使用kill -l和trap -l都可以列出llnux系统的信号名称。

man kill
       -l     Print a list of signal names.  These are found in /usr/include/linux/signal.h
help trap
       -l        print a list of signal names and their corresponding numbers
[root@mysql ~]# kill -l
 1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL       5) SIGTRAP
 6) SIGABRT      7) SIGBUS       8) SIGFPE       9) SIGKILL     10) SIGUSR1
......          #总共64个信号

2. *linux信号注释说明*

1) SIGHUP   本信号在用户终端连接(正常或非正常)结束时发出, 通常是在终端的控制进程结束时, 通知同一session内的各个作业, 这时它们与控制终端不再关联。
2) SIGINT   程序终止(interrupt)信号, 在用户键入INTR字符(通常是Ctrl-C)时发出,用于通知前台进程组终止进程。
3) SIGQUIT  和SIGINT类似, 但由QUIT字符(通常是Ctrl-/)来控制. 进程在因收到SIGQUIT退出时会产生core文件, 在这个意义上类似于一个程序错误信号。
4)SIGILL   执行了非法指令. 通常是因为可执行文件本身出现错误, 或者试图执行数据段. 堆栈溢出时也有可能产生这个信号。
5) SIGTRAP  由断点指令或其它trap指令产生. 由debugger使用。
6) SIGABRT  调用abort函数生成的信号。
7) SIGBUS   非法地址, 包括内存地址对齐(alignment)出错。比如访问一个四个字长的整数, 但其地址不是4的倍数。它与SIGSEGV的区别在于后者是由于对合法存储地址的非法访问触发的(如访问不属于自己存储空间或只读存储空间)。
8) SIGFPE   在发生致命的算术运算错误时发出. 不仅包括浮点运算错误, 还包括溢出及除数为0等其它所有的算术的错误。
9) SIGKILL  用来立即结束程序的运行. 本信号不能被阻塞、处理和忽略。如果管理员发现某个进程终止不了,可尝试发送这个信号。
10) SIGUSR1 留给用户使用
11) SIGSEGV 试图访问未分配给自己的内存, 或试图往没有写权限的内存地址写数据.
12) SIGUSR2 留给用户使用
13) SIGPIPE   管道破裂。这个信号通常在进程间通信产生,比如采用FIFO(管道)通信的两个进程,读管道没打开或者意外终止就往管道写,写进程会收到SIGPIPE信号。此外用Socket通信的两个进程,写进程在写Socket的时候,读进程已经终止。
14) SIGALRM   时钟定时信号, 计算的是实际的时间或时钟时间. alarm函数使用该信号.
15) SIGTERM   程序结束(terminate)信号, 与SIGKILL不同的是该信号可以被阻塞和处理。通常用来要求程序自己正常退出,shell命令kill缺省产生这个信号。如果进程终止不了,我们才会尝试SIGKILL。
17) SIGCHLD   子进程结束时, 父进程会收到这个信号。如果父进程没有处理这个信号,也没有等待(wait)子进程,子进程虽然终止,但是还会在内核进程表中占有表项,这时的子进程称为僵尸进程。这种情 况我们应该避免(父进程或者忽略SIGCHILD信号,或者捕捉它,或者wait它派生的子进程,或者父进程先终止,这时子进程的终止自动由init进程 来接管)。
18) SIGCONT   让一个停止(stopped)的进程继续执行. 本信号不能被阻塞. 可以用一个handler来让程序在由stopped状态变为继续执行时完成特定的工作. 例如, 重新显示提示符
19) SIGSTOP   停止(stopped)进程的执行. 注意它和terminate以及interrupt的区别:该进程还未结束, 只是暂停执行. 本信号不能被阻塞, 处理或忽略.
20) SIGTSTP   停止进程的运行, 但该信号可以被处理和忽略. 用户键入SUSP字符时(通常是Ctrl-Z)发出这个信号
21) SIGTTIN   当后台作业要从用户终端读数据时, 该作业中的所有进程会收到SIGTTIN信号. 缺省时这些进程会停止执行.
22) SIGTTOU   类似于SIGTTIN, 但在写终端(或修改终端模式)时收到.
23) SIGURG    有”紧急”数据或out-of-band数据到达socket时产生.
24) SIGXCPU   超过CPU时间资源限制. 这个限制可以由getrlimit/setrlimit来读取/改变。
25) SIGXFSZ   当进程企图扩大文件以至于超过文件大小资源限制。
26) SIGVTALRM虚拟时钟信号. 类似于SIGALRM, 但是计算的是该进程占用的CPU时间.
27) SIGPROF   类似于SIGALRM/SIGVTALRM, 但包括该进程用的CPU时间以及系统调用的时间.
28) SIGWINCH  窗口大小改变时发出.
29) SIGIO     文件描述符准备就绪, 可以开始进行输入/输出操作.
30) SIGPWR    Power failure

3. *常用信号*

在使用信号名时需要省略SIG前缀,通常我们需要忽略的信号有HUP、INT、QUIT、TSTP、TERM,也就是信号l,2,3,15,20。

信号 说明
HUP(1) 挂起,通常因终端掉线或用户退出而引发
INT(2) 中断,通常因按下Ctrl+C组合键而引发
QUIT(3) 退出,通常因按下Ctrl+/组合键而引发
ABRT(6) 中止,通常因某些严重的执行错误而引发
ALRM(14) 报警,通常用来处理超时
TERM(15) 终止,通常在系统关机时发送
TSTP(20) 停止进程的运行,但该信号可以被处理和忽略.用户键入SUSP字符时(通常是Ctrl+z)发出这个信号

4. *trap命令*

trap命令是内置命令,需要使用help trap查看帮助。trap命令用于在接收到信号后将要采取的行动。trap命令的一种常见用途是在脚本程序被中断时完成清理工作。

语法:

Ø trap -l 把所有信号打印出来

Ø trap -p把当前的trap设置打印出来

Ø trap "" singals ===>为空表示这个信号失效

Ø trap "commands" singals ===> 收到signals指定的信号时,信号功能复位同时执行commands命令。

Ø trap singals ===>没有命令部分,信号复原

用stty -a可以列出中断信号与键盘的对应。

范例1:

[root@mysql ~]# trap "" 2   #此时Ctrl+c失效

[root@mysql ~]# trap -p    #查看  

trap -- '' SIGINT

[root@mysql ~]# trap 2    #此时Ctrl+c生效

[root@mysql ~]# ^C

[root@mysql ~]# trap "echo -n 'you can not use ctrl+c'" 2 #收到2信号时执行echo

[root@mysql ~]# ^Cyou can not use ctrl+c     #测试

范例2:同时处理多个信号

[root@mysql ~]# trap "" 1 2 3 15 20
[root@mysql ~]# trap -p
trap -- '' SIGHUP
trap -- '' SIGINT
trap -- '' SIGQUIT
trap -- '' SIGTERM
#TSTP(20)命令没有显示出来,但在脚本中可以实现
[root@mysql ~]# cat trap.sh 
trap "" 1 2 3 15 20
trap -p
[root@mysql ~]# sh trap.sh 
trap -- '' TSTP
[root@mysql ~]# trap 1 2 3 15 20
[root@mysql ~]# sh trap.sh 
trap -- '' HUP
trap -- '' INT
trap -- '' QUIT
trap -- '' TERM
trap -- '' TSTP
[root@mysql ~]# trap 1 2 3 15 20
[root@mysql ~]# sh trap.sh 
trap -- '' HUP
trap -- '' INT
trap -- '' QUIT
trap -- '' TERM
trap -- '' TSTP
#可以批量使用信号名来忽略信号,但信号名不可以批量取消
[root@mysql ~]# trap 1 2 3 15 20
[root@mysql ~]# trap -p
[root@mysql ~]# trap "" HUP INT QUIT TERM TSTP
[root@mysql ~]# trap -p
trap -- '' SIGHUP
trap -- '' SIGINT
trap -- '' SIGQUIT
trap -- '' SIGTERM
[root@mysql ~]# trap HUP INT QUIT TERM TSTP
[root@mysql ~]# trap -p
trap -- '' SIGHUP
trap -- 'HUP' SIGINT
trap -- 'HUP' SIGQUIT
trap -- 'HUP' SIGTERM
[root@mysql ~]# trap ":" HUP INT QUIT TERM TSTP
[root@mysql ~]# ^C
# :也是一个命令,执行后$?为0

5. *Linux信号的生产应用案例*

请记住,脚本程序通常是以从上到下的顺序解释执行的,所以必须在你想保护的那部分代码以前指定trap命令。

触发信号后清理文件

[root@mysql ~]# cat trap_rm_file.sh 
#!/bin/bash
trap "find /tmp -type f -name "website_*"|xargs rm -rf && exit" INT
while :
do
  touch /tmp/website_$(date +%F-%T)
  sleep 1
done
[root@mysql ~]# sh trap_rm_file.sh

另起一个窗口查看文件,发现会生成好多文件,回到脚本执行窗口按Ctrl+c结束,再查看文件发现已经删除

n Shell跳板机(触发信号后屏蔽信号)

l)首先做好sshkey验证或使用expect脚本。

2)实现传统的远程连接菜单选择脚本

3)利用linux信号防止用户在跳板机上操作。

4)用户登录后即调用脚本。

知识点1:trap信号

知识点2:ssh key免密钥登录(参考以前的文档)

知识点3: /etc/profile.d/ ==>加载系统登陆程序的一个目录

\放在******/etc/profile.d/****目录下的文件即使没有执行权限也可以开机自动执行****

*脚本程序*

[root@backup scripts]# cat tiaobanji.sh 
#!/bin/bash

USER=liwen
function trapper(){
   trap "" HUP INT QUIT TERM TSTP
}

function menu() {
cat <<EOF
#################HOST LIST#################
        1)192.168.80.101
        2)192.168.80.102
        3)192.168.80.103
        4)192.168.80.104
        5)192.168.80.105
        6)192.168.80.106
        7)192.168.80.107
###########################################
EOF
}

function select_host() {
   case "$1" in
        1)
           ssh -p52113 $USER@192.168.80.101
        ;;
        2)
           ssh -p52113 $USER@192.168.80.102
        ;;
        3)
           ssh -p52113 $USER@192.168.80.103
        ;;
        4)
           ssh -p52113 $USER@192.168.80.104
        ;;
        5)
           ssh -p52113 $USER@192.168.80.105
        ;;
        6)
           ssh -p52113 $USER@192.168.80.106
        ;;
        7|*)
           ssh -p52113 $USER@192.168.80.107
   esac
}

function main() {
trapper
while true
do
   clear
   menu
   read -p "please select host:" num
  select_host $num
done  
}

main

*开机自启动*

[root@backup ~]# cd /etc/profile.d/
[root@backup ~]# cd /etc/profile.d/
[root@backup profile.d]# vim tiaoban.sh
[ $UID -ne 0 ] && ./server/scripts/tiaobanji.sh
#root用户UID为0,当root用户登录时不执行此脚本,其他用户都执行

6. *跳板机安全应用*

1) 首先跳板机禁止外网IP登录,只能内网IP登录。

ListenAddress 192.168.80.107

2) 其他服务器有外网IP的也别忘了禁止外网IP登录,只能内网IP登录。同时禁止root登录,等做完ssh key认证,连密玛登录也禁了,只能通过证书登录,而且只有跳板机有其他服务器的密钥。

PasswordAuthentication no

3) 先远程拨号登录VPN,然后登录跳板机,然后再从跳板机登录其他服务器。

服务器技术交流群请加微信 YJZyjz