summaryrefslogtreecommitdiff
path: root/lib/ssh/src/ssh_tcpip_forward_acceptor.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ssh/src/ssh_tcpip_forward_acceptor.erl')
-rw-r--r--lib/ssh/src/ssh_tcpip_forward_acceptor.erl113
1 files changed, 113 insertions, 0 deletions
diff --git a/lib/ssh/src/ssh_tcpip_forward_acceptor.erl b/lib/ssh/src/ssh_tcpip_forward_acceptor.erl
new file mode 100644
index 0000000000..60a0a7a0e1
--- /dev/null
+++ b/lib/ssh/src/ssh_tcpip_forward_acceptor.erl
@@ -0,0 +1,113 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: The supervisor for tcpip-forwarding acceptor
+%%----------------------------------------------------------------------
+
+-module(ssh_tcpip_forward_acceptor).
+
+-export([supervised_start/6,
+ start_link/6]).
+
+-include("ssh.hrl").
+
+%%%----------------------------------------------------------------
+supervised_start(FwdSup, {ListenAddrStr, ListenPort}, ConnectToAddr, ChanType, ChanCB, ConnPid) ->
+ case get_fwd_listen_opts(ListenAddrStr) of
+ {ok,Opts} ->
+ %% start listening on Addr:BoundPort
+ case gen_tcp:listen(ListenPort, [binary,
+ {reuseaddr,true},
+ {active,false} | Opts]) of
+ {ok,LSock} ->
+ {ok,{_, TrueListenPort}} = inet:sockname(LSock),
+ ssh_tcpip_forward_acceptor_sup:start_child(FwdSup,
+ LSock,
+ {ListenAddrStr,TrueListenPort},
+ ConnectToAddr,
+ ChanType,
+ ChanCB,
+ ConnPid),
+ {ok, TrueListenPort};
+
+ {error,Error} ->
+ {error,Error}
+ end;
+
+ {error,Error} ->
+ {error,Error}
+ end.
+
+
+%%%----------------------------------------------------------------
+start_link(LSock, {ListenAddrStr,ListenPort}, ConnectToAddr, ChanType, ChanCB, ConnPid) ->
+ Pid = proc_lib:spawn_link(
+ fun() ->
+ acceptor_loop(LSock, ListenAddrStr, ListenPort, ConnectToAddr, ChanType, ChanCB, ConnPid)
+ end),
+ {ok, Pid}.
+
+%%%================================================================
+%%%
+%%% Internal
+%%%
+acceptor_loop(LSock, ListenAddrStr, ListenPort, ConnectToAddr, ChanType, ChanCB, ConnPid) ->
+ case gen_tcp:accept(LSock) of
+ {ok, Sock} ->
+ {ok, {RemHost,RemPort}} = inet:peername(Sock),
+ RemHostBin = list_to_binary(encode_ip(RemHost)),
+ Data =
+ case ConnectToAddr of
+ undefined ->
+ <<?STRING(ListenAddrStr), ?UINT32(ListenPort),
+ ?STRING(RemHostBin), ?UINT32(RemPort)>>
+ end,
+ case ssh_connection:open_channel(ConnPid, ChanType, Data, infinity) of
+ {ok,ChId} ->
+ gen_tcp:controlling_process(Sock, ConnPid),
+ ConnPid ! {fwd_connect_received, Sock, ChId, ChanCB};
+ _ ->
+ gen_tcp:close(Sock)
+ end,
+ acceptor_loop(LSock, ListenAddrStr, ListenPort, ConnectToAddr, ChanType, ChanCB, ConnPid);
+
+ {error,closed} ->
+ ok
+ end.
+
+%%%----------------------------------------------------------------
+get_fwd_listen_opts(<<"">> ) -> {ok, []};
+get_fwd_listen_opts(<<"0.0.0.0">> ) -> {ok, [inet]};
+get_fwd_listen_opts(<<"::">> ) -> {ok, [inet6]};
+get_fwd_listen_opts(<<"localhost">>) -> {ok, [{ip,loopback}]};
+get_fwd_listen_opts(AddrStr) ->
+ case inet:getaddr(binary_to_list(AddrStr), inet) of
+ {ok, Addr} -> {ok, [{ip,Addr}]};
+ {error,Error} -> {error,Error}
+ end.
+
+%%%----------------------------------------------------------------
+encode_ip(Addr) when is_tuple(Addr) ->
+ case catch inet_parse:ntoa(Addr) of
+ {'EXIT',_} -> false;
+ A -> A
+ end.