diff options
Diffstat (limited to 'lib/ssh/src/ssh_tcpip_forward_acceptor.erl')
-rw-r--r-- | lib/ssh/src/ssh_tcpip_forward_acceptor.erl | 113 |
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. |