在屏幕会话中访问 SSH 客户端 IP 地址

Posted

技术标签:

【中文标题】在屏幕会话中访问 SSH 客户端 IP 地址【英文标题】:Access SSH client IP address, within a screen session 【发布时间】:2016-09-25 12:25:39 【问题描述】:

可以通过环境变量(例如 SSH_CONNECTION)访问正在连接的 SSH 客户端的 IP 地址,如

中所述

Find the IP address of the client in an SSH session

不过,在 GNU 屏幕会话中,这些环境变量是由启动屏幕的人定义的。对于稍后进入已经存在的屏幕会话的人(例如从另一台主机),是否有任何方法也可以获取 SSH 连接信息?

我想不出一种方法来确定这一点,但是这在例如不同人之间共享屏幕会话的情况下很有用。

【问题讨论】:

链接的问题有几个答案,有些涉及环境变量以外的东西。 可能是这样,但我仍然想知道是否有办法找出谁在屏幕会话中调用了某个脚本,尤其是。如果屏幕会话可能由不同的人共享。 您可以向上遍历当前进程的 PPID 并查看它们的环境变量和标准句柄(在 Linux 上通过 /proc)。 @n.m. - 我仍然不明白这将如何帮助我区分不同的客户。让我们假设两个客户端(两个用户)通过 SSH 从不同的 IP 连接到机器,比如说 root。如果两者都在此处的给定屏幕会话 (screen -x) 中处于活动状态,并且其中一个在此处调用脚本 - 有没有办法告诉他们中的哪一个(即通过 SSH 客户端 IP)实际上这样做了?在这种情况下,PPID 将是相同的。 嗯,不,那是不可能的。这就像让几个人在您的键盘上键入,然后试图确定谁键入了什么。一个人可以输入l,另一个人是s,而另一个人按下回车键,谁调用了ls?和screen完全一样。 【参考方案1】:

如果屏幕会话以 root 身份启动,您可以,但它不会完全可靠

    如果两个用户在同一个屏幕窗口中键入,他们将在同一个 shell 中进行交互。一个人可以写一个命令。对方可以按<enter>键。

    您必须访问环境变量 SSH_CONNECTION(或更好的 SSH_CLIENT),这只有在您是 root 用户或在屏幕会话中使用相同用户时才有可能。

假设您是屏幕会话中的根用户,您可以通过使用ps 命令并查找最后一个活动会话来了解屏幕会话中的最后一个活动用户。

ps h -C screen katime -o pid,user

通过使用 pid 并访问 /proc/<pid>/environ 文件,您可以获得 SSH_CLIENT 变量。

sed -z '/SSH_CLIENT/p;d' /proc/`ps h -C screen katime -o pid |head -1`/environ

--> SSH_CLIENT=257.31.120.12

所有这些都假设您的屏幕以 root 身份执行

您还可以选择记录所有活动连接。 对于这种需要,我建议您存储完整的连接列表及其最后的活动。

ps eh -C screen kstime -o pid,atime | while read pid stime; do echo -n "$stime: ";\
    gawk -v 'RS=\0' -F= '$1=="SSH_CLIENT" print $2' /proc/$pid/environ; done

Result:
00:00:00: 257.31.120.12 61608 22
00:07:11: 258.1.2.3.4 49947 22

请注意,如果您觉得更容易,也可以解析ps eh -C screen kstime -o args 命令的结果。

编辑:

这是一个有效的 Debian 命令,用于让所有当前连接到同一屏幕会话的用户:

 find /var/run/screen/
     -name $(pstree -sp $$ |sed 's/.*screen(\([0-9]*\)).*/\1/;q').*
     -printf "%h\n"
      | cut -f2 -d-

【讨论】:

感谢您为此付出的努力!正如你所说,不是 100% 的案例都有效,但这样我可以很好地覆盖我感兴趣的案例。【参考方案2】:

如果sshd 是连接到服务器的唯一方式,您可以检查last 命令的输出,该命令将列出所有连接的IP addresseshostnames

ec2-user]# last
ec2-user pts/0        115.250.185.183  Sun May 29 13:49   still logged in
ec2-user pts/0        115.250.140.241  Sat May 28 07:26 - 10:15  (02:48)
root     pts/4        113.21.68.105    Tue May  3 10:15 - 10:15  (00:00)

或者(在 Linux 上),您可以检查 /var/log/secure,其中 sshd 通常会记录所有连接的所有详细信息,即使它们不会导致成功登录。

【讨论】:

到目前为止,这对我的问题没有多大帮助。我在机器上有一些脚本,可以由具有 SSH 访问权限的不同人(来自不同的客户端 IP)调用。调用时,这些脚本会记录谁(如:客户端 IP)调用它们以及何时调用它们。为了确定这里的客户端 IP,我使用了 SSH_CONNECTION 的信息——除非使用屏幕会话(尤其是共享会话),否则工作正常。我想知道是否有一种可靠的方法可以从屏幕会话中知道谁调用了脚本(可能有多个人在给定时间登录到它)。 @weiresr 有趣的问题,但在 imo 设计中这是不可能的。当您附加屏幕会话时,您将冒充启动会话(或者更好地说,会话中的程序)的用户 - 承担所有后果。 @hek2mgl 好吧,我最近看到的一件事是,您至少可以在屏幕中获得附加显示器的列表(C-a :displays)。像这样的东西可以在一定程度上帮助我朝着我想要的方向前进——但我不知道是否可以通过脚本访问该信息,即使那样它也无法告诉我(通过设计)哪个触发了某个命令, 如果当前连接了多个显示器。 @weiresr 我编辑了自己的答案以添加一个示例,说明如何使用/var/run/screen 目录实现它【参考方案3】:

如果您尝试支持多显示模式('screen -x'),那么正如上面有人所说,您可能不走运。

另一方面,如果您可以假设单用户模式,那么您可以为屏幕命令创建一个包装器/别名,将环境变量携带到屏幕中(请参阅“屏幕 -X 东西...”);在这种情况下,您只是传递具有适当值的 SSH_CLIENT。

如果您可以假设给定用户名来自单个位置(或者,如果多个位置,则只需选择最近的),那么您可以在“last”命令的输出上执行一些 grep/sed。

client_ip=`last -ai | grep "still logged in" | grep "$USER " | grep -v '0.0.0.0' | tail -n 1 | sed 's/.* //g'`
echo "Hello $client_ip"

【讨论】:

感谢您的输入,但在屏幕内 SSH_TTY(就像 SSH_CONNECTION)给了我开始屏幕的人的价值。因此,如果我再次从另一个 SSH 会话进入现有屏幕,我似乎无法通过这种方式获得当前连接的 TTY。 你是对的。我不确定如何处理多显示器案例,但我对单用户模式提出了一些想法,以防它以某种方式适用于您。 我最感兴趣的是 screen -x 场景,因为我们经常在一个给定的屏幕上同时有多个人。在这里了解更多选项仍然很有趣,谢谢:)【参考方案4】:

如果您的屏幕通常以分离模式启动,则在您的 .screenrc 中添加以下内容:

shell -$SHELL

然后您的屏幕将包含所有变量。 对于您遇到的当前正在运行的屏幕,只需运行即可。

source ~/.bash_profile

替换路径和文件名以匹配您的环境。

【讨论】:

以上是关于在屏幕会话中访问 SSH 客户端 IP 地址的主要内容,如果未能解决你的问题,请参考以下文章

Nginx 会话保持

HAProxy基于cookie实现客户端会话保持

Linux SSH无交互式访问配置

服务器变更IP地址后SSH链接失败的解决办法

14.4web排错三部曲

如何在 Meteor 中访问客户端 IP 地址? [复制]