1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2008-2018. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19%% 20 21%% 22%%---------------------------------------------------------------------- 23%% Purpose: The supervisor for tcpip-forwarding acceptor 24%%---------------------------------------------------------------------- 25 26-module(ssh_tcpip_forward_acceptor). 27 28-export([supervised_start/6, 29 start_link/6]). 30 31-include("ssh.hrl"). 32 33%%%---------------------------------------------------------------- 34supervised_start(FwdSup, {ListenAddrStr, ListenPort}, ConnectToAddr, ChanType, ChanCB, ConnPid) -> 35 case get_fwd_listen_opts(ListenAddrStr) of 36 {ok,Opts} -> 37 %% start listening on Addr:BoundPort 38 case gen_tcp:listen(ListenPort, [binary, 39 {reuseaddr,true}, 40 {active,false} | Opts]) of 41 {ok,LSock} -> 42 {ok,{_, TrueListenPort}} = inet:sockname(LSock), 43 ssh_tcpip_forward_acceptor_sup:start_child(FwdSup, 44 LSock, 45 {ListenAddrStr,TrueListenPort}, 46 ConnectToAddr, 47 ChanType, 48 ChanCB, 49 ConnPid), 50 {ok, TrueListenPort}; 51 52 {error,Error} -> 53 {error,Error} 54 end; 55 56 {error,Error} -> 57 {error,Error} 58 end. 59 60 61%%%---------------------------------------------------------------- 62start_link(LSock, {ListenAddrStr,ListenPort}, ConnectToAddr, ChanType, ChanCB, ConnPid) -> 63 Pid = proc_lib:spawn_link( 64 fun() -> 65 acceptor_loop(LSock, ListenAddrStr, ListenPort, ConnectToAddr, ChanType, ChanCB, ConnPid) 66 end), 67 {ok, Pid}. 68 69%%%================================================================ 70%%% 71%%% Internal 72%%% 73acceptor_loop(LSock, ListenAddrStr, ListenPort, ConnectToAddr, ChanType, ChanCB, ConnPid) -> 74 case gen_tcp:accept(LSock) of 75 {ok, Sock} -> 76 {ok, {RemHost,RemPort}} = inet:peername(Sock), 77 RemHostBin = list_to_binary(encode_ip(RemHost)), 78 Data = 79 case ConnectToAddr of 80 undefined -> 81 <<?STRING(ListenAddrStr), ?UINT32(ListenPort), 82 ?STRING(RemHostBin), ?UINT32(RemPort)>>; 83 {ConnectToHost, ConnectToPort} -> 84 <<?STRING(ConnectToHost), ?UINT32(ConnectToPort), 85 ?STRING(RemHostBin), ?UINT32(RemPort)>> 86 end, 87 case ssh_connection:open_channel(ConnPid, ChanType, Data, infinity) of 88 {ok,ChId} -> 89 gen_tcp:controlling_process(Sock, ConnPid), 90 ConnPid ! {fwd_connect_received, Sock, ChId, ChanCB}; 91 _ -> 92 gen_tcp:close(Sock) 93 end, 94 acceptor_loop(LSock, ListenAddrStr, ListenPort, ConnectToAddr, ChanType, ChanCB, ConnPid); 95 96 {error,closed} -> 97 ok 98 end. 99 100%%%---------------------------------------------------------------- 101get_fwd_listen_opts(<<"">> ) -> {ok, []}; 102get_fwd_listen_opts(<<"0.0.0.0">> ) -> {ok, [inet]}; 103get_fwd_listen_opts(<<"::">> ) -> {ok, [inet6]}; 104get_fwd_listen_opts(<<"localhost">>) -> {ok, [{ip,loopback}]}; 105get_fwd_listen_opts(AddrStr) -> 106 case inet:getaddr(binary_to_list(AddrStr), inet) of 107 {ok, Addr} -> {ok, [{ip,Addr}]}; 108 {error,Error} -> {error,Error} 109 end. 110 111%%%---------------------------------------------------------------- 112encode_ip(Addr) when is_tuple(Addr) -> 113 case catch inet_parse:ntoa(Addr) of 114 {'EXIT',_} -> false; 115 A -> A 116 end. 117