--- lbbs/src/test_ssh_server.c 2025/06/21 02:15:18 1.9 +++ lbbs/src/test_ssh_server.c 2025/12/19 06:30:40 1.20 @@ -1,35 +1,34 @@ -/*************************************************************************** - test_ssh_server.c - description - ------------------- - Copyright : (C) 2004-2025 by Leaflet - Email : leaflet@leafok.com - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 3 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * test_ssh_server + * - tester for network server with SSH support + * + * Copyright (C) 2004-2025 Leaflet + */ // This test was written based on libssh example/proxy.c +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include "log.h" #include #include #include #include -#ifndef BUF_SIZE -#define BUF_SIZE 2048 -#endif +enum test_ssh_server_constant_t +{ + BUF_SIZE = 2048, +}; -#define SSH_HOST_RSA_KEYFILE "../conf/ssh_host_rsa_key" +static const char SSH_HOST_RSA_KEY_FILE[] = "../conf/ssh_host_rsa_key"; +static const char SSH_HOST_ED25519_KEY_FILE[] = "../conf/ssh_host_ed25519_key"; +static const char SSH_HOST_ECDSA_KEY_FILE[] = "../conf/ssh_host_ecdsa_key"; -#define USER "test" -#define PASSWORD "123456" +static const char USER[] = "test"; +static const char PASSWORD[] = "123456"; static ssh_channel SSH_channel; static int authenticated = 0; @@ -41,16 +40,16 @@ static int auth_password(ssh_session ses { (void)userdata; - log_common("Authenticating user %s pwd %s\n", user, password); + log_common("Authenticating user %s pwd %s", user, password); if (strcmp(user, USER) == 0 && strcmp(password, PASSWORD) == 0) { authenticated = 1; - log_common("Authenticated\n"); + log_common("Authenticated"); return SSH_AUTH_SUCCESS; } if (tries >= 3) { - log_error("Too many authentication tries\n"); + log_error("Too many authentication tries"); ssh_disconnect(session); error = 1; return SSH_AUTH_DENIED; @@ -70,7 +69,7 @@ static int pty_request(ssh_session sessi (void)px; (void)py; (void)userdata; - log_common("Allocated terminal\n"); + log_common("Allocated terminal"); return 0; } @@ -79,7 +78,7 @@ static int shell_request(ssh_session ses (void)session; (void)channel; (void)userdata; - log_common("Allocated shell\n"); + log_common("Allocated shell"); return 0; } @@ -87,7 +86,7 @@ struct ssh_channel_callbacks_struct chan .channel_pty_request_function = pty_request, .channel_shell_request_function = shell_request}; -static ssh_channel new_session_channel(ssh_session session, void *userdata) +static ssh_channel channel_open(ssh_session session, void *userdata) { (void)session; (void)userdata; @@ -95,7 +94,7 @@ static ssh_channel new_session_channel(s if (SSH_channel != NULL) return NULL; - log_common("Allocated session channel\n"); + log_common("Allocated session channel"); SSH_channel = ssh_channel_new(session); ssh_callbacks_init(&channel_cb); ssh_set_channel_callbacks(SSH_channel, &channel_cb); @@ -112,38 +111,66 @@ int ssh_server(const char *hostaddr, uns struct ssh_server_callbacks_struct cb = { .userdata = NULL, .auth_password_function = auth_password, - .channel_open_request_session_function = new_session_channel}; + .channel_open_request_session_function = channel_open}; + + long int ssh_timeout = 0; char buf[BUF_SIZE]; char host[128] = ""; int i, r; + int ssh_key_valid = 0; int ssh_log_level = SSH_LOG_PROTOCOL; ssh_init(); sshbind = ssh_bind_new(); + if (ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, SSH_HOST_RSA_KEY_FILE) < 0) + { + log_error("Error loading SSH RSA key: %s", SSH_HOST_RSA_KEY_FILE); + } + else + { + ssh_key_valid = 1; + } + if (ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, SSH_HOST_ED25519_KEY_FILE) < 0) + { + log_error("Error loading SSH ED25519 key: %s", SSH_HOST_ED25519_KEY_FILE); + } + else + { + ssh_key_valid = 1; + } + if (ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, SSH_HOST_ECDSA_KEY_FILE) < 0) + { + log_error("Error loading SSH ECDSA key: %s", SSH_HOST_ECDSA_KEY_FILE); + } + else + { + ssh_key_valid = 1; + } + + if (!ssh_key_valid) + { + log_error("Error: no valid SSH host key"); + ssh_bind_free(sshbind); + return -1; + } + if (ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDADDR, hostaddr) < 0 || ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT, &port) < 0 || - ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, SSH_HOST_RSA_KEYFILE) < 0 || - ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY_ALGORITHMS, "ssh-rsa,rsa-sha2-512,rsa-sha2-256,ecdsa-sha2-nistp256") < 0 || - ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_PUBKEY_ACCEPTED_KEY_TYPES, "ssh-rsa,rsa-sha2-512,rsa-sha2-256,ecdsa-sha2-nistp256") < 0 || - ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_KEY_EXCHANGE, "curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group14-sha256,diffie-hellman-group14-sha1") < 0 || - ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HMAC_C_S, "umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1") < 0 || - ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HMAC_S_C, "umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1") < 0 || - ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_CIPHERS_C_S, "chacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com") < 0 || - ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_CIPHERS_S_C, "chacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com") < 0 || + ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY_ALGORITHMS, "+ssh-ed25519,ecdsa-sha2-nistp256,ssh-rsa") < 0 || ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_LOG_VERBOSITY, &ssh_log_level) < 0) { - log_error("Error setting SSH bind options: %s\n", ssh_get_error(sshbind)); + log_error("Error setting SSH bind options: %s", ssh_get_error(sshbind)); ssh_bind_free(sshbind); return -1; } if (ssh_bind_listen(sshbind) < 0) { - log_error("Error listening at SSH server port: %s\n", ssh_get_error(sshbind)); + log_error("Error listening at SSH server port: %s", ssh_get_error(sshbind)); ssh_bind_free(sshbind); return -1; } @@ -163,10 +190,19 @@ int ssh_server(const char *hostaddr, uns ssh_callbacks_init(&cb); ssh_set_server_callbacks(session, &cb); + ssh_timeout = 60; // second + if (ssh_options_set(session, SSH_OPTIONS_TIMEOUT, &ssh_timeout) < 0) + { + log_error("Error setting SSH options: %s", ssh_get_error(session)); + ssh_disconnect(session); + _exit(1); + } + if (ssh_handle_key_exchange(session)) { - log_error("ssh_handle_key_exchange: %s\n", ssh_get_error(session)); - return 1; + log_error("ssh_handle_key_exchange: %s", ssh_get_error(session)); + ssh_disconnect(session); + _exit(1); } ssh_set_auth_methods(session, SSH_AUTH_METHOD_PASSWORD | SSH_AUTH_METHOD_GSSAPI_MIC); @@ -180,7 +216,7 @@ int ssh_server(const char *hostaddr, uns r = ssh_event_dopoll(event, -1); if (r == SSH_ERROR) { - log_error("Error : %s\n", ssh_get_error(session)); + log_error("Error : %s", ssh_get_error(session)); ssh_disconnect(session); _exit(1); } @@ -188,15 +224,23 @@ int ssh_server(const char *hostaddr, uns if (error) { - log_error("Error, exiting loop\n"); + log_error("Error, exiting loop"); _exit(1); } else { - log_common("Authenticated and got a channel\n"); + log_common("Authenticated and got a channel"); + } + + ssh_timeout = 0; + if (ssh_options_set(session, SSH_OPTIONS_TIMEOUT, &ssh_timeout) < 0) + { + log_error("Error setting SSH options: %s", ssh_get_error(session)); + ssh_disconnect(session); + _exit(1); } - snprintf(buf, sizeof(buf), "Hello, welcome to the Sample SSH proxy.\r\nPlease select your destination: "); + snprintf(buf, sizeof(buf), "Hello, welcome to the Sample SSH proxy.\nPlease select your destination: "); ssh_channel_write(SSH_channel, buf, (uint32_t)strlen(buf)); do { @@ -217,11 +261,11 @@ int ssh_server(const char *hostaddr, uns } else { - log_error("Error: %s\n", ssh_get_error(session)); + log_error("Error: %s", ssh_get_error(session)); _exit(1); } } while (i > 0); - snprintf(buf, sizeof(buf), "Trying to connect to \"%s\"\r\n", host); + snprintf(buf, sizeof(buf), "Trying to connect to \"%s\"\n", host); ssh_channel_write(SSH_channel, buf, (uint32_t)strlen(buf)); log_common("%s", buf); @@ -230,13 +274,13 @@ int ssh_server(const char *hostaddr, uns _exit(0); case -1: - log_error("Failed to fork\n"); + log_error("Failed to fork"); break; } } else { - log_error("%s\n", ssh_get_error(sshbind)); + log_error("%s", ssh_get_error(sshbind)); } /* Since the session has been passed to a child fork, do some cleaning