107 行
3.1 KiB
C
107 行
3.1 KiB
C
/* pssh keyscan —— SSH 主机密钥扫描 (平替 ssh-keyscan)
|
|
*
|
|
* 用法:
|
|
* paze-keyscan [-p port] [-t type] host...
|
|
* host 支持 [host]:port 形式
|
|
*
|
|
* 输出 known_hosts 兼容格式:
|
|
* host keytype base64blob (port 22)
|
|
* [host]:port keytype base64blob (其他端口)
|
|
*/
|
|
#include "paze/ssh.h"
|
|
#include "paze/encoding.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
static void key_type_name(const uint8_t *blob, size_t blen, char *out, size_t outsz) {
|
|
if (blen >= 4) {
|
|
uint32_t kl = ((uint32_t)blob[0] << 24) | ((uint32_t)blob[1] << 16) |
|
|
((uint32_t)blob[2] << 8) | blob[3];
|
|
if (4 + kl <= blen && kl < outsz) {
|
|
memcpy(out, blob + 4, kl);
|
|
out[kl] = '\0';
|
|
return;
|
|
}
|
|
}
|
|
snprintf(out, outsz, "unknown");
|
|
}
|
|
|
|
static int scan_one(const char *host, uint16_t port, const char *type_filter) {
|
|
ssh_session_t *s = ssh_session_new(0);
|
|
if (!s) return -1;
|
|
ssh_session_set_hostkey_check(s, 2); /* StrictHostKeyChecking=no */
|
|
|
|
if (ssh_client_connect(s, host, port) < 0) {
|
|
fprintf(stderr, "paze-keyscan: %s:%u connection failed\n", host, port);
|
|
ssh_session_free(s);
|
|
return -1;
|
|
}
|
|
|
|
size_t blen = 0;
|
|
const uint8_t *blob = ssh_session_server_key(s, &blen);
|
|
if (!blob || blen == 0) {
|
|
fprintf(stderr, "paze-keyscan: %s:%u no host key\n", host, port);
|
|
ssh_session_free(s);
|
|
return -1;
|
|
}
|
|
|
|
char kt[128];
|
|
key_type_name(blob, blen, kt, sizeof(kt));
|
|
if (type_filter && strcmp(kt, type_filter) != 0) {
|
|
ssh_session_free(s);
|
|
return 0; /* 类型不匹配,跳过 */
|
|
}
|
|
|
|
char b64[8192];
|
|
paze_base64_encode(blob, blen, b64);
|
|
if (port != 22)
|
|
printf("[%s]:%u %s %s\n", host, port, kt, b64);
|
|
else
|
|
printf("%s %s %s\n", host, kt, b64);
|
|
fflush(stdout);
|
|
|
|
ssh_session_free(s);
|
|
return 0;
|
|
}
|
|
|
|
int pssh_cmd_keyscan(int argc, char **argv) {
|
|
uint16_t port = 22;
|
|
const char *type_filter = NULL;
|
|
const char *hosts[64];
|
|
int nhosts = 0;
|
|
|
|
for (int i = 1; i < argc; i++) {
|
|
if ((strcmp(argv[i], "-p") == 0) && i + 1 < argc) port = (uint16_t)atoi(argv[++i]);
|
|
else if ((strcmp(argv[i], "-t") == 0) && i + 1 < argc) type_filter = argv[++i];
|
|
else if (argv[i][0] == '-') continue;
|
|
else if (nhosts < 64) hosts[nhosts++] = argv[i];
|
|
}
|
|
|
|
if (nhosts == 0) {
|
|
fprintf(stderr, "Usage: paze-keyscan [-p port] [-t type] host...\n");
|
|
return 1;
|
|
}
|
|
|
|
for (int i = 0; i < nhosts; i++) {
|
|
const char *h = hosts[i];
|
|
uint16_t p = port;
|
|
char hostbuf[512];
|
|
/* 支持 [host]:port */
|
|
if (h[0] == '[') {
|
|
const char *close_b = strchr(h, ']');
|
|
if (close_b && close_b[1] == ':') {
|
|
size_t hl = (size_t)(close_b - h - 1);
|
|
if (hl < sizeof(hostbuf)) {
|
|
memcpy(hostbuf, h + 1, hl);
|
|
hostbuf[hl] = '\0';
|
|
h = hostbuf;
|
|
p = (uint16_t)atoi(close_b + 2);
|
|
}
|
|
}
|
|
}
|
|
scan_one(h, p, type_filter);
|
|
}
|
|
return 0;
|
|
}
|