diff options
Diffstat (limited to 'lib/ssl/src')
-rw-r--r-- | lib/ssl/src/dtls_connection.erl | 2 | ||||
-rw-r--r-- | lib/ssl/src/ssl.erl | 2 | ||||
-rw-r--r-- | lib/ssl/src/ssl_connection.erl | 2 | ||||
-rw-r--r-- | lib/ssl/src/ssl_connection.hrl | 23 | ||||
-rw-r--r-- | lib/ssl/src/ssl_internal.hrl | 14 | ||||
-rw-r--r-- | lib/ssl/src/ssl_manager.erl | 184 | ||||
-rw-r--r-- | lib/ssl/src/ssl_session.erl | 9 | ||||
-rw-r--r-- | lib/ssl/src/ssl_session_cache.erl | 8 | ||||
-rw-r--r-- | lib/ssl/src/ssl_session_cache_api.erl | 1 | ||||
-rw-r--r-- | lib/ssl/src/ssl_tls_dist_proxy.erl | 43 | ||||
-rw-r--r-- | lib/ssl/src/ssl_v3.erl | 1 |
11 files changed, 207 insertions, 82 deletions
diff --git a/lib/ssl/src/dtls_connection.erl b/lib/ssl/src/dtls_connection.erl index 78662e0ea2..153d3fef48 100644 --- a/lib/ssl/src/dtls_connection.erl +++ b/lib/ssl/src/dtls_connection.erl @@ -145,7 +145,7 @@ init([Role, Host, Port, Socket, {SSLOpts0, _} = Options, User, CbInfo]) -> process_flag(trap_exit, true), State0 = initial_state(Role, Host, Port, Socket, Options, User, CbInfo), Handshake = ssl_handshake:init_handshake_history(), - TimeStamp = calendar:datetime_to_gregorian_seconds({date(), time()}), + TimeStamp = erlang:monotonic_time(), try ssl_config:init(SSLOpts0, Role) of {ok, Ref, CertDbHandle, FileRefHandle, CacheHandle, CRLDbInfo, OwnCert, Key, DHParams} -> Session = State0#state.session, diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl index 03495cfd90..6551308935 100644 --- a/lib/ssl/src/ssl.erl +++ b/lib/ssl/src/ssl.erl @@ -1190,6 +1190,8 @@ assert_proplist([]) -> assert_proplist([{Key,_} | Rest]) when is_atom(Key) -> assert_proplist(Rest); %% Handle exceptions +assert_proplist([{raw,_,_,_} | Rest]) -> + assert_proplist(Rest); assert_proplist([inet | Rest]) -> assert_proplist(Rest); assert_proplist([inet6 | Rest]) -> diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index 12a56df69f..241871dc38 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -974,7 +974,7 @@ ssl_config(Opts, Role, State) -> {ok, Ref, CertDbHandle, FileRefHandle, CacheHandle, CRLDbInfo, OwnCert, Key, DHParams} = ssl_config:init(Opts, Role), Handshake = ssl_handshake:init_handshake_history(), - TimeStamp = calendar:datetime_to_gregorian_seconds({date(), time()}), + TimeStamp = erlang:monotonic_time(), Session = State#state.session, State#state{tls_handshake_history = Handshake, session = Session#session{own_certificate = OwnCert, diff --git a/lib/ssl/src/ssl_connection.hrl b/lib/ssl/src/ssl_connection.hrl index 9a58f2b8f7..bb41ef2b62 100644 --- a/lib/ssl/src/ssl_connection.hrl +++ b/lib/ssl/src/ssl_connection.hrl @@ -48,27 +48,28 @@ socket_options :: #socket_options{}, connection_states :: #connection_states{} | secret_printout(), protocol_buffers :: term() | secret_printout() , %% #protocol_buffers{} from tls_record.hrl or dtls_recor.hrl - tls_handshake_history :: ssl_handshake:ssl_handshake_history() | secret_printout(), - cert_db :: reference(), + tls_handshake_history :: ssl_handshake:ssl_handshake_history() | secret_printout() + | 'undefined', + cert_db :: reference() | 'undefined', session :: #session{} | secret_printout(), session_cache :: db_handle(), session_cache_cb :: atom(), crl_db :: term(), - negotiated_version :: ssl_record:ssl_version(), + negotiated_version :: ssl_record:ssl_version() | 'undefined', client_certificate_requested = false :: boolean(), key_algorithm :: ssl_cipher:key_algo(), hashsign_algorithm = {undefined, undefined}, cert_hashsign_algorithm, - public_key_info :: ssl_handshake:public_key_info(), - private_key :: public_key:private_key() | secret_printout(), + public_key_info :: ssl_handshake:public_key_info() | 'undefined', + private_key :: public_key:private_key() | secret_printout() | 'undefined', diffie_hellman_params:: #'DHParameter'{} | undefined | secret_printout(), diffie_hellman_keys :: {PublicKey :: binary(), PrivateKey :: binary()} | #'ECPrivateKey'{} | undefined | secret_printout(), - psk_identity :: binary(), % server psk identity hint - srp_params :: #srp_user{} | secret_printout(), - srp_keys ::{PublicKey :: binary(), PrivateKey :: binary()} | secret_printout(), - premaster_secret :: binary() | secret_printout() , + psk_identity :: binary() | 'undefined', % server psk identity hint + srp_params :: #srp_user{} | secret_printout() | 'undefined', + srp_keys ::{PublicKey :: binary(), PrivateKey :: binary()} | secret_printout() | 'undefined', + premaster_secret :: binary() | secret_printout() | 'undefined', file_ref_db :: db_handle(), - cert_db_ref :: certdb_ref(), + cert_db_ref :: certdb_ref() | 'undefined', bytes_to_read :: undefined | integer(), %% bytes to read in passive mode user_data_buffer :: undefined | binary() | secret_printout(), renegotiation :: undefined | {boolean(), From::term() | internal | peer}, @@ -81,7 +82,7 @@ expecting_finished = false ::boolean(), negotiated_protocol = undefined :: undefined | binary(), client_ecc, % {Curves, PointFmt} - tracker :: pid(), %% Tracker process for listen socket + tracker :: pid() | 'undefined', %% Tracker process for listen socket sni_hostname = undefined }). diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl index 8c7ed9c0d1..913746598f 100644 --- a/lib/ssl/src/ssl_internal.hrl +++ b/lib/ssl/src/ssl_internal.hrl @@ -93,16 +93,16 @@ validate_extensions_fun, depth :: integer(), certfile :: binary(), - cert :: public_key:der_encoded() | secret_printout(), + cert :: public_key:der_encoded() | secret_printout() | 'undefined', keyfile :: binary(), - key :: {'RSAPrivateKey' | 'DSAPrivateKey' | 'ECPrivateKey' | 'PrivateKeyInfo', public_key:der_encoded()} | secret_printout(), - password :: string() | secret_printout(), - cacerts :: [public_key:der_encoded()] | secret_printout(), + key :: {'RSAPrivateKey' | 'DSAPrivateKey' | 'ECPrivateKey' | 'PrivateKeyInfo', public_key:der_encoded()} | secret_printout() | 'undefined', + password :: string() | secret_printout() | 'undefined', + cacerts :: [public_key:der_encoded()] | secret_printout() | 'undefined', cacertfile :: binary(), dh :: public_key:der_encoded() | secret_printout(), - dhfile :: binary() | secret_printout(), + dhfile :: binary() | secret_printout() | 'undefined', user_lookup_fun, % server option, fun to lookup the user - psk_identity :: binary() | secret_printout() , + psk_identity :: binary() | secret_printout() | 'undefined', srp_identity, % client option {User, Password} ciphers, % %% Local policy for the server if it want's to reuse the session @@ -118,7 +118,7 @@ %% undefined if not hibernating, or number of ms of %% inactivity after which ssl_connection will go into %% hibernation - hibernate_after :: boolean(), + hibernate_after :: boolean() | 'undefined', %% This option should only be set to true by inet_tls_dist erl_dist = false :: boolean(), alpn_advertised_protocols = undefined :: [binary()] | undefined , diff --git a/lib/ssl/src/ssl_manager.erl b/lib/ssl/src/ssl_manager.erl index cc15678f23..00e95f5c5b 100644 --- a/lib/ssl/src/ssl_manager.erl +++ b/lib/ssl/src/ssl_manager.erl @@ -46,15 +46,19 @@ -include_lib("kernel/include/file.hrl"). -record(state, { - session_cache_client, - session_cache_server, - session_cache_cb, - session_lifetime, - certificate_db, - session_validation_timer, + session_cache_client :: db_handle(), + session_cache_server :: db_handle(), + session_cache_cb :: atom(), + session_lifetime :: integer(), + certificate_db :: db_handle(), + session_validation_timer :: reference(), last_delay_timer = {undefined, undefined},%% Keep for testing purposes - last_pem_check, - clear_pem_cache + last_pem_check :: erlang:timestamp(), + clear_pem_cache :: integer(), + session_cache_client_max :: integer(), + session_cache_server_max :: integer(), + session_server_invalidator :: undefined | pid(), + session_client_invalidator :: undefined | pid() }). -define(GEN_UNIQUE_ID_MAX_TRIES, 10). @@ -62,7 +66,7 @@ -define(CLEAR_PEM_CACHE, 120000). -define(CLEAN_SESSION_DB, 60000). -define(CLEAN_CERT_DB, 500). --define(NOT_TO_BIG, 10). +-define(DEFAULT_MAX_SESSION_CACHE, 1000). %%==================================================================== %% API @@ -87,7 +91,8 @@ manager_name(dist) -> %%-------------------------------------------------------------------- start_link(Opts) -> DistMangerName = manager_name(normal), - gen_server:start_link({local, DistMangerName}, ?MODULE, [DistMangerName, Opts], []). + gen_server:start_link({local, DistMangerName}, + ?MODULE, [DistMangerName, Opts], []). %%-------------------------------------------------------------------- -spec start_link_dist(list()) -> {ok, pid()} | ignore | {error, term()}. @@ -97,7 +102,8 @@ start_link(Opts) -> %%-------------------------------------------------------------------- start_link_dist(Opts) -> DistMangerName = manager_name(dist), - gen_server:start_link({local, DistMangerName}, ?MODULE, [DistMangerName, Opts], []). + gen_server:start_link({local, DistMangerName}, + ?MODULE, [DistMangerName, Opts], []). %%-------------------------------------------------------------------- -spec connection_init(binary()| {der, list()}, client | server, @@ -167,7 +173,8 @@ new_session_id(Port) -> %% be called by ssl-connection processes. %%-------------------------------------------------------------------- clean_cert_db(Ref, File) -> - erlang:send_after(?CLEAN_CERT_DB, get(ssl_manager), {clean_cert_db, Ref, File}), + erlang:send_after(?CLEAN_CERT_DB, get(ssl_manager), + {clean_cert_db, Ref, File}), ok. %%-------------------------------------------------------------------- @@ -235,10 +242,12 @@ init([Name, Opts]) -> SessionLifeTime = proplists:get_value(session_lifetime, Opts, ?'24H_in_sec'), CertDb = ssl_pkix_db:create(), - ClientSessionCache = CacheCb:init([{role, client} | - proplists:get_value(session_cb_init_args, Opts, [])]), - ServerSessionCache = CacheCb:init([{role, server} | - proplists:get_value(session_cb_init_args, Opts, [])]), + ClientSessionCache = + CacheCb:init([{role, client} | + proplists:get_value(session_cb_init_args, Opts, [])]), + ServerSessionCache = + CacheCb:init([{role, server} | + proplists:get_value(session_cb_init_args, Opts, [])]), Timer = erlang:send_after(SessionLifeTime * 1000 + 5000, self(), validate_sessions), Interval = pem_check_interval(), @@ -250,7 +259,11 @@ init([Name, Opts]) -> session_lifetime = SessionLifeTime, session_validation_timer = Timer, last_pem_check = os:timestamp(), - clear_pem_cache = Interval + clear_pem_cache = Interval, + session_cache_client_max = + max_session_cache_size(session_cache_client_max), + session_cache_server_max = + max_session_cache_size(session_cache_server_max) }}. %%-------------------------------------------------------------------- @@ -267,7 +280,8 @@ init([Name, Opts]) -> handle_call({{connection_init, <<>>, Role, {CRLCb, UserCRLDb}}, _Pid}, _From, #state{certificate_db = [CertDb, FileRefDb, PemChace | _] = Db} = State) -> Ref = make_ref(), - Result = {ok, Ref, CertDb, FileRefDb, PemChace, session_cache(Role, State), {CRLCb, crl_db_info(Db, UserCRLDb)}}, + Result = {ok, Ref, CertDb, FileRefDb, PemChace, + session_cache(Role, State), {CRLCb, crl_db_info(Db, UserCRLDb)}}, {reply, Result, State#state{certificate_db = Db}}; handle_call({{connection_init, Trustedcerts, Role, {CRLCb, UserCRLDb}}, Pid}, _From, @@ -305,7 +319,8 @@ handle_call({{cache_pem,File}, _Pid}, _, _:Reason -> {reply, {error, Reason}, State} end; -handle_call({unconditionally_clear_pem_cache, _},_, #state{certificate_db = [_,_,PemChace | _]} = State) -> +handle_call({unconditionally_clear_pem_cache, _},_, + #state{certificate_db = [_,_,PemChace | _]} = State) -> ssl_pkix_db:clear(PemChace), {reply, ok, State}. @@ -317,27 +332,12 @@ handle_call({unconditionally_clear_pem_cache, _},_, #state{certificate_db = [_,_ %% %% Description: Handling cast messages %%-------------------------------------------------------------------- -handle_cast({register_session, Host, Port, Session}, - #state{session_cache_client = Cache, - session_cache_cb = CacheCb} = State) -> - TimeStamp = calendar:datetime_to_gregorian_seconds({date(), time()}), - NewSession = Session#session{time_stamp = TimeStamp}, - - case CacheCb:select_session(Cache, {Host, Port}) of - no_session -> - CacheCb:update(Cache, {{Host, Port}, - NewSession#session.session_id}, NewSession); - Sessions -> - register_unique_session(Sessions, NewSession, CacheCb, Cache, {Host, Port}) - end, +handle_cast({register_session, Host, Port, Session}, State0) -> + State = ssl_client_register_session(Host, Port, Session, State0), {noreply, State}; -handle_cast({register_session, Port, Session}, - #state{session_cache_server = Cache, - session_cache_cb = CacheCb} = State) -> - TimeStamp = calendar:datetime_to_gregorian_seconds({date(), time()}), - NewSession = Session#session{time_stamp = TimeStamp}, - CacheCb:update(Cache, {Port, NewSession#session.session_id}, NewSession), +handle_cast({register_session, Port, Session}, State0) -> + State = server_register_session(Port, Session, State0), {noreply, State}; handle_cast({invalidate_session, Host, Port, @@ -411,10 +411,10 @@ handle_info({clean_cert_db, Ref, File}, end, {noreply, State}; -handle_info({'EXIT', _, _}, State) -> - %% Session validator died!! Do we need to take any action? - %% maybe error log - {noreply, State}; +handle_info({'EXIT', Pid, _}, #state{session_client_invalidator = Pid} = State) -> + {noreply, State#state{session_client_invalidator = undefined}}; +handle_info({'EXIT', Pid, _}, #state{session_server_invalidator = Pid} = State) -> + {noreply, State#state{session_server_invalidator = undefined}}; handle_info(_Info, State) -> {noreply, State}. @@ -495,7 +495,15 @@ delay_time() -> ?CLEAN_SESSION_DB end. -invalidate_session(Cache, CacheCb, Key, Session, #state{last_delay_timer = LastTimer} = State) -> +max_session_cache_size(CacheType) -> + case application:get_env(ssl, CacheType) of + {ok, Size} when is_integer(Size) -> + Size; + _ -> + ?DEFAULT_MAX_SESSION_CACHE + end. + +invalidate_session(Cache, CacheCb, Key, Session, State) -> case CacheCb:lookup(Cache, Key) of undefined -> %% Session is already invalidated {noreply, State}; @@ -503,15 +511,23 @@ invalidate_session(Cache, CacheCb, Key, Session, #state{last_delay_timer = LastT CacheCb:delete(Cache, Key), {noreply, State}; _ -> - %% When a registered session is invalidated we need to wait a while before deleting - %% it as there might be pending connections that rightfully needs to look - %% up the session data but new connections should not get to use this session. - CacheCb:update(Cache, Key, Session#session{is_resumable = false}), - TRef = - erlang:send_after(delay_time(), self(), {delayed_clean_session, Key, Cache}), - {noreply, State#state{last_delay_timer = last_delay_timer(Key, TRef, LastTimer)}} + delayed_invalidate_session(CacheCb, Cache, Key, Session, State) end. +delayed_invalidate_session(CacheCb, Cache, Key, Session, + #state{last_delay_timer = LastTimer} = State) -> + %% When a registered session is invalidated we need to + %% wait a while before deleting it as there might be + %% pending connections that rightfully needs to look up + %% the session data but new connections should not get to + %% use this session. + CacheCb:update(Cache, Key, Session#session{is_resumable = false}), + TRef = + erlang:send_after(delay_time(), self(), + {delayed_clean_session, Key, Cache}), + {noreply, State#state{last_delay_timer = + last_delay_timer(Key, TRef, LastTimer)}}. + last_delay_timer({{_,_},_}, TRef, {LastServer, _}) -> {LastServer, TRef}; last_delay_timer({_,_}, TRef, {_, LastClient}) -> @@ -530,12 +546,12 @@ new_id(Port, Tries, Cache, CacheCb) -> Id = crypto:rand_bytes(?NUM_OF_SESSION_ID_BYTES), case CacheCb:lookup(Cache, {Port, Id}) of undefined -> - Now = calendar:datetime_to_gregorian_seconds({date(), time()}), + Now = erlang:monotonic_time(), %% New sessions can not be set to resumable %% until handshake is compleate and the %% other session values are set. CacheCb:update(Cache, {Port, Id}, #session{session_id = Id, - is_resumable = false, + is_resumable = new, time_stamp = Now}), Id; _ -> @@ -557,15 +573,62 @@ clean_cert_db(Ref, CertDb, RefDb, PemCache, File) -> ok end. +ssl_client_register_session(Host, Port, Session, #state{session_cache_client = Cache, + session_cache_cb = CacheCb, + session_cache_client_max = Max, + session_client_invalidator = Pid0} = State) -> + TimeStamp = erlang:monotonic_time(), + NewSession = Session#session{time_stamp = TimeStamp}, + + case CacheCb:select_session(Cache, {Host, Port}) of + no_session -> + Pid = do_register_session({{Host, Port}, + NewSession#session.session_id}, + NewSession, Max, Pid0, Cache, CacheCb), + State#state{session_client_invalidator = Pid}; + Sessions -> + register_unique_session(Sessions, NewSession, {Host, Port}, State) + end. + +server_register_session(Port, Session, #state{session_cache_server_max = Max, + session_cache_server = Cache, + session_cache_cb = CacheCb, + session_server_invalidator = Pid0} = State) -> + TimeStamp = erlang:monotonic_time(), + NewSession = Session#session{time_stamp = TimeStamp}, + Pid = do_register_session({Port, NewSession#session.session_id}, + NewSession, Max, Pid0, Cache, CacheCb), + State#state{session_server_invalidator = Pid}. + +do_register_session(Key, Session, Max, Pid, Cache, CacheCb) -> + try CacheCb:size(Cache) of + N when N > Max -> + invalidate_session_cache(Pid, CacheCb, Cache); + _ -> + CacheCb:update(Cache, Key, Session), + Pid + catch + error:undef -> + CacheCb:update(Cache, Key, Session), + Pid + end. + + %% Do not let dumb clients create a gigantic session table %% for itself creating big delays at connection time. -register_unique_session(Sessions, Session, CacheCb, Cache, PartialKey) -> +register_unique_session(Sessions, Session, PartialKey, + #state{session_cache_client_max = Max, + session_cache_client = Cache, + session_cache_cb = CacheCb, + session_client_invalidator = Pid0} = State) -> case exists_equivalent(Session , Sessions) of true -> - ok; + State; false -> - CacheCb:update(Cache, {PartialKey, - Session#session.session_id}, Session) + Pid = do_register_session({PartialKey, + Session#session.session_id}, + Session, Max, Pid0, Cache, CacheCb), + State#state{session_client_invalidator = Pid} end. exists_equivalent(_, []) -> @@ -620,7 +683,8 @@ pem_check_interval() -> end. is_before_checkpoint(Time, CheckPoint) -> - calendar:datetime_to_gregorian_seconds(calendar:now_to_datetime(CheckPoint)) - + calendar:datetime_to_gregorian_seconds( + calendar:now_to_datetime(CheckPoint)) - calendar:datetime_to_gregorian_seconds(Time) > 0. add_trusted_certs(Pid, Trustedcerts, Db) -> @@ -641,3 +705,9 @@ crl_db_info([_,_,_,Local], {internal, Info}) -> crl_db_info(_, UserCRLDb) -> UserCRLDb. +%% Only start a session invalidator if there is not +%% one already active +invalidate_session_cache(undefined, CacheCb, Cache) -> + start_session_validator(Cache, CacheCb, {invalidate_before, erlang:monotonic_time()}); +invalidate_session_cache(Pid, _CacheCb, _Cache) -> + Pid. diff --git a/lib/ssl/src/ssl_session.erl b/lib/ssl/src/ssl_session.erl index 1849a05314..2b24bff5ff 100644 --- a/lib/ssl/src/ssl_session.erl +++ b/lib/ssl/src/ssl_session.erl @@ -61,13 +61,16 @@ client_id(ClientInfo, Cache, CacheCb, OwnCert) -> SessionId end. --spec valid_session(#session{}, seconds()) -> boolean(). +-spec valid_session(#session{}, seconds() | {invalidate_before, integer()}) -> boolean(). %% %% Description: Check that the session has not expired %%-------------------------------------------------------------------- +valid_session(#session{time_stamp = TimeStamp}, {invalidate_before, Before}) -> + TimeStamp > Before; valid_session(#session{time_stamp = TimeStamp}, LifeTime) -> - Now = calendar:datetime_to_gregorian_seconds({date(), time()}), - Now - TimeStamp < LifeTime. + Now = erlang:monotonic_time(), + Lived = erlang:convert_time_unit(Now-TimeStamp, native, seconds), + Lived < LifeTime. server_id(Port, <<>>, _SslOpts, _Cert, _, _) -> {ssl_manager:new_session_id(Port), undefined}; diff --git a/lib/ssl/src/ssl_session_cache.erl b/lib/ssl/src/ssl_session_cache.erl index cfc48cd935..9585e613e6 100644 --- a/lib/ssl/src/ssl_session_cache.erl +++ b/lib/ssl/src/ssl_session_cache.erl @@ -27,7 +27,7 @@ -include("ssl_internal.hrl"). -export([init/1, terminate/1, lookup/2, update/3, delete/2, foldl/3, - select_session/2]). + select_session/2, size/1]). %%-------------------------------------------------------------------- %% Description: Return table reference. Called by ssl_manager process. @@ -86,6 +86,12 @@ select_session(Cache, PartialKey) -> [{{{PartialKey,'_'}, '$1'},[],['$1']}]). %%-------------------------------------------------------------------- +%% Description: Returns the cache size +%%-------------------------------------------------------------------- +size(Cache) -> + ets:info(Cache, size). + +%%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- cache_name(Name) -> diff --git a/lib/ssl/src/ssl_session_cache_api.erl b/lib/ssl/src/ssl_session_cache_api.erl index 536b52c44b..8f62c25be5 100644 --- a/lib/ssl/src/ssl_session_cache_api.erl +++ b/lib/ssl/src/ssl_session_cache_api.erl @@ -33,3 +33,4 @@ -callback delete(db_handle(), key()) -> any(). -callback foldl(fun(), term(), db_handle()) -> term(). -callback select_session(db_handle(), {host(), inet:port_number()} | inet:port_number()) -> [#session{}]. +-callback size(db_handle()) -> integer(). diff --git a/lib/ssl/src/ssl_tls_dist_proxy.erl b/lib/ssl/src/ssl_tls_dist_proxy.erl index fda08cb87f..d384264b53 100644 --- a/lib/ssl/src/ssl_tls_dist_proxy.erl +++ b/lib/ssl/src/ssl_tls_dist_proxy.erl @@ -48,6 +48,47 @@ accept(Listen) -> connect(Ip, Port) -> gen_server:call(?MODULE, {connect, Ip, Port}, infinity). + +do_listen(Options) -> + {First,Last} = case application:get_env(kernel,inet_dist_listen_min) of + {ok,N} when is_integer(N) -> + case application:get_env(kernel, + inet_dist_listen_max) of + {ok,M} when is_integer(M) -> + {N,M}; + _ -> + {N,N} + end; + _ -> + {0,0} + end, + do_listen(First, Last, listen_options([{backlog,128}|Options])). + +do_listen(First,Last,_) when First > Last -> + {error,eaddrinuse}; +do_listen(First,Last,Options) -> + case gen_tcp:listen(First, Options) of + {error, eaddrinuse} -> + do_listen(First+1,Last,Options); + Other -> + Other + end. + +listen_options(Opts0) -> + Opts1 = + case application:get_env(kernel, inet_dist_use_interface) of + {ok, Ip} -> + [{ip, Ip} | Opts0]; + _ -> + Opts0 + end, + case application:get_env(kernel, inet_dist_listen_options) of + {ok,ListenOpts} -> + ListenOpts ++ Opts1; + _ -> + Opts1 + end. + %%==================================================================== %% gen_server callbacks %%==================================================================== @@ -62,7 +103,7 @@ init([]) -> handle_call({listen, Name}, _From, State) -> case gen_tcp:listen(0, [{active, false}, {packet,?PPRE}]) of {ok, Socket} -> - {ok, World} = gen_tcp:listen(0, [{active, false}, binary, {packet,?PPRE}]), + {ok, World} = do_listen([{active, false}, binary, {packet,?PPRE}, {reuseaddr, true}]), {ok, TcpAddress} = get_tcp_address(Socket), {ok, WorldTcpAddress} = get_tcp_address(World), {_,Port} = WorldTcpAddress#net_address.address, diff --git a/lib/ssl/src/ssl_v3.erl b/lib/ssl/src/ssl_v3.erl index 5e043624a7..f169059a75 100644 --- a/lib/ssl/src/ssl_v3.erl +++ b/lib/ssl/src/ssl_v3.erl @@ -144,6 +144,7 @@ suites() -> ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA, ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA, ?TLS_RSA_WITH_AES_128_CBC_SHA, + ?TLS_DHE_RSA_WITH_DES_CBC_SHA, ?TLS_RSA_WITH_DES_CBC_SHA ]. |