diff options
author | Evgeniy Khramtsov <ekhramtsov@process-one.net> | 2014-06-01 13:34:51 +0400 |
---|---|---|
committer | Evgeniy Khramtsov <ekhramtsov@process-one.net> | 2014-06-01 13:35:14 +0400 |
commit | f446e7fc0b230ffb80d382efeb2fe8e18262e306 (patch) | |
tree | 5d9bfd195c50a1f66b07f025638073198243b910 /src/mod_sip_proxy.erl | |
parent | Fix '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.erl | 65 |
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 [] -> []; |