From fe706697ed1094aaa7ad41ba5b6f865bab40d5f9 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Mon, 10 Apr 2023 14:23:17 +0200 Subject: [PATCH] Support for direct-streamlocal@openssh.com UNIX socket connection (#945) This patch allow to use direct-streamlocal service from OpenSSH 6.7, that allows UNIX socket connections. Mods: - delete unrelated condition: Ref: https://github.com/libssh2/libssh2/pull/216#discussion_r374748111 - rebase on master, whitespace updates. Patch-by: @gjalves Gustavo Junior Alves Closes #216 Closes #632 Closes #945 --- docs/Makefile.am | 1 + docs/libssh2_channel_direct_streamlocal_ex.3 | 33 ++++++++ include/libssh2.h | 5 ++ src/channel.c | 79 ++++++++++++++++++++ 4 files changed, 118 insertions(+) create mode 100644 docs/libssh2_channel_direct_streamlocal_ex.3 diff --git a/docs/Makefile.am b/docs/Makefile.am index b2f2e5c9..1e41bac2 100644 --- a/docs/Makefile.am +++ b/docs/Makefile.am @@ -14,6 +14,7 @@ dist_man_MANS = \ libssh2_banner_set.3 \ libssh2_base64_decode.3 \ libssh2_channel_close.3 \ + libssh2_channel_direct_streamlocal_ex.3 \ libssh2_channel_direct_tcpip.3 \ libssh2_channel_direct_tcpip_ex.3 \ libssh2_channel_eof.3 \ diff --git a/docs/libssh2_channel_direct_streamlocal_ex.3 b/docs/libssh2_channel_direct_streamlocal_ex.3 new file mode 100644 index 00000000..c39b039b --- /dev/null +++ b/docs/libssh2_channel_direct_streamlocal_ex.3 @@ -0,0 +1,33 @@ +.TH libssh2_channel_direct_streamlocal_ex 3 "10 Apr 2023" "libssh2 1.11.0" "libssh2 manual" +.SH NAME +libssh2_channel_direct_streamlocal_ex - Tunnel a UNIX socket connection through an SSH session +.SH SYNOPSIS +#include + +LIBSSH2_CHANNEL * +libssh2_channel_direct_streamlocal_ex(LIBSSH2_SESSION *session, const char *socket_path, const char *shost, int sport); + +LIBSSH2_CHANNEL * +libssh2_channel_direct_streamlocal(LIBSSH2_SESSION *session, const char *socket_path, const char *shost, int sport); + +.SH DESCRIPTION +\fIsession\fP - Session instance as returned by +.BR libssh2_session_init_ex(3) + +\fIsocket_path\fP - UNIX socket to connect to using the SSH host as a proxy. + +\fIshost\fP - Host to tell the SSH server the connection originated on. + +\fIsport\fP - Port to tell the SSH server the connection originated from. + +Tunnel a UNIX socket connection through the SSH transport via the remote host to +a third party. Communication from the client to the SSH server remains +encrypted, communication from the server to the 3rd party host travels +in cleartext. + +.SH RETURN VALUE +Pointer to a newly allocated LIBSSH2_CHANNEL instance, or NULL on errors. +.SH ERRORS +\fILIBSSH2_ERROR_ALLOC\fP - An internal memory allocation call failed. +.SH SEE ALSO +.BR libssh2_session_init_ex(3) diff --git a/include/libssh2.h b/include/libssh2.h index 325631ed..2848192d 100644 --- a/include/libssh2.h +++ b/include/libssh2.h @@ -791,6 +791,11 @@ libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION *session, const char *host, #define libssh2_channel_direct_tcpip(session, host, port) \ libssh2_channel_direct_tcpip_ex((session), (host), (port), "127.0.0.1", 22) +LIBSSH2_API LIBSSH2_CHANNEL * +libssh2_channel_direct_streamlocal_ex(LIBSSH2_SESSION * session, + const char *socket_path, + const char *shost, int sport); + LIBSSH2_API LIBSSH2_LISTENER * libssh2_channel_forward_listen_ex(LIBSSH2_SESSION *session, const char *host, int port, int *bound_port, diff --git a/src/channel.c b/src/channel.c index 832d69db..f1db4d72 100644 --- a/src/channel.c +++ b/src/channel.c @@ -452,6 +452,85 @@ libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION *session, const char *host, return ptr; } +/* + * libssh2_channel_direct_streamlocal_ex + * + * Tunnel TCP/IP connect through the SSH session to direct UNIX socket + */ +static LIBSSH2_CHANNEL * +channel_direct_streamlocal(LIBSSH2_SESSION * session, const char *socket_path, + const char *shost, int sport) +{ + LIBSSH2_CHANNEL *channel; + unsigned char *s; + + if(session->direct_state == libssh2_NB_state_idle) { + session->direct_host_len = strlen(socket_path); + session->direct_shost_len = strlen(shost); + session->direct_message_len = + session->direct_host_len + session->direct_shost_len + 12; + + _libssh2_debug((session, LIBSSH2_TRACE_CONN, + "Requesting direct-streamlocal session to %s", + socket_path)); + + s = session->direct_message = + LIBSSH2_ALLOC(session, session->direct_message_len); + if(!session->direct_message) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for direct-streamlocal connection"); + return NULL; + } + _libssh2_store_str(&s, socket_path, session->direct_host_len); + _libssh2_store_str(&s, shost, session->direct_shost_len); + _libssh2_store_u32(&s, sport); + } + + channel = + _libssh2_channel_open(session, "direct-streamlocal@openssh.com", + sizeof("direct-streamlocal@openssh.com") - 1, + LIBSSH2_CHANNEL_WINDOW_DEFAULT, + LIBSSH2_CHANNEL_PACKET_DEFAULT, + session->direct_message, + session->direct_message_len); + + if(!channel && + libssh2_session_last_errno(session) == LIBSSH2_ERROR_EAGAIN) { + /* The error code is still set to LIBSSH2_ERROR_EAGAIN, set our state + to created to avoid re-creating the package on next invoke */ + session->direct_state = libssh2_NB_state_created; + return NULL; + } + /* by default we set (keep?) idle state... */ + session->direct_state = libssh2_NB_state_idle; + + LIBSSH2_FREE(session, session->direct_message); + session->direct_message = NULL; + + return channel; +} + +/* + * libssh2_channel_direct_streamlocal_ex + * + * Tunnel TCP/IP connect through the SSH session to direct UNIX socket + */ +LIBSSH2_API LIBSSH2_CHANNEL * +libssh2_channel_direct_streamlocal_ex(LIBSSH2_SESSION * session, + const char *socket_path, + const char *shost, int sport) +{ + LIBSSH2_CHANNEL *ptr; + + if(!session) + return NULL; + + BLOCK_ADJUST_ERRNO(ptr, session, + channel_direct_streamlocal(session, + socket_path, shost, sport)); + return ptr; +} + /* * channel_forward_listen *