7

是否有一些 cli 工具可以用来验证 known_hosts 的内容?也许尝试 ping 那里的所有主机,看看我是否可以连接到每个主机?

可能使用ssh-keygen或者ssh-keyscan

4

2 回答 2

5

如果你有所有可用主机的列表,你可以这样做:

ssh-keyscan -t rsa,dsa -f hosts_list > ~/.ssh/known_hosts_revised

这将生成一个新的known_hosts_revised,您可以diff使用当前创建一个know_hosts以查看差异。

如果您不需要比较它,您可以简单... > ~/.ssh/known_hosts地覆盖它(警告:原件known_hosts将丢失!)

信息来源是ssh-keyscan(1)的 OpenBSD 手册页。

编辑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
于 2019-05-16T06:18:31.343 回答
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设置为]:if present(新样式)的位置。如果该字符串不存在,我们检查旧样式并重置p

如果p是肯定的,我们有一个端口规范。提取端口并从主机名中删除(它和方括号)。否则,端口为 22。

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

读入整个 known_hosts 文件后,我们迭代作为数组type,port键的元组对port_list,将它们拆分为一个名为 的数组a,然后ssh-keyscan在它们上运行。

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

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

于 2019-05-22T16:49:59.507 回答