diff options
author | Ryo Nakamura <upa@haeena.net> | 2024-04-12 23:08:22 +0900 |
---|---|---|
committer | Ryo Nakamura <upa@haeena.net> | 2024-04-12 23:08:22 +0900 |
commit | a1b9afefe50fbbdf6391e94ab21e6e7645eabe4d (patch) | |
tree | 8f0fa87ac9c014395a60781c9a3af55060d6b70a | |
parent | bf7e2c3ae340464d4de7b4ba105decdbd7c40450 (diff) |
add -o SSH_OPTION option
-rw-r--r-- | doc/mscp.1.in | 14 | ||||
-rw-r--r-- | doc/mscp.rst | 14 | ||||
-rw-r--r-- | include/mscp.h | 1 | ||||
-rw-r--r-- | src/main.c | 21 | ||||
-rw-r--r-- | src/ssh.c | 16 | ||||
-rw-r--r-- | test/test_e2e.py | 38 |
6 files changed, 89 insertions, 15 deletions
diff --git a/doc/mscp.1.in b/doc/mscp.1.in index 182fc84..3513488 100644 --- a/doc/mscp.1.in +++ b/doc/mscp.1.in @@ -47,7 +47,10 @@ mscp \- copy files over multiple SSH connections .BI \-P \ PORT\c ] [\c -.BI \-F \ CONFIG\c +.BI \-F \ SSH_CONFIG\c +] +[\c +.BI \-o \ SSH_OPTION\c ] [\c .BI \-i \ IDENTITY\c @@ -247,13 +250,20 @@ Specifies the port number to connect to on the remote machine as with ssh(1) and scp(1). .TP -.B \-F \fICONFIG\fR +.B \-F \fISSH_CONFIG\fR Specifies an alternative per-user ssh configuration file. Note that acceptable options in the configuration file are what .I libssh supports. .TP +.B \-o \fISSH_OPTION\fR +Specifies ssh options in the format used in ssh_config. Note that +acceptable options are what +.I libssh +supports. + +.TP .B \-i \fIIDENTITY\fR Specifies the identity file for public key authentication. diff --git a/doc/mscp.rst b/doc/mscp.rst index 0585267..27dc325 100644 --- a/doc/mscp.rst +++ b/doc/mscp.rst @@ -2,7 +2,7 @@ MSCP ==== -:Date: v0.1.5-10-g00fa2c7 +:Date: v0.1.5-13-gf2f0dab NAME ==== @@ -17,9 +17,9 @@ SYNOPSIS *CHECKPOINT* ] [ **-R** *CHECKPOINT* ] [ **-s** *MIN_CHUNK_SIZE* ] [ **-S** *MAX_CHUNK_SIZE* ] [ **-a** *NR_AHEAD* ] [ **-b** *BUF_SIZE* ] [ **-L** *LIMIT_BITRATE* ] [ **-l** *LOGIN_NAME* ] [ **-P** *PORT* ] [ -**-F** *CONFIG* ] [ **-i** *IDENTITY* ] [ **-c** *CIPHER* ] [ **-M** -*HMAC* ] [ **-C** *COMPRESS* ] [ **-g** *CONGESTION* ] *source ... -target* +**-F** *SSH_CONFIG* ] [ **-o** *SSH_OPTION* ] [ **-i** *IDENTITY* ] [ +**-c** *CIPHER* ] [ **-M** *HMAC* ] [ **-C** *COMPRESS* ] [ **-g** +*CONGESTION* ] *source ... target* DESCRIPTION =========== @@ -144,11 +144,15 @@ OPTIONS Specifies the port number to connect to on the remote machine as with ssh(1) and scp(1). -**-F CONFIG** +**-F SSH_CONFIG** Specifies an alternative per-user ssh configuration file. Note that acceptable options in the configuration file are what *libssh* supports. +**-o SSH_OPTION** + Specifies ssh options in the format used in ssh_config. Note that + acceptable options are what *libssh* supports. + **-i IDENTITY** Specifies the identity file for public key authentication. diff --git a/include/mscp.h b/include/mscp.h index c16a332..fa8af65 100644 --- a/include/mscp.h +++ b/include/mscp.h @@ -61,6 +61,7 @@ struct mscp_ssh_opts { char *port; /** ssh port */ int ai_family; /** address family */ char *config; /** path to ssh_config, default ~/.ssh/config*/ + char **options; /** array of ssh_config options, terminated by NULL */ char *identity; /** path to private key */ char *cipher; /** cipher spec */ char *hmac; /** hmacp spec */ @@ -28,8 +28,9 @@ void usage(bool print_help) " [-u max_startups] [-I interval] [-W checkpoint] [-R checkpoint]\n" " [-s min_chunk_sz] [-S max_chunk_sz] [-a nr_ahead]\n" " [-b buf_sz] [-L limit_bitrate]\n" - " [-l login_name] [-P port] [-F ssh_config] [-i identity_file]\n" - " [-c cipher_spec] [-M hmac_spec] [-C compress] [-g congestion]\n" + " [-l login_name] [-P port] [-F ssh_config] [-o ssh_option]\n" + " [-i identity_file] [-c cipher_spec] [-M hmac_spec]\n" + " [-C compress] [-g congestion]\n" " source ... target\n" "\n"); @@ -60,7 +61,8 @@ void usage(bool print_help) "\n" " -l LOGIN_NAME login name\n" " -P PORT port number\n" - " -F CONFIG path to user ssh config (default ~/.ssh/config)\n" + " -F SSH_CONFIG path to user ssh config (default ~/.ssh/config)\n" + " -o SSH_OPTION ssh_config option\n" " -i IDENTITY identity file for public key authentication\n" " -c CIPHER cipher spec\n" " -M HMAC hmac spec\n" @@ -267,6 +269,7 @@ int main(int argc, char **argv) int direction = 0; char *remote = NULL, *checkpoint_save = NULL, *checkpoint_load = NULL; bool dryrun = false, resume = false; + int nr_options = 0; size_t factor = 1; char *unit; @@ -274,7 +277,7 @@ int main(int argc, char **argv) memset(&o, 0, sizeof(o)); o.severity = MSCP_SEVERITY_WARN; -#define mscpopts "n:m:u:I:W:R:s:S:a:b:L:46vqDrl:P:i:F:c:M:C:g:pdNh" +#define mscpopts "n:m:u:I:W:R:s:S:a:b:L:46vqDrl:P:i:F:o:c:M:C:g:pdNh" while ((ch = getopt(argc, argv, mscpopts)) != -1) { switch (ch) { case 'n': @@ -359,6 +362,16 @@ int main(int argc, char **argv) case 'F': s.config = optarg; break; + case 'o': + nr_options++; + s.options = realloc(s.options, sizeof(char *) * (nr_options + 1)); + if (!s.options) { + pr_err("realloc: %s", strerrno()); + return 1; + } + s.options[nr_options - 1] = optarg; + s.options[nr_options] = NULL; + break; case 'i': s.identity = optarg; break; @@ -4,12 +4,13 @@ #include <unistd.h> #include <stdlib.h> -#include "libssh/callbacks.h" - #include <ssh.h> #include <mscp.h> #include <strerrno.h> +#include "libssh/callbacks.h" +#include "libssh/options.h" + static int ssh_verify_known_hosts(ssh_session session); static int ssh_authenticate_kbdint(ssh_session session); @@ -87,6 +88,17 @@ static int ssh_set_opts(ssh_session ssh, struct mscp_ssh_opts *opts) return -1; } + if (opts->options) { + int n; + for (n = 0; opts->options[n]; n++) { + if (ssh_config_parse_string(ssh, opts->options[n]) != SSH_OK) { + priv_set_errv("failed to set ssh option %s: %s", + opts->options[n]); + return -1; + } + } + } + return 0; } diff --git a/test/test_e2e.py b/test/test_e2e.py index 9e0b313..b6ac1dc 100644 --- a/test/test_e2e.py +++ b/test/test_e2e.py @@ -496,6 +496,40 @@ def test_config_ng(mscp, src_prefix, dst_prefix): src.cleanup() dst.cleanup() + +param_valid_option_ok = [ + [ "-o", "Port=8022" ], + [ "-o", "Port=8022", "-o", "User=root" ], + [ "-o", "unknown-option-is-silently-ignored" ], +] +@pytest.mark.parametrize("src_prefix, dst_prefix", param_remote_prefix) +@pytest.mark.parametrize("option", param_valid_option_ok) +def test_inline_option_ok(mscp, src_prefix, dst_prefix, option): + """ change port number with -o option. it should be ok. """ + src = File("src", size = 1024 * 1024).make() + dst = File("dst") + run2ok([mscp, "-vvv"] + option + + [src_prefix + src.path, dst_prefix + dst.path]) + assert check_same_md5sum(src, dst) + src.cleanup() + dst.cleanup() + + +param_valid_option_ng = [ + [ "-o", "Port=8023" ], + [ "-o", "User=invaliduser" ], +] +@pytest.mark.parametrize("src_prefix, dst_prefix", param_remote_prefix) +@pytest.mark.parametrize("option", param_valid_option_ng) +def test_inline_option_ng(mscp, src_prefix, dst_prefix, option): + """ change port number with -o option. it should be ng. """ + src = File("src", size = 1024 * 1024).make() + dst = File("dst") + run2ng([mscp, "-vvv"] + option + + [src_prefix + src.path, dst_prefix + dst.path]) + src.cleanup() + + # username test assumes that this test runs inside a container, see Dockerfiles def test_specify_passphrase_via_env(mscp): src = File(os.getcwd() + "/src", size = 1024).make() @@ -552,8 +586,8 @@ def test_10k_files(mscp, src_prefix, dst_prefix): @pytest.mark.parametrize("src_prefix, dst_prefix", param_remote_prefix) def test_checkpoint_dump_and_resume(mscp, src_prefix, dst_prefix): - src1 = File("src1", size = 512 * 1024 * 1024).make() - src2 = File("src2", size = 512 * 1024 * 1024).make() + src1 = File("src1", size = 64 * 1024 * 1024).make() + src2 = File("src2", size = 64 * 1024 * 1024).make() dst1 = File("dst/src1") dst2 = File("dst/src2") run2ok([mscp, "-vvv", "-W", "checkpoint", "-D", |