Skip to content

Commit

Permalink
Remove fast_tls from sockets
Browse files Browse the repository at this point in the history
  • Loading branch information
NelsonVides committed Jan 9, 2025
1 parent 98bc2d6 commit bab9e06
Show file tree
Hide file tree
Showing 6 changed files with 30 additions and 103 deletions.
43 changes: 5 additions & 38 deletions src/c2s/mongoose_c2s_ranch.erl
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
}).

-type state() :: #state{}.
-type transport() :: ranch_tcp | just_tls | fast_tls.
-type transport() :: ranch_tcp | just_tls.

-spec socket_new(term(), mongoose_listener:options()) -> state().
socket_new({ranch_tcp, RanchRef}, #{proxy_protocol := true}) ->
Expand All @@ -48,40 +48,22 @@ socket_peername(#state{ip = Ip}) ->

-spec tcp_to_tls(state(), mongoose_listener:options()) ->
{ok, state()} | {error, term()}.
tcp_to_tls(#state{socket = TcpSocket} = State, #{tls := #{module := TlsMod} = TlsConfig}) ->
case tcp_to_tls(TlsMod, TcpSocket, TlsConfig) of
tcp_to_tls(#state{socket = TcpSocket} = State, #{tls := TlsConfig}) ->
case do_tcp_to_tls(TcpSocket, TlsConfig) of
{ok, TlsSocket} ->
{ok, State#state{transport = TlsMod, socket = TlsSocket}};
{ok, State#state{transport = just_tls, socket = TlsSocket}};
{error, Reason} ->
{error, Reason}
end.

tcp_to_tls(fast_tls, TcpSocket, TlsConfig) ->
PreparedOpts = mongoose_tls:prepare_options(fast_tls, maps:remove(module, TlsConfig)),
ranch_tcp:setopts(TcpSocket, [{active, false}]),
case fast_tls:tcp_to_tls(TcpSocket, PreparedOpts) of
{ok, TlsSocket} ->
fast_tls:recv_data(TlsSocket, <<>>),
{ok, TlsSocket};
Other -> Other
end;
tcp_to_tls(just_tls, TcpSocket, TlsConfig) ->
do_tcp_to_tls(TcpSocket, TlsConfig) ->
case just_tls:tcp_to_tls(TcpSocket, TlsConfig) of
{ok, TlsSocket} -> {ok, TlsSocket};
Other -> Other
end.

-spec socket_handle_data(state(), {tcp | ssl, term(), iodata()}) ->
iodata() | {raw, [exml:element()]} | {error, term()}.
socket_handle_data(#state{transport = fast_tls, socket = TlsSocket}, {tcp, _, Data}) ->
case fast_tls:recv_data(TlsSocket, Data) of
{ok, DecryptedData} ->
mongoose_instrument:execute(
c2s_tls_data_in, #{}, #{byte_size => iolist_size(DecryptedData)}),
DecryptedData;
{error, Reason} ->
{error, Reason}
end;
socket_handle_data(#state{transport = just_tls}, {ssl, _, Data}) ->
mongoose_instrument:execute(c2s_tls_data_in, #{}, #{byte_size => iolist_size(Data)}),
Data;
Expand All @@ -90,16 +72,12 @@ socket_handle_data(#state{transport = ranch_tcp, socket = Socket}, {tcp, Socket,
Data.

-spec socket_activate(state()) -> ok.
socket_activate(#state{transport = fast_tls, socket = Socket}) ->
fast_tls:setopts(Socket, [{active, once}]);
socket_activate(#state{transport = just_tls, socket = Socket}) ->
just_tls:setopts(Socket, [{active, once}]);
socket_activate(#state{transport = ranch_tcp, socket = Socket}) ->
ranch_tcp:setopts(Socket, [{active, once}]).

-spec socket_close(state()) -> ok.
socket_close(#state{transport = fast_tls, socket = Socket}) ->
fast_tls:close(Socket);
socket_close(#state{transport = just_tls, socket = Socket}) ->
just_tls:close(Socket);
socket_close(#state{transport = ranch_tcp, socket = Socket}) ->
Expand All @@ -117,9 +95,6 @@ socket_send_xml(#state{transport = Transport, socket = Socket}, XML) ->
end.

-spec send(transport(), ranch_transport:socket(), iodata()) -> ok | {error, term()}.
send(fast_tls, Socket, Data) ->
mongoose_instrument:execute(c2s_tls_data_out, #{}, #{byte_size => iolist_size(Data)}),
fast_tls:send(Socket, Data);
send(just_tls, Socket, Data) ->
mongoose_instrument:execute(c2s_tls_data_out, #{}, #{byte_size => iolist_size(Data)}),
just_tls:send(Socket, Data);
Expand All @@ -129,14 +104,6 @@ send(ranch_tcp, Socket, Data) ->

-spec get_peer_certificate(state(), mongoose_listener:options()) ->
mongoose_c2s_socket:peercert_return().
get_peer_certificate(#state{transport = fast_tls, socket = Socket}, #{tls := TlsOpts}) ->
case {fast_tls:get_verify_result(Socket), fast_tls:get_peer_certificate(Socket), TlsOpts} of
{0, {ok, Cert}, _} -> {ok, Cert};
%% 18 is OpenSSL's and fast_tls's error code for self-signed certs
{18, {ok, Cert}, #{verify_mode := selfsigned_peer}} -> {ok, Cert};
{Error, {ok, Cert}, _} -> {bad_cert, fast_tls:get_cert_verify_string(Error, Cert)};
{_, error, _} -> no_peer_cert
end;
get_peer_certificate(#state{transport = just_tls, socket = Socket}, _) ->
just_tls:get_peer_certificate(Socket);
get_peer_certificate(#state{transport = ranch_tcp}, _) ->
Expand Down
12 changes: 3 additions & 9 deletions src/global_distrib/mod_global_distrib_receiver.erl
Original file line number Diff line number Diff line change
Expand Up @@ -170,15 +170,9 @@ do_setopts_and_receive_data(Socket, Buffer, RawData, State) ->
end.

do_receive_data(Socket, Buffer, RawData, State) ->
case mod_global_distrib_transport:recv_data(Socket, RawData) of
{ok, Data} ->
NewState = handle_buffered(State#state{buffer = <<Buffer/binary, Data/binary>>}),
{noreply, NewState};
{error, closed} ->
{stop, normal, State};
Other ->
{stop, {recv_data_failed, Other}, State}
end.
{ok, Data} = mod_global_distrib_transport:recv_data(Socket, RawData),
NewState = handle_buffered(State#state{buffer = <<Buffer/binary, Data/binary>>}),
{noreply, NewState}.

-spec handle_data(Data :: binary(), state()) -> state().
handle_data(GdStart, State = #state{host = undefined}) ->
Expand Down
30 changes: 15 additions & 15 deletions src/global_distrib/mod_global_distrib_transport.erl
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
-author('[email protected]').

-record(?MODULE, {
transport :: fast_tls | gen_tcp,
socket :: fast_tls:tls_socket() | gen_tcp:socket()
transport :: just_tls | gen_tcp,
socket :: just_tls:tls_socket() | gen_tcp:socket()
}).

-type t() :: #?MODULE{}.
Expand All @@ -38,9 +38,9 @@ wrap(Socket, ConnOpts) ->
-spec wrap(gen_tcp:socket(), #{tls := mongoose_tls:options()}, ExtraOpts :: map()) ->
{ok, t()} | {error, any()}.
wrap(Socket, #{tls := Opts}, ExtraOpts) ->
PreparedOpts = mongoose_tls:prepare_options(fast_tls, maps:merge(Opts, ExtraOpts)),
case fast_tls:tcp_to_tls(Socket, PreparedOpts) of
{ok, TLSSocket} -> {ok, #?MODULE{transport = fast_tls, socket = TLSSocket}};
PreparedOpts = maps:merge(Opts, ExtraOpts),
case just_tls:tcp_to_tls(Socket, PreparedOpts) of
{ok, TLSSocket} -> {ok, #?MODULE{transport = just_tls, socket = TLSSocket}};
Error -> Error
end;
wrap(Socket, #{}, _ExtraOpts) ->
Expand All @@ -49,32 +49,32 @@ wrap(Socket, #{}, _ExtraOpts) ->
-spec setopts(t(), Opts :: proplists:proplist()) -> ok | {error, term()}.
setopts(#?MODULE{transport = gen_tcp, socket = Socket}, Opts) ->
inet:setopts(Socket, Opts);
setopts(#?MODULE{transport = fast_tls, socket = Socket}, Opts) ->
fast_tls:setopts(Socket, Opts).
setopts(#?MODULE{transport = just_tls, socket = Socket}, Opts) ->
just_tls:setopts(Socket, Opts).

-spec recv_data(t(), Data :: binary()) -> {ok, binary()} | {error, any()}.
recv_data(#?MODULE{transport = gen_tcp}, Data) ->
{ok, Data};
recv_data(#?MODULE{transport = fast_tls, socket = Socket}, Data) ->
fast_tls:recv_data(Socket, Data).
recv_data(#?MODULE{transport = just_tls, socket = Socket}, Data) ->
just_tls:recv_data(Socket, Data).

-spec close(t()) -> ok | {error, any()}.
close(#?MODULE{transport = gen_tcp, socket = Socket}) ->
gen_tcp:close(Socket);
close(#?MODULE{transport = fast_tls, socket = Socket}) ->
fast_tls:close(Socket).
close(#?MODULE{transport = just_tls, socket = Socket}) ->
just_tls:close(Socket).

-spec send(t(), Data :: binary()) -> ok | {error, any()}.
send(#?MODULE{transport = gen_tcp, socket = Socket}, Data) ->
gen_tcp:send(Socket, Data);
send(#?MODULE{transport = fast_tls, socket = Socket}, Data) ->
fast_tls:send(Socket, Data).
send(#?MODULE{transport = just_tls, socket = Socket}, Data) ->
just_tls:send(Socket, Data).

-spec peername(t()) -> {inet:ip_address(), inet:port_number()} | unknown.
peername(#?MODULE{transport = gen_tcp, socket = Socket}) ->
normalize_peername(inet:peername(Socket));
peername(#?MODULE{transport = fast_tls, socket = Socket}) ->
normalize_peername(fast_tls:peername(Socket)).
peername(#?MODULE{transport = just_tls, socket = Socket}) ->
normalize_peername(just_tls:peername(Socket)).

-spec normalize_peername({ok, {inet:ip_address(), inet:port_number()}} | any()) ->
{inet:ip_address(), inet:port_number()} | unknown.
Expand Down
6 changes: 1 addition & 5 deletions src/just_tls.erl
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,6 @@ tcp_to_tls(TCPSocket, Options) ->
send(#tls_socket{ssl_socket = SSLSocket}, Packet) -> ssl:send(SSLSocket, Packet).

%% -callback recv_data(tls_socket(), binary()) -> {ok, binary()} | {error, any()}.
recv_data(_, <<"">>) ->
%% such call is required for fast_tls to accomplish
%% tls handshake, for just_tls we can ignore it
{ok, <<"">>};
recv_data(#tls_socket{ssl_socket = SSLSocket}, Data1) ->
case ssl:recv(SSLSocket, 0, 0) of
{ok, Data2} -> {ok, <<Data1/binary, Data2/binary>>};
Expand Down Expand Up @@ -187,7 +183,7 @@ fail_if_no_peer_cert_opt(#{}) -> false.
%% `disconnect_on_failure` is a boolean parameter:
%% true - drop connection if certificate verification failed
%% false - connect anyway, but later return {bad_cert,Error}
%% on certificate verification (the same as fast_tls do).
%% on certificate verification.
verify_fun_opt(#{verify_mode := Mode, disconnect_on_failure := false}) ->
Ref = erlang:make_ref(),
{Ref, verify_fun(Ref, Mode)};
Expand Down
30 changes: 5 additions & 25 deletions src/mongoose_tls.erl
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,6 @@
%%% @copyright (C) 1999-2018, Erlang Solutions Ltd
%%% @author Denys Gonchar <[email protected]>
%%% @doc this module provides general TLS interface for MongooseIM.
%%%
%%% by default tls_module is set to fast_tls, alternatively it can be any
%%% module that implements mongoose_tls behaviour
%%% @end
%%%=============================================================================
-module(mongoose_tls).
-copyright("2018, Erlang Solutions Ltd.").
Expand All @@ -30,13 +26,13 @@

-ignore_xref([get_sockmod/1]).

-type tls_socket() :: fast_tls:tls_socket() | just_tls:tls_socket().
-type tls_socket() :: just_tls:tls_socket().
-type cert() :: {ok, Cert::any()} | {bad_cert, bitstring()} | no_peer_cert.

%% Options used for client-side and server-side TLS connections.
%% All modules implementing this behaviour have to support the mandatory 'verify_mode' option.
%% Other options should be supported if the implementing module supports it.
-type options() :: #{module => module(), % fast_tls by default
-type options() :: #{module => module(),
connect => boolean(), % set to 'true' for a client-side call to tcp_to_tls/2
verify_mode := peer | selfsigned_peer | none,
mode => tls | starttls | starttls_required, % only ejabberd_s2s_out doesn't use it (yet)
Expand All @@ -50,10 +46,8 @@
keyfile => string(),
password => string(),
versions => [atom()],
server_name_indication => sni_options(), % client-only

% only for fast_tls
protocol_options => [string()]}.
server_name_indication => sni_options() % client-only
}.

-type sni_options() :: #{enabled := boolean,
protocol := default | https,
Expand Down Expand Up @@ -105,7 +99,7 @@

-spec tcp_to_tls(inet:socket(), options()) -> {ok, socket()} | {error, any()}.
tcp_to_tls(TCPSocket, Opts) ->
Module = maps:get(module, Opts, fast_tls),
Module = maps:get(module, Opts, just_tls),
PreparedOpts = prepare_options(Module, maps:remove(module, Opts)),
case Module:tcp_to_tls(TCPSocket, PreparedOpts) of
{ok, TLSSocket} ->
Expand All @@ -119,23 +113,9 @@ tcp_to_tls(TCPSocket, Opts) ->
end.

-spec prepare_options(module(), options()) -> any().
prepare_options(fast_tls, Opts) ->
%% fast_tls is an external library and its API cannot use Opts directly
lists:flatmap(fun({K, V}) -> fast_tls_opt(K, V) end, maps:to_list(Opts));
prepare_options(_Module, Opts) ->
Opts.

fast_tls_opt(connect, true) -> [connect];
fast_tls_opt(connect, false) -> [];
fast_tls_opt(mode, _) -> [];
fast_tls_opt(verify_mode, peer) -> [];
fast_tls_opt(verify_mode, none) -> [verify_none];
fast_tls_opt(cacertfile, File) -> [{cafile, File}];
fast_tls_opt(dhfile, File) -> [{dhfile, File}];
fast_tls_opt(certfile, File) -> [{certfile, File}];
fast_tls_opt(ciphers, Ciphers) -> [{ciphers, Ciphers}];
fast_tls_opt(protocol_options, ProtoOpts) -> [{protocol_options, string:join(ProtoOpts, "|")}].

default_ciphers() ->
"TLSv1.2:TLSv1.3".

Expand Down
12 changes: 1 addition & 11 deletions src/s2s/mongoose_transport.erl
Original file line number Diff line number Diff line change
Expand Up @@ -197,17 +197,7 @@ handle_call({tcp_to_tls, TLSOpts}, From, #state{socket = TCPSocket} = State0) ->
{ok, TLSSocket} ->
State1 = reset_parser(State0),
State2 = State1#state{socket = TLSSocket, sockmod = mongoose_tls},
%% fast_tls requires dummy recv_data/2 call to accomplish TLS
%% handshake. such call is simply ignored by just_tls backend.
case mongoose_tls:recv_data(TLSSocket, <<>>) of
{ok, TLSData} ->
State3 = process_data(TLSData, State2),
{noreply, State3, hibernate_or_timeout(State3)};
{error, Reason} ->
?LOG_WARNING(#{what => tcp_to_tls_failed, reason => Reason,
dest_pid => State2#state.dest_pid}),
{stop, normal, State2}
end;
{noreply, State2, hibernate_or_timeout(State2)};
{error, Reason} ->
?LOG_WARNING(#{what => tcp_to_tls_failed, reason => Reason,
dest_pid => State0#state.dest_pid}),
Expand Down

0 comments on commit bab9e06

Please sign in to comment.