summaryrefslogtreecommitdiff
path: root/src/mod_sip_proxy.erl
diff options
context:
space:
mode:
authorEvgeniy Khramtsov <ekhramtsov@process-one.net>2014-06-01 13:34:51 +0400
committerEvgeniy Khramtsov <ekhramtsov@process-one.net>2014-06-01 13:35:14 +0400
commitf446e7fc0b230ffb80d382efeb2fe8e18262e306 (patch)
tree5d9bfd195c50a1f66b07f025638073198243b910 /src/mod_sip_proxy.erl
parentFix 'via' option lookup (diff)
Sign 'Record-Route' in order to proxy unauthorized ACKs
Diffstat (limited to 'src/mod_sip_proxy.erl')
-rw-r--r--src/mod_sip_proxy.erl65
1 files changed, 62 insertions, 3 deletions
diff --git a/src/mod_sip_proxy.erl b/src/mod_sip_proxy.erl
index f25acbd4..2294ba45 100644
--- a/src/mod_sip_proxy.erl
+++ b/src/mod_sip_proxy.erl
@@ -23,6 +23,8 @@
-include("logger.hrl").
-include("esip.hrl").
+-define(SIGN_LIFETIME, 300). %% in seconds.
+
-record(state, {host = <<"">> :: binary(),
opts = [] :: [{certfile, binary()}],
orig_trid,
@@ -42,7 +44,33 @@ start_link(LServer, Opts) ->
route(SIPMsg, _SIPSock, TrID, Pid) ->
?GEN_FSM:send_event(Pid, {SIPMsg, TrID}).
-route(Req, LServer, Opts) ->
+route(#sip{hdrs = Hdrs} = Req, LServer, Opts) ->
+ case proplists:get_bool(authenticated, Opts) of
+ true ->
+ route_statelessly(Req, LServer, Opts);
+ false ->
+ ConfiguredRoute = get_configured_route(LServer),
+ ConfiguredBareRoute = ConfiguredRoute#uri{user = <<"">>},
+ case esip:get_hdrs('route', Hdrs) of
+ [{_, URI, _}|_] ->
+ BareURI = URI#uri{user = <<"">>},
+ case cmp_uri(BareURI, ConfiguredBareRoute) of
+ true ->
+ case is_signed_by_me(URI#uri.user, Hdrs) of
+ true ->
+ route_statelessly(Req, LServer, Opts);
+ false ->
+ error
+ end;
+ false ->
+ error
+ end;
+ [] ->
+ error
+ end
+ end.
+
+route_statelessly(Req, LServer, Opts) ->
Req1 = prepare_request(LServer, Req),
case connect(Req1, add_certfile(LServer, Opts)) of
{ok, SIPSocketsWithURIs} ->
@@ -253,7 +281,11 @@ add_record_route_and_set_uri(URI, LServer, #sip{hdrs = Hdrs} = Req) ->
case is_request_within_dialog(Req) of
false ->
RR_URI = get_configured_route(LServer),
- Hdrs1 = [{'record-route', [{<<>>, RR_URI, []}]}|Hdrs],
+ {MSecs, Secs, _} = now(),
+ TS = list_to_binary(integer_to_list(MSecs*1000000 + Secs)),
+ Sign = make_sign(TS, Hdrs),
+ NewRR_URI = RR_URI#uri{user = <<TS/binary, $-, Sign/binary>>},
+ Hdrs1 = [{'record-route', [{<<>>, NewRR_URI, []}]}|Hdrs],
Req#sip{uri = URI, hdrs = Hdrs1};
true ->
Req
@@ -263,6 +295,31 @@ is_request_within_dialog(#sip{hdrs = Hdrs}) ->
{_, _, Params} = esip:get_hdr('to', Hdrs),
esip:has_param(<<"tag">>, Params).
+make_sign(TS, Hdrs) ->
+ {_, #uri{user = FUser, host = FServer}, FParams} = esip:get_hdr('from', Hdrs),
+ {_, #uri{user = TUser, host = TServer}, _} = esip:get_hdr('to', Hdrs),
+ LFUser = jlib:nodeprep(FUser),
+ LTUser = jlib:nodeprep(TUser),
+ LFServer = jlib:nameprep(FServer),
+ LTServer = jlib:nameprep(TServer),
+ FromTag = esip:get_param(<<"tag">>, FParams),
+ CallID = esip:get_hdr('call-id', Hdrs),
+ SharedKey = ejabberd_config:get_option(shared_key, fun(V) -> V end),
+ p1_sha:sha([SharedKey, LFUser, LFServer, LTUser, LTServer,
+ FromTag, CallID, TS]).
+
+is_signed_by_me(TS_Sign, Hdrs) ->
+ try
+ [TSBin, Sign] = str:tokens(TS_Sign, <<"-">>),
+ TS = list_to_integer(binary_to_list(TSBin)),
+ {MSecs, Secs, _} = now(),
+ NowTS = MSecs*1000000 + Secs,
+ true = (NowTS - TS) =< ?SIGN_LIFETIME,
+ Sign == make_sign(TSBin, Hdrs)
+ catch _:_ ->
+ false
+ end.
+
get_configured_vias(LServer) ->
gen_mod:get_module_opt(
LServer, mod_sip, via,
@@ -323,12 +380,14 @@ cmp_uri(_, _) ->
prepare_request(LServer, #sip{hdrs = Hdrs} = Req) ->
ConfiguredRoute = get_configured_route(LServer),
+ ConfiguredBareRoute = ConfiguredRoute#uri{user = <<"">>},
Hdrs1 = lists:flatmap(
fun({Hdr, HdrList}) when Hdr == 'route';
Hdr == 'record-route' ->
case lists:filter(
fun({_, URI, _}) ->
- not cmp_uri(URI, ConfiguredRoute)
+ BareURI = URI#uri{user = <<"">>},
+ not cmp_uri(BareURI, ConfiguredBareRoute)
end, HdrList) of
[] ->
[];