Sign 'Record-Route' in order to proxy unauthorized ACKs

This commit is contained in:
Evgeniy Khramtsov 2014-06-01 13:34:51 +04:00
parent b75b5ebeb2
commit f446e7fc0b
2 changed files with 71 additions and 11 deletions

View File

@ -80,7 +80,9 @@ response(_Resp, _SIPSock) ->
request(#sip{method = <<"ACK">>} = Req, SIPSock) -> request(#sip{method = <<"ACK">>} = Req, SIPSock) ->
case action(Req, SIPSock) of case action(Req, SIPSock) of
{relay, LServer} -> {relay, LServer} ->
mod_sip_proxy:route(Req, LServer, []); mod_sip_proxy:route(Req, LServer, [{authenticated, true}]);
{proxy_auth, LServer} ->
mod_sip_proxy:route(Req, LServer, [{authenticated, false}]);
_ -> _ ->
error error
end; end;
@ -112,20 +114,20 @@ request(Req, SIPSock, TrID, Action) ->
?INFO_MSG("failed to proxy request ~p: ~p", [Req, Err]), ?INFO_MSG("failed to proxy request ~p: ~p", [Req, Err]),
Err Err
end; end;
{proxy_auth, Host} -> {proxy_auth, LServer} ->
make_response( make_response(
Req, Req,
#sip{status = 407, #sip{status = 407,
type = response, type = response,
hdrs = [{'proxy-authenticate', hdrs = [{'proxy-authenticate',
make_auth_hdr(Host)}]}); make_auth_hdr(LServer)}]});
{auth, Host} -> {auth, LServer} ->
make_response( make_response(
Req, Req,
#sip{status = 401, #sip{status = 401,
type = response, type = response,
hdrs = [{'www-authenticate', hdrs = [{'www-authenticate',
make_auth_hdr(Host)}]}); make_auth_hdr(LServer)}]});
deny -> deny ->
make_response(Req, #sip{status = 403, make_response(Req, #sip{status = 403,
type = response}); type = response});
@ -169,7 +171,7 @@ action(#sip{method = <<"REGISTER">>, type = request, hdrs = Hdrs,
true -> true ->
register; register;
false -> false ->
{auth, ToURI#uri.host} {auth, jlib:nameprep(ToURI#uri.host)}
end; end;
false -> false ->
deny deny
@ -259,8 +261,7 @@ process(Req, _) ->
hdrs = [{'allow', allow()}]}). hdrs = [{'allow', allow()}]}).
make_auth_hdr(LServer) -> make_auth_hdr(LServer) ->
Realm = jlib:nameprep(LServer), {<<"Digest">>, [{<<"realm">>, esip:quote(LServer)},
{<<"Digest">>, [{<<"realm">>, esip:quote(Realm)},
{<<"qop">>, esip:quote(<<"auth">>)}, {<<"qop">>, esip:quote(<<"auth">>)},
{<<"nonce">>, esip:quote(esip:make_hexstr(20))}]}. {<<"nonce">>, esip:quote(esip:make_hexstr(20))}]}.

View File

@ -23,6 +23,8 @@
-include("logger.hrl"). -include("logger.hrl").
-include("esip.hrl"). -include("esip.hrl").
-define(SIGN_LIFETIME, 300). %% in seconds.
-record(state, {host = <<"">> :: binary(), -record(state, {host = <<"">> :: binary(),
opts = [] :: [{certfile, binary()}], opts = [] :: [{certfile, binary()}],
orig_trid, orig_trid,
@ -42,7 +44,33 @@ start_link(LServer, Opts) ->
route(SIPMsg, _SIPSock, TrID, Pid) -> route(SIPMsg, _SIPSock, TrID, Pid) ->
?GEN_FSM:send_event(Pid, {SIPMsg, TrID}). ?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), Req1 = prepare_request(LServer, Req),
case connect(Req1, add_certfile(LServer, Opts)) of case connect(Req1, add_certfile(LServer, Opts)) of
{ok, SIPSocketsWithURIs} -> {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 case is_request_within_dialog(Req) of
false -> false ->
RR_URI = get_configured_route(LServer), 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}; Req#sip{uri = URI, hdrs = Hdrs1};
true -> true ->
Req Req
@ -263,6 +295,31 @@ is_request_within_dialog(#sip{hdrs = Hdrs}) ->
{_, _, Params} = esip:get_hdr('to', Hdrs), {_, _, Params} = esip:get_hdr('to', Hdrs),
esip:has_param(<<"tag">>, Params). 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) -> get_configured_vias(LServer) ->
gen_mod:get_module_opt( gen_mod:get_module_opt(
LServer, mod_sip, via, LServer, mod_sip, via,
@ -323,12 +380,14 @@ cmp_uri(_, _) ->
prepare_request(LServer, #sip{hdrs = Hdrs} = Req) -> prepare_request(LServer, #sip{hdrs = Hdrs} = Req) ->
ConfiguredRoute = get_configured_route(LServer), ConfiguredRoute = get_configured_route(LServer),
ConfiguredBareRoute = ConfiguredRoute#uri{user = <<"">>},
Hdrs1 = lists:flatmap( Hdrs1 = lists:flatmap(
fun({Hdr, HdrList}) when Hdr == 'route'; fun({Hdr, HdrList}) when Hdr == 'route';
Hdr == 'record-route' -> Hdr == 'record-route' ->
case lists:filter( case lists:filter(
fun({_, URI, _}) -> fun({_, URI, _}) ->
not cmp_uri(URI, ConfiguredRoute) BareURI = URI#uri{user = <<"">>},
not cmp_uri(BareURI, ConfiguredBareRoute)
end, HdrList) of end, HdrList) of
[] -> [] ->
[]; [];