diff options
author | Hans Nilsson <hans@erlang.org> | 2019-09-02 15:13:41 +0200 |
---|---|---|
committer | Hans Nilsson <hans@erlang.org> | 2019-09-20 10:31:47 +0200 |
commit | 6169211c12a48c31eadba4473940a28aa675c944 (patch) | |
tree | 1192300ea8b2edb6b428400e0d3959f15af78b99 | |
parent | 604499b2b752fe0c09c06dc2e7d10e767f4d5456 (diff) | |
download | erlang-6169211c12a48c31eadba4473940a28aa675c944.tar.gz |
ssh: direct-tcpip, client part
-rw-r--r-- | lib/ssh/doc/src/ssh.xml | 21 | ||||
-rw-r--r-- | lib/ssh/src/ssh.erl | 56 | ||||
-rw-r--r-- | lib/ssh/src/ssh_connection.erl | 2 | ||||
-rw-r--r-- | lib/ssh/src/ssh_connection_handler.erl | 20 | ||||
-rw-r--r-- | lib/ssh/src/ssh_tcpip_forward_acceptor.erl | 3 |
5 files changed, 100 insertions, 2 deletions
diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml index b38ab2ce5f..bb8893f4a7 100644 --- a/lib/ssh/doc/src/ssh.xml +++ b/lib/ssh/doc/src/ssh.xml @@ -1323,6 +1323,27 @@ </p> </desc> </func> + + <func> + <name name="tcpip_tunnel_to_server" arity="5" since=""/> + <name name="tcpip_tunnel_to_server" arity="6" since=""/> + <fsummary>TCP/IP tunneling from a client to a server ("direct-tcpip")</fsummary> + <desc> + <p>Tells the local client to listen to <c>ListenHost:ListenPort</c>. When someone + connects to that address, the connection is forwarded in an encrypted channel to the peer server + of <c>ConnectionRef</c>. That server then connects to <c>ConnectToHost:ConnectToPort</c>. + </p> + <p>The returned <c>TrueListenPort</c> is the port that is listened to. It is the same as + <c>ListenPort</c>, except when <c>ListenPort = 0</c>. In that case a free port is selected + by the underlying OS. + </p> + <p>Note that in case of an Erlang/OTP SSH server (daemon) as peer, that server must have been + started with the option + <seealso marker="#type-tcpip_tunnel_in_daemon_option">tcpip_tunnel_in</seealso> + to allow the connection. + </p> + </desc> + </func> </funcs> diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl index 1471654a89..dc50c9cd6c 100644 --- a/lib/ssh/src/ssh.erl +++ b/lib/ssh/src/ssh.erl @@ -40,7 +40,8 @@ stop_listener/1, stop_listener/2, stop_listener/3, stop_daemon/1, stop_daemon/2, stop_daemon/3, shell/1, shell/2, shell/3, - tcpip_tunnel_from_server/5, tcpip_tunnel_from_server/6 + tcpip_tunnel_from_server/5, tcpip_tunnel_from_server/6, + tcpip_tunnel_to_server/5, tcpip_tunnel_to_server/6 ]). %%% "Deprecated" types export: @@ -566,6 +567,59 @@ chk_algos_opts(Opts) -> end. %%-------------------------------------------------------------------- +%% Ask local client to listen to ListenHost:ListenPort. When someone +%% connects that address, connect to ConnectToHost:ConnectToPort from +%% the server. +%%-------------------------------------------------------------------- +-spec tcpip_tunnel_to_server(ConnectionRef, + ListenHost, ListenPort, + ConnectToHost, ConnectToPort + ) -> + {ok,TrueListenPort} | {error, term()} when + ConnectionRef :: connection_ref(), + ListenHost :: host(), + ListenPort :: inet:port_number(), + ConnectToHost :: host(), + ConnectToPort :: inet:port_number(), + TrueListenPort :: inet:port_number(). + +tcpip_tunnel_to_server(ConnectionHandler, ListenHost, ListenPort, ConnectToHost, ConnectToPort) -> + tcpip_tunnel_to_server(ConnectionHandler, ListenHost, ListenPort, ConnectToHost, ConnectToPort, infinity). + + +-spec tcpip_tunnel_to_server(ConnectionRef, + ListenHost, ListenPort, + ConnectToHost, ConnectToPort, + Timeout) -> + {ok,TrueListenPort} | {error, term()} when + ConnectionRef :: connection_ref(), + ListenHost :: host(), + ListenPort :: inet:port_number(), + ConnectToHost :: host(), + ConnectToPort :: inet:port_number(), + Timeout :: timeout(), + TrueListenPort :: inet:port_number(). + +tcpip_tunnel_to_server(ConnectionHandler, ListenHost, ListenPort, ConnectToHost0, ConnectToPort, Timeout) -> + SockOpts = [], + try + list_to_binary( + case mangle_connect_address(ConnectToHost0,SockOpts) of + IP when is_tuple(IP) -> inet_parse:ntoa(IP); + _ when is_list(ConnectToHost0) -> ConnectToHost0 + end) + of + ConnectToHost -> + ssh_connection_handler:handle_direct_tcpip(ConnectionHandler, + mangle_tunnel_address(ListenHost), ListenPort, + ConnectToHost, ConnectToPort, + Timeout) + catch + _:_ -> + {error, bad_connect_to_address} + end. + +%%-------------------------------------------------------------------- %% Ask remote server to listen to ListenHost:ListenPort. When someone %% connects that address, connect to ConnectToHost:ConnectToPort from %% the client. diff --git a/lib/ssh/src/ssh_connection.erl b/lib/ssh/src/ssh_connection.erl index 1c22b095e8..3fb4222d53 100644 --- a/lib/ssh/src/ssh_connection.erl +++ b/lib/ssh/src/ssh_connection.erl @@ -685,7 +685,7 @@ handle_msg(#ssh_msg_channel_open{channel_type = "direct-tcpip", send_buf = queue:new() }), gen_tcp:controlling_process(Sock, Pid), - ssh_tcpip_forward_srv:use_socket(Pid, Sock), + inet:setopts(Sock, [{active,once}]), {channel_open_confirmation_msg(RemoteId, ChId, ?DEFAULT_WINDOW_SIZE, diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl index bae27da330..3ed42aff8d 100644 --- a/lib/ssh/src/ssh_connection_handler.erl +++ b/lib/ssh/src/ssh_connection_handler.erl @@ -49,6 +49,7 @@ available_hkey_algorithms/2, open_channel/6, start_channel/5, + handle_direct_tcpip/6, request/6, request/7, reply_request/3, global_request/5, @@ -207,6 +208,10 @@ start_channel(ConnectionHandler, CallbackModule, ChannelId, Args, Exec) -> Args, Exec, Opts). %%-------------------------------------------------------------------- +handle_direct_tcpip(ConnectionHandler, ListenHost, ListenPort, ConnectToHost, ConnectToPort, Timeout) -> + call(ConnectionHandler, {handle_direct_tcpip, ListenHost, ListenPort, ConnectToHost, ConnectToPort, Timeout}). + +%%-------------------------------------------------------------------- -spec request(connection_ref(), pid(), channel_id(), @@ -1583,6 +1588,21 @@ handle_event(info, {fwd_connect_received, Sock, ChId, ChanCB}, StateName, #data{ inet:setopts(Sock, [{active,once}]), keep_state_and_data; +handle_event({call,From}, + {handle_direct_tcpip, ListenHost, ListenPort, ConnectToHost, ConnectToPort, _Timeout}, + _StateName, + #data{connection_state = #connection{sub_system_supervisor=SubSysSup}}) -> + case ssh_tcpip_forward_acceptor:supervised_start(ssh_subsystem_sup:tcpip_fwd_supervisor(SubSysSup), + {ListenHost, ListenPort}, + {ConnectToHost, ConnectToPort}, + "direct-tcpip", ssh_tcpip_forward_client, + self()) of + {ok,LPort} -> + {keep_state_and_data, [{reply,From,{ok,LPort}}]}; + {error,Error} -> + {keep_state_and_data, [{reply,From,{error,Error}}]} + end; + handle_event(info, UnexpectedMessage, StateName, D = #data{ssh_params = Ssh}) -> case unexpected_fun(UnexpectedMessage, D) of report -> diff --git a/lib/ssh/src/ssh_tcpip_forward_acceptor.erl b/lib/ssh/src/ssh_tcpip_forward_acceptor.erl index 60a0a7a0e1..6f2fda2bf9 100644 --- a/lib/ssh/src/ssh_tcpip_forward_acceptor.erl +++ b/lib/ssh/src/ssh_tcpip_forward_acceptor.erl @@ -79,6 +79,9 @@ acceptor_loop(LSock, ListenAddrStr, ListenPort, ConnectToAddr, ChanType, ChanCB, case ConnectToAddr of undefined -> <<?STRING(ListenAddrStr), ?UINT32(ListenPort), + ?STRING(RemHostBin), ?UINT32(RemPort)>>; + {ConnectToHost, ConnectToPort} -> + <<?STRING(ConnectToHost), ?UINT32(ConnectToPort), ?STRING(RemHostBin), ?UINT32(RemPort)>> end, case ssh_connection:open_channel(ConnPid, ChanType, Data, infinity) of |