文件

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;
}