diff options
-rw-r--r-- | lib/ssh/doc/src/ssh.xml | 6 | ||||
-rw-r--r-- | lib/ssh/src/ssh.erl | 26 | ||||
-rw-r--r-- | lib/ssh/test/ssh_basic_SUITE.erl | 50 | ||||
-rw-r--r-- | lib/ssl/src/ssl_connection.erl | 17 | ||||
-rw-r--r-- | lib/ssl/src/ssl_connection.hrl | 1 | ||||
-rw-r--r-- | lib/ssl/src/tls_connection.erl | 10 |
6 files changed, 83 insertions, 27 deletions
diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml index 5a141ced3c..876eba598a 100644 --- a/lib/ssh/doc/src/ssh.xml +++ b/lib/ssh/doc/src/ssh.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>2004</year><year>2013</year> + <year>2004</year><year>2014</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -97,6 +97,8 @@ <seealso marker="ssh_connection#session_channel/2">ssh_connection:session_channel/[2, 4]</seealso>.</p> <p>Options are:</p> <taglist> + <tag><c><![CDATA[{inet, inet | inet6}]]></c></tag> + <item> IP version to use.</item> <tag><c><![CDATA[{user_dir, string()}]]></c></tag> <item> <p>Sets the user directory i.e. the directory containing @@ -230,6 +232,8 @@ port.</p> <p>Options are:</p> <taglist> + <tag><c><![CDATA[{inet, inet | inet6}]]></c></tag> + <item> IP version to use when the host address is specified as <c>any</c>. </item> <tag><c><![CDATA[{subsystems, [subsystem_spec()]]]></c></tag> <item> Provides specifications for handling of subsystems. The diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl index 240de69eff..bf7ba0be7f 100644 --- a/lib/ssh/src/ssh.erl +++ b/lib/ssh/src/ssh.erl @@ -74,8 +74,7 @@ connect(Host, Port, Options, Timeout) -> {_, Transport, _} = TransportOpts = proplists:get_value(transport, Options, {tcp, gen_tcp, tcp_closed}), ConnectionTimeout = proplists:get_value(connect_timeout, Options, infinity), - Inet = proplists:get_value(inet, SshOptions, inet), - try Transport:connect(Host, Port, [ {active, false}, Inet | SocketOptions], ConnectionTimeout) of + try Transport:connect(Host, Port, [ {active, false} | SocketOptions], ConnectionTimeout) of {ok, Socket} -> Opts = [{user_pid, self()}, {host, Host} | fix_idle_time(SshOptions)], ssh_connection_handler:start_connection(client, Socket, Opts, Timeout); @@ -256,8 +255,8 @@ do_start_daemon(Host, Port, Options, SocketOptions) -> handle_options(Opts) -> try handle_option(proplists:unfold(Opts), [], []) of - {_,_} = Options -> - Options + {Inet, Ssh} -> + {handle_ip(Inet), Ssh} catch throw:Error -> Error @@ -436,8 +435,9 @@ handle_inet_option({active, _} = Opt) -> throw({error, {{eoptions, Opt}, "Ssh has built in flow control, " "and activ is handled internaly user is not allowd" "to specify this option"}}); -handle_inet_option({inet, Value} = Opt) when (Value == inet) or (Value == inet6) -> - Opt; + +handle_inet_option({inet, Value}) when (Value == inet) or (Value == inet6) -> + Value; handle_inet_option({reuseaddr, _} = Opt) -> throw({error, {{eoptions, Opt},"Is set internaly user is not allowd" "to specify this option"}}); @@ -460,3 +460,17 @@ handle_pref_algs([H|T], Acc) -> _ -> false end. + +handle_ip(Inet) -> %% Default to ipv4 + case lists:member(inet, Inet) of + true -> + Inet; + false -> + case lists:member(inet6, Inet) of + true -> + Inet; + false -> + [inet | Inet] + end + end. + diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl index ba38c1da40..bf7fb4c73e 100644 --- a/lib/ssh/test/ssh_basic_SUITE.erl +++ b/lib/ssh/test/ssh_basic_SUITE.erl @@ -66,7 +66,8 @@ groups() -> basic_tests() -> [send, close, peername_sockname, exec, exec_compressed, shell, cli, known_hosts, - idle_time, rekey, openssh_zlib_basic_test]. + idle_time, rekey, openssh_zlib_basic_test, + misc_ssh_options, inet_option]. %%-------------------------------------------------------------------- @@ -175,16 +176,47 @@ misc_ssh_options(Config) when is_list(Config) -> SystemDir = filename:join(?config(priv_dir, Config), system), UserDir = ?config(priv_dir, Config), - CMiscOpt0 = [{connecect_timeout, 1000}, {ip_v6_disabled, false}, {user_dir, UserDir}], - CMiscOpt1 = [{connecect_timeout, infinity}, {ip_v6_disabled, true}, {user_dir, UserDir}], - SMiscOpt0 = [{ip_v6_disabled, false}, {user_dir, UserDir}, {system_dir, SystemDir}], - SMiscOpt1 = [{ip_v6_disabled, true}, {user_dir, UserDir}, {system_dir, SystemDir}], + CMiscOpt0 = [{connect_timeout, 1000}, {user_dir, UserDir}], + CMiscOpt1 = [{connect_timeout, infinity}, {user_dir, UserDir}], + SMiscOpt0 = [{user_dir, UserDir}, {system_dir, SystemDir}], + SMiscOpt1 = [{user_dir, UserDir}, {system_dir, SystemDir}], + + basic_test([{client_opts, CMiscOpt0}, {server_opts, SMiscOpt0}]), + basic_test([{client_opts, CMiscOpt1}, {server_opts, SMiscOpt1}]). + +%%-------------------------------------------------------------------- +inet_option() -> + [{doc, "Test configuring IPv4"}]. +inet_option(Config) when is_list(Config) -> + SystemDir = filename:join(?config(priv_dir, Config), system), + UserDir = ?config(priv_dir, Config), - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), + ClientOpts = [{silently_accept_hosts, true}, + {user_dir, UserDir}, + {user_interaction, false}], + ServerOpts = [{system_dir, SystemDir}, + {user_dir, UserDir}, + {failfun, fun ssh_test_lib:failfun/2}], + + basic_test([{client_opts, [{inet, inet} | ClientOpts]}, + {server_opts, [{inet, inet} | ServerOpts]}]). - basic_test([{client_opts, CMiscOpt0 ++ ClientOpts}, {server_opts, SMiscOpt0 ++ ServerOpts}]), - basic_test([{client_opts, CMiscOpt1 ++ ClientOpts}, {server_opts, SMiscOpt1 ++ ServerOpts}]). +%%-------------------------------------------------------------------- +inet6_option() -> + [{doc, "Test configuring IPv6"}]. +inet6_option(Config) when is_list(Config) -> + SystemDir = filename:join(?config(priv_dir, Config), system), + UserDir = ?config(priv_dir, Config), + + ClientOpts = [{silently_accept_hosts, true}, + {user_dir, UserDir}, + {user_interaction, false}], + ServerOpts = [{system_dir, SystemDir}, + {user_dir, UserDir}, + {failfun, fun ssh_test_lib:failfun/2}], + + basic_test([{client_opts, [{inet, inet6} | ClientOpts]}, + {server_opts, [{inet, inet6} | ServerOpts]}]). %%-------------------------------------------------------------------- exec() -> diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index 34006612a2..c4771b03d5 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -322,6 +322,7 @@ abbreviated(#hello_request{}, State0, Connection) -> abbreviated(#finished{verify_data = Data} = Finished, #state{role = server, negotiated_version = Version, + expecting_finished = true, tls_handshake_history = Handshake, session = #session{master_secret = MasterSecret}, connection_states = ConnectionStates0} = @@ -334,7 +335,8 @@ abbreviated(#finished{verify_data = Data} = Finished, ssl_record:set_client_verify_data(current_both, Data, ConnectionStates0), Connection:next_state_connection(abbreviated, ack_connection( - State#state{connection_states = ConnectionStates})); + State#state{connection_states = ConnectionStates, + expecting_finished = false})); #alert{} = Alert -> Connection:handle_own_alert(Alert, Version, abbreviated, State) end; @@ -354,7 +356,7 @@ abbreviated(#finished{verify_data = Data} = Finished, finalize_handshake(State0#state{connection_states = ConnectionStates1}, abbreviated, Connection), Connection:next_state_connection(abbreviated, - ack_connection(State)); + ack_connection(State#state{expecting_finished = false})); #alert{} = Alert -> Connection:handle_own_alert(Alert, Version, abbreviated, State0) end; @@ -365,7 +367,7 @@ abbreviated(#next_protocol{selected_protocol = SelectedProtocol}, #state{role = server, expecting_next_protocol_negotiation = true} = State0, Connection) -> {Record, State} = Connection:next_record(State0#state{next_protocol = SelectedProtocol}), - Connection:next_state(abbreviated, abbreviated, Record, State); + Connection:next_state(abbreviated, abbreviated, Record, State#state{expecting_next_protocol_negotiation = false}); abbreviated(timeout, State, _) -> {next_state, abbreviated, State, hibernate }; @@ -589,6 +591,7 @@ cipher(#finished{verify_data = Data} = Finished, host = Host, port = Port, role = Role, + expecting_finished = true, session = #session{master_secret = MasterSecret} = Session0, connection_states = ConnectionStates0, @@ -599,7 +602,7 @@ cipher(#finished{verify_data = Data} = Finished, MasterSecret, Handshake0) of verified -> Session = register_session(Role, Host, Port, Session0), - cipher_role(Role, Data, Session, State, Connection); + cipher_role(Role, Data, Session, State#state{expecting_finished = false}, Connection); #alert{} = Alert -> Connection:handle_own_alert(Alert, Version, cipher, State) end; @@ -607,7 +610,8 @@ cipher(#finished{verify_data = Data} = Finished, %% only allowed to send next_protocol message after change cipher spec %% & before finished message and it is not allowed during renegotiation cipher(#next_protocol{selected_protocol = SelectedProtocol}, - #state{role = server, expecting_next_protocol_negotiation = true} = State0, Connection) -> + #state{role = server, expecting_next_protocol_negotiation = true, + expecting_finished = true} = State0, Connection) -> {Record, State} = Connection:next_record(State0#state{next_protocol = SelectedProtocol}), Connection:next_state(cipher, cipher, Record, State#state{expecting_next_protocol_negotiation = false}); @@ -1034,9 +1038,6 @@ server_hello_done(State, Connection) -> HelloDone = ssl_handshake:server_hello_done(), Connection:send_handshake(HelloDone, State). - - - handle_peer_cert(Role, PeerCert, PublicKeyInfo, #state{session = #session{cipher_suite = CipherSuite} = Session} = State0, Connection) -> diff --git a/lib/ssl/src/ssl_connection.hrl b/lib/ssl/src/ssl_connection.hrl index 592889b177..c544a0591f 100644 --- a/lib/ssl/src/ssl_connection.hrl +++ b/lib/ssl/src/ssl_connection.hrl @@ -77,6 +77,7 @@ terminated = false ::boolean(), allow_renegotiate = true ::boolean(), expecting_next_protocol_negotiation = false ::boolean(), + expecting_finished = false ::boolean(), next_protocol = undefined :: undefined | binary(), client_ecc, % {Curves, PointFmt} tracker :: pid() %% Tracker process for listen socket diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl index 2ab085321a..26de51985a 100644 --- a/lib/ssl/src/tls_connection.erl +++ b/lib/ssl/src/tls_connection.erl @@ -444,12 +444,16 @@ next_state(_, StateName, #ssl_tls{type = ?APPLICATION_DATA, fragment = Data}, St next_state(StateName, StateName, Record, State) end; next_state(Current, Next, #ssl_tls{type = ?CHANGE_CIPHER_SPEC, fragment = <<1>>} = - _ChangeCipher, - #state{connection_states = ConnectionStates0} = State0) -> + _ChangeCipher, + #state{connection_states = ConnectionStates0} = State0) + when Next == cipher; Next == abbreviated -> ConnectionStates1 = ssl_record:activate_pending_connection_state(ConnectionStates0, read), {Record, State} = next_record(State0#state{connection_states = ConnectionStates1}), - next_state(Current, Next, Record, State); + next_state(Current, Next, Record, State#state{expecting_finished = true}); +next_state(Current, _Next, #ssl_tls{type = ?CHANGE_CIPHER_SPEC, fragment = <<1>>} = + _ChangeCipher, #state{negotiated_version = Version} = State) -> + handle_own_alert(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE), Version, Current, State); next_state(Current, Next, #ssl_tls{type = _Unknown}, State0) -> %% Ignore unknown type {Record, State} = next_record(State0), |