bash 如何在不实际执行 ssh 的情况下查找远程主机是否可通过 SSH 访问

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/35741323/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 14:19:49  来源:igfitidea点击:

How to find if remote host is reachable over SSH without actually doing ssh

linuxbashshellunixssh

提问by Todd A. Jacobs

I have multiple remote hosts connected to my local host (server-A). TO ensure/filter the list of hosts which are genuinely reachable to localhost , I do ping test.

我有多个远程主机连接到我的本地主机(服务器-A)。为了确保/过滤真正可以访问 localhost 的主机列表,我进行了 ping 测试。

ping -c1 <remotehost-IP> 

if [ "$?" != "0" ];then
echo "Not reachable.Exiting..."
exit 1;
fi

However ping test could not provide me any check to ensure that filtered remotehost-IPs are reachable over SSH connection /port 22.

但是,ping 测试无法为我提供任何检查,以确保可以通过 SSH 连接/端口 22 访问已过滤的远程主机 IP。

    non-root-user@localhost>ssh 172.26.192.15
    ssh: connect to host 172.26.192.15 port 22: Connection refused
 non-root-user@localhost>echo $?
 1

non-root-user@localhost>ssh -v  172.26.192.15
OpenSSH_3.9p1, OpenSSL 0.9.7a Feb 19 2003
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: Applying options for *
debug1: Connecting to 172.26.192.15 [172.26.192.15] port 22.
debug1: connect to address 172.26.192.15 port 22: Connection refused
ssh: connect to host 172.26.192.15 port 22: Connection refused

Query:

询问:

Above check work for me if connection is refused. However, if SSH connection is possible then I enter into the remote host or proceed to password prompt. Which cause barrier to check return code.

如果连接被拒绝,上面的检查对我有用。但是,如果可以进行 SSH 连接,那么我会进入远程主机或继续密码提示。这会导致检查返回码的障碍。

So I wanted to know if there is any way to check if the remote IP WOULD be reachable or not reachable over SSH beforehand. ?

所以我想知道是否有任何方法可以事先检查远程 IP 是否可以通过 SSH 访问。?

回答by Ze_Gitan

Netcat should also do the job.

Netcat 也应该完成这项工作。

nc -z host 22

-z specifies that no data be sent and to only scan for running daemons

-z 指定不发送数据并且只扫描正在运行的守护进程

The output will look something like this:

输出将如下所示:

Connection to localhost 22 port [tcp/ssh] succeeded!

So if you want to handle this a little more programmatically you could just throw the output to /dev/null and then check that the $? is equal to 0 to verify that the connection is available.

所以如果你想以编程方式处理这个问题,你可以将输出扔到 /dev/null 然后检查 $? 等于 0 以验证连接是否可用。

回答by Slack Flag

This is the simplest command that satisfies the question (without need for nmap or nc):

这是满足问题的最简单命令(不需要 nmap 或 nc):

ssh -o PubkeyAuthentication=no -o PasswordAuthentication=no -o KbdInteractiveAuthentication=no -o ChallengeResponseAuthentication=no host.foo.com 2>&1 | grep "Permission denied"

Explanation: attempt to connect with the usual auth methods disabled and grep STDERR for "Permission denied". Returns exit status 0 if the host is serving SSH, regardless of credentials, and does not hang waiting for password input.

说明:尝试连接禁用的常用身份验证方法并 grep STDERR 获取“权限被拒绝”。如果主机正在为 SSH 提供服务,无论凭据如何,并且不会挂起等待密码输入,则返回退出状态 0。

回答by Todd A. Jacobs

A Bash-Specific Solution

特定于 Bash 的解决方案

If you are using the Bash shell specifically, then you have access to TCP and UDP sockets. For example:

如果您专门使用 Bash shell,那么您可以访问 TCP 和 UDP 套接字。例如:

if (exec 3<>/dev/tcp/74.207.252.238/22) 2> /dev/null; then
    echo open
else
    echo closed
fi

This won't tell you if the actual protocol in use is really SSH, but is often sufficient to determine that a given port is listening. Your mileage may vary.

这不会告诉您实际使用的协议是否真的是 SSH,但通常足以确定给定的端口正在侦听。你的旅费可能会改变。

回答by Basile Starynkevitch

The other answers are checking if some process is listening on the remote machine on the SSH port 22.

其他答案是检查某个进程是否正在 SSH 端口 22 上侦听远程计算机。

But that process might not be an sshddaemon (some sysadmins are starting other daemons on that port, e.g. some HTTPS service...).

但该进程可能不是sshd守护进程(某些系统管理员正在该端口上启动其他守护进程,例如某些 HTTPS 服务...)。

Or the remote sshddaemon has been configured with a non-POSIX shell. For example, as a GCC contributor, I am using sshthru svnto gcc.gnu.orgbut I cannotrun a shell command there...

或者远程sshd守护程序已配置为非 POSIX shell。例如,作为 GCC 贡献者,我正在使用sshthru svntogcc.gnu.org但我无法在那里运行 shell 命令......

So I believe you should really try the sshcommand. If the remote machine is POSIX and you expect to have some Posix shell runnable thru ssh, try ssh remotehost /bin/true(or perhaps ssh remotehost 'echo $$', with the hope that echowould be a remote shell builtin)

所以我相信你真的应该试试这个ssh命令。如果远程机器是 POSIX 并且您希望通过 某些 Posix shell 运行ssh,请尝试ssh remotehost /bin/true(或者ssh remotehost 'echo $$',希望是echo内置的远程 shell)

Also, an sshcommand could temporarily fail (e.g. because the remote host has too many processes running under your user, so the forkinside sshdwould fail)

此外,ssh命令可能会暂时失败(例如,因为远程主机在您的用户下运行的进程太多,因此fork内部sshd会失败)

If you want that inside some program, consider using some library like libssh.

如果您希望在某个程序中使用它,请考虑使用诸如libssh 之类的

BTW, you can configure your local.ssh/configto never ask any password (or pass with -Fsome specific configuration file ensuring that no password is asked), or (as commented by CodeGnome), use ssh -o BatchMode=yesto disable password prompts.

顺便说一句,您可以将本地配置.ssh/config为从不询问任何密码(或通过-F某些特定的配置文件确保不询问密码),或者(如CodeGnome所评论),用于ssh -o BatchMode=yes禁用密码提示。

回答by dbndhjefj

You could use nmap:

你可以使用nmap

nmap -p 22 --open -sV 172.26.192.0/24 > sshservers

回答by Todd A. Jacobs

Grep Output from Nmap

来自 Nmap 的 Grep 输出

If you need an exit status, grep the results from nmap and use the exit status from grep. For example:

如果您需要退出状态,请从 nmap 中 grep 结果并使用 grep 中的退出状态。例如:

$ nmap -sT -Pn -p 22 host.example.com | egrep 'open\s+ssh'
22/tcp open  ssh

In this example, the exit status will be from grep, not nmap. Grep will return 0if the port is open, and 1if it isn't. You can use the results directly, or branch off of $?. For example:

在这个例子中,退出状态将来自 grep,而不是 nmap。0如果端口打开,1则Grep 将返回,否则将返回。您可以直接使用结果,也可以从$?. 例如:

nmap -sT -Pn -p 22 host.example.com | egrep -q 'open\s+ssh'
if [[ $? -ne 0 ]]; then
    echo 'Not reachable. Exiting ...' > /dev/stderr
    exit 1
fi