aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml2
-rw-r--r--Makefile.in2
-rw-r--r--doc/guide.tex12
-rw-r--r--include/ns.hrl1
-rw-r--r--src/ejabberd_auth_external.erl2
-rw-r--r--src/ejabberd_c2s.erl150
-rw-r--r--src/ejabberd_odbc.erl2
-rw-r--r--src/mod_carboncopy.erl37
-rw-r--r--src/mod_muc_log.erl24
-rw-r--r--src/mod_offline.erl39
-rw-r--r--src/mod_sip.erl21
-rw-r--r--src/mod_sip_proxy.erl54
-rw-r--r--src/mod_sip_registrar.erl7
13 files changed, 210 insertions, 143 deletions
diff --git a/.travis.yml b/.travis.yml
index 5b093b668..f04d55bda 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -20,7 +20,7 @@ before_script:
script:
- ./autogen.sh
- - ./configure --enable-transient_supervisors --enable-all --disable-http --disable-odbc
+ - ./configure --enable-all --disable-http --disable-odbc
- make
- make test
- grep -q 'TEST COMPLETE, \([[:digit:]]*\) ok, .* of \1 ' logs/raw.log
diff --git a/Makefile.in b/Makefile.in
index 3350d32cc..b0d8be31b 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -151,6 +151,8 @@ install: all
# Binary C programs
$(INSTALL) -d $(PBINDIR)
$(INSTALL) -m 750 $(O_USER) tools/captcha.sh $(PBINDIR)
+ -[ -f deps/p1_pam/priv/bin/epam ] \
+ && $(INSTALL) -m 750 $(O_USER) deps/p1_pam/priv/bin/epam $(PBINDIR)
#
# Binary system libraries
$(INSTALL) -d $(SODIR)
diff --git a/doc/guide.tex b/doc/guide.tex
index d0afd38a6..a7ff11fff 100644
--- a/doc/guide.tex
+++ b/doc/guide.tex
@@ -930,8 +930,10 @@ This is a detailed description of each option allowed by the listening modules:
\titem{ciphers: Ciphers} OpenSSL ciphers list in the same format accepted by
`\verb|openssl ciphers|' command.
\titem{protocol\_options: ProtocolOpts} \ind{options!protocol\_options}
- List of general options relating to SSL/TLS. These map to \verb|<a href="https://www.openssl.org/docs/ssl/SSL_CTX_set_options.html">OpenSSL's set_options()</a>|.
- For a full list of options available in ejabberd, \verb|<a href="https://github.com/processone/tls/blob/master/c_src/options.h">see the source</a>|.
+ List of general options relating to SSL/TLS. These map to
+ \footahref{https://www.openssl.org/docs/ssl/SSL\_CTX\_set\_options.html}{OpenSSL's set\_options()}.
+ For a full list of options available in ejabberd,
+ \footahref{https://github.com/processone/tls/blob/master/c\_src/options.h}{see the source}.
The default entry is: \verb|"no_sslv2"|
\titem{default\_host: undefined|HostName\}}
If the HTTP request received by ejabberd contains the HTTP header \term{Host}
@@ -1110,8 +1112,10 @@ There are some additional global options that can be specified in the ejabberd c
\titem{s2s\_ciphers: Ciphers} \ind{options!s2s\_ciphers} OpenSSL ciphers list
in the same format accepted by `\verb|openssl ciphers|' command.
\titem{s2s\_protocol\_options: ProtocolOpts} \ind{options!s2s\_protocol\_options}
- List of general options relating to SSL/TLS. These map to \verb|<a href="https://www.openssl.org/docs/ssl/SSL_CTX_set_options.html">OpenSSL's set_options()</a>|.
- For a full list of options available in ejabberd, \verb|<a href="https://github.com/processone/tls/blob/protocol_options/c_src/options.h">see the source</a>|.
+ List of general options relating to SSL/TLS. These map to
+ \footahref{https://www.openssl.org/docs/ssl/SSL\_CTX\_set\_options.html}{OpenSSL's set\_options()}.
+ For a full list of options available in ejabberd,
+ \footahref{https://github.com/processone/tls/blob/master/c\_src/options.h}{see the source}.
The default entry is: \verb|"no_sslv2"|
\titem{outgoing\_s2s\_families: [Family, ...]} \ind{options!outgoing\_s2s\_families}
Specify which address families to try, in what order.
diff --git a/include/ns.hrl b/include/ns.hrl
index aa6150cfd..ac8105e9c 100644
--- a/include/ns.hrl
+++ b/include/ns.hrl
@@ -42,6 +42,7 @@
-define(NS_IQDATA, <<"jabber:iq:data">>).
-define(NS_DELAY91, <<"jabber:x:delay">>).
-define(NS_DELAY, <<"urn:xmpp:delay">>).
+-define(NS_HINTS, <<"urn:xmpp:hints">>).
-define(NS_EXPIRE, <<"jabber:x:expire">>).
-define(NS_EVENT, <<"jabber:x:event">>).
-define(NS_CHATSTATES,
diff --git a/src/ejabberd_auth_external.erl b/src/ejabberd_auth_external.erl
index 51c1c620a..74263f748 100644
--- a/src/ejabberd_auth_external.erl
+++ b/src/ejabberd_auth_external.erl
@@ -186,6 +186,8 @@ check_password_extauth(User, Server, Password) ->
try_register_extauth(User, Server, Password) ->
extauth:try_register(User, Server, Password).
+check_password_cache(User, Server, Password, 0) ->
+ check_password_external_cache(User, Server, Password);
check_password_cache(User, Server, Password,
CacheTime) ->
case get_last_access(User, Server) of
diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl
index 00ecaa008..14bd4fb7a 100644
--- a/src/ejabberd_c2s.erl
+++ b/src/ejabberd_c2s.erl
@@ -788,18 +788,11 @@ wait_for_feature_request({xmlstreamelement, El},
StateData#state.tls_options)]
end,
Socket = StateData#state.socket,
+ BProceed = xml:element_to_binary(#xmlel{name = <<"proceed">>,
+ attrs = [{<<"xmlns">>, ?NS_TLS}]}),
TLSSocket = (StateData#state.sockmod):starttls(Socket,
TLSOpts,
- xml:element_to_binary(#xmlel{name
- =
- <<"proceed">>,
- attrs
- =
- [{<<"xmlns">>,
- ?NS_TLS}],
- children
- =
- []})),
+ BProceed),
fsm_next_state(wait_for_stream,
StateData#state{socket = TLSSocket,
streamid = new_id(),
@@ -820,17 +813,10 @@ wait_for_feature_request({xmlstreamelement, El},
case xml:get_tag_cdata(Method) of
<<"zlib">> ->
Socket = StateData#state.socket,
+ BCompressed = xml:element_to_binary(#xmlel{name = <<"compressed">>,
+ attrs = [{<<"xmlns">>, ?NS_COMPRESS}]}),
ZlibSocket = (StateData#state.sockmod):compress(Socket,
- xml:element_to_binary(#xmlel{name
- =
- <<"compressed">>,
- attrs
- =
- [{<<"xmlns">>,
- ?NS_COMPRESS}],
- children
- =
- []})),
+ BCompressed),
fsm_next_state(wait_for_stream,
StateData#state{socket = ZlibSocket,
streamid = new_id()});
@@ -973,9 +959,7 @@ wait_for_sasl_response(closed, StateData) ->
{stop, normal, StateData}.
resource_conflict_action(U, S, R) ->
- OptionRaw = case ejabberd_sm:is_existing_resource(U, S,
- R)
- of
+ OptionRaw = case ejabberd_sm:is_existing_resource(U, S, R) of
true ->
ejabberd_config:get_option(
{resource_conflict, S},
@@ -1096,7 +1080,7 @@ wait_for_session({xmlstreamelement, El}, StateData) ->
?INFO_MSG("(~w) Opened session for ~s",
[NewStateData#state.socket,
jlib:jid_to_string(JID)]),
- Res = jlib:make_result_iq_reply(El#xmlel{children = []}),
+ Res = jlib:make_result_iq_reply(El#xmlel{children = []}),
NewState = send_stanza(NewStateData, Res),
change_shaper(NewState, JID),
{Fs, Ts} = ejabberd_hooks:run_fold(
@@ -1224,13 +1208,7 @@ session_established2(El, StateData) ->
_ ->
Err = jlib:make_error_reply(NewEl,
?ERR_JID_MALFORMED),
- case is_stanza(Err) of
- true ->
- send_stanza(NewStateData, Err);
- false ->
- send_element(NewStateData, Err),
- NewStateData
- end
+ send_packet(NewStateData, Err)
end;
_ ->
case Name of
@@ -1662,7 +1640,7 @@ handle_info({route, From, To,
jlib:replace_from_to_attrs(jlib:jid_to_string(From),
jlib:jid_to_string(To), NewAttrs),
FixedPacket = #xmlel{name = Name, attrs = Attrs2, children = Els},
- SentStateData = send_stanza(NewState, FixedPacket),
+ SentStateData = send_packet(NewState, FixedPacket),
ejabberd_hooks:run(user_receive_packet,
SentStateData#state.server,
[SentStateData#state.jid, From, To, FixedPacket]),
@@ -1853,6 +1831,19 @@ send_stanza(StateData, Stanza) ->
send_element(StateData, Stanza),
StateData.
+send_packet(StateData, Packet) when StateData#state.mgmt_state == active;
+ StateData#state.mgmt_state == pending ->
+ case is_stanza(Packet) of
+ true ->
+ send_stanza(StateData, Packet);
+ false ->
+ send_element(StateData, Packet),
+ StateData
+ end;
+send_packet(StateData, Stanza) ->
+ send_element(StateData, Stanza),
+ StateData.
+
send_header(StateData, Server, Version, Lang)
when StateData#state.xml_socket ->
VersionAttr = case Version of
@@ -1901,12 +1892,11 @@ new_id() -> randoms:get_string().
is_auth_packet(El) ->
case jlib:iq_query_info(El) of
- #iq{id = ID, type = Type, xmlns = ?NS_AUTH,
- sub_el = SubEl} ->
- #xmlel{children = Els} = SubEl,
- {auth, ID, Type,
- get_auth_tags(Els, <<"">>, <<"">>, <<"">>, <<"">>)};
- _ -> false
+ #iq{id = ID, type = Type, xmlns = ?NS_AUTH, sub_el = SubEl} ->
+ #xmlel{children = Els} = SubEl,
+ {auth, ID, Type,
+ get_auth_tags(Els, <<"">>, <<"">>, <<"">>, <<"">>)};
+ _ -> false
end.
is_stanza(#xmlel{name = Name, attrs = Attrs}) when Name == <<"message">>;
@@ -2229,18 +2219,16 @@ remove_element(E, Set) ->
roster_change(IJID, ISubscription, StateData) ->
LIJID = jlib:jid_tolower(IJID),
- IsFrom = (ISubscription == both) or
- (ISubscription == from),
+ IsFrom = (ISubscription == both) or (ISubscription == from),
IsTo = (ISubscription == both) or (ISubscription == to),
- OldIsFrom = (?SETS):is_element(LIJID,
- StateData#state.pres_f),
- FSet = if IsFrom ->
- (?SETS):add_element(LIJID, StateData#state.pres_f);
- true -> remove_element(LIJID, StateData#state.pres_f)
+ OldIsFrom = (?SETS):is_element(LIJID, StateData#state.pres_f),
+ FSet = if
+ IsFrom -> (?SETS):add_element(LIJID, StateData#state.pres_f);
+ not IsFrom -> remove_element(LIJID, StateData#state.pres_f)
end,
- TSet = if IsTo ->
- (?SETS):add_element(LIJID, StateData#state.pres_t);
- true -> remove_element(LIJID, StateData#state.pres_t)
+ TSet = if
+ IsTo -> (?SETS):add_element(LIJID, StateData#state.pres_t);
+ not IsTo -> remove_element(LIJID, StateData#state.pres_t)
end,
case StateData#state.pres_last of
undefined ->
@@ -2334,11 +2322,10 @@ process_privacy_iq(From, To,
NewStateData.
resend_offline_messages(StateData) ->
- case
- ejabberd_hooks:run_fold(resend_offline_messages_hook,
- StateData#state.server, [],
- [StateData#state.user, StateData#state.server])
- of
+ case ejabberd_hooks:run_fold(resend_offline_messages_hook,
+ StateData#state.server, [],
+ [StateData#state.user, StateData#state.server])
+ of
Rs -> %%when is_list(Rs) ->
lists:foreach(fun ({route, From, To,
#xmlel{} = Packet}) ->
@@ -2358,33 +2345,26 @@ resend_offline_messages(StateData) ->
end.
resend_subscription_requests(#state{user = User,
- server = Server} =
- StateData) ->
+ server = Server} = StateData) ->
PendingSubscriptions =
ejabberd_hooks:run_fold(resend_subscription_requests_hook,
Server, [], [User, Server]),
lists:foldl(fun (XMLPacket, AccStateData) ->
- send_stanza(AccStateData, XMLPacket)
+ send_packet(AccStateData, XMLPacket)
end,
StateData,
PendingSubscriptions).
get_showtag(undefined) -> <<"unavailable">>;
get_showtag(Presence) ->
- case xml:get_path_s(Presence,
- [{elem, <<"show">>}, cdata])
- of
- <<"">> -> <<"available">>;
- ShowTag -> ShowTag
+ case xml:get_path_s(Presence, [{elem, <<"show">>}, cdata]) of
+ <<"">> -> <<"available">>;
+ ShowTag -> ShowTag
end.
get_statustag(undefined) -> <<"">>;
get_statustag(Presence) ->
- case xml:get_path_s(Presence,
- [{elem, <<"status">>}, cdata])
- of
- ShowTag -> ShowTag
- end.
+ xml:get_path_s(Presence, [{elem, <<"status">>}, cdata]).
process_unauthenticated_stanza(StateData, El) ->
NewEl = case xml:get_tag_attr_s(<<"xml:lang">>, El) of
@@ -2484,23 +2464,27 @@ is_ip_blacklisted({IP, _Port}) ->
%% returns invalid-from|NewElement
check_from(El, FromJID) ->
case xml:get_tag_attr(<<"from">>, El) of
- false -> El;
- {value, SJID} ->
- JID = jlib:string_to_jid(SJID),
- case JID of
- error -> 'invalid-from';
- #jid{} ->
- if (JID#jid.luser == FromJID#jid.luser) and
- (JID#jid.lserver == FromJID#jid.lserver)
- and (JID#jid.lresource == FromJID#jid.lresource) ->
- El;
- (JID#jid.luser == FromJID#jid.luser) and
- (JID#jid.lserver == FromJID#jid.lserver)
- and (JID#jid.lresource == <<"">>) ->
- El;
- true -> 'invalid-from'
- end
- end
+ false ->
+ El;
+ {value, SJID} ->
+ JID = jlib:string_to_jid(SJID),
+ case JID of
+ error ->
+ 'invalid-from';
+ #jid{} ->
+ if
+ (JID#jid.luser == FromJID#jid.luser) and
+ (JID#jid.lserver == FromJID#jid.lserver) and
+ (JID#jid.lresource == FromJID#jid.lresource) ->
+ El;
+ (JID#jid.luser == FromJID#jid.luser) and
+ (JID#jid.lserver == FromJID#jid.lserver) and
+ (JID#jid.lresource == <<"">>) ->
+ El;
+ true ->
+ 'invalid-from'
+ end
+ end
end.
fsm_limit_opts(Opts) ->
diff --git a/src/ejabberd_odbc.erl b/src/ejabberd_odbc.erl
index 2b852bfaa..49a4f30b4 100644
--- a/src/ejabberd_odbc.erl
+++ b/src/ejabberd_odbc.erl
@@ -588,7 +588,7 @@ db_opts(Host) ->
[odbc, Server];
_ ->
Port = ejabberd_config:get_option(
- {port, Host},
+ {odbc_port, Host},
fun(P) when is_integer(P), P > 0, P < 65536 -> P end,
case Type of
mysql -> ?MYSQL_PORT;
diff --git a/src/mod_carboncopy.erl b/src/mod_carboncopy.erl
index 16f0c06fc..6f3101fcd 100644
--- a/src/mod_carboncopy.erl
+++ b/src/mod_carboncopy.erl
@@ -143,24 +143,29 @@ check_and_forward(JID, To, #xmlel{name = <<"message">>, attrs = Attrs} = Packet,
<<"chat">> ->
case xml:get_subtag(Packet, <<"private">>) of
false ->
- case xml:get_subtag(Packet,<<"received">>) of
+ case xml:get_subtag(Packet, <<"no-copy">>) of
false ->
- %% We must check if a packet contains "<sent><forwarded></sent></forwarded>" tags in order to avoid
- %% receiving message back to original sender.
- SubTag = xml:get_subtag(Packet,<<"sent">>),
- if SubTag == false ->
- send_copies(JID, To, Packet, Direction);
- true ->
- case xml:get_subtag(SubTag,<<"forwarded">>) of
- false->
- send_copies(JID, To, Packet, Direction);
- _ ->
- stop
- end
- end;
+ case xml:get_subtag(Packet,<<"received">>) of
+ false ->
+ %% We must check if a packet contains "<sent><forwarded></sent></forwarded>"
+ %% tags in order to avoid receiving message back to original sender.
+ SubTag = xml:get_subtag(Packet,<<"sent">>),
+ if SubTag == false ->
+ send_copies(JID, To, Packet, Direction);
+ true ->
+ case xml:get_subtag(SubTag,<<"forwarded">>) of
+ false->
+ send_copies(JID, To, Packet, Direction);
+ _ ->
+ stop
+ end
+ end;
+ _ ->
+ %% stop the hook chain, we don't want mod_logdb to register this message (duplicate)
+ stop
+ end;
_ ->
- %% stop the hook chain, we don't want mod_logdb to register this message (duplicate)
- stop
+ ok
end;
_ ->
ok
diff --git a/src/mod_muc_log.erl b/src/mod_muc_log.erl
index b4db67b3d..ac6bea4fa 100644
--- a/src/mod_muc_log.erl
+++ b/src/mod_muc_log.erl
@@ -233,16 +233,22 @@ code_change(_OldVsn, State, _Extra) -> {ok, State}.
%%% Internal functions
%%--------------------------------------------------------------------
add_to_log2(text, {Nick, Packet}, Room, Opts, State) ->
- case {xml:get_subtag(Packet, <<"subject">>),
- xml:get_subtag(Packet, <<"body">>)}
+ case {xml:get_subtag(Packet, <<"no-store">>),
+ xml:get_subtag(Packet, <<"no-permanent-store">>)}
of
- {false, false} -> ok;
- {false, SubEl} ->
- Message = {body, xml:get_tag_cdata(SubEl)},
- add_message_to_log(Nick, Message, Room, Opts, State);
- {SubEl, _} ->
- Message = {subject, xml:get_tag_cdata(SubEl)},
- add_message_to_log(Nick, Message, Room, Opts, State)
+ {false, false} ->
+ case {xml:get_subtag(Packet, <<"subject">>),
+ xml:get_subtag(Packet, <<"body">>)}
+ of
+ {false, false} -> ok;
+ {false, SubEl} ->
+ Message = {body, xml:get_tag_cdata(SubEl)},
+ add_message_to_log(Nick, Message, Room, Opts, State);
+ {SubEl, _} ->
+ Message = {subject, xml:get_tag_cdata(SubEl)},
+ add_message_to_log(Nick, Message, Room, Opts, State)
+ end;
+ {_, _} -> ok
end;
add_to_log2(roomconfig_change, _Occupants, Room, Opts,
State) ->
diff --git a/src/mod_offline.erl b/src/mod_offline.erl
index fca227d31..f27d35830 100644
--- a/src/mod_offline.erl
+++ b/src/mod_offline.erl
@@ -237,22 +237,39 @@ store_packet(From, To, Packet) ->
Type = xml:get_tag_attr_s(<<"type">>, Packet),
if (Type /= <<"error">>) and (Type /= <<"groupchat">>)
and (Type /= <<"headline">>) ->
- case check_event(From, To, Packet) of
- true ->
- #jid{luser = LUser, lserver = LServer} = To,
- TimeStamp = now(),
- #xmlel{children = Els} = Packet,
- Expire = find_x_expire(TimeStamp, Els),
- gen_mod:get_module_proc(To#jid.lserver, ?PROCNAME) !
- #offline_msg{us = {LUser, LServer},
- timestamp = TimeStamp, expire = Expire,
- from = From, to = To, packet = Packet},
- stop;
+ case has_no_storage_hint(Packet) of
+ false ->
+ case check_event(From, To, Packet) of
+ true ->
+ #jid{luser = LUser, lserver = LServer} = To,
+ TimeStamp = now(),
+ #xmlel{children = Els} = Packet,
+ Expire = find_x_expire(TimeStamp, Els),
+ gen_mod:get_module_proc(To#jid.lserver, ?PROCNAME) !
+ #offline_msg{us = {LUser, LServer},
+ timestamp = TimeStamp, expire = Expire,
+ from = From, to = To, packet = Packet},
+ stop;
+ _ -> ok
+ end;
_ -> ok
end;
true -> ok
end.
+has_no_storage_hint(Packet) ->
+ case xml:get_subtag(Packet, <<"no-store">>) of
+ #xmlel{attrs = Attrs} ->
+ case xml:get_attr_s(<<"xmlns">>, Attrs) of
+ ?NS_HINTS ->
+ true;
+ _ ->
+ false
+ end;
+ _ ->
+ false
+ end.
+
%% Check if the packet has any content about XEP-0022 or XEP-0085
check_event(From, To, Packet) ->
#xmlel{name = Name, attrs = Attrs, children = Els} =
diff --git a/src/mod_sip.erl b/src/mod_sip.erl
index 8ed4ed8cf..4b733c623 100644
--- a/src/mod_sip.erl
+++ b/src/mod_sip.erl
@@ -12,7 +12,7 @@
-behaviour(esip).
%% API
--export([start/2, stop/1, prepare_request/1, make_response/2, at_my_host/1]).
+-export([start/2, stop/1, make_response/2, is_my_host/1, at_my_host/1]).
%% esip_callbacks
-export([data_in/2, data_out/2, message_in/2, message_out/2,
@@ -77,6 +77,13 @@ message_out(_, _) ->
response(_Resp, _SIPSock) ->
ok.
+request(#sip{method = <<"ACK">>} = Req, SIPSock) ->
+ case action(Req, SIPSock) of
+ {relay, LServer} ->
+ mod_sip_proxy:route(Req, LServer, []);
+ _ ->
+ error
+ end;
request(_Req, _SIPSock) ->
error.
@@ -251,18 +258,6 @@ process(Req, _) ->
make_response(Req, #sip{type = response, status = 405,
hdrs = [{'allow', allow()}]}).
-prepare_request(#sip{hdrs = Hdrs1} = Req) ->
- MF = esip:get_hdr('max-forwards', Hdrs1),
- Hdrs2 = esip:set_hdr('max-forwards', MF-1, Hdrs1),
- Hdrs3 = lists:filter(
- fun({'proxy-authorization', {_, Params}}) ->
- Realm = esip:unquote(esip:get_param(<<"realm">>, Params)),
- not is_my_host(jlib:nameprep(Realm));
- (_) ->
- true
- end, Hdrs2),
- Req#sip{hdrs = Hdrs3}.
-
make_auth_hdr(LServer) ->
Realm = jlib:nameprep(LServer),
{<<"Digest">>, [{<<"realm">>, esip:quote(Realm)},
diff --git a/src/mod_sip_proxy.erl b/src/mod_sip_proxy.erl
index cae75bff8..b05c49061 100644
--- a/src/mod_sip_proxy.erl
+++ b/src/mod_sip_proxy.erl
@@ -12,7 +12,7 @@
-behaviour(?GEN_FSM).
%% API
--export([start/2, start_link/2, route/4]).
+-export([start/2, start_link/2, route/3, route/4]).
%% gen_fsm callbacks
-export([init/1, wait_for_request/2, wait_for_response/2,
@@ -42,6 +42,19 @@ start_link(LServer, Opts) ->
route(SIPMsg, _SIPSock, TrID, Pid) ->
?GEN_FSM:send_event(Pid, {SIPMsg, TrID}).
+route(Req, LServer, Opts) ->
+ Req1 = prepare_request(LServer, Req),
+ case connect(Req1, add_certfile(LServer, Opts)) of
+ {ok, SIPSockets} ->
+ lists:foreach(
+ fun(SIPSocket) ->
+ Req2 = add_via(SIPSocket, LServer, Req1),
+ esip:send(SIPSocket, Req2)
+ end, SIPSockets);
+ _ ->
+ error
+ end.
+
%%%===================================================================
%%% gen_fsm callbacks
%%%===================================================================
@@ -51,7 +64,7 @@ init([Host, Opts]) ->
wait_for_request({#sip{type = request} = Req, TrID}, State) ->
Opts = State#state.opts,
- Req1 = mod_sip:prepare_request(Req),
+ Req1 = prepare_request(State#state.host, Req),
case connect(Req1, Opts) of
{ok, SIPSockets} ->
NewState =
@@ -59,8 +72,9 @@ wait_for_request({#sip{type = request} = Req, TrID}, State) ->
fun(_SIPSocket, {error, _} = Err) ->
Err;
(SIPSocket, #state{tr_ids = TrIDs} = AccState) ->
- Req2 = add_via(SIPSocket, State#state.host, Req1),
- case esip:request(SIPSocket, Req2,
+ Req2 = add_record_route(SIPSocket, State#state.host, Req1),
+ Req3 = add_via(SIPSocket, State#state.host, Req2),
+ case esip:request(SIPSocket, Req3,
{?MODULE, route, [self()]}) of
{ok, ClientTrID} ->
NewTrIDs = [ClientTrID|TrIDs],
@@ -234,6 +248,11 @@ add_via(#sip_socket{type = Transport}, LServer, #sip{hdrs = Hdrs} = Req) ->
{<<"rport">>, <<"">>}]},
Req#sip{hdrs = [{'via', [Via]}|Hdrs]}.
+add_record_route(_SIPSocket, LServer, #sip{hdrs = Hdrs} = Req) ->
+ URI = #uri{host = LServer, params = [{<<"lr">>, <<"">>}]},
+ Hdrs1 = [{'record-route', [{<<>>, URI, []}]}|Hdrs],
+ Req#sip{hdrs = Hdrs1}.
+
get_configured_vias(LServer) ->
gen_mod:get_module_opt(
LServer, ?MODULE, via,
@@ -275,3 +294,30 @@ choose_best_response(#state{responses = Responses} = State) ->
ok
end
end.
+
+prepare_request(Host, #sip{hdrs = Hdrs} = Req) ->
+ Hdrs1 = lists:flatmap(
+ fun({Hdr, HdrList}) when Hdr == 'route';
+ Hdr == 'record-route' ->
+ case lists:filter(
+ fun({_, #uri{user = <<"">>, host = Host1}, _}) ->
+ Host1 /= Host
+ end, HdrList) of
+ [] ->
+ [];
+ HdrList1 ->
+ [{Hdr, HdrList1}]
+ end;
+ (Hdr) ->
+ [Hdr]
+ end, Hdrs),
+ MF = esip:get_hdr('max-forwards', Hdrs1),
+ Hdrs2 = esip:set_hdr('max-forwards', MF-1, Hdrs1),
+ Hdrs3 = lists:filter(
+ fun({'proxy-authorization', {_, Params}}) ->
+ Realm = esip:unquote(esip:get_param(<<"realm">>, Params)),
+ not mod_sip:is_my_host(jlib:nameprep(Realm));
+ (_) ->
+ true
+ end, Hdrs2),
+ Req#sip{hdrs = Hdrs3}.
diff --git a/src/mod_sip_registrar.erl b/src/mod_sip_registrar.erl
index 57c55be08..689efe48e 100644
--- a/src/mod_sip_registrar.erl
+++ b/src/mod_sip_registrar.erl
@@ -57,8 +57,13 @@ request(#sip{hdrs = Hdrs} = Req, SIPSock) ->
ok ->
?INFO_MSG("unregister SIP session for user ~s@~s from ~s",
[LUser, LServer, inet_parse:ntoa(PeerIP)]),
+ Contact = {<<"">>, #uri{user = LUser, host = LServer},
+ [{<<"expires">>, <<"0">>}]},
mod_sip:make_response(
- Req, #sip{type = response, status = 200});
+ Req,
+ #sip{type = response,
+ status = 200,
+ hdrs = [{'contact', [Contact]}]});
{error, Why} ->
{Status, Reason} = make_status(Why),
mod_sip:make_response(