summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2011-02-10 09:48:15 +0100
committerHarald Welte <laforge@gnumonks.org>2011-02-10 09:48:15 +0100
commit6ef56d0a73ed192388be9eb85075f244413cbffb (patch)
tree641a62086a167ef367ac318e68b1b3f3b1b05f8f
parent0aa140b166b4a590b0fdfd28593d546e105028f6 (diff)
introcue new MAP translation code
-rw-r--r--src/map_masq.erl290
1 files changed, 290 insertions, 0 deletions
diff --git a/src/map_masq.erl b/src/map_masq.erl
new file mode 100644
index 0000000..06ec88c
--- /dev/null
+++ b/src/map_masq.erl
@@ -0,0 +1,290 @@
+% MAP masquerading application
+
+% (C) 2010-2011 by Harald Welte <laforge@gnumonks.org>
+% (C) 2010-2011 by On-Waves
+%
+% All Rights Reserved
+%
+% This program is free software; you can redistribute it and/or modify
+% it under the terms of the GNU General Public License as published by
+% the Free Software Foundation; either version 2 of the License, or
+% (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License along
+% with this program; if not, write to the Free Software Foundation, Inc.,
+% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+
+-module(map_masq).
+-author('Harald Welte <laforge@gnumonks.org>').
+%-compile(export_all).
+
+-export([mangle_map/1]).
+
+-define(PATCH_HLR_NUMBER, [1]).
+-define(PATCH_SGSN_NUMBER, [2]).
+-define(PATCH_SGSN_ADDRESS, [3]).
+-define(PATCH_VMSC_ADDRESS, [4]).
+-define(PATCH_GSMSCF_ADDRESS, [5]).
+
+-include_lib("osmo_map/include/map.hrl").
+
+mangle_msisdn(from_stp, _Opcode, AddrIn) ->
+ {ok, IntPfx} = application:get_env(intern_pfx),
+ mgw_nat:isup_party_internationalize(AddrIn, IntPfx).
+
+patch(#'SendRoutingInfoArg'{msisdn = Msisdn} = P) ->
+ AddrInDec = map_codec:parse_addr_string(Msisdn),
+ io:format("MSISDN IN = ~p~n", [AddrInDec]),
+ AddrOutDec = mangle_msisdn(from_stp, 22, AddrInDec),
+ io:format("MSISDN OUT = ~p~n", [AddrOutDec]),
+ AddrOutBin = map_codec:encode_addr_string(AddrOutDec),
+ P#'SendRoutingInfoArg'{msisdn = AddrOutBin};
+
+% patch a UpdateGprsLocationArg and replace SGSN number and SGSN address
+% !!! TESTING ONLY !!!
+patch(#'UpdateGprsLocationArg'{} = P) ->
+ P#'UpdateGprsLocationArg'{'sgsn-Number'= ?PATCH_SGSN_NUMBER,
+ 'sgsn-Address' = ?PATCH_SGSN_ADDRESS};
+
+% Some other SGSN is sendingu us a GPRS location update. In the response,
+% we indicate teh HLR number, which we need to masquerade
+patch(#'UpdateGprsLocationRes'{} = P) ->
+ P#'UpdateGprsLocationRes'{'hlr-Number' = ?PATCH_HLR_NUMBER};
+
+% Some other MSC/VLR is sendingu us a GSM location update. In the response,
+% we indicate teh HLR number, which we need to masquerade
+patch(#'UpdateLocationRes'{} = P) ->
+ P#'UpdateLocationRes'{'hlr-Number' = ?PATCH_HLR_NUMBER};
+
+% HLR responds to VLR's MAP_RESTORE_REQ (i.e. it has lost information)
+patch(#'RestoreDataRes'{} = P) ->
+ P#'RestoreDataRes'{'hlr-Number' = ?PATCH_HLR_NUMBER};
+
+% HLR sends subscriber data to VLR/SGSN, including CAMEL info
+patch(#'InsertSubscriberDataArg'{'vlrCamelSubscriptionInfo'=VlrCamel,
+ 'sgsn-CAMEL-SubscriptionInfo'=SgsnCamel} = Arg) ->
+ Arg#'InsertSubscriberDataArg'{'vlrCamelSubscriptionInfo'=patch(VlrCamel),
+ 'sgsn-CAMEL-SubscriptionInfo'=patch(SgsnCamel)};
+
+% HLR sends subscriber data to gsmSCF
+patch(#'AnyTimeSubscriptionInterrogationRes'{'camel-SubscriptionInfo'=Csi} = P) ->
+ P#'AnyTimeSubscriptionInterrogationRes'{'camel-SubscriptionInfo'=patch(Csi)};
+
+patch(asn1_NOVALUE) ->
+ asn1_NOVALUE;
+
+% CAMEL related parsing
+
+% this is part of the InsertSubscriberData HLR -> VLR
+patch(#'VlrCamelSubscriptionInfo'{'o-CSI'=Ocsi, 'mo-sms-CSI'=MoSmsCsi,
+ 'mt-sms-CSI'=MtSmsCsi, 'ss-CSI'=SsCsi} = P) ->
+ P#'VlrCamelSubscriptionInfo'{'o-CSI'=patch(Ocsi),
+ 'mo-sms-CSI'=patch(MoSmsCsi),
+ 'mt-sms-CSI'=patch(MtSmsCsi),
+ 'ss-CSI'=patch(SsCsi)};
+
+% this is part of the InsertSubscriberData HLR -> SGSN
+patch(#'SGSN-CAMEL-SubscriptionInfo'{'gprs-CSI'=GprsCsi,
+ 'mo-sms-CSI'=MoSmsCsi,
+ 'mt-sms-CSI'=MtSmsCsi} = P) ->
+ P#'SGSN-CAMEL-SubscriptionInfo'{'gprs-CSI'=patch(GprsCsi),
+ 'mo-sms-CSI'=patch(MoSmsCsi),
+ 'mt-sms-CSI'=patch(MtSmsCsi)};
+
+% this is part of the Anytime Subscription Interrogation Result HLR->gsmSCF
+patch(#'CAMEL-SubscriptionInfo'{'o-CSI'=Ocsi,
+ 'd-CSI'=Dcsi,
+ 't-CSI'=Tcsi,
+ 'vt-CSI'=Vtcsi,
+ %'tif-CSI'=Tifcsi,
+ 'gprs-CSI'=GprsCsi,
+ 'mo-sms-CSI'=MoSmsCsi,
+ 'ss-CSI'=SsCsi,
+ 'm-CSI'=Mcsi,
+ 'mt-sms-CSI'=MtSmsCsi,
+ 'mg-csi'=MgCsi,
+ 'o-IM-CSI'=OimCsi,
+ 'd-IM-CSI'=DimCsi,
+ 'vt-IM-CSI'=VtImCsi} = P) ->
+ P#'CAMEL-SubscriptionInfo'{'o-CSI'=patch(Ocsi),
+ 'd-CSI'=patch(Dcsi),
+ 't-CSI'=patch(Tcsi),
+ 'vt-CSI'=patch(Vtcsi),
+ 'gprs-CSI'=patch(GprsCsi),
+ 'mo-sms-CSI'=patch(MoSmsCsi),
+ 'ss-CSI'=patch(SsCsi),
+ 'm-CSI'=patch(Mcsi),
+ 'mt-sms-CSI'=patch(MtSmsCsi),
+ 'mg-csi'=patch(MgCsi),
+ 'o-IM-CSI'=patch(OimCsi),
+ 'd-IM-CSI'=patch(DimCsi),
+ 'vt-IM-CSI'=patch(VtImCsi)};
+
+patch(#'T-CSI'{'t-BcsmCamelTDPDataList'=TdpList} = P) ->
+ P#'T-CSI'{'t-BcsmCamelTDPDataList'=patch_tBcsmCamelTDPDataList(TdpList)};
+patch(#'M-CSI'{'gsmSCF-Address'=GsmScfAddr} = P) ->
+ P#'M-CSI'{'gsmSCF-Address'=?PATCH_GSMSCF_ADDRESS};
+patch(#'MG-CSI'{'gsmSCF-Address'=GsmScfAddr} = P) ->
+ P#'MG-CSI'{'gsmSCF-Address'=?PATCH_GSMSCF_ADDRESS};
+patch(#'O-CSI'{'o-BcsmCamelTDPDataList'=TdpList} = P) ->
+ P#'O-CSI'{'o-BcsmCamelTDPDataList'=patch_oBcsmCamelTDPDataList(TdpList)};
+patch(#'D-CSI'{'dp-AnalysedInfoCriteriaList'=List} = P) ->
+ P#'D-CSI'{'dp-AnalysedInfoCriteriaList'=patch_AnInfoCritList(List)};
+patch(#'SMS-CSI'{'sms-CAMEL-TDP-DataList'=TdpList} = P) ->
+ P#'SMS-CSI'{'sms-CAMEL-TDP-DataList'=patch_SmsCamelTDPDataList(TdpList)};
+patch(#'SS-CSI'{'ss-CamelData'=Sscd} = P) ->
+ P#'SS-CSI'{'ss-CamelData'=patch(Sscd)};
+patch(#'GPRS-CSI'{'gprs-CamelTDPDataList'=TdpList} = P) ->
+ P#'GPRS-CSI'{'gprs-CamelTDPDataList'=patch_GprsCamelTDPDataList(TdpList)};
+patch(#'SS-CamelData'{'gsmSCF-Address'=GsmScfAddr} = P) ->
+ P#'SS-CamelData'{'gsmSCF-Address'=?PATCH_GSMSCF_ADDRESS};
+patch(#'O-BcsmCamelTDPData'{'gsmSCF-Address'=GsmScfAddr} = P) ->
+ P#'O-BcsmCamelTDPData'{'gsmSCF-Address'=?PATCH_GSMSCF_ADDRESS};
+patch(#'SMS-CAMEL-TDP-Data'{'gsmSCF-Address'=GsmScfAddr} = P) ->
+ P#'SMS-CAMEL-TDP-Data'{'gsmSCF-Address'=?PATCH_GSMSCF_ADDRESS};
+patch(#'GPRS-CamelTDPData'{'gsmSCF-Address'=GsmScfAddr} = P) ->
+ P#'GPRS-CamelTDPData'{'gsmSCF-Address'=?PATCH_GSMSCF_ADDRESS};
+patch(#'DP-AnalysedInfoCriterium'{'gsmSCF-Address'=GsmScfAddr} = P) ->
+ P#'DP-AnalysedInfoCriterium'{'gsmSCF-Address'=?PATCH_GSMSCF_ADDRESS}.
+
+patch_oBcsmCamelTDPDataList(List) ->
+ % we reverse the origianl list, as the tail recursive _acc function
+ % will invert the order of components again
+ patch_oBcsmCamelTDPDataList_acc(lists:reverse(List), []).
+patch_oBcsmCamelTDPDataList_acc([], NewList) -> NewList;
+patch_oBcsmCamelTDPDataList_acc([TdpData|Tail], NewList) ->
+ NewTdpData = patch(TdpData#'O-BcsmCamelTDPData'{}),
+ patch_oBcsmCamelTDPDataList_acc(Tail, [NewTdpData|NewList]).
+
+patch_tBcsmCamelTDPDataList(List) ->
+ % we reverse the origianl list, as the tail recursive _acc function
+ % will invert the order of components again
+ patch_tBcsmCamelTDPDataList_acc(lists:reverse(List), []).
+patch_tBcsmCamelTDPDataList_acc([], NewList) -> NewList;
+patch_tBcsmCamelTDPDataList_acc([TdpData|Tail], NewList) ->
+ NewTdpData = patch(TdpData#'T-BcsmCamelTDPData'{}),
+ patch_tBcsmCamelTDPDataList_acc(Tail, [NewTdpData|NewList]).
+
+patch_AnInfoCritList(List) ->
+ % we reverse the origianl list, as the tail recursive _acc function
+ % will invert the order of components again
+ patch_AnInfoCritList_acc(lists:reverse(List), []).
+patch_AnInfoCritList_acc([], NewList) -> NewList;
+patch_AnInfoCritList_acc([Crit|Tail], NewList) ->
+ NewCrit = patch(Crit#'DP-AnalysedInfoCriterium'{}),
+ patch_AnInfoCritList_acc(Tail, [NewCrit|NewList]).
+
+patch_GprsCamelTDPDataList(List) ->
+ % we reverse the origianl list, as the tail recursive _acc function
+ % will invert the order of components again
+ patch_GprsCamelTDPDataList_acc(lists:reverse(List), []).
+patch_GprsCamelTDPDataList_acc([], NewList) -> NewList;
+patch_GprsCamelTDPDataList_acc([TdpData|Tail], NewList) ->
+ NewTdpData = patch(TdpData#'GPRS-CamelTDPData'{}),
+ patch_GprsCamelTDPDataList_acc(Tail, [NewTdpData|NewList]).
+
+patch_SmsCamelTDPDataList(List) ->
+ % we reverse the origianl list, as the tail recursive _acc function
+ % will invert the order of components again
+ patch_SmsCamelTDPDataList_acc(lists:reverse(List), []).
+patch_SmsCamelTDPDataList_acc([], NewList) -> NewList;
+patch_SmsCamelTDPDataList_acc([TdpData|Tail], NewList) ->
+ NewTdpData = patch(TdpData#'SMS-CAMEL-TDP-Data'{}),
+ patch_GprsCamelTDPDataList_acc(Tail, [NewTdpData|NewList]).
+
+
+
+% process the Argument of a particular MAP invocation
+process_component_arg(OpCode, Arg) ->
+ case Arg of
+ asn1_NOVALUE -> Arg;
+ _ -> patch(Arg)
+ end.
+
+% recurse over all components
+handle_tcap_components(List) ->
+ % we reverse the origianl list, as the tail recursive _acc function
+ % will invert the order of components again
+ handle_tcap_components_acc(lists:reverse(List), []).
+handle_tcap_components_acc([], NewComponents) -> NewComponents;
+handle_tcap_components_acc([Component|Tail], NewComponents) ->
+ case Component of
+ {basicROS, {Primitive, Body}} ->
+ io:format("handle component ~p primitive ~n", [Component]),
+ case Body of
+ % BEGIN
+ #'MapSpecificPDUs_begin_components_SEQOF_basicROS_invoke'{opcode={local, OpCode},
+ argument=Arg} ->
+ NewArg = process_component_arg(OpCode, Arg),
+ NewBody = Body#'MapSpecificPDUs_begin_components_SEQOF_basicROS_invoke'{argument=NewArg};
+ #'MapSpecificPDUs_begin_components_SEQOF_basicROS_returnResult'{result=#'MapSpecificPDUs_begin_components_SEQOF_basicROS_returnResult_result'{opcode={local, OpCode}, result=Arg}} ->
+ NewArg = process_component_arg(OpCode, Arg),
+ NewBody = Body#'MapSpecificPDUs_begin_components_SEQOF_basicROS_returnResult'{result=#'MapSpecificPDUs_begin_components_SEQOF_basicROS_returnResult_result'{result=NewArg}};
+ #'MapSpecificPDUs_begin_components_SEQOF_returnResultNotLast'{result=#'MapSpecificPDUs_begin_components_SEQOF_returnResultNotLast_result'{opcode={local, OpCode}, result=Arg}} ->
+ NewArg = process_component_arg(OpCode, Arg),
+ NewBody = Body#'MapSpecificPDUs_begin_components_SEQOF_returnResultNotLast'{result=#'MapSpecificPDUs_begin_components_SEQOF_returnResultNotLast_result'{result=NewArg}};
+ % END
+ #'MapSpecificPDUs_end_components_SEQOF_basicROS_invoke'{opcode={local, OpCode},
+ argument=Arg} ->
+ NewArg = process_component_arg(OpCode, Arg),
+ NewBody = Body#'MapSpecificPDUs_end_components_SEQOF_basicROS_invoke'{argument=NewArg};
+ #'MapSpecificPDUs_end_components_SEQOF_basicROS_returnResult'{result=#'MapSpecificPDUs_end_components_SEQOF_basicROS_returnResult_result'{opcode={local, OpCode}, result=Arg}} ->
+ NewArg = process_component_arg(OpCode, Arg),
+ NewBody = Body#'MapSpecificPDUs_end_components_SEQOF_basicROS_returnResult'{result=#'MapSpecificPDUs_end_components_SEQOF_basicROS_returnResult_result'{result=NewArg}};
+ #'MapSpecificPDUs_end_components_SEQOF_returnResultNotLast'{result=#'MapSpecificPDUs_end_components_SEQOF_returnResultNotLast_result'{opcode={local, OpCode}, result=Arg}} ->
+ NewArg = process_component_arg(OpCode, Arg),
+ NewBody = Body#'MapSpecificPDUs_end_components_SEQOF_returnResultNotLast'{result=#'MapSpecificPDUs_end_components_SEQOF_returnResultNotLast_result'{result=NewArg}};
+ % CONTINUE
+ #'MapSpecificPDUs_continue_components_SEQOF_basicROS_invoke'{opcode={local, OpCode},
+ argument=Arg} ->
+ NewArg = process_component_arg(OpCode, Arg),
+ NewBody = Body#'MapSpecificPDUs_continue_components_SEQOF_basicROS_invoke'{argument=NewArg};
+ #'MapSpecificPDUs_continue_components_SEQOF_basicROS_returnResult'{result=#'MapSpecificPDUs_continue_components_SEQOF_basicROS_returnResult_result'{opcode={local, OpCode}, result=Arg}} ->
+ NewArg = process_component_arg(OpCode, Arg),
+ NewBody = Body#'MapSpecificPDUs_end_components_SEQOF_basicROS_returnResult'{result=#'MapSpecificPDUs_end_components_SEQOF_basicROS_returnResult_result'{result=NewArg}};
+ #'MapSpecificPDUs_continue_components_SEQOF_returnResultNotLast'{result=#'MapSpecificPDUs_continue_components_SEQOF_returnResultNotLast_result'{opcode={local, OpCode}, result=Arg}} ->
+ NewArg = process_component_arg(OpCode, Arg),
+ NewBody = Body#'MapSpecificPDUs_continue_components_SEQOF_returnResultNotLast'{result=#'MapSpecificPDUs_continue_components_SEQOF_returnResultNotLast_result'{result=NewArg}};
+ _ ->
+ NewBody = Body
+ end,
+ %NewBody = setelement(5, Body, NewArg)
+ NewComponent = {basicROS, {Primitive, NewBody}};
+ _ ->
+ NewComponent = Component
+ end,
+ io:format("=> modified component ~p~n", [NewComponent]),
+ handle_tcap_components_acc(Tail, [NewComponent|NewComponents]).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Actual mangling of the decoded MAP messages
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+mangle_map({Type, TcapMsgDec}) ->
+ case {Type, TcapMsgDec} of
+ {'unidirectional', #'MapSpecificPDUs_unidirectional'{dialoguePortion=Dialg,
+ components=Components}} ->
+ NewComponents = handle_tcap_components(Components),
+ NewTcapMsgDec = TcapMsgDec#'MapSpecificPDUs_unidirectional'{components=NewComponents};
+ {'begin', #'MapSpecificPDUs_begin'{components=Components}} ->
+ NewComponents = handle_tcap_components(Components),
+ NewTcapMsgDec = TcapMsgDec#'MapSpecificPDUs_begin'{components=NewComponents};
+ {'continue', #'MapSpecificPDUs_continue'{dialoguePortion=Dialg, components=Components}} ->
+ NewComponents = handle_tcap_components(Components),
+ NewTcapMsgDec = TcapMsgDec#'MapSpecificPDUs_continue'{components=NewComponents};
+ {'end', #'MapSpecificPDUs_end'{components=Components}} ->
+ NewComponents = handle_tcap_components(Components),
+ NewTcapMsgDec = TcapMsgDec#'MapSpecificPDUs_end'{components=NewComponents};
+ _ ->
+ NewTcapMsgDec = TcapMsgDec
+ end,
+ io:format("new TcapMsgDec ~p~n", [NewTcapMsgDec]),
+ {Type, NewTcapMsgDec}.
+