Log errors from `ranch:handshake`

Fixes #11171

An MQTT user encountered TLS handshake timeouts with their IoT device,
and the actual error from `ssl:handshake` / `ranch:handshake` was not
caught and logged.

At this time, `ranch` uses `exit(normal)` in the case of timeouts, but
that should change in the future
(https://github.com/ninenines/ranch/issues/336)
This commit is contained in:
Luke Bakken 2024-05-06 08:24:38 -07:00
parent 746c06f77c
commit 620fff22f1
No known key found for this signature in database
GPG Key ID: D99DE30E43EAE440
5 changed files with 104 additions and 80 deletions

View File

@ -560,7 +560,7 @@ failed_to_recv_proxy_header(Ref, Error) ->
end, end,
rabbit_log:debug(Msg, [Error]), rabbit_log:debug(Msg, [Error]),
% The following call will clean up resources then exit % The following call will clean up resources then exit
_ = ranch:handshake(Ref), _ = catch ranch:handshake(Ref),
exit({shutdown, failed_to_recv_proxy_header}). exit({shutdown, failed_to_recv_proxy_header}).
handshake(Ref, ProxyProtocolEnabled) -> handshake(Ref, ProxyProtocolEnabled) ->
@ -572,14 +572,22 @@ handshake(Ref, ProxyProtocolEnabled) ->
{error, protocol_error, Error} -> {error, protocol_error, Error} ->
failed_to_recv_proxy_header(Ref, Error); failed_to_recv_proxy_header(Ref, Error);
{ok, ProxyInfo} -> {ok, ProxyInfo} ->
{ok, Sock} = ranch:handshake(Ref), case catch ranch:handshake(Ref) of
{'EXIT', normal} ->
{error, handshake_failed};
{ok, Sock} ->
setup_socket(Sock), setup_socket(Sock),
{ok, {rabbit_proxy_socket, Sock, ProxyInfo}} {ok, {rabbit_proxy_socket, Sock, ProxyInfo}}
end
end; end;
false -> false ->
{ok, Sock} = ranch:handshake(Ref), case catch ranch:handshake(Ref) of
{'EXIT', normal} ->
{error, handshake_failed};
{ok, Sock} ->
setup_socket(Sock), setup_socket(Sock),
{ok, Sock} {ok, Sock}
end
end. end.
setup_socket(Sock) -> setup_socket(Sock) ->

View File

@ -162,6 +162,10 @@ shutdown(Pid, Explanation) ->
no_return(). no_return().
init(Parent, HelperSups, Ref) -> init(Parent, HelperSups, Ref) ->
?LG_PROCESS_TYPE(reader), ?LG_PROCESS_TYPE(reader),
%% Note:
%% This function could return an error if the handshake times out.
%% It is less likely to happen here as compared to MQTT, so
%% crashing with a `badmatch` seems appropriate.
{ok, Sock} = rabbit_networking:handshake(Ref, {ok, Sock} = rabbit_networking:handshake(Ref,
application:get_env(rabbit, proxy_protocol, false)), application:get_env(rabbit, proxy_protocol, false)),
Deb = sys:debug_options([]), Deb = sys:debug_options([]),

View File

@ -71,8 +71,12 @@ close_connection(Pid, Reason) ->
init(Ref) -> init(Ref) ->
process_flag(trap_exit, true), process_flag(trap_exit, true),
logger:set_process_metadata(#{domain => ?RMQLOG_DOMAIN_CONN ++ [mqtt]}), logger:set_process_metadata(#{domain => ?RMQLOG_DOMAIN_CONN ++ [mqtt]}),
{ok, Sock} = rabbit_networking:handshake(Ref, ProxyProtocolEnabled = application:get_env(?APP_NAME, proxy_protocol, false),
application:get_env(?APP_NAME, proxy_protocol, false)), case rabbit_networking:handshake(Ref, ProxyProtocolEnabled) of
{error, Reason} ->
?LOG_ERROR("MQTT could not establish connection: ~s", [Reason]),
{stop, Reason};
{ok, Sock} ->
RealSocket = rabbit_net:unwrap_socket(Sock), RealSocket = rabbit_net:unwrap_socket(Sock),
case rabbit_net:connection_string(Sock, inbound) of case rabbit_net:connection_string(Sock, inbound) of
{ok, ConnStr} -> {ok, ConnStr} ->
@ -99,6 +103,7 @@ init(Ref) ->
?LOG_ERROR("MQTT could not get connection string: ~p", [Reason]), ?LOG_ERROR("MQTT could not get connection string: ~p", [Reason]),
rabbit_net:fast_close(RealSocket), rabbit_net:fast_close(RealSocket),
{stop, Reason} {stop, Reason}
end
end. end.
handle_call({info, InfoItems}, _From, State) -> handle_call({info, InfoItems}, _From, State) ->

View File

@ -63,10 +63,14 @@ close_connection(Pid, Reason) ->
init([SupHelperPid, Ref, Configuration]) -> init([SupHelperPid, Ref, Configuration]) ->
process_flag(trap_exit, true), process_flag(trap_exit, true),
{ok, Sock} = rabbit_networking:handshake(Ref, ProxyProtocolEnabled = application:get_env(rabbitmq_stomp, proxy_protocol, false),
application:get_env(rabbitmq_stomp, proxy_protocol, false)), case rabbit_networking:handshake(Ref, ProxyProtocolEnabled) of
{error, Reason} ->
rabbit_log_connection:error(
"STOMP could not establish connection: ~s", [Reason]),
{stop, Reason};
{ok, Sock} ->
RealSocket = rabbit_net:unwrap_socket(Sock), RealSocket = rabbit_net:unwrap_socket(Sock),
case rabbit_net:connection_string(Sock, inbound) of case rabbit_net:connection_string(Sock, inbound) of
{ok, ConnStr} -> {ok, ConnStr} ->
ConnName = rabbit_data_coercion:to_binary(ConnStr), ConnName = rabbit_data_coercion:to_binary(ConnStr),
@ -105,9 +109,9 @@ init([SupHelperPid, Ref, Configuration]) ->
{error, Reason} -> {error, Reason} ->
rabbit_net:fast_close(RealSocket), rabbit_net:fast_close(RealSocket),
terminate({network_error, Reason}, undefined) terminate({network_error, Reason}, undefined)
end
end. end.
handle_call({info, InfoItems}, _From, State) -> handle_call({info, InfoItems}, _From, State) ->
Infos = lists:map( Infos = lists:map(
fun(InfoItem) -> fun(InfoItem) ->

View File

@ -135,10 +135,13 @@ init([KeepaliveSup,
heartbeat := Heartbeat, heartbeat := Heartbeat,
transport := ConnTransport}]) -> transport := ConnTransport}]) ->
process_flag(trap_exit, true), process_flag(trap_exit, true),
{ok, Sock} = ProxyProtocolEnabled =
rabbit_networking:handshake(Ref, application:get_env(rabbitmq_stream, proxy_protocol, false),
application:get_env(rabbitmq_stream, %% Note:
proxy_protocol, false)), %% This function could return an error if the handshake times out.
%% It is less likely to happen here as compared to MQTT, so
%% crashing with a `badmatch` seems appropriate.
{ok, Sock} = rabbit_networking:handshake(Ref, ProxyProtocolEnabled),
RealSocket = rabbit_net:unwrap_socket(Sock), RealSocket = rabbit_net:unwrap_socket(Sock),
case rabbit_net:connection_string(Sock, inbound) of case rabbit_net:connection_string(Sock, inbound) of
{ok, ConnStr} -> {ok, ConnStr} ->