summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyo Nakamura <upa@haeena.net>2024-04-14 15:49:27 +0900
committerRyo Nakamura <upa@haeena.net>2024-04-14 16:22:31 +0900
commit4ce62079cf1254553cd34e5d3b315e1548bfa191 (patch)
treefcf4188cbfa79402c933f37db9bd218fc3d235b8
parente47d5b76e6cfcd649960019ca8c58d7c5d5a5930 (diff)
add -J proxyjump option (#15)
-rw-r--r--doc/mscp.1.in16
-rw-r--r--doc/mscp.rst11
-rw-r--r--include/mscp.h1
-rwxr-xr-xscripts/test-in-container.sh3
-rw-r--r--src/main.c12
-rw-r--r--src/ssh.c10
-rw-r--r--test/test_e2e.py25
7 files changed, 71 insertions, 7 deletions
diff --git a/doc/mscp.1.in b/doc/mscp.1.in
index 4d3184e..c180a13 100644
--- a/doc/mscp.1.in
+++ b/doc/mscp.1.in
@@ -56,6 +56,9 @@ mscp \- copy files over multiple SSH connections
.BI \-i \ IDENTITY\c
]
[\c
+.BI \-J \ DESTINATION\c
+]
+[\c
.BI \-c \ CIPHER\c
]
[\c
@@ -271,6 +274,19 @@ supports.
Specifies the identity file for public key authentication.
.TP
+.B \-J \fIDESTINATION\fR
+A shortcut to define a
+.B ProxyJump
+configuration directive. Each SFTP session of
+.B mscp
+connects to the target host by first making an
+.B ssh
+connection to the jump host described by
+.I destination.
+
+
+
+.TP
.B \-c \fICIPHER\fR
Selects the cipher to use for encrypting the data transfer. See
.UR https://\:www\:.libssh\:.org/\:features/
diff --git a/doc/mscp.rst b/doc/mscp.rst
index 9935d21..213e9c5 100644
--- a/doc/mscp.rst
+++ b/doc/mscp.rst
@@ -2,7 +2,7 @@
MSCP
====
-:Date: v0.1.5-16-ga1ba6f1
+:Date: v0.1.5-18-ge47d5b7
NAME
====
@@ -18,8 +18,8 @@ SYNOPSIS
**-S** *MAX_CHUNK_SIZE* ] [ **-a** *NR_AHEAD* ] [ **-b** *BUF_SIZE* ] [
**-L** *LIMIT_BITRATE* ] [ **-l** *LOGIN_NAME* ] [ **-P** *PORT* ] [
**-F** *SSH_CONFIG* ] [ **-o** *SSH_OPTION* ] [ **-i** *IDENTITY* ] [
-**-c** *CIPHER* ] [ **-M** *HMAC* ] [ **-C** *COMPRESS* ] [ **-g**
-*CONGESTION* ] *source ... target*
+**-J** *DESTINATION* ] [ **-c** *CIPHER* ] [ **-M** *HMAC* ] [ **-C**
+*COMPRESS* ] [ **-g** *CONGESTION* ] *source ... target*
DESCRIPTION
===========
@@ -159,6 +159,11 @@ OPTIONS
**-i IDENTITY**
Specifies the identity file for public key authentication.
+**-J DESTINATION**
+ A shortcut to define a **ProxyJump** configuration directive. Each
+ SFTP session of **mscp** connects to the target host by first making
+ an **ssh** connection to the jump host described by *destination.*
+
**-c CIPHER**
Selects the cipher to use for encrypting the data transfer. See
`libssh features <https://www.libssh.org/features/>`__.
diff --git a/include/mscp.h b/include/mscp.h
index fa8af65..8519f23 100644
--- a/include/mscp.h
+++ b/include/mscp.h
@@ -63,6 +63,7 @@ struct mscp_ssh_opts {
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 *proxyjump; /** ProxyJump configuration directive (shortcut) */
char *cipher; /** cipher spec */
char *hmac; /** hmacp spec */
char *compress; /** yes, no, zlib@openssh.com */
diff --git a/scripts/test-in-container.sh b/scripts/test-in-container.sh
index 21a9969..e4e10fc 100755
--- a/scripts/test-in-container.sh
+++ b/scripts/test-in-container.sh
@@ -12,6 +12,9 @@ set -x
echo "Port 22" >> /etc/ssh/sshd_config
echo "Port 8022" >> /etc/ssh/sshd_config
+## Alpine default sshd disables TcpForwarding, which is required for proxyjump test
+sed -i -e 's/AllowTcpForwarding no/AllowTcpForwarding yes/' /etc/ssh/sshd_config
+
# Run sshd
if [ ! -e /var/run/sshd.pid ]; then
/usr/sbin/sshd
diff --git a/src/main.c b/src/main.c
index ae163e5..de53e30 100644
--- a/src/main.c
+++ b/src/main.c
@@ -24,12 +24,12 @@ void usage(bool print_help)
{
printf("mscp " MSCP_BUILD_VERSION ": copy files over multiple SSH connections\n"
"\n"
- "Usage: mscp [-46vqDpdNh] [-n nr_conns] [-m coremask]\n"
- " [-u max_startups] [-I interval] [-W checkpoint] [-R checkpoint]\n"
+ "Usage: mscp [-46vqDpdNh] [-n nr_conns] [-m coremask] [-u max_startups]\n"
+ " [-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] [-o ssh_option]\n"
- " [-i identity_file] [-c cipher_spec] [-M hmac_spec]\n"
+ " [-i identity_file] [-J destination] [-c cipher_spec] [-M hmac_spec]\n"
" [-C compress] [-g congestion]\n"
" source ... target\n"
"\n");
@@ -64,6 +64,7 @@ void usage(bool print_help)
" -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"
+ " -J DESTINATION ProxyJump destination\n"
" -c CIPHER cipher spec\n"
" -M HMAC hmac spec\n"
" -C COMPRESS enable compression: "
@@ -277,7 +278,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:o:c:M:C:g:pdNh"
+#define mscpopts "n:m:u:I:W:R:s:S:a:b:L:46vqDrl:P:F:o:i:J:c:M:C:g:pdNh"
while ((ch = getopt(argc, argv, mscpopts)) != -1) {
switch (ch) {
case 'n':
@@ -375,6 +376,9 @@ int main(int argc, char **argv)
case 'i':
s.identity = optarg;
break;
+ case 'J':
+ s.proxyjump = optarg;
+ break;
case 'c':
s.cipher = optarg;
break;
diff --git a/src/ssh.c b/src/ssh.c
index 7c9e94e..d647c4b 100644
--- a/src/ssh.c
+++ b/src/ssh.c
@@ -88,6 +88,16 @@ static int ssh_set_opts(ssh_session ssh, struct mscp_ssh_opts *opts)
return -1;
}
+ if (opts->proxyjump) {
+ char buf[256];
+ memset(buf, 0, sizeof(buf));
+ snprintf(buf, sizeof(buf), "proxyjump=%s", opts->proxyjump);
+ if (ssh_config_parse_string(ssh, buf) != SSH_OK) {
+ priv_set_errv("failed to set ssh option: %s", buf);
+ return -1;
+ }
+ }
+
if (opts->options) {
int n;
for (n = 0; opts->options[n]; n++) {
diff --git a/test/test_e2e.py b/test/test_e2e.py
index b6ac1dc..9b1bc4a 100644
--- a/test/test_e2e.py
+++ b/test/test_e2e.py
@@ -530,6 +530,31 @@ def test_inline_option_ng(mscp, src_prefix, dst_prefix, option):
src.cleanup()
+@pytest.mark.parametrize("src_prefix, dst_prefix", param_remote_prefix)
+def test_porxyjump_ok(mscp, src_prefix, dst_prefix):
+ """ test -J proxyjump option"""
+ src = File("src", size = 10 * 1024 * 1024).make()
+ dst = File("dst")
+ # use small min-chunk-size to use multiple connections
+ run2ok([mscp, "-n", 4, "-s", 1024 * 1024, "-vvv",
+ "-J", "localhost:8022",
+ src_prefix + src.path, dst_prefix + dst.path])
+ assert check_same_md5sum(src, dst)
+ src.cleanup()
+ dst.cleanup()
+
+
+@pytest.mark.parametrize("src_prefix, dst_prefix", param_remote_prefix)
+def test_porxyjump_ng(mscp, src_prefix, dst_prefix):
+ """ test -J proxyjump option, invalid jump node causes fail"""
+ src = File("src", size = 10 * 1024 * 1024).make()
+ dst = File("dst")
+ # use small min-chunk-size to use multiple connections
+ run2ng([mscp, "-n", 4, "-s", 1024 * 1024, "-vvv",
+ "-J", "invaliduser@localhost:8022",
+ 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()