summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Nilsson <hans@erlang.org>2019-08-14 16:45:47 +0200
committerHans Nilsson <hans@erlang.org>2019-09-20 10:31:47 +0200
commit2837fbeb8f582cabce64123f29c2ef20b8b1e25c (patch)
treee28b4d6edbd7266976c6f7e1812cb5fbd8dfef99
parent6169211c12a48c31eadba4473940a28aa675c944 (diff)
downloaderlang-2837fbeb8f582cabce64123f29c2ef20b8b1e25c.tar.gz
ssh: Basic tests and interop tests
Some servers in some distros are installed with port forwarding disabled. This is testable by trying to use them. Reading config files is not enough.
-rw-r--r--lib/ssh/test/ssh_to_openssh_SUITE.erl235
1 files changed, 232 insertions, 3 deletions
diff --git a/lib/ssh/test/ssh_to_openssh_SUITE.erl b/lib/ssh/test/ssh_to_openssh_SUITE.erl
index 334281f53b..3c5e56131f 100644
--- a/lib/ssh/test/ssh_to_openssh_SUITE.erl
+++ b/lib/ssh/test/ssh_to_openssh_SUITE.erl
@@ -48,10 +48,18 @@ all() ->
end.
groups() ->
- [{erlang_client, [], [erlang_shell_client_openssh_server
+ [{erlang_client, [], [tunnel_in_erlclient_erlserver,
+ tunnel_out_erlclient_erlserver,
+ {group, tunnel_distro_server},
+ erlang_shell_client_openssh_server
]},
- {erlang_server, [], [erlang_server_openssh_client_renegotiate
- ]}
+ {tunnel_distro_server, [], [tunnel_in_erlclient_openssh_server,
+ tunnel_out_erlclient_openssh_server]},
+ {erlang_server, [], [{group, tunnel_distro_client},
+ erlang_server_openssh_client_renegotiate
+ ]},
+ {tunnel_distro_client, [], [tunnel_in_non_erlclient_erlserver,
+ tunnel_out_non_erlclient_erlserver]}
].
init_per_suite(Config) ->
@@ -73,6 +81,14 @@ init_per_group(erlang_server, Config) ->
ssh_test_lib:setup_dsa_known_host(DataDir, UserDir),
ssh_test_lib:setup_rsa_known_host(DataDir, UserDir),
Config;
+init_per_group(G, Config) when G==tunnel_distro_server ;
+ G==tunnel_distro_client ->
+ case no_forwarding() of
+ true ->
+ {skip, "port forwarding disabled in external ssh"};
+ false ->
+ Config
+ end;
init_per_group(erlang_client, Config) ->
CommonAlgs = ssh_test_lib:algo_intersection(
ssh:default_algorithms(),
@@ -177,8 +193,184 @@ erlang_server_openssh_client_renegotiate(Config) ->
end.
%%--------------------------------------------------------------------
+tunnel_out_non_erlclient_erlserver(Config) ->
+ SystemDir = proplists:get_value(data_dir, Config),
+ PrivDir = proplists:get_value(priv_dir, Config),
+ KnownHosts = filename:join(PrivDir, "known_hosts"),
+
+ {_Pid, Host, Port} = ssh_test_lib:daemon([{tcpip_tunnel_out, true},
+ {system_dir, SystemDir},
+ {failfun, fun ssh_test_lib:failfun/2}]),
+ {ToSock, _ToHost, ToPort} = tunneling_listner(),
+
+ ListenHost = {127,0,0,1},
+ ListenPort = 2345,
+
+ Cmd = ssh_test_lib:open_sshc_cmd(Host, Port,
+ [" -o UserKnownHostsFile=", KnownHosts,
+ " -o StrictHostKeyChecking=no",
+ " -R ",integer_to_list(ListenPort),":127.0.0.1:",integer_to_list(ToPort)]),
+ spawn(fun() ->
+ ct:log(["ssh command:\r\n ",Cmd],[]),
+ R = os:cmd(Cmd),
+ ct:log(["ssh returned:\r\n",R],[])
+ end),
+
+ ct:sleep(1000),
+ test_tunneling(ToSock, ListenHost, ListenPort).
+
+%%--------------------------------------------------------------------
+tunnel_in_non_erlclient_erlserver(Config) ->
+ SystemDir = proplists:get_value(data_dir, Config),
+ UserDir = proplists:get_value(priv_dir, Config),
+ KnownHosts = filename:join(UserDir, "known_hosts"),
+ {_Pid, Host, Port} = ssh_test_lib:daemon([{tcpip_tunnel_in, true},
+ {system_dir, SystemDir},
+ {failfun, fun ssh_test_lib:failfun/2}]),
+ {ToSock, _ToHost, ToPort} = tunneling_listner(),
+
+ ListenHost = {127,0,0,1},
+ ListenPort = 2345,
+
+ Cmd =
+ ssh_test_lib:open_sshc_cmd(Host, Port,
+ [" -o UserKnownHostsFile=", KnownHosts,
+ " -o StrictHostKeyChecking=no",
+ " -L ",integer_to_list(ListenPort),":127.0.0.1:",integer_to_list(ToPort)]),
+ spawn(fun() ->
+ ct:log(["ssh command:\r\n ",Cmd],[]),
+ R = os:cmd(Cmd),
+ ct:log(["ssh returned:\r\n",R],[])
+ end),
+ ct:sleep(1000),
+ test_tunneling(ToSock, ListenHost, ListenPort).
+
+%%--------------------------------------------------------------------
+tunnel_in_erlclient_erlserver(Config) ->
+ SystemDir = proplists:get_value(data_dir, Config),
+ UserDir = proplists:get_value(priv_dir, Config),
+ {_Pid, Host, Port} = ssh_test_lib:daemon([{tcpip_tunnel_in, true},
+ {system_dir, SystemDir},
+ {user_dir, UserDir},
+ {user_passwords, [{"foo", "bar"}]},
+ {failfun, fun ssh_test_lib:failfun/2}]),
+ C = ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
+ {user_dir, UserDir},
+ {user,"foo"},{password,"bar"},
+ {user_interaction, false}]),
+ {ToSock, ToHost, ToPort} = tunneling_listner(),
+
+ ListenHost = {127,0,0,1},
+ {ok,ListenPort} = ssh:tcpip_tunnel_to_server(C, ListenHost,0, ToHost,ToPort, 2000),
+
+ test_tunneling(ToSock, ListenHost, ListenPort).
+
+%%--------------------------------------------------------------------
+tunnel_in_erlclient_openssh_server(_Config) ->
+ C = ssh_test_lib:connect(loopback, 22, [{silently_accept_hosts, true},
+ {user_interaction, false}]),
+ {ToSock, ToHost, ToPort} = tunneling_listner(),
+
+ ListenHost = {127,0,0,1},
+ {ok,ListenPort} = ssh:tcpip_tunnel_to_server(C, ListenHost,0, ToHost,ToPort, 5000),
+
+ test_tunneling(ToSock, ListenHost, ListenPort).
+
+%%--------------------------------------------------------------------
+tunnel_out_erlclient_erlserver(Config) ->
+ SystemDir = proplists:get_value(data_dir, Config),
+ UserDir = proplists:get_value(priv_dir, Config),
+ {_Pid, Host, Port} = ssh_test_lib:daemon([{tcpip_tunnel_out, true},
+ {system_dir, SystemDir},
+ {user_dir, UserDir},
+ {user_passwords, [{"foo", "bar"}]},
+ {failfun, fun ssh_test_lib:failfun/2}]),
+ C = ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
+ {user_dir, UserDir},
+ {user,"foo"},{password,"bar"},
+ {user_interaction, false}]),
+ {ToSock, ToHost, ToPort} = tunneling_listner(),
+
+ ListenHost = {127,0,0,1},
+ {ok,ListenPort} = ssh:tcpip_tunnel_from_server(C, ListenHost,0, ToHost,ToPort, 5000),
+
+ test_tunneling(ToSock, ListenHost, ListenPort).
+
+%%--------------------------------------------------------------------
+tunnel_out_erlclient_openssh_server(_Config) ->
+ C = ssh_test_lib:connect(loopback, 22, [{silently_accept_hosts, true},
+ {user_interaction, false}]),
+ {ToSock, ToHost, ToPort} = tunneling_listner(),
+
+ ListenHost = {127,0,0,1},
+ {ok,ListenPort} = ssh:tcpip_tunnel_from_server(C, ListenHost,0, ToHost,ToPort, 5000),
+
+ test_tunneling(ToSock, ListenHost, ListenPort).
+
+%%--------------------------------------------------------------------
%%% Internal functions -----------------------------------------------
%%--------------------------------------------------------------------
+tunneling_listner() ->
+ {ok,LSock} = gen_tcp:listen(0, [{active,false}]),
+ {ok, {LHost,LPort}} = inet:sockname(LSock),
+ {LSock, LHost, LPort}.
+
+test_tunneling(ListenSocket, Host, Port) ->
+ {ok,Client1} = gen_tcp:connect(Host, Port, [{active,false}]),
+ {ok,Server1} = gen_tcp:accept(ListenSocket),
+ {ok,Client2} = gen_tcp:connect(Host, Port, [{active,false}]),
+ {ok,Server2} = gen_tcp:accept(ListenSocket),
+ send_rcv("Hi!", Client1, Server1),
+ send_rcv("Happy to see you!", Server1, Client1),
+ send_rcv("Hi, you to!", Client2, Server2),
+ send_rcv("Happy to see you also!", Server2, Client2),
+ close_and_check(Client1, Server1),
+ send_rcv("Still there?", Client2, Server2),
+ send_rcv("Yes!", Server2, Client2),
+ close_and_check(Server2, Client2).
+
+
+tcp_connect(Host, Port, Options) ->
+ tcp_connect(Host, Port, Options, 0).
+tcp_connect(Host, Port, Options, Timeout) ->
+ ct:log("Try connect to ~p:~p ~p Timeout=~p", [Host, Port, Options, Timeout]),
+ case gen_tcp:connect(Host, Port, Options, Timeout) of
+ {error,econnrefused} ->
+ timer:sleep( 2*max(Timeout,250)),
+ tcp_connect(Host, Port, Options, 2*max(Timeout,250));
+ {error,timeout} ->
+ timer:sleep( 2*max(Timeout,250)),
+ tcp_connect(Host, Port, Options, 2*max(Timeout,250));
+ {ok,S} ->
+ ct:log("connect to ~p:~p ~p Timeout=~p -> ~p", [Host, Port, Options, Timeout, S]),
+ {ok,S}
+ end.
+
+close_and_check(OneSide, OtherSide) ->
+ ok = gen_tcp:close(OneSide),
+ ok = chk_closed(OtherSide).
+
+
+chk_closed(Sock) ->
+ chk_closed(Sock, 0).
+chk_closed(Sock, Timeout) ->
+ case gen_tcp:recv(Sock, 0, Timeout) of
+ {error,closed} ->
+ ok;
+ {error,timeout} ->
+ chk_closed(Sock, 2*max(Timeout,250));
+ Other ->
+ Other
+ end.
+
+send_rcv(Txt, From, To) ->
+ ct:log("Send ~p from ~p to ~p", [Txt, From, To]),
+ ok = gen_tcp:send(From, Txt),
+ ct:log("Recv ~p on ~p", [Txt, To]),
+ {ok,Txt} = gen_tcp:recv(To, 0, 5000),
+ ok.
+
+%%--------------------------------------------------------------------
receive_data(Data, Conn) ->
receive
Info when is_binary(Info) ->
@@ -256,3 +448,40 @@ comment(AtomList) ->
ct:comment(
string:join(lists:map(fun erlang:atom_to_list/1, AtomList),
", ")).
+
+%%%----------------------------------------------------------------
+no_forwarding() ->
+ %%% Check if the ssh of the OS has tunneling enabled
+ Cmnd = "ssh -R 0:localhost:4567 localhost exit",
+ FailRegExp =
+ "Port forwarding is disabled"
+ "|remote port forwarding failed"
+ "|Bad.*specification",
+ {Result,TheText} =
+ try
+ Parent = self(),
+ Pid = spawn(fun() ->
+ Parent ! {self(), os:cmd(Cmnd)}
+ end),
+ receive
+ {Pid, Txt} ->
+ case re:run(Txt, FailRegExp) of
+ {match,_} -> {true,Txt};
+ _ -> {false,Txt}
+ end
+ after 10000 ->
+ ct:log("*** TIMEOUT ***",[]),
+ {true,""}
+ end
+ catch C:E:S ->
+ ct:log("Exception in no_forwarding():~n~p:~p~n~p~n", [C,E,S]),
+ {true, ""}
+ end,
+ ct:log("---- os:cmd(~p) returned:~n~s~n"
+ "~n"
+ "---- Checking with regexp~n"
+ "~p~n"
+ "~n"
+ "---- The function no_forwarding() returns ~p",
+ [Cmnd,TheText, FailRegExp, Result]),
+ Result.