mirror of
https://git.libssh.org/projects/libssh.git
synced 2026-06-11 12:56:21 +09:00
config: support ConnectTimeout time values
Signed-off-by: Nuhiat-Arefin <nuhiatarefin@gmail.com> Reviewed-by: Jakub Jelen <jjelen@redhat.com> Merge-Request: <https://gitlab.com/libssh/libssh-mirror/-/merge_requests/815>
This commit is contained in:
committed by
Jakub Jelen
parent
e34704c203
commit
d157f13b27
87
src/config.c
87
src/config.c
@@ -894,6 +894,69 @@ ssh_config_get_auth_option(enum ssh_config_opcode_e opcode)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static long ssh_config_convtime(const char *p, long notfound)
|
||||
{
|
||||
char *endp = NULL;
|
||||
long total = 0;
|
||||
long value;
|
||||
long multiplier;
|
||||
|
||||
if (p == NULL || *p == '\0') {
|
||||
return notfound;
|
||||
}
|
||||
|
||||
while (*p != '\0') {
|
||||
errno = 0;
|
||||
value = strtol(p, &endp, 10);
|
||||
if (p == endp || errno != 0 || value < 0) {
|
||||
return notfound;
|
||||
}
|
||||
|
||||
switch (*endp) {
|
||||
case '\0':
|
||||
case 's':
|
||||
case 'S':
|
||||
multiplier = 1;
|
||||
break;
|
||||
case 'm':
|
||||
case 'M':
|
||||
multiplier = 60;
|
||||
break;
|
||||
case 'h':
|
||||
case 'H':
|
||||
multiplier = 60 * 60;
|
||||
break;
|
||||
case 'd':
|
||||
case 'D':
|
||||
multiplier = 24 * 60 * 60;
|
||||
break;
|
||||
case 'w':
|
||||
case 'W':
|
||||
multiplier = 7 * 24 * 60 * 60;
|
||||
break;
|
||||
default:
|
||||
return notfound;
|
||||
}
|
||||
|
||||
/*
|
||||
* OpenSSH accepts ConnectTimeout values only up to INT_MAX
|
||||
* seconds: see openssh-portable/misc.c:convtime().
|
||||
*/
|
||||
if (value > (INT_MAX - total) / multiplier) {
|
||||
return notfound;
|
||||
}
|
||||
total += value * multiplier;
|
||||
|
||||
if (*endp == '\0') {
|
||||
p = endp;
|
||||
} else {
|
||||
p = endp + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
#define CHECK_COND_OR_FAIL(cond, error_message) \
|
||||
if ((cond)) { \
|
||||
SSH_LOG(SSH_LOG_DEBUG, \
|
||||
@@ -930,7 +993,7 @@ static int ssh_config_parse_line_internal(ssh_session session,
|
||||
char *keyword = NULL;
|
||||
char *lowerhost = NULL;
|
||||
size_t len;
|
||||
int i, rv;
|
||||
int i, rv, cmp;
|
||||
uint8_t *seen = session->opts.options_seen;
|
||||
long l;
|
||||
int64_t ll;
|
||||
@@ -1418,12 +1481,22 @@ static int ssh_config_parse_line_internal(ssh_session session,
|
||||
}
|
||||
break;
|
||||
case SOC_TIMEOUT:
|
||||
l = ssh_config_get_long(&s, -1);
|
||||
CHECK_COND_OR_FAIL(l < 0, "Invalid argument");
|
||||
if (*parsing) {
|
||||
ssh_options_set(session, SSH_OPTIONS_TIMEOUT, &l);
|
||||
}
|
||||
break;
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
CHECK_COND_OR_FAIL(p == NULL, "Missing argument");
|
||||
cmp = strcmp(p, "none");
|
||||
if (cmp == 0) {
|
||||
if (*parsing) {
|
||||
session->opts.timeout = (unsigned long)SSH_TIMEOUT_INFINITE;
|
||||
session->opts.timeout_usec = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
l = ssh_config_convtime(p, -1);
|
||||
CHECK_COND_OR_FAIL(l < 0, "Invalid argument");
|
||||
if (*parsing) {
|
||||
ssh_options_set(session, SSH_OPTIONS_TIMEOUT, &l);
|
||||
}
|
||||
break;
|
||||
case SOC_STRICTHOSTKEYCHECK:
|
||||
i = ssh_config_get_yesno(&s, -1);
|
||||
CHECK_COND_OR_FAIL(i < 0, "Invalid argument");
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#define LIBSSH_STATIC
|
||||
|
||||
#ifndef _WIN32
|
||||
@@ -58,6 +60,7 @@ extern LIBSSH_THREAD int ssh_log_level;
|
||||
#define LIBSSH_TESTCONFIG_LOGLEVEL_MISSING "libssh_test_loglevel_missing.tmp"
|
||||
#define LIBSSH_TESTCONFIG_JUMP "libssh_test_jump.tmp"
|
||||
#define LIBSSH_TESTCONFIG_NUMERIC_INVALID "libssh_test_numeric_invalid.tmp"
|
||||
#define LIBSSH_TESTCONFIG_TIMEOUT_SUFFIX "libssh_test_timeout_suffix.tmp"
|
||||
|
||||
#define LIBSSH_TESTCONFIG_STRING1 \
|
||||
"User "USERNAME"\nInclude "LIBSSH_TESTCONFIG2"\n\n"
|
||||
@@ -344,6 +347,8 @@ static int setup_config_files(void **state)
|
||||
unlink(LIBSSH_TESTCONFIG_MATCH_COMPLEX);
|
||||
unlink(LIBSSH_TESTCONFIG_LOGLEVEL_MISSING);
|
||||
unlink(LIBSSH_TESTCONFIG_JUMP);
|
||||
unlink(LIBSSH_TESTCONFIG_NUMERIC_INVALID);
|
||||
unlink(LIBSSH_TESTCONFIG_TIMEOUT_SUFFIX);
|
||||
|
||||
torture_write_file(LIBSSH_TESTCONFIG1,
|
||||
LIBSSH_TESTCONFIG_STRING1);
|
||||
@@ -455,6 +460,8 @@ static int teardown_config_files(void **state)
|
||||
unlink(LIBSSH_TESTCONFIG_MATCH_COMPLEX);
|
||||
unlink(LIBSSH_TESTCONFIG_LOGLEVEL_MISSING);
|
||||
unlink(LIBSSH_TESTCONFIG_JUMP);
|
||||
unlink(LIBSSH_TESTCONFIG_NUMERIC_INVALID);
|
||||
unlink(LIBSSH_TESTCONFIG_TIMEOUT_SUFFIX);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -860,6 +867,63 @@ static void torture_config_numeric_invalid_string(void **state)
|
||||
torture_config_numeric_invalid(state, NULL);
|
||||
}
|
||||
|
||||
static void torture_config_timeout_suffix(void **state, const char *file)
|
||||
{
|
||||
ssh_session session = *state;
|
||||
struct timeout_case {
|
||||
const char *host;
|
||||
const char *value;
|
||||
long expected;
|
||||
bool infinite;
|
||||
} cases[] = {
|
||||
{"seconds", "30s", 30, false},
|
||||
{"seconds_upper", "30S", 30, false},
|
||||
{"minutes", "1m", 60, false},
|
||||
{"minutes_upper", "1M", 60, false},
|
||||
{"days", "30d", 30L * 24 * 60 * 60, false},
|
||||
{"days_upper", "1D", 24L * 60 * 60, false},
|
||||
{"weeks_upper", "1W", 7L * 24 * 60 * 60, false},
|
||||
{"int_max", "3550w5d3h14m7s", INT_MAX, false},
|
||||
{"repeat_s", "30s30s", 60, false},
|
||||
{"repeat_h", "1h1h", 7200, false},
|
||||
{"compound", "1h30m", 5400, false},
|
||||
{"compound_upper", "1H30M", 5400, false},
|
||||
{"none", "none", 0, true},
|
||||
};
|
||||
char config[256];
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cases); i++) {
|
||||
torture_reset_config(session);
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, cases[i].host);
|
||||
snprintf(config,
|
||||
sizeof(config),
|
||||
"Host %s\n\tConnectTimeout %s\n",
|
||||
cases[i].host,
|
||||
cases[i].value);
|
||||
if (file != NULL) {
|
||||
torture_write_file(file, config);
|
||||
}
|
||||
_parse_config(session, file, file != NULL ? NULL : config, SSH_OK);
|
||||
if (cases[i].infinite) {
|
||||
assert_int_equal(session->opts.timeout,
|
||||
(unsigned long)SSH_TIMEOUT_INFINITE);
|
||||
assert_int_equal(session->opts.timeout_usec, 0);
|
||||
} else {
|
||||
assert_int_equal(session->opts.timeout, cases[i].expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void torture_config_timeout_suffix_file(void **state)
|
||||
{
|
||||
torture_config_timeout_suffix(state, LIBSSH_TESTCONFIG_TIMEOUT_SUFFIX);
|
||||
}
|
||||
|
||||
static void torture_config_timeout_suffix_string(void **state)
|
||||
{
|
||||
torture_config_timeout_suffix(state, NULL);
|
||||
}
|
||||
/**
|
||||
* @brief Helper for checking hostname, username and port of ssh_jump_info_struct
|
||||
*/
|
||||
@@ -3716,6 +3780,12 @@ int torture_run_tests(void)
|
||||
cmocka_unit_test_setup_teardown(torture_config_numeric_invalid_string,
|
||||
setup,
|
||||
teardown),
|
||||
cmocka_unit_test_setup_teardown(torture_config_timeout_suffix_file,
|
||||
setup,
|
||||
teardown),
|
||||
cmocka_unit_test_setup_teardown(torture_config_timeout_suffix_string,
|
||||
setup,
|
||||
teardown),
|
||||
cmocka_unit_test_setup_teardown(torture_config_unknown_file,
|
||||
setup,
|
||||
teardown),
|
||||
|
||||
Reference in New Issue
Block a user