验证 .ssh/known_hosts 文件的内容

8

有没有一些可以用来验证 known_hosts 内容的命令行工具?也许可以尝试对其中的所有主机进行 ping 测试并查看是否能够连接到每个主机吗?

可能会使用 ssh-keygenssh-keyscan

2个回答

5
如果您有所有可用主机的列表,可以这样做:
ssh-keyscan -t rsa,dsa -f hosts_list > ~/.ssh/known_hosts_revised

这将生成一个新的known_hosts_revised文件,您可以将其与当前的know_hosts文件进行对比以查看差异。
如果不需要进行比较,只需执行... > ~/.ssh/known_hosts即可覆盖它(警告:原始known_hosts将会丢失!)
这些信息来源于OpenBSD man页面的ssh-keyscan(1)编辑hosts_list是期望接受的内容:
1.2.3.4,1.2.4.4 name.my.domain,name,n.my.domain,n,1.2.3.4,1.2.4.4

1

对于我的设置来说,使用ssh-keyscan是不可能的,因为我有一个庞大的~/.ssh/config文件。我使用了很多代理命令、跳板主机和替代的Hostname声明。

例如:

# Connect to Tor nodes
Host *.onion
  ProxyCommand socat - SOCKS4A:localhost:%h:%p,socksport=9050

# Work jump box
Host bastion
  Hostname bastion.work.com

# Office system, e.g. bob.office -> bastion -> bob.work.com
Host *.office
  ProxyCommand ssh bastion nc -w600s $(echo "%h" |sed 's/\.office$/work.com/') %p

# Home system, e.g. adam -> home.com -> adam-laptop.local
Host adam
  Hostname adam-laptop.local
  ProxyJump home.com

以上方法均不可行。

以下是一个应该适用于其余情况的脚本:

#!/usr/bin/awk -f

!/^#/ && NF > 2 {
  split($1, hosts, ",")
  key_type = $2
  gsub(/^ssh-/, "", key_type)
  gsub(/-.*/, "", key_type)
  for (h in hosts) {
    p = index(hosts[h], "]:")   # [host]:port (supports raw IPv6 hosts)
    if (!p && hosts[h] ~ /^[^:]+:[0-9]+$/) p = index(hosts[h], ":")  # host:port
    if (p > 0) {
      port = substr(hosts[h], p + 2)
      gsub("\[|\]?:" port, "", hosts[h])
    } else {
      port = 22
    }
    if (seen[key_type,port,hosts[h]]++) next  # prevent duplicate lookups
    if (port_list[key_type,port]) { comma = "," } else { comma = "" }
    port_list[key_type,port] = port_list[key_type,port] comma hosts[h]
  }
}
END {
  for (tp in port_list) {
    split(tp, a, SUBSEP)
    system("echo ssh-keyscan -t " a[1] " -p " a[2] " " port_list[tp])
  }
}

去掉 echo 部分,一旦您确信这将执行您想要的操作。

这个程序解析没有注释的行并且至少有3个字段(因为格式是 host_list key_type key_hash)。它会将主机列表拆分,因为它可以逗号分隔,并且需要进一步解析,因为它可能包含端口,但 ssh-keyscan 不能接受以 known_hosts 使用的主机格式。

有两种指定端口的方式:

  1. 旧式样式不适用于裸IPv6地址,是 host:port
  2. 新样式对于裸IPv6地址是必需的,即 [host]:port

如果存在 ]: 字符串(新风格),则设置 p 为该位置。如果该字符串不存在,则检查旧风格并重置 p

如果 p 为正数,则有一个端口规范。提取端口并从主机名中删除它和方括号。否则,端口为22。

为了防止重复条目,我们检查它们并继续进行,如果我们已经看到了类型、端口和主机组合(只有第一次运行时x++为false(0))。最后,我们将主机推送到以类型和端口为键的port_list数组中的逗号分隔列表字符串。

在读取整个known_hosts文件后,我们迭代键控port_list数组的type,port元组对,将它们拆分成名为a的数组,并在其上运行ssh-keyscan

像这样运行:awk -f 'this_script.awk' ~/.ssh/known_hosts,如果你喜欢它输出的ssh-keyscan命令,请从系统命令中删除echo并重新运行。

不要将此输出管道传输到~/.ssh/known_hosts您需要手动审查结果(并可能过滤注释)。另外,您不能将输出重定向到输入中使用的文件之一。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接