From 2253665df5045881fd1b52014f19173c1835d168 Mon Sep 17 00:00:00 2001 From: paulc Date: Mon, 23 Jan 2012 16:45:49 +0000 Subject: [PATCH] Implemented matching by CIC range so multiple manglers can run on same PC. Added capability to mangle routing label and CIC of ISUP messages. git-svn-id: http://voip.null.ro/svn/yate@4817 acf43c95-373e-0410-b603-e72c3f656dc1 --- conf.d/isupmangler.conf.sample | 32 ++++++- modules/sig/isupmangler.cpp | 152 ++++++++++++++++++++++++--------- 2 files changed, 141 insertions(+), 43 deletions(-) diff --git a/conf.d/isupmangler.conf.sample b/conf.d/isupmangler.conf.sample index 96769a22..3f720b0f 100644 --- a/conf.d/isupmangler.conf.sample +++ b/conf.d/isupmangler.conf.sample @@ -26,18 +26,44 @@ ; Can be one of ITU,ANSI,ANSI8,China,Japan,Japan5 ;pointcodetype= -; defaultpointcode: string: DPC of the ISUP messages to intercept +; defaultpointcode: string: DPC of the ISUP messages to match ;defaultpointcode= -; remotepointcode: string: OPC of the ISUP messages to intercept +; remotepointcode: string: OPC of the ISUP messages to match ;remotepointcode= -; symmetric: boolean: Intercept and mangle messages in the opposite direction too +; symmetric: boolean: Match and mangle messages in the opposite direction too (DPC->OPC) ; Symmetric should be enabled if intercepting more than just IAM ;symmetric=no +; cic_min: int: Minimum circuit code to match +;cic_min=1 + +; cic_max: int: Maximum circuit code to match +;cic_max=16383 + ; intercept: keyword: What class of messages to intercept +; none: Intercept no message, just mangle routing label and CIC ; iam: Only intercept IAM ; cdr: Intercept most CDR related messages: IAM,SAM,ACM,CPG,ANM,CON,SUS,RES,REL,RLC ; all: Intercept almost all messages, except UPT,UPA,NRM,PAM,CNF,USR ;intercept=iam + + +; The following set: settings apply to all matched messages, not just those intercepted +; These mangle the routing label and circuit codes before any other handling + +; set:opc: int: OPC numeric value to overwrite in message label +; The special value "mirror" will set the received DPC +;set:opc= + +; set:dpc: int: DPC numeric value to overwrite in message label +; The special value "mirror" will set the received OPC +;set:dpc= + +; set:sls: int: Signaling Link Selection to overwrite in message label +; The special value "cic" will use the circuit code after any altering +;set:sls= + +; set:cic: int: Offset to apply to the circuit codes in message body +;set:cic=0 diff --git a/modules/sig/isupmangler.cpp b/modules/sig/isupmangler.cpp index 11f91a65..54027396 100644 --- a/modules/sig/isupmangler.cpp +++ b/modules/sig/isupmangler.cpp @@ -34,13 +34,17 @@ class IsupIntercept : public SS7ISUP YCLASS(IsupIntercept,SS7ISUP) public: enum What { - Iam, // IAM only - Cdr, // IAM,SAM,ACM,CPG,ANM,CON,SUS,RES,REL,RLC + None = 0, // No messages, just mangling + Iam, // IAM only + Cdr, // IAM,SAM,ACM,CPG,ANM,CON,SUS,RES,REL,RLC All }; inline IsupIntercept(const NamedList& params) : SignallingComponent(params,¶ms), SS7ISUP(params), - m_used(true), m_symmetric(false), m_what(Iam) + m_used(true), m_symmetric(false), m_what(Iam), + m_cicMin(1), m_cicMax(16383), + m_setOpc(0), m_setDpc(0), m_setSls(-2), m_setCic(0), + m_resend(true) { } virtual bool initialize(const NamedList* config); void dispatched(SS7MsgISUP& isup, const Message& msg, const SS7Label& label, int sls, bool accepted); @@ -50,10 +54,14 @@ protected: virtual bool processMSU(SS7MsgISUP::Type type, unsigned int cic, const unsigned char* paramPtr, unsigned int paramLen, const SS7Label& label, SS7Layer3* network, int sls); + bool shouldIntercept(SS7MsgISUP::Type type) const; private: bool m_used; bool m_symmetric; What m_what; + unsigned int m_cicMin, m_cicMax; + int m_setOpc, m_setDpc, m_setSls, m_setCic; + bool m_resend; }; class IsupMessage : public Message @@ -89,6 +97,8 @@ public: }; static const TokenDict s_dict_what[] = { + { "nothing", IsupIntercept::None }, + { "none", IsupIntercept::None }, { "IAM", IsupIntercept::Iam }, { "iam", IsupIntercept::Iam }, { "CDR", IsupIntercept::Cdr }, @@ -98,6 +108,17 @@ static const TokenDict s_dict_what[] = { { 0, 0 } }; +static const TokenDict s_dict_pc[] = { + { "mirror", -1 }, + { 0, 0 } +}; + +static const TokenDict s_dict_sls[] = { + { "cic", -1 }, + { "circuit", -1 }, + { 0, 0 } +}; + static ObjList s_manglers; INIT_PLUGIN(IsupMangler); @@ -108,43 +129,29 @@ bool IsupIntercept::initialize(const NamedList* config) if (!config) return false; SS7ISUP::initialize(config); + SS7Router* router = YOBJECT(SS7Router,network()); + m_resend = config->getBoolValue("resend",!(router && router->transferring())); m_symmetric = config->getBoolValue("symmetric",m_symmetric); m_what = (What)config->getIntValue("intercept",s_dict_what,m_what); - Debug(this,DebugAll,"Added %u Point Codes, intercepts %s %s", + m_cicMin = config->getIntValue("cic_min",m_cicMin); + m_cicMax = config->getIntValue("cic_max",m_cicMax); + m_setOpc = config->getIntValue("set:opc",s_dict_pc,m_setOpc); + m_setDpc = config->getIntValue("set:dpc",s_dict_pc,m_setDpc); + m_setSls = config->getIntValue("set:sls",s_dict_sls,m_setSls); + m_setCic = config->getIntValue("set:cic",m_setCic); + Debug(this,DebugAll,"Added %u Point Codes, intercepts %s %s, cic=%u-%u", setPointCode(*config),lookup(m_what,s_dict_what,"???"), - (m_symmetric) ? "both ways" : "one way"); + (m_symmetric) ? "both ways" : "one way", + m_cicMin,m_cicMax); return true; } -HandledMSU IsupIntercept::receivedMSU(const SS7MSU& msu, const SS7Label& label, SS7Layer3* network, int sls) +bool IsupIntercept::shouldIntercept(SS7MsgISUP::Type type) const { - if (msu.getSIF() != sif()) - return HandledMSU::Rejected; - if (!hasPointCode(label.dpc()) || !handlesRemotePC(label.opc())) { - if (!m_symmetric || !hasPointCode(label.opc()) || !handlesRemotePC(label.dpc())) - return HandledMSU::Rejected; - } - // we should have at least 2 bytes CIC and 1 byte message type - const unsigned char* s = msu.getData(label.length()+1,3); - if (!s) { - Debug(this,DebugNote,"Got short MSU"); - return HandledMSU::Rejected; - } - unsigned int len = msu.length()-label.length()-1; - unsigned int cic = s[0] | (s[1] << 8); - SS7MsgISUP::Type type = (SS7MsgISUP::Type)s[2]; - String name = SS7MsgISUP::lookup(type); - if (!name) { - String tmp; - tmp.hexify((void*)s,len,' '); - Debug(this,DebugMild,"Received unknown ISUP type 0x%02x, cic=%u, length %u: %s", - type,cic,len,tmp.c_str()); - name = (int)type; - } switch (type) { - // always intercept IAM + // almost always intercept IAM case SS7MsgISUP::IAM: - break; + return (m_what >= Iam); // other CDR relevant messages case SS7MsgISUP::SAM: case SS7MsgISUP::ACM: @@ -155,9 +162,7 @@ HandledMSU IsupIntercept::receivedMSU(const SS7MSU& msu, const SS7Label& label, case SS7MsgISUP::RES: case SS7MsgISUP::REL: case SS7MsgISUP::RLC: - if (m_what >= Cdr) - break; - return HandledMSU::Rejected; + return (m_what >= Cdr); // we shouldn't mess with these messages case SS7MsgISUP::UPT: case SS7MsgISUP::UPA: @@ -165,16 +170,83 @@ HandledMSU IsupIntercept::receivedMSU(const SS7MSU& msu, const SS7Label& label, case SS7MsgISUP::PAM: case SS7MsgISUP::CNF: case SS7MsgISUP::USR: - return HandledMSU::Rejected; + return false; // intercepting all messages is risky default: - if (m_what >= All) - break; - // let the message pass through + return (m_what >= All); + } +} + +HandledMSU IsupIntercept::receivedMSU(const SS7MSU& msu, const SS7Label& label, SS7Layer3* network, int sls) +{ + if (msu.getSIF() != sif()) + return HandledMSU::Rejected; + if (!hasPointCode(label.dpc()) || !handlesRemotePC(label.opc())) { + if (!m_symmetric || !hasPointCode(label.opc()) || !handlesRemotePC(label.dpc())) return HandledMSU::Rejected; } - return processMSU(type,cic,s+3,len-3,label,network,sls) ? - HandledMSU::Accepted : HandledMSU::Rejected; + // horrible - create a pair of writable aliases to alter data in place + SS7MSU& rwMsu = const_cast(msu); + SS7Label& rwLbl = const_cast(label); + // we should have at least 2 bytes CIC and 1 byte message type + unsigned char* s = rwMsu.getData(label.length()+1,3); + if (!s) { + Debug(this,DebugNote,"Got short MSU"); + return HandledMSU::Rejected; + } + unsigned int len = msu.length()-label.length()-1; + unsigned int cic = s[0] | (s[1] << 8); + if (cic < m_cicMin || cic > m_cicMax) + return HandledMSU::Rejected; + + SS7MsgISUP::Type type = (SS7MsgISUP::Type)s[2]; + String name = SS7MsgISUP::lookup(type); + if (!name) { + String tmp; + tmp.hexify((void*)s,len,' '); + Debug(this,DebugMild,"Received unknown ISUP type 0x%02x, cic=%u, length %u: %s", + type,cic,len,tmp.c_str()); + name = (int)type; + } + XDebug(this,DebugAll,"Received ISUP type %s, cic=%u, length %u",name.c_str(),cic,len); + + // intercepted as message or not, apply mangling now + if (m_setCic) { + cic += m_setCic; + s[0] = (cic & 0xff); + s[1] = ((cic >> 8) & 0xff); + } + bool changed = false; + if (m_setSls >= -1) { + changed = true; + rwLbl.setSls(((m_setSls >= 0) ? m_setSls : cic) & 0xff); + } + if (m_setOpc || m_setDpc) { + changed = true; + SS7PointCode opc(label.opc()); + SS7PointCode dpc(label.dpc()); + if (m_setOpc > 0) + rwLbl.opc().unpack(label.type(),m_setOpc); + else if (m_setOpc < 0) + rwLbl.opc() = dpc; + if (m_setDpc > 0) + rwLbl.dpc().unpack(label.type(),m_setDpc); + else if (m_setDpc < 0) + rwLbl.dpc() = opc; + } + if (changed) + rwLbl.store(rwMsu.getData(1)); + + if (shouldIntercept(type) && processMSU(type,cic,s+3,len-3,label,network,sls)) + return HandledMSU::Accepted; + if (!(m_setDpc || m_resend)) + return HandledMSU::Rejected; + // if we altered the DPC or we are no STP we should transmit as new message + if (transmitMSU(rwMsu,rwLbl,rwLbl.sls()) >= 0) + return HandledMSU::Accepted; + Debug(this,DebugWarn,"Failed to forward mangled %s (%u) [%p]", + SS7MsgISUP::lookup(type),cic,this); + return HandledMSU::Failure; } bool IsupIntercept::processMSU(SS7MsgISUP::Type type, unsigned int cic,