25
1
mirror of https://github.com/processone/ejabberd.git synced 2024-12-18 17:24:31 +01:00
xmpp.chapril.org-ejabberd/src/mod_s2s_bidi.erl
2024-11-05 13:26:42 +01:00

148 lines
4.8 KiB
Erlang

%%%-------------------------------------------------------------------
%%% Created : 20 Oct 2024 by Pawel Chmielowski <pawel@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2024 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
%%% published by the Free Software Foundation; either version 2 of the
%%% License, or (at your option) any later version.
%%%
%%% This program is distributed in the hope that it will be useful,
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%% You should have received a copy of the GNU General Public License along
%%% with this program; if not, write to the Free Software Foundation, Inc.,
%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
%%%
%%%-------------------------------------------------------------------
-module(mod_s2s_bidi).
-behaviour(gen_mod).
-protocol({xep, 288, '1.0.1', '24.10', "complete", ""}).
%% gen_mod API
-export([start/2, stop/1, reload/3, depends/2, mod_options/1]).
-export([mod_doc/0]).
%% Hooks
-export([s2s_in_packet/2, s2s_out_packet/2,
s2s_in_features/2, s2s_in_auth_result/3, s2s_out_unauthenticated_features/2, s2s_in_handle_info/2]).
-include_lib("xmpp/include/xmpp.hrl").
-include("logger.hrl").
-include("translate.hrl").
%%%===================================================================
%%% API
%%%===================================================================
start(_Host, _Opts) ->
{ok, [{hook, s2s_in_pre_auth_features, s2s_in_features, 50},
{hook, s2s_in_post_auth_features, s2s_in_features, 50},
{hook, s2s_in_unauthenticated_packet, s2s_in_packet, 50},
{hook, s2s_in_authenticated_packet, s2s_in_packet, 50},
{hook, s2s_in_handle_info, s2s_in_handle_info, 50},
{hook, s2s_in_auth_result, s2s_in_auth_result, 50},
{hook, s2s_out_unauthenticated_features, s2s_out_unauthenticated_features, 50},
{hook, s2s_out_packet, s2s_out_packet, 50}]}.
stop(_Host) ->
ok.
reload(_Host, _NewOpts, _OldOpts) ->
ok.
depends(_Host, _Opts) ->
[].
mod_options(_Host) ->
[].
mod_doc() ->
#{desc =>
[?T("The module adds support for "
"https://xmpp.org/extensions/xep-0288.html"
"[XEP-0288: Bidirectional Server-to-Server Connections] that allows using "
"single s2s connection to communicate in both directions.")],
note => "added in 24.10",
opts => [],
example =>
["modules:",
" mod_s2s_bidi: {}"]}.
s2s_in_features(Acc, _) ->
[#s2s_bidi{}|Acc].
s2s_in_packet(State, #s2s_bidi{}) ->
{stop, State#{bidi_enabled => true}};
s2s_in_packet(State, _) ->
State.
s2s_out_unauthenticated_features(#{db_verify := _} = State, _) ->
State;
s2s_out_unauthenticated_features(State, #stream_features{} = Pkt) ->
try xmpp:try_subtag(Pkt, #s2s_bidi{}) of
#s2s_bidi{} ->
ejabberd_s2s_out:send(State#{bidi_enabled => true}, #s2s_bidi{});
_ ->
State
catch _:{xmpp_codec, _Why} ->
State
end;
s2s_out_unauthenticated_features(State, _Pkt) ->
State.
s2s_out_packet(#{bidi_enabled := true, ip := {IP, _}} = State, Pkt0)
when ?is_stanza(Pkt0) ->
To = xmpp:get_to(Pkt0),
case check_from_to(State, xmpp:get_from(Pkt0), To) of
ok ->
Pkt = xmpp:put_meta(Pkt0, ip, IP),
LServer = ejabberd_router:host_of_route(To#jid.lserver),
State1 = ejabberd_hooks:run_fold(s2s_in_authenticated_packet,
LServer, State, [Pkt]),
{Pkt1, State2} = ejabberd_hooks:run_fold(s2s_receive_packet, LServer,
{Pkt, State1}, []),
case Pkt1 of
drop -> ok;
_ -> ejabberd_router:route(Pkt1)
end,
{stop, State2};
{error, Err} ->
{stop, ejabberd_s2s_out:send(State, Err)}
end;
s2s_out_packet(#{db_verify := _} = State, #stream_features{}) ->
State;
s2s_out_packet(State, #stream_features{} = Pkt) ->
try xmpp:try_subtag(Pkt, #s2s_bidi{}) of
#s2s_bidi{} ->
ejabberd_s2s_out:send(State#{bidi_enabled => true}, #s2s_bidi{})
catch _:{xmpp_codec, _Why} ->
State
end;
s2s_out_packet(State, _Pkt) ->
State.
s2s_in_handle_info(State, {route, Pkt}) when ?is_stanza(Pkt) ->
ejabberd_s2s_in:send(State, Pkt);
s2s_in_handle_info(State, _Info) ->
State.
check_from_to(#{remote_server := RServer}, #jid{lserver = FromServer},
#jid{lserver = ToServer}) ->
if
RServer /= FromServer -> {error, xmpp:serr_invalid_from()};
true ->
case ejabberd_router:is_my_route(ToServer) of
false -> {error, xmpp:serr_host_unknown()};
_ -> ok
end
end.
s2s_in_auth_result(#{server := LServer, bidi_enabled := true} = State, true, RServer) ->
ejabberd_s2s:register_connection({LServer, RServer}),
State;
s2s_in_auth_result(State, _, _) ->
State.