From fb90763e3da5b93e75908f5b0bb97f58163b910b Mon Sep 17 00:00:00 2001 From: Paul Guyot Date: Mon, 16 Jan 2012 13:01:07 +0100 Subject: Robustness and improvement to distribution over SSL Fix a bug where the caller would timeout and ssl_tls_dist_proxy would crash. Fix a bug where a timeout from the SSL layer would block the distribution forever (typically when a non-SSL node tries to connect to an SSL node). Add this very case as a test (test_server tries to connect to SSL nodes). Run the proxy exclusively on the loopback interface. --- lib/ssl/src/inet_tls_dist.erl | 14 +++++++++---- lib/ssl/src/ssl_tls_dist_proxy.erl | 40 +++++++++++++++++++------------------- lib/ssl/test/ssl_dist_SUITE.erl | 10 ++++++++-- 3 files changed, 38 insertions(+), 26 deletions(-) (limited to 'lib') diff --git a/lib/ssl/src/inet_tls_dist.erl b/lib/ssl/src/inet_tls_dist.erl index 115527aae0..bc395cb6d5 100644 --- a/lib/ssl/src/inet_tls_dist.erl +++ b/lib/ssl/src/inet_tls_dist.erl @@ -57,7 +57,7 @@ accept_connection(AcceptPid, Socket, MyNode, Allowed, SetupTime) -> setup(Node, Type, MyNode, LongOrShortNames,SetupTime) -> Kernel = self(), - spawn(fun() -> do_setup(Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) end). + spawn_opt(fun() -> do_setup(Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) end, [link, {priority, max}]). do_setup(Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) -> [Name, Address] = splitnode(Node, LongOrShortNames), @@ -229,9 +229,7 @@ connect_hs_data(Kernel, Node, MyNode, Socket, Timer, Version, Ip, TcpPort, Addre accept_hs_data(Kernel, MyNode, Socket, Timer, Allowed) -> common_hs_data(Kernel, MyNode, Socket, Timer, #hs_data{ allowed = Allowed, - f_address = fun(S, N) -> - ssl_tls_dist_proxy:get_remote_id(S, N) - end + f_address = fun get_remote_id/2 }). common_hs_data(Kernel, MyNode, Socket, Timer, HsData) -> @@ -273,3 +271,11 @@ common_hs_data(Kernel, MyNode, Socket, Timer, HsData) -> P = proplists:get_value(send_pend, Stats, 0), {ok, R,W,P} end}. + +get_remote_id(Socket, _Node) -> + case ssl_tls_dist_proxy:get_tcp_address(Socket) of + {ok, Address} -> + Address; + {error, _Reason} -> + ?shutdown(no_node) + end. diff --git a/lib/ssl/src/ssl_tls_dist_proxy.erl b/lib/ssl/src/ssl_tls_dist_proxy.erl index d63eada571..aa762f26d7 100644 --- a/lib/ssl/src/ssl_tls_dist_proxy.erl +++ b/lib/ssl/src/ssl_tls_dist_proxy.erl @@ -19,7 +19,7 @@ -module(ssl_tls_dist_proxy). --export([listen/1, accept/1, connect/2, get_remote_id/2]). +-export([listen/1, accept/1, connect/2, get_tcp_address/1]). -export([init/1, start_link/0, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3, ssl_options/2]). @@ -47,9 +47,6 @@ accept(Listen) -> connect(Ip, Port) -> gen_server:call(?MODULE, {connect, Ip, Port}, infinity). -get_remote_id(Socket, Node) -> - gen_server:call(?MODULE, {get_remote_id, {Socket,Node}}, infinity). - %%==================================================================== %% gen_server callbacks %%==================================================================== @@ -65,8 +62,8 @@ 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}]), - TcpAddress = get_tcp_address(Socket), - WorldTcpAddress = get_tcp_address(World), + {ok, TcpAddress} = get_tcp_address(Socket), + {ok, WorldTcpAddress} = get_tcp_address(World), {_,Port} = WorldTcpAddress#net_address.address, {ok, Creation} = erl_epmd:register_node(Name, Port), {reply, {ok, {Socket, TcpAddress, Creation}}, @@ -87,17 +84,16 @@ handle_call({connect, Ip, Port}, {From, _}, State) -> receive {Pid, go_ahead, LPort} -> Res = {ok, Socket} = try_connect(LPort), - ok = gen_tcp:controlling_process(Socket, From), - flush_old_controller(From, Socket), - {reply, Res, State}; + case gen_tcp:controlling_process(Socket, From) of + {error, badarg} = Error -> {reply, Error, State}; % From is dead anyway. + ok -> + flush_old_controller(From, Socket), + {reply, Res, State} + end; {Pid, Error} -> {reply, Error, State} end; -handle_call({get_remote_id, {Socket,_Node}}, _From, State) -> - Address = get_tcp_address(Socket), - {reply, Address, State}; - handle_call(_What, _From, State) -> {reply, ok, State}. @@ -117,14 +113,18 @@ code_change(_OldVsn, St, _Extra) -> %%% Internal functions %%-------------------------------------------------------------------- get_tcp_address(Socket) -> - {ok, Address} = inet:sockname(Socket), - {ok, Host} = inet:gethostname(), - #net_address{ + case inet:sockname(Socket) of + {ok, Address} -> + {ok, Host} = inet:gethostname(), + NetAddress = #net_address{ address = Address, host = Host, protocol = proxy, family = inet - }. + }, + {ok, NetAddress}; + {error, _} = Error -> Error + end. accept_loop(Proxy, erts = Type, Listen, Extra) -> process_flag(priority, max), @@ -178,8 +178,8 @@ setup_proxy(Ip, Port, Parent) -> Opts = get_ssl_options(client), case ssl:connect(Ip, Port, [{active, true}, binary, {packet,?PPRE}] ++ Opts) of {ok, World} -> - {ok, ErtsL} = gen_tcp:listen(0, [{active, true}, binary, {packet,?PPRE}]), - #net_address{address={_,LPort}} = get_tcp_address(ErtsL), + {ok, ErtsL} = gen_tcp:listen(0, [{active, true}, {ip, {127,0,0,1}}, binary, {packet,?PPRE}]), + {ok, #net_address{address={_,LPort}}} = get_tcp_address(ErtsL), Parent ! {self(), go_ahead, LPort}, case gen_tcp:accept(ErtsL) of {ok, Erts} -> @@ -194,7 +194,7 @@ setup_proxy(Ip, Port, Parent) -> setup_connection(World, ErtsListen) -> process_flag(trap_exit, true), - TcpAddress = get_tcp_address(ErtsListen), + {ok, TcpAddress} = get_tcp_address(ErtsListen), {_Addr,Port} = TcpAddress#net_address.address, {ok, Erts} = gen_tcp:connect({127,0,0,1}, Port, [{active, true}, binary, {packet,?PPRE}]), ssl:setopts(World, [{active,true}, {packet,?PPRE}]), diff --git a/lib/ssl/test/ssl_dist_SUITE.erl b/lib/ssl/test/ssl_dist_SUITE.erl index 8fe55ee7a4..06182970e3 100644 --- a/lib/ssl/test/ssl_dist_SUITE.erl +++ b/lib/ssl/test/ssl_dist_SUITE.erl @@ -26,7 +26,7 @@ -define(DEFAULT_TIMETRAP_SECS, 240). --define(AWAIT_SLL_NODE_UP_TIMEOUT, 30000). +-define(AWAIT_SSL_NODE_UP_TIMEOUT, 30000). -record(node_handle, {connection_handler, @@ -120,6 +120,12 @@ basic(Config) when is_list(Config) -> pang = net_adm:ping(Node1), pang = net_adm:ping(Node2), + %% SSL nodes should not be able to communicate with the test_server node + %% either (and ping should return eventually). + TestServer = node(), + pang = apply_on_ssl_node(NH1, fun () -> net_adm:ping(TestServer) end), + pang = apply_on_ssl_node(NH2, fun () -> net_adm:ping(TestServer) end), + %% %% Check that we are able to communicate over the erlang %% distribution between the ssl nodes. @@ -380,7 +386,7 @@ mk_node_cmdline(ListenPort, Name, Args) -> %% await_ssl_node_up(Name, LSock) -> - case gen_tcp:accept(LSock, ?AWAIT_SLL_NODE_UP_TIMEOUT) of + case gen_tcp:accept(LSock, ?AWAIT_SSL_NODE_UP_TIMEOUT) of timeout -> gen_tcp:close(LSock), ?t:format("Timeout waiting for ssl node ~s to come up~n", -- cgit v1.2.3