aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ssh
diff options
context:
space:
mode:
authorMicael Karlberg <[email protected]>2013-11-13 17:20:31 +0100
committerMicael Karlberg <[email protected]>2013-11-13 17:20:31 +0100
commit8bcd32dfceec3b4381747046b82eec42487c7518 (patch)
treecca7f396b6b3bd98950e5fc7713dfc9988633b10 /lib/ssh
parentdc6f086a0751677da8724df397a062ab154f34cb (diff)
parentb166476d2674c056ed5f737170074e71fbdc4bfd (diff)
downloadotp-8bcd32dfceec3b4381747046b82eec42487c7518.tar.gz
otp-8bcd32dfceec3b4381747046b82eec42487c7518.tar.bz2
otp-8bcd32dfceec3b4381747046b82eec42487c7518.zip
Merge branch 'bmk/snmp/handling_corrupt_atl_when_converting/r16/OTP-11453' into bmk/snmp/snmp425_integration
Conflicts: lib/snmp/src/misc/snmp_log.erl
Diffstat (limited to 'lib/ssh')
-rw-r--r--lib/ssh/doc/src/ssh.xml32
-rw-r--r--lib/ssh/doc/src/ssh_server_key_api.xml10
-rw-r--r--lib/ssh/src/ssh.erl24
-rw-r--r--lib/ssh/src/ssh_connection_handler.erl29
-rw-r--r--lib/ssh/test/Makefile5
-rw-r--r--lib/ssh/test/ssh_basic_SUITE.erl51
-rw-r--r--lib/ssh/test/ssh_peername_sockname_server.erl56
7 files changed, 184 insertions, 23 deletions
diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml
index 141d3df38e..896b98edc2 100644
--- a/lib/ssh/doc/src/ssh.xml
+++ b/lib/ssh/doc/src/ssh.xml
@@ -141,7 +141,7 @@
<p>Sets the preferred public key algorithm to use for user
authentication. If the the preferred algorithm fails for
some reason, the other algorithm is tried. The default is
- to try <c><![CDATA[ssh_rsa]]></c> first.</p>
+ to try <c><![CDATA['ssh-rsa']]></c> first.</p>
</item>
<tag><c><![CDATA[{pref_public_key_algs, list()}]]></c></tag>
<item>
@@ -248,7 +248,7 @@
requested by the client. Default is to use the erlang shell:
<c><![CDATA[{shell, start, []}]]></c>
</item>
- <tag><c><![CDATA[{ssh_cli,{channel_callback(),
+ <tag><c><![CDATA[{ssh_cli, {channel_callback(),
channel_init_args()}}]]></c></tag>
<item>
Provides your own cli implementation, i.e. a channel callback
@@ -334,6 +334,20 @@
</func>
<func>
+ <name>peername(ConnectionRef) -> {ok, {Address,Port}} | {error,Error} </name>
+ <fsummary> </fsummary>
+ <type>
+ <v> ConnectionRef = ssh_connection_ref()</v>
+ <v> Address = ip_address()</v>
+ <v> Port = integer()</v>
+ </type>
+ <desc>
+ <p>Returns the address and port for the other end of a connection.
+ </p>
+ </desc>
+ </func>
+
+ <func>
<name>shell(Host) -> </name>
<name>shell(Host, Option) -> </name>
<name>shell(Host, Port, Option) -> _</name>
@@ -353,6 +367,20 @@
</func>
<func>
+ <name>sockname(ConnectionRef) -> {ok, {Address,Port}} | {error,Error} </name>
+ <fsummary> </fsummary>
+ <type>
+ <v> ConnectionRef = ssh_connection_ref()</v>
+ <v> Address = ip_address()</v>
+ <v> Port = integer()</v>
+ </type>
+ <desc>
+ <p>Returns the local address and port number for a connection.
+ </p>
+ </desc>
+ </func>
+
+ <func>
<name>start() -> </name>
<name>start(Type) -> ok | {error, Reason}</name>
<fsummary>Starts the SSH application. </fsummary>
diff --git a/lib/ssh/doc/src/ssh_server_key_api.xml b/lib/ssh/doc/src/ssh_server_key_api.xml
index c4562e1211..51e1fc1f2e 100644
--- a/lib/ssh/doc/src/ssh_server_key_api.xml
+++ b/lib/ssh/doc/src/ssh_server_key_api.xml
@@ -29,7 +29,7 @@
-behaviour(ssh_server_key_api).
</modulesummary>
<description>
- <p> Behaviour describing the API for an SSH server's public key handling.By implementing the callbacks defined
+ <p> Behaviour describing the API for an SSH server's public key handling. By implementing the callbacks defined
in this behavior it is possible to customize the SSH server's public key
handling. By default the SSH application implements this behavior
with help of the standard openssh files, see <seealso marker="SSH_app"> ssh(6)</seealso>.</p>
@@ -44,9 +44,9 @@
<p> boolean() = true | false</p>
<p> string() = [byte()]</p>
- <p> public_key() = #'RSAPublicKey'{}| {integer(), #'Dss-Parms'{}}| term()</p>
- <p> private_key() = #'RSAPublicKey'{}| {integer(), #'Dss-Parms'{}}| term()</p>
- <p> public_key_algorithm() = 'ssh-rsa'| 'ssh-dss' | atom()</p>
+ <p> public_key() = #'RSAPublicKey'{} | {integer(), #'Dss-Parms'{}} | term()</p>
+ <p> private_key() = #'RSAPrivateKey'{} | #'DSAPrivateKey'{} | term()</p>
+ <p> public_key_algorithm() = 'ssh-rsa' | 'ssh-dss' | atom()</p>
</section>
<funcs>
@@ -56,7 +56,7 @@
<fsummary>Fetches the hosts private key </fsummary>
<type>
<v>Algorithm = public_key_algorithm()</v>
- <d> Host key algorithm. Should support 'ssh-rsa'| 'ssh-dss' but additional algorithms
+ <d> Host key algorithm. Should support 'ssh-rsa' | 'ssh-dss' but additional algorithms
can be handled.</d>
<v> DaemonOptions = proplists:proplist() </v>
<d>Options provided to <seealso marker="ssh#daemon-2">ssh:daemon/[2,3]</seealso></d>
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index 7d5478c3f6..80d20abbbd 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -28,6 +28,8 @@
-export([start/0, start/1, stop/0, connect/3, connect/4, close/1, connection_info/2,
channel_info/3,
daemon/1, daemon/2, daemon/3,
+ peername/1,
+ sockname/1,
stop_listener/1, stop_listener/2, stop_daemon/1, stop_daemon/2,
shell/1, shell/2, shell/3]).
@@ -245,6 +247,28 @@ shell(Host, Port, Options) ->
end.
%%--------------------------------------------------------------------
+%% Function: peername(ConnectionRef) -> {ok, {Host,Port}}
+%% | {error,Error}
+%%
+%% Description: Returns the peer address of the connection
+%%--------------------------------------------------------------------
+peername(ConnectionRef) ->
+ [{peer, {_Name,{IP,Port}}}] =
+ ssh_connection_manager:connection_info(ConnectionRef, [peer]),
+ {ok, {IP,Port}}.
+
+%%--------------------------------------------------------------------
+%% Function: sockname(ConnectionRef) -> {ok, {Host,Port}}
+%% | {error,Error}
+%%
+%% Description: Returns the local address of the connection
+%%--------------------------------------------------------------------
+sockname(ConnectionRef) ->
+ [{sockname, Result}] =
+ ssh_connection_manager:connection_info(ConnectionRef, [sockname]),
+ Result.
+
+%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
fix_idle_time(SshOptions) ->
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index 9de4dd5967..c3e8a3c742 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -46,7 +46,7 @@
handle_sync_event/4, handle_info/3, terminate/3, code_change/4]).
%% spawn export
--export([ssh_info_handler/3]).
+-export([ssh_info_handler/4]).
-record(state, {
transport_protocol, % ex: tcp
@@ -533,7 +533,7 @@ handle_event(renegotiate, StateName, State) ->
{next_state, StateName, State};
handle_event({info, From, Options}, StateName, #state{ssh_params = Ssh} = State) ->
- spawn(?MODULE, ssh_info_handler, [Options, Ssh, From]),
+ spawn(?MODULE, ssh_info_handler, [Options, Ssh, State, From]),
{next_state, StateName, State};
handle_event(data_size, connected, #state{ssh_params = Ssh0} = State) ->
{ok, [{send_oct,Sent}]} = inet:getstat(State#state.socket, [send_oct]),
@@ -1022,26 +1022,29 @@ retry_fun(User, Reason, Opts) ->
catch Fun(User, Reason)
end.
-ssh_info_handler(Options, Ssh, From) ->
- Info = ssh_info(Options, Ssh, []),
+ssh_info_handler(Options, Ssh, State, From) ->
+ Info = ssh_info(Options, Ssh, State, []),
ssh_connection_manager:send_msg({channel_requst_reply, From, Info}).
-ssh_info([], _, Acc) ->
+ssh_info([], _, _, Acc) ->
Acc;
ssh_info([client_version | Rest], #ssh{c_vsn = IntVsn,
- c_version = StringVsn} = SshParams, Acc) ->
- ssh_info(Rest, SshParams, [{client_version, {IntVsn, StringVsn}} | Acc]);
+ c_version = StringVsn} = SshParams, State, Acc) ->
+ ssh_info(Rest, SshParams, State, [{client_version, {IntVsn, StringVsn}} | Acc]);
ssh_info([server_version | Rest], #ssh{s_vsn = IntVsn,
- s_version = StringVsn} = SshParams, Acc) ->
- ssh_info(Rest, SshParams, [{server_version, {IntVsn, StringVsn}} | Acc]);
+ s_version = StringVsn} = SshParams, State, Acc) ->
+ ssh_info(Rest, SshParams, State, [{server_version, {IntVsn, StringVsn}} | Acc]);
-ssh_info([peer | Rest], #ssh{peer = Peer} = SshParams, Acc) ->
- ssh_info(Rest, SshParams, [{peer, Peer} | Acc]);
+ssh_info([peer | Rest], #ssh{peer = Peer} = SshParams, State, Acc) ->
+ ssh_info(Rest, SshParams, State, [{peer, Peer} | Acc]);
-ssh_info([ _ | Rest], SshParams, Acc) ->
- ssh_info(Rest, SshParams, Acc).
+ssh_info([sockname | Rest], SshParams, #state{socket=Socket}=State, Acc) ->
+ ssh_info(Rest, SshParams, State, [{sockname,inet:sockname(Socket)}|Acc]);
+
+ssh_info([ _ | Rest], SshParams, State, Acc) ->
+ ssh_info(Rest, SshParams, State, Acc).
log_error(Reason) ->
Report = io_lib:format("Erlang ssh connection handler failed with reason: "
diff --git a/lib/ssh/test/Makefile b/lib/ssh/test/Makefile
index f5db31baee..13caafc055 100644
--- a/lib/ssh/test/Makefile
+++ b/lib/ssh/test/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2004-2012. All Rights Reserved.
+# Copyright Ericsson AB 2004-2013. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -38,7 +38,8 @@ MODULES= \
ssh_sftpd_SUITE \
ssh_sftpd_erlclient_SUITE \
ssh_connection_SUITE \
- ssh_echo_server
+ ssh_echo_server \
+ ssh_peername_sockname_server
HRL_FILES_NEEDED_IN_TEST= \
$(ERL_TOP)/lib/ssh/src/ssh.hrl \
diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl
index 0aa60624bf..e8f1d5213c 100644
--- a/lib/ssh/test/ssh_basic_SUITE.erl
+++ b/lib/ssh/test/ssh_basic_SUITE.erl
@@ -22,6 +22,7 @@
-module(ssh_basic_SUITE).
-include_lib("common_test/include/ct.hrl").
+-include_lib("kernel/include/inet.hrl").
%% Note: This directive should only be used in test suites.
-compile(export_all).
@@ -48,7 +49,9 @@ all() ->
close].
groups() ->
- [{dsa_key, [], [send, exec, exec_compressed, shell, known_hosts, idle_time, rekey, openssh_zlib_basic_test]},
+ [{dsa_key, [], [send,
+ peername_sockname,
+ exec, exec_compressed, shell, known_hosts, idle_time, rekey, openssh_zlib_basic_test]},
{rsa_key, [], [send, exec, exec_compressed, shell, known_hosts, idle_time, rekey, openssh_zlib_basic_test]},
{dsa_pass_key, [], [pass_phrase]},
{rsa_pass_key, [], [pass_phrase]},
@@ -473,6 +476,52 @@ send(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
+peername_sockname() ->
+ [{doc, "Test ssh:peername/1 and ssh:sockname/1"}].
+peername_sockname(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ SystemDir = filename:join(?config(priv_dir, Config), system),
+ UserDir = ?config(priv_dir, Config),
+
+ {_Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
+ {user_dir, UserDir},
+ {subsystems, [{"peername_sockname",
+ {ssh_peername_sockname_server, []}}
+ ]}
+ ]),
+ ConnectionRef =
+ ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
+ {user_dir, UserDir},
+ {user_interaction, false}]),
+ {ok, ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity),
+ success = ssh_connection:subsystem(ConnectionRef, ChannelId, "peername_sockname", infinity),
+ {ok,{HostPeerClient,PortPeerClient}} = ssh:peername(ConnectionRef),
+ {ok,{HostSockClient,PortSockClient}} = ssh:sockname(ConnectionRef),
+ receive
+ {ssh_cm, ConnectionRef, {data, ChannelId, _, Response}} ->
+ {PeerNameSrv,SockNameSrv} = binary_to_term(Response),
+ {ok,{HostPeerSrv,PortPeerSrv}} = PeerNameSrv,
+ {ok,{HostSockSrv,PortSockSrv}} = SockNameSrv,
+ host_equal(HostPeerSrv, HostSockClient),
+ PortPeerSrv = PortSockClient,
+ host_equal(HostSockSrv, HostPeerClient),
+ PortSockSrv = PortPeerClient,
+ host_equal(HostSockSrv, Host),
+ PortSockSrv = Port
+ after 10000 ->
+ throw(timeout)
+ end.
+
+host_equal(H1, H2) ->
+ not ordsets:is_disjoint(ips(H1), ips(H2)).
+
+ips(IP) when is_tuple(IP) -> ordsets:from_list([IP]);
+ips(Name) when is_list(Name) ->
+ {ok,#hostent{h_addr_list=IPs4}} = inet:gethostbyname(Name,inet),
+ {ok,#hostent{h_addr_list=IPs6}} = inet:gethostbyname(Name,inet6),
+ ordsets:from_list(IPs4++IPs6).
+
+%%--------------------------------------------------------------------
close() ->
[{doc, "Simulate that we try to close an already closed connection"}].
close(Config) when is_list(Config) ->
diff --git a/lib/ssh/test/ssh_peername_sockname_server.erl b/lib/ssh/test/ssh_peername_sockname_server.erl
new file mode 100644
index 0000000000..7664f3ee25
--- /dev/null
+++ b/lib/ssh/test/ssh_peername_sockname_server.erl
@@ -0,0 +1,56 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+
+-module(ssh_peername_sockname_server).
+
+%% The purpose of this module is to perform tests on the server side of an
+%% ssh connection.
+
+
+-behaviour(ssh_daemon_channel).
+-record(state, {}).
+
+-export([init/1, handle_msg/2, handle_ssh_msg/2, terminate/2]).
+
+init([]) ->
+ {ok, #state{}}.
+
+handle_msg({ssh_channel_up, ChannelId, ConnectionManager}, State) ->
+ ssh_connection:send(ConnectionManager, ChannelId,
+ term_to_binary(
+ {catch ssh:peername(ConnectionManager),
+ catch ssh:sockname(ConnectionManager)
+ })
+ ),
+ {ok, State}.
+
+handle_ssh_msg({ssh_cm, _, {exit_signal, ChannelId, _, _Error, _}},
+ State) ->
+ {stop, ChannelId, State};
+
+handle_ssh_msg({ssh_cm, _, {exit_status, ChannelId, _Status}}, State) ->
+ {stop, ChannelId, State};
+
+handle_ssh_msg({ssh_cm, _CM, _}, State) ->
+ {ok, State}.
+
+terminate(_Reason, _State) ->
+ ok.