休眠时远程 shell 会话注销

休眠时远程 shell 会话注销

我经常发现笔记本电脑关闭得太快,而远程 ssh 会话却很少打开。唤醒后我发现几个死机壳,它们还没有关闭 :/

如何在休眠/挂起/关机时强制彻底退出远程 ssh 会话?

PS 在 gentoo 和 ubuntu 上

答案1

在休眠或挂起之前终止 ssh 客户端。

在 Ubuntu lucid 上,暂停脚本位于 中/etc/pm/sleep.d。文档位于pm-action(8)手册页中。添加/etc/pm/sleep.d/20_dariusz_kill_ssh包含类似以下内容的内容

#!/bin/sh
case $1 in
  suspend|hibernate) pkill -x ssh;;
esac

我不知道 Gentoo 上相应的脚本在哪里。如果您这样做,您可能需要进行优化以排除 ssh 到 localhost。

对于关机,您不需要执行任何操作,正常关机脚本已经干净地终止了 ssh 客户端(因此它们将关闭连接)。

请注意,让会话保持打开状态并不是什么大问题。尽早终止会话的好处就是可以恢复 ssh 服务器上的一些资源和一些防火墙。因此,您可以在恢复时终止客户端,并且只有在连接丢失时才可以。如果您选择这种方法,我认为正确的位置是在网络脚本中:在网络中断时记录活动的 ssh 会话,并在网络恢复时终止它们。

以下是概念验证(完全未经测试)。在/etc/network/if-down.d/ssh-sessions-record(Ubuntu 位置)中,记录与消失的接口关联的 IP 地址以及接口关闭的时间:

#!/bin/sh
{
  echo OLD_IP=$(ifconfig "$IFACE" | sed -n 's/^ *inet addr:\([0-9.]\+\).*/\1/p')
  echo OLD_DATE=$(date +%s)
} >"/var/run/$IFACE.ssh-sessions-record"

在 中/etc/network/if-up.d/ssh-sessions-record,终止通过此网络接口的 ssh 连接,但前提是 IP 地址已更改或经过了足够长的时间导致服务器可能已超时:

#!/bin/sh
if [ -e "/var/run/$IFACE.ssh-sessions-record" ]; then
. "/var/run/$IFACE.ssh-sessions-record"
NEW_IP=$(ifconfig "$IFACE" | sed -n 's/^ *inet addr:\([0-9.]\+\).*/\1/p')
NEW_DATE=$(date +%s)
if [ "$NEW_IP" != "$OLD_IP" ] || [ $(($NEW_DATE-$OLD_DATE)) -ge 300 ]; then
  ## Kill all ssh processes that were connecting through $OLD_IP
  for pid in $(lsof -Fp -n -i "tcp@$OLD_IP"); do
    if [ "$(ps -$pid -o comm=)" = "ssh" ]; then
      kill $pid
    fi
  done
fi

答案2

既然还没有人尝试过,那我就试一试。如果没有别的办法,也许这会激励别人。

我手边没有笔记本电脑或最新的 Gentoo,所以也许 Ubuntu 就足够了。我当前的桌面是 Ubuntu 10.04... 您没有提到您的版本 - 希望它接近。

无论如何,我会查看 Upstart 配置(如果您不使用 Upstart,则查看 /etc/inittab)。通过以下方式验证您是否正在运行 upstart:

# dpkg --list | grep upstart
ii  upstart          0.6.5-7     event-based init daemon

显然,如果您没有看到类似的东西,那么您可能正在使用 init。这两个工具(upstart 和 init)都旨在在启动、关闭等(即事件)时执行操作。

对于 Upstart,请进入 /etc/init 目录并查看其中的文件。由于我没有使用笔记本电脑,因此没有“休眠或挂起”功能,但我敢打赌您有。尝试在其中进行一些 grep 操作以查看:

/etc/init# egrep -i "suspend|hibernate" *

然而,我的控制-alt-delete.conf这个文件给我的感觉很有趣。如果我看一下,就会发现:

/etc/init# cat control-alt-delete.conf 
# control-alt-delete - emergency keypress handling
#
# This task is run whenever the Control-Alt-Delete key combination is
# pressed, and performs a safe reboot of the machine.

description     "emergency keypress handling"
author          "Scott James Remnant <[email protected]>"

start on control-alt-delete

task
exec shutdown -r now "Control-Alt-Delete pressed"

我敢打赌,您可以自定义最后一行来编写一些 SSH 注销脚本,或者任何您喜欢的脚本。您需要更新(或创建)正确的配置文件。我猜笔记本电脑安装会有一些针对休眠/挂起/等的特定内容。查看其他一些文件(如 apport.conf),我发现配置文件实际上支持嵌入其中的脚本。

如果您正在处理 init 而不是 upstart,请尝试查看 /etc/inittab 行,例如:

# What to do when the power fails/returns.
pf::powerwait:/etc/init.d/powerfail start
pn::powerfailnow:/etc/init.d/powerfail now
po::powerokwait:/etc/init.d/powerfail stop
...
# What to do when CTRL-ALT-DEL is pressed.
ca:12345:ctrlaltdel:/sbin/shutdown -t1 -a -r now

一旦根据您的配置找到了理想的位置,编写一个可以杀死它们或类似操作的 bash 脚本就不会太困难了。

简单示例:

#!/bin/bash
kill -9 `ps -ef | grep "[s]sh " | awk '{print $2}'`

我希望这至少能给你一个起点。也许有更简单的方法,但我用笔记本电脑不多,不知道。

差点忘了:假设您执行了其中任何一项,您可能需要反弹 init 才能使其生效:

# kill -HUP 1

相关内容