diff options
-rw-r--r-- | .travis.yml | 2 | ||||
-rw-r--r-- | Makefile.in | 2 | ||||
-rw-r--r-- | doc/guide.tex | 12 | ||||
-rw-r--r-- | include/ns.hrl | 1 | ||||
-rw-r--r-- | src/ejabberd_auth_external.erl | 2 | ||||
-rw-r--r-- | src/ejabberd_c2s.erl | 150 | ||||
-rw-r--r-- | src/ejabberd_odbc.erl | 2 | ||||
-rw-r--r-- | src/mod_carboncopy.erl | 37 | ||||
-rw-r--r-- | src/mod_muc_log.erl | 24 | ||||
-rw-r--r-- | src/mod_offline.erl | 39 | ||||
-rw-r--r-- | src/mod_sip.erl | 21 | ||||
-rw-r--r-- | src/mod_sip_proxy.erl | 54 | ||||
-rw-r--r-- | src/mod_sip_registrar.erl | 7 |
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( |