////////////////////////////////////////////////////////////////// // // New Neighboring System for GNU Gatekeeper // // Copyright (c) Citron Network Inc. 2002-2003 // // This work is published under the GNU Public License (GPL) // see file COPYING for details. // We also explicitely grant the right to link this code // with the OpenH323 library. // // initial author: Chih-Wei Huang // initial version: 05/30/2003 // ////////////////////////////////////////////////////////////////// #if defined(_WIN32) && (_MSC_VER <= 1200) #pragma warning(disable:4786) // warning about too long debug symbol off #pragma warning(disable:4284) #endif #include #include #include #include "gk_const.h" #include "stl_supp.h" #include "GkClient.h" #include "RasPDU.h" #include "RasSrv.h" #include "RasTbl.h" #include "Routing.h" #include "sigmsg.h" #include "cisco.h" #include "Neighbor.h" using std::multimap; using std::make_pair; using std::find_if; using std::bind2nd; using std::equal_to; using std::mem_fun; using Routing::Route; namespace Neighbors { const char *NeighborSection = "RasSrv::Neighbors"; const char *LRQFeaturesSection = "RasSrv::LRQFeatures"; class OldGK : public Neighbor { // override from class Neighbor virtual bool SetProfile(const PString &, const PString &); }; class GnuGK : public Neighbor { // override from class Neighbor virtual bool OnSendingLRQ(H225_LocationRequest &, const AdmissionRequest &); virtual bool OnSendingLRQ(H225_LocationRequest &, const SetupRequest &); virtual bool OnSendingLRQ(H225_LocationRequest &, const FacilityRequest &); virtual bool IsAcceptable(RasMsg *ras) const; }; class CiscoGK : public Neighbor { public: // override from class Neighbor virtual bool OnSendingLRQ(H225_LocationRequest &, const AdmissionRequest &); virtual bool OnSendingLRQ(H225_LocationRequest &, const LocationRequest &); virtual bool OnSendingLRQ(H225_LocationRequest &, const SetupRequest &); virtual bool CheckReply(RasMsg *msg) const; }; // stupid Clarent gatekeeper class ClarentGK : public Neighbor { // override from class Neighbor virtual bool OnSendingLRQ(H225_LocationRequest &); }; // a gatekeeper by Korea vendor class GlonetGK : public Neighbor { // override from class Neighbor virtual bool OnSendingLRQ(H225_LocationRequest &, const AdmissionRequest &); virtual bool OnSendingLRQ(H225_LocationRequest &, const LocationRequest &); virtual bool OnSendingLRQ(H225_LocationRequest &, const SetupRequest &); virtual bool OnSendingLRQ(H225_LocationRequest &, const FacilityRequest &); bool BuildLRQ(H225_LocationRequest &, WORD); }; namespace { // anonymous namespace SimpleCreator OldGKCreator("OldGK"); SimpleCreator GnuGKCreator("GnuGK"); SimpleCreator CiscoGKCreator("CiscoGK"); SimpleCreator ClarentGKCreator("ClarentGK"); SimpleCreator GlonetGKCreator("GlonetGK"); int challenge; const char OID_T[] = "0.0.8.235.0.2.5"; } // if we put nomatch into anonymous namespace, // stupid VC can't find it, why?? static const PrefixInfo nomatch(-1, 0); // template class LRQSender typedef Functor2 LRQFunctor; template class LRQSender : public LRQFunctor { public: LRQSender(const R & r) : m_r(r) {} virtual PrefixInfo operator()(Neighbor *, WORD) const; private: const R & m_r; }; template PrefixInfo LRQSender::operator()(Neighbor *nb, WORD seqnum) const { if (const H225_ArrayOf_AliasAddress *dest = m_r.GetAliases()) { H225_ArrayOf_AliasAddress aliases; if (PrefixInfo info = nb->GetPrefixInfo(*dest, aliases)) { H225_RasMessage lrq_ras; H225_LocationRequest & lrq = nb->BuildLRQ(lrq_ras, seqnum, aliases); if (nb->OnSendingLRQ(lrq, m_r) && nb->SendLRQ(lrq_ras)) return info; } } return nomatch; } class LRQForwarder : public LRQFunctor { public: LRQForwarder(const LocationRequest & l) : m_lrq(l) {} virtual PrefixInfo operator()(Neighbor *, WORD) const; private: const LocationRequest & m_lrq; }; PrefixInfo LRQForwarder::operator()(Neighbor *nb, WORD /*seqnum*/) const { H225_ArrayOf_AliasAddress aliases; if (PrefixInfo info = nb->GetPrefixInfo(m_lrq.GetRequest().m_destinationInfo, aliases)) { H225_RasMessage lrq_ras; lrq_ras.SetTag(H225_RasMessage::e_locationRequest); H225_LocationRequest & lrq = lrq_ras; // copy and forward lrq = m_lrq.GetRequest(); lrq.m_destinationInfo = aliases; // include hopCount if configured and not already included if (nb->GetDefaultHopCount() >= 1 && !lrq.HasOptionalField(H225_LocationRequest::e_hopCount)) { lrq.IncludeOptionalField(H225_LocationRequest::e_hopCount); lrq.m_hopCount = nb->GetDefaultHopCount(); } if (nb->OnSendingLRQ(lrq, m_lrq) && nb->SendLRQ(lrq_ras)) return info; } return nomatch; } // class Neighbor Neighbor::Neighbor() { m_rasSrv = RasServer::Instance(); } Neighbor::~Neighbor() { PTRACE(1, "NB\tDelete neighbor " << m_id); } bool Neighbor::SendLRQ(H225_RasMessage & lrq_ras) { return m_rasSrv->SendRas(lrq_ras, GetIP(), m_port); } PIPSocket::Address Neighbor::GetIP() const { if (m_dynamic) { PIPSocket::ClearNameCache(); // Retrieve the ip address at this time if (!GetTransportAddress(m_name, GK_DEF_UNICAST_RAS_PORT, m_ip, m_port)) { PTRACE(1, "NB\tCan't get neighbor ip for " << m_name); } } return m_ip; } H225_LocationRequest & Neighbor::BuildLRQ(H225_RasMessage & lrq_ras, WORD seqnum, const H225_ArrayOf_AliasAddress & dest) { lrq_ras.SetTag(H225_RasMessage::e_locationRequest); H225_LocationRequest & lrq = lrq_ras; lrq.m_requestSeqNum = seqnum; lrq.m_destinationInfo = dest; // Perform outbound per GK rewrite on the destination of the LRQ Toolkit::Instance()->GWRewriteE164(m_id,false,lrq.m_destinationInfo[0]); lrq.m_replyAddress = m_rasSrv->GetRasAddress(GetIP()); // lrq.IncludeOptionalField(H225_LocationRequest::e_gatekeeperIdentifier); // lrq.m_gatekeeperIdentifier = Toolkit::GKName(); // lrq.IncludeOptionalField(H225_LocationRequest::e_nonStandardData); // lrq.m_nonStandardData.m_data.SetValue(m_id); lrq.IncludeOptionalField(H225_LocationRequest::e_sourceInfo); lrq.m_sourceInfo.SetSize(1); H323SetAliasAddress(Toolkit::GKName(), lrq.m_sourceInfo[0], H225_AliasAddress::e_h323_ID); m_rasSrv->GetGkClient()->SetNBPassword(lrq, Toolkit::GKName()); if (m_forwardHopCount >= 1) { // what if set hopCount = 1? lrq.IncludeOptionalField(H225_LocationRequest::e_hopCount); lrq.m_hopCount = m_forwardHopCount; } return lrq; } bool Neighbor::SetProfile(const PString & id, const PString & type) { PConfig *config = GkConfig(); PString section("Neighbor::" + (m_id = id)); m_gkid = config->GetString(section, "GatekeeperIdentifier", id); m_name = config->GetString(section, "Host", ""); m_dynamic = Toolkit::AsBool(config->GetString(section, "Dynamic", "0")); if (!m_dynamic && !GetTransportAddress(m_name, GK_DEF_UNICAST_RAS_PORT, m_ip, m_port)) return false; PINDEX i; m_sendPrefixes.clear(); PString sprefix(config->GetString(section, "SendPrefixes", "")); PStringArray sprefixes(sprefix.Tokenise(",", false)); for (i = 0; i < sprefixes.GetSize(); ++i) { PStringArray p(sprefixes[i].Tokenise(":=", false)); m_sendPrefixes[p[0]] = (p.GetSize() > 1) ? p[1].AsInteger() : 1; } PString aprefix(config->GetString(section, "AcceptPrefixes", "*")); m_acceptPrefixes = PStringArray(aprefix.Tokenise(",", false)); SetForwardedInfo(section); PString info = " of type " + type; if (!sprefix) info = " send=" + sprefix; if (!aprefix) info += " accept=" + aprefix; PTRACE(1, "Set neighbor " << id << '(' << (m_dynamic ? m_name : AsString(m_ip, m_port)) << ')' << info); return true; } PrefixInfo Neighbor::GetPrefixInfo(const H225_ArrayOf_AliasAddress & aliases, H225_ArrayOf_AliasAddress & dest) { Prefixes::iterator iter, biter = m_sendPrefixes.begin(), eiter = m_sendPrefixes.end(); for (PINDEX i = 0; i < aliases.GetSize(); ++i) { H225_AliasAddress & alias = aliases[i]; iter = m_sendPrefixes.find(alias.GetTagName()); if (iter != eiter) { dest.SetSize(1); dest[0] = alias; return PrefixInfo(100, (short)iter->second); } PString destination(AsString(alias, false)); while (iter != biter) { --iter; // search in reverse order const int len = MatchPrefix(destination, iter->first); if (len < 0) { return nomatch; } else if (len > 0) { dest.SetSize(1); dest[0] = alias; return PrefixInfo((short)len, (short)iter->second); } } } iter = m_sendPrefixes.find("*"); if (iter == eiter) return nomatch; dest = aliases; return PrefixInfo(0, (short)iter->second); } bool Neighbor::OnSendingLRQ(H225_LocationRequest &) { return true; } bool Neighbor::OnSendingLRQ(H225_LocationRequest & lrq, const AdmissionRequest &) { return OnSendingLRQ(lrq); } bool Neighbor::OnSendingLRQ(H225_LocationRequest & lrq, const LocationRequest &orig_lrq) { // adjust hopCount to be lesser or equal to the original value if( orig_lrq.GetRequest().HasOptionalField(H225_LocationRequest::e_hopCount) ) if( lrq.HasOptionalField(H225_LocationRequest::e_hopCount) ) { if( lrq.m_hopCount > orig_lrq.GetRequest().m_hopCount ) lrq.m_hopCount = orig_lrq.GetRequest().m_hopCount; } else { lrq.IncludeOptionalField(H225_LocationRequest::e_hopCount); lrq.m_hopCount = orig_lrq.GetRequest().m_hopCount; } return OnSendingLRQ(lrq); } bool Neighbor::OnSendingLRQ(H225_LocationRequest & lrq, const SetupRequest &) { return OnSendingLRQ(lrq); } bool Neighbor::OnSendingLRQ(H225_LocationRequest & lrq, const FacilityRequest &) { return OnSendingLRQ(lrq); } bool Neighbor::CheckReply(RasMsg *ras) const { if( ras->IsFrom(GetIP(), 0 /*m_port*/) ) return true; else { const H225_NonStandardParameter *params = ras->GetNonStandardParam(); return params ?(strncmp(m_id, params->m_data.AsString(), m_id.GetLength()) == 0) :false; } } bool Neighbor::IsAcceptable(RasMsg *ras) const { if (ras->IsFrom(GetIP(), 0 /*m_port*/)) { // ras must be an LRQ H225_LocationRequest & lrq = (*ras)->m_recvRAS; PINDEX i, j, sz = m_acceptPrefixes.GetSize(); H225_ArrayOf_AliasAddress & aliases = lrq.m_destinationInfo; for (j = 0; j < aliases.GetSize(); ++j) { H225_AliasAddress & alias = aliases[j]; for (i = 0; i < sz; ++i) if (m_acceptPrefixes[i] == alias.GetTagName()) return true; PString destination(AsString(alias, false)); int maxlen = 0; for (i = 0; i < sz; ++i) { const PString & prefix = m_acceptPrefixes[i]; const int len = MatchPrefix(destination, prefix); if (len < 0) return false; else if (len > maxlen) maxlen = len; } if (maxlen > 0) return true; } for (i = 0; i < sz; ++i) if (m_acceptPrefixes[i] == "*") return true; } return false; } void Neighbor::SetForwardedInfo(const PString & section) { PConfig *config = GkConfig(); m_forwardHopCount = (WORD)config->GetInteger(section, "ForwardHopCount", 0); m_acceptForwarded = Toolkit::AsBool(config->GetString(section, "AcceptForwardedLRQ", "1")); m_forwardResponse = Toolkit::AsBool(config->GetString(section, "ForwardResponse", "0")); PString forwardto(config->GetString(section, "ForwardLRQ", "0")); if (forwardto *= "never") m_forwardto = -1; else if (forwardto *= "always") m_forwardto = 1; else m_forwardto = 0; } // class OldGK bool OldGK::SetProfile(const PString & id, const PString & args) { m_id = m_gkid = id; PStringArray cfg(args.Tokenise(";", true)); m_name = cfg[0].Trim(); m_sendPrefixes.clear(); if (cfg.GetSize() > 1) { PStringArray p = cfg[1].Tokenise(",", false); for (PINDEX i = 0; i < p.GetSize(); ++i) m_sendPrefixes[p[i]] = 1; } else m_sendPrefixes["*"] = 1; m_acceptPrefixes.SetSize(1); m_acceptPrefixes[0] = "*"; if (cfg.GetSize() > 2) m_password = cfg[2]; m_dynamic = (cfg.GetSize() > 3) ? Toolkit::AsBool(cfg[3]) : false; if (!m_dynamic && !GetTransportAddress(m_name, GK_DEF_UNICAST_RAS_PORT, m_ip, m_port)) return false; SetForwardedInfo(LRQFeaturesSection); if (Toolkit::AsBool(GkConfig()->GetString(LRQFeaturesSection, "AlwaysForwardLRQ", "0"))) m_forwardto = 1; PTRACE(1, "Set neighbor " << m_gkid << '(' << (m_dynamic ? m_name : AsString(m_ip, m_port)) << ')' << (cfg.GetSize() > 1 ? (" for prefix " + cfg[1]) : PString())); return true; } // class GnuGK bool GnuGK::OnSendingLRQ(H225_LocationRequest & lrq, const AdmissionRequest & request) { lrq.IncludeOptionalField(H225_LocationRequest::e_gatekeeperIdentifier); lrq.m_gatekeeperIdentifier = Toolkit::GKName(); lrq.IncludeOptionalField(H225_LocationRequest::e_nonStandardData); lrq.m_nonStandardData.m_data.SetValue(m_id); const H225_AdmissionRequest & arq = request.GetRequest(); lrq.IncludeOptionalField(H225_LocationRequest::e_sourceInfo); lrq.m_sourceInfo = arq.m_srcInfo; if (arq.HasOptionalField(H225_AdmissionRequest::e_canMapAlias)) { lrq.IncludeOptionalField(H225_LocationRequest::e_canMapAlias); lrq.m_canMapAlias = arq.m_canMapAlias; } return true; } bool GnuGK::OnSendingLRQ(H225_LocationRequest & lrq, const SetupRequest & request) { lrq.IncludeOptionalField(H225_LocationRequest::e_gatekeeperIdentifier); lrq.m_gatekeeperIdentifier = Toolkit::GKName(); lrq.IncludeOptionalField(H225_LocationRequest::e_nonStandardData); lrq.m_nonStandardData.m_data.SetValue(m_id); const H225_Setup_UUIE & setup = request.GetRequest(); if (setup.HasOptionalField(H225_Setup_UUIE::e_sourceAddress)) { lrq.IncludeOptionalField(H225_LocationRequest::e_sourceInfo); lrq.m_sourceInfo = setup.m_sourceAddress; } lrq.IncludeOptionalField(H225_LocationRequest::e_canMapAlias); lrq.m_canMapAlias = TRUE; return true; } bool GnuGK::OnSendingLRQ(H225_LocationRequest & lrq, const FacilityRequest & /*request*/) { lrq.IncludeOptionalField(H225_LocationRequest::e_gatekeeperIdentifier); lrq.m_gatekeeperIdentifier = Toolkit::GKName(); lrq.IncludeOptionalField(H225_LocationRequest::e_nonStandardData); lrq.m_nonStandardData.m_data.SetValue(m_id); lrq.IncludeOptionalField(H225_LocationRequest::e_canMapAlias); lrq.m_canMapAlias = TRUE; return true; } bool GnuGK::IsAcceptable(RasMsg *ras) const { if (Neighbor::IsAcceptable(ras)) { if (!m_acceptForwarded) { H225_LocationRequest & lrq = (*ras)->m_recvRAS; return lrq.HasOptionalField(H225_LocationRequest::e_gatekeeperIdentifier) && lrq.m_gatekeeperIdentifier.GetValue() == m_gkid; } return true; } return false; } // class CiscoGK bool CiscoGK::OnSendingLRQ(H225_LocationRequest &lrq, const AdmissionRequest &req) { const H225_AdmissionRequest &arq = req.GetRequest(); Cisco_LRQnonStandardInfo nonStandardData; nonStandardData.m_ttl = m_forwardHopCount >= 1 ? m_forwardHopCount : 5; nonStandardData.IncludeOptionalField(Cisco_LRQnonStandardInfo::e_gatewaySrcInfo); nonStandardData.m_gatewaySrcInfo.SetSize(arq.m_srcInfo.GetSize()); for (PINDEX i = 0; i < arq.m_srcInfo.GetSize(); i++) nonStandardData.m_gatewaySrcInfo[i] = arq.m_srcInfo[i]; if (arq.HasOptionalField(H225_AdmissionRequest::e_callIdentifier)) { nonStandardData.IncludeOptionalField(Cisco_LRQnonStandardInfo::e_callIdentifier); nonStandardData.m_callIdentifier = arq.m_callIdentifier; } // Cisco GK needs these lrq.IncludeOptionalField(H225_LocationRequest::e_nonStandardData); lrq.m_nonStandardData.m_nonStandardIdentifier.SetTag(H225_NonStandardIdentifier::e_h221NonStandard); H225_H221NonStandard & h221 = lrq.m_nonStandardData.m_nonStandardIdentifier; h221.m_manufacturerCode = 18; h221.m_t35CountryCode = 181; h221.m_t35Extension = 0; PPER_Stream buff; nonStandardData.Encode(buff); buff.CompleteEncoding(); lrq.m_nonStandardData.m_data = buff; lrq.IncludeOptionalField(H225_LocationRequest::e_canMapAlias); lrq.m_canMapAlias = TRUE; return true; } // class CiscoGK bool CiscoGK::OnSendingLRQ(H225_LocationRequest &lrq, const LocationRequest &req) { if (lrq.HasOptionalField(H225_LocationRequest::e_nonStandardData) && lrq.m_nonStandardData.GetTag() == H225_NonStandardIdentifier::e_h221NonStandard) { const H225_H221NonStandard &h221 = lrq.m_nonStandardData.m_nonStandardIdentifier; if (h221.m_manufacturerCode == 18 && h221.m_t35CountryCode == 181) return true; lrq.RemoveOptionalField(H225_LocationRequest::e_nonStandardData); } Cisco_LRQnonStandardInfo nonStandardData; nonStandardData.m_ttl = m_forwardHopCount >= 1 ? m_forwardHopCount : 5; if (lrq.HasOptionalField(H225_LocationRequest::e_sourceInfo)) { nonStandardData.IncludeOptionalField(Cisco_LRQnonStandardInfo::e_gatewaySrcInfo); nonStandardData.m_gatewaySrcInfo.SetSize(lrq.m_sourceInfo.GetSize()); for (PINDEX i = 0; i < lrq.m_sourceInfo.GetSize(); i++) nonStandardData.m_gatewaySrcInfo[i] = lrq.m_sourceInfo[i]; } lrq.IncludeOptionalField(H225_LocationRequest::e_nonStandardData); lrq.m_nonStandardData.m_nonStandardIdentifier.SetTag(H225_NonStandardIdentifier::e_h221NonStandard); H225_H221NonStandard & h221 = lrq.m_nonStandardData.m_nonStandardIdentifier; h221.m_manufacturerCode = 18; h221.m_t35CountryCode = 181; h221.m_t35Extension = 0; PPER_Stream buff; nonStandardData.Encode(buff); buff.CompleteEncoding(); lrq.m_nonStandardData.m_data = buff; lrq.IncludeOptionalField(H225_LocationRequest::e_canMapAlias); lrq.m_canMapAlias = TRUE; return true; } // class CiscoGK bool CiscoGK::OnSendingLRQ(H225_LocationRequest &lrq, const SetupRequest &req) { const Q931 &setup = req.GetWrapper()->GetQ931(); const H225_Setup_UUIE &setupBody = req.GetRequest(); Cisco_LRQnonStandardInfo nonStandardData; nonStandardData.m_ttl = m_forwardHopCount >= 1 ? m_forwardHopCount : 5; if (setupBody.HasOptionalField(H225_Setup_UUIE::e_sourceAddress)) { nonStandardData.IncludeOptionalField(Cisco_LRQnonStandardInfo::e_gatewaySrcInfo); nonStandardData.m_gatewaySrcInfo.SetSize(setupBody.m_sourceAddress.GetSize()); for (PINDEX i = 0; i < setupBody.m_sourceAddress.GetSize(); i++) nonStandardData.m_gatewaySrcInfo[i] = setupBody.m_sourceAddress[i]; } if (setupBody.HasOptionalField(H225_Setup_UUIE::e_callIdentifier)) { nonStandardData.IncludeOptionalField(Cisco_LRQnonStandardInfo::e_callIdentifier); nonStandardData.m_callIdentifier = setupBody.m_callIdentifier; } if (setup.HasIE(Q931::CallingPartyNumberIE)) { PBYTEArray data = setup.GetIE(Q931::CallingPartyNumberIE); if ((data[0] & 0x80) == 0x80 && data.GetSize() >= 2) { nonStandardData.IncludeOptionalField(Cisco_LRQnonStandardInfo::e_callingOctet3a); nonStandardData.m_callingOctet3a = data[1]; } } // Cisco GK needs these lrq.IncludeOptionalField(H225_LocationRequest::e_nonStandardData); lrq.m_nonStandardData.m_nonStandardIdentifier.SetTag(H225_NonStandardIdentifier::e_h221NonStandard); H225_H221NonStandard & h221 = lrq.m_nonStandardData.m_nonStandardIdentifier; h221.m_manufacturerCode = 18; h221.m_t35CountryCode = 181; h221.m_t35Extension = 0; PPER_Stream buff; nonStandardData.Encode(buff); buff.CompleteEncoding(); lrq.m_nonStandardData.m_data = buff; lrq.IncludeOptionalField(H225_LocationRequest::e_canMapAlias); lrq.m_canMapAlias = TRUE; return true; } bool CiscoGK::CheckReply(RasMsg *msg) const { if (msg->IsFrom(GetIP(), 0)) return true; if (msg->GetTag() != H225_RasMessage::e_locationConfirm && msg->GetTag() != H225_RasMessage::e_locationReject) return false; H225_NonStandardParameter *nonStandardData = msg->GetNonStandardParam(); if (nonStandardData == NULL) return false; if (nonStandardData->m_nonStandardIdentifier.GetTag() != H225_NonStandardIdentifier::e_h221NonStandard) return false; H225_H221NonStandard &h221 = nonStandardData->m_nonStandardIdentifier; if (h221.m_manufacturerCode != 18 || h221.m_t35CountryCode != 181) return false; PPER_Stream strm(nonStandardData->m_data); Cisco_LRQnonStandardInfo ciscoNonStandardData; if (ciscoNonStandardData.Decode(strm)) { // here should go additional checks to match callIdentifier, for example } else PTRACE(5, "NB\tFailed to decode Cisco nonStandardInfo field"); return true; } // class ClarentGK bool ClarentGK::OnSendingLRQ(H225_LocationRequest & lrq) { // Clarent gatekeeper can't decode nonStandardData, stupid! lrq.RemoveOptionalField(H225_LocationRequest::e_nonStandardData); return true; } // class GlonetGK bool GlonetGK::OnSendingLRQ(H225_LocationRequest & lrq, const AdmissionRequest & request) { return BuildLRQ(lrq, (WORD)request.GetRequest().m_callReferenceValue); } bool GlonetGK::OnSendingLRQ(H225_LocationRequest &, const LocationRequest &) { // not supported, since LRQ doesn't have call reference value return false; } bool GlonetGK::OnSendingLRQ(H225_LocationRequest & lrq, const SetupRequest & request) { return BuildLRQ(lrq, (WORD)request.GetWrapper()->GetCallReference()); } bool GlonetGK::OnSendingLRQ(H225_LocationRequest & lrq, const FacilityRequest & request) { return BuildLRQ(lrq, (WORD)request.GetWrapper()->GetCallReference()); } bool GlonetGK::BuildLRQ(H225_LocationRequest & lrq, WORD crv) { lrq.IncludeOptionalField(H225_LocationRequest::e_sourceInfo); lrq.m_sourceInfo.SetSize(2); H323SetAliasAddress(Toolkit::GKName(), lrq.m_sourceInfo[0], H225_AliasAddress::e_h323_ID); H323SetAliasAddress(PString(crv), lrq.m_sourceInfo[1]); return true; } // class LRQRequester class LRQRequester : public RasRequester { public: LRQRequester(const LRQFunctor &); ~LRQRequester(); bool Send(NeighborList::List &, Neighbor * = 0); int GetReqNumber() const { return m_requests.size(); } H225_LocationConfirm *WaitForDestination(int); PString GetNeighborUsed() { return m_neighbor_used; } // override from class RasRequester virtual bool IsExpected(const RasMsg *) const; virtual void Process(RasMsg *); virtual bool OnTimeout(); private: struct Request { Request(Neighbor *n) : m_neighbor(n), m_reply(0), m_count(1) {} Neighbor *m_neighbor; RasMsg *m_reply; int m_count; }; typedef multimap Queue; Queue m_requests; PMutex m_rmutex; const LRQFunctor & m_sendto; RasMsg *m_result; PString m_neighbor_used; }; LRQRequester::LRQRequester(const LRQFunctor & fun) : m_sendto(fun), m_result(0) { AddFilter(H225_RasMessage::e_locationConfirm); AddFilter(H225_RasMessage::e_locationReject); m_rasSrv->RegisterHandler(this); } LRQRequester::~LRQRequester() { m_rasSrv->UnregisterHandler(this); } bool LRQRequester::Send(NeighborList::List & neighbors, Neighbor *requester) { PWaitAndSignal lock(m_rmutex); NeighborList::List::iterator iter = neighbors.begin(); while (iter != neighbors.end()) { Neighbor *nb = *iter++; if (nb != requester) if (PrefixInfo info = m_sendto(nb, m_seqNum)) m_requests.insert(make_pair(info, nb)); } if (m_requests.empty()) return false; m_retry = 2; // TODO: configurable PTRACE(2, "NB\t" << m_requests.size() << " LRQ(s) sent"); return true; } H225_LocationConfirm *LRQRequester::WaitForDestination(int timeout) { while (WaitForResponse(timeout)) if (m_result) break; else GetReply(); // ignore and increase iterator return m_result ? &(H225_LocationConfirm &)(*m_result)->m_recvRAS : 0; } bool LRQRequester::IsExpected(const RasMsg *ras) const { return RasHandler::IsExpected(ras) && (ras->GetSeqNum() == m_seqNum); } void LRQRequester::Process(RasMsg *ras) { PWaitAndSignal lock(m_rmutex); for (Queue::iterator iter = m_requests.begin(); iter != m_requests.end(); ++iter) { Request & req = iter->second; if (req.m_neighbor->CheckReply(ras)) { PTRACE(5,"NB\tReceived "<GetTagName()<<" message matched" <<" pending LRQ for neighbor "<GetId() <<':'<GetIP() ); unsigned tag = ras->GetTag(); if (tag == H225_RasMessage::e_requestInProgress) { if (H225_NonStandardParameter *params = ras->GetNonStandardParam()) { PStringArray param(params->m_data.AsString().Tokenise(":", false)); if (param.GetSize() > 1) req.m_count += param[1].AsInteger(); } RasRequester::Process(ras); } else if (tag == H225_RasMessage::e_locationConfirm) { --req.m_count; // Note: to avoid race condition, the order is important if (iter == m_requests.begin()) // the highest priority m_result = ras; AddReply(req.m_reply = ras); m_neighbor_used = req.m_neighbor->GetId(); // record neighbor used if (m_result) m_sync.Signal(); } else { // should be H225_RasMessage::e_locationReject --req.m_count; delete ras; if (req.m_count <= 0 && req.m_reply == 0) { PTRACE(5,"NB\tLRQ rejected for neighbor "<GetId() <<':'<GetIP() ); m_requests.erase(iter); if (m_requests.empty()) RasRequester::Stop(); else if (RasMsg *reply = m_requests.begin()->second.m_reply) m_result = reply, RasRequester::Stop(); } } return; } } PTRACE(1, "RAS\tUnknown reply " << ras->GetTagName()); delete ras; } bool LRQRequester::OnTimeout() { PWaitAndSignal lock(m_rmutex); if (m_requests.empty()) return false; Queue::iterator iter, biter = m_requests.begin(), eiter = m_requests.end(); for (iter = biter; iter != eiter; ++iter) { m_result = iter->second.m_reply; if (m_result) return false; } if (m_retry-- == 0) return false; // re-send LRQs for (iter = biter; iter != eiter; ++iter) { m_sendto(iter->second.m_neighbor, m_seqNum); iter->second.m_count = 1; // reset count } m_sentTime = PTime(); PTRACE(2, "NB\t" << m_requests.size() << " LRQ(s) re-sent"); return true; } // class NeighborList NeighborList::NeighborList() { Factory::SetDefaultCreator(&OldGKCreator); // OnReload is called by holder } NeighborList::~NeighborList() { DeleteObjectsInContainer(m_neighbors); } void NeighborList::OnReload() { challenge = rand(); PStringToString cfgs(GkConfig()->GetAllKeyValues(NeighborSection)); PINDEX i, sz = cfgs.GetSize(); List::iterator iter = m_neighbors.begin(); while (iter != m_neighbors.end()) { List::iterator it = iter++; for (i = 0; i < sz; ++i) if ((*it)->GetId() == cfgs.GetKeyAt(i)) break; if (i == sz) { Neighbor * r = *it; m_neighbors.erase(it); delete r; } } for (i = 0; i < sz; ++i) { const PString & nbid = cfgs.GetKeyAt(i); const PString & type = cfgs.GetDataAt(i); iter = find_if(m_neighbors.begin(), m_neighbors.end(), compose1(bind2nd(equal_to(), nbid), mem_fun(&Neighbor::GetId)) ); bool newnb = (iter == m_neighbors.end()); Neighbor *nb = newnb ? Factory::Create(type) : *iter; if (nb->SetProfile(nbid, type)) { if (newnb) m_neighbors.push_back(nb); } else { PTRACE(1, "NB\tCan't get profile for neighbor " << nbid); delete nb; if (!newnb) m_neighbors.erase(iter); } } } bool NeighborList::CheckLRQ(RasMsg *ras) const { return find_if(m_neighbors.begin(), m_neighbors.end(), bind2nd(mem_fun(&Neighbor::IsAcceptable), ras)) != m_neighbors.end(); } bool NeighborList::CheckIP(const PIPSocket::Address & addr) const { return find_if(m_neighbors.begin(), m_neighbors.end(), bind2nd(mem_fun(&Neighbor::IsFrom), &addr)) != m_neighbors.end(); } PString NeighborList::GetNeighborIdBySigAdr(const H225_TransportAddress & sigAd) { PIPSocket::Address ipaddr; // Get the Neigbor IP address from the transport address if (!GetIPFromTransportAddr(sigAd, ipaddr)) { return PString(""); } return GetNeighborIdBySigAdr(ipaddr); } PString NeighborList::GetNeighborIdBySigAdr(const PIPSocket::Address & sigAd) { List::iterator findNeighbor; // Attempt to find the neigbor in the list findNeighbor = find_if(m_neighbors.begin(), m_neighbors.end(), bind2nd(mem_fun(&Neighbor::IsFrom), &sigAd)); if (findNeighbor == m_neighbors.end()) { return PString(""); } return (*findNeighbor)->GetId(); } /* Not used currently H225_CryptoH323Token BuildAccessToken(const H225_TransportAddress & dest, const PIPSocket::Address & addr) { H225_CryptoH323Token token; token.SetTag(H225_CryptoH323Token::e_nestedcryptoToken); H235_CryptoToken & nestedCryptoToken = token; nestedCryptoToken.SetTag(H235_CryptoToken::e_cryptoHashedToken); H235_CryptoToken_cryptoHashedToken & cryptoHashedToken = nestedCryptoToken; // "T" indicates that the hashed token is used for authentication and integrity cryptoHashedToken.m_tokenOID = OID_T; H235_ClearToken & clearToken = cryptoHashedToken.m_hashedVals; clearToken.IncludeOptionalField(H235_ClearToken::e_timeStamp); int timeStamp = time(0); clearToken.m_timeStamp = timeStamp; DWORD key = addr ^ timeStamp ^ challenge; PTEACypher::Key cryptokey; memset(&cryptokey, challenge, sizeof(PTEACypher::Key)); memcpy(&cryptokey, &key, sizeof(DWORD)); PTEACypher cypher(cryptokey); PPER_Stream strm; dest.Encode(strm); PString hashed(cypher.Encode(strm)); cryptoHashedToken.m_token.m_hash.SetData(hashed.GetLength() * 8, hashed); return token; } */ bool DecodeAccessToken(const H225_CryptoH323Token & token, const PIPSocket::Address & addr, H225_TransportAddress & dest) { if (token.GetTag() != H225_CryptoH323Token::e_nestedcryptoToken) return false; const H235_CryptoToken & nestedCryptoToken = token; if (nestedCryptoToken.GetTag() != H235_CryptoToken::e_cryptoHashedToken) return false; const H235_CryptoToken_cryptoHashedToken & cryptoHashedToken = nestedCryptoToken; if (cryptoHashedToken.m_tokenOID.AsString() != OID_T) return false; const H235_ClearToken & clearToken = cryptoHashedToken.m_hashedVals; if (!clearToken.HasOptionalField(H235_ClearToken::e_timeStamp)) return false; int now = time(0), timeStamp = clearToken.m_timeStamp.GetValue(); if (timeStamp > now || (now - timeStamp) > 30) return false; const PASN_BitString & bitstring = cryptoHashedToken.m_token.m_hash; PString hashed((const char *)bitstring.GetDataPointer(), bitstring.GetSize() / 8); DWORD key = addr ^ timeStamp ^ challenge; PTEACypher::Key cryptokey; memset(&cryptokey, challenge, sizeof(PTEACypher::Key)); memcpy(&cryptokey, &key, sizeof(DWORD)); PTEACypher cypher(cryptokey); PPER_Stream strm; return cypher.Decode(hashed, strm) && dest.Decode(strm); } } // end of namespace Neighbors namespace Routing { using namespace Neighbors; class NeighborPolicy : public Policy { public: NeighborPolicy(); private: // override from class Policy virtual bool IsActive(); virtual bool OnRequest(AdmissionRequest &); virtual bool OnRequest(LocationRequest &); virtual bool OnRequest(SetupRequest &); virtual bool OnRequest(FacilityRequest &); typedef NeighborList::List List; List & m_neighbors; int m_neighborTimeout; }; NeighborPolicy::NeighborPolicy() : m_neighbors(*RasServer::Instance()->GetNeighbors()) { m_neighborTimeout = GkConfig()->GetInteger(LRQFeaturesSection, "NeighborTimeout", 5) * 1000; m_name = "Neighbor"; } bool NeighborPolicy::IsActive() { return !m_neighbors.empty(); } template inline void CopyCryptoTokens(const H225_LocationConfirm *lcf, H2250 & msg) { // copy access tokens if (lcf->HasOptionalField(H225_LocationConfirm::e_cryptoTokens)) { msg.IncludeOptionalField(H2250::e_cryptoTokens); msg.m_cryptoTokens = lcf->m_cryptoTokens; } } bool NeighborPolicy::OnRequest(AdmissionRequest & arq_obj) { LRQSender functor(arq_obj); LRQRequester request(functor); if (request.Send(m_neighbors)) { if (H225_LocationConfirm *lcf = request.WaitForDestination(m_neighborTimeout)) { Route route(m_name, lcf->m_callSignalAddress); route.m_routeId = request.GetNeighborUsed(); route.m_flags |= Route::e_toNeighbor; arq_obj.AddRoute(route); RasMsg *ras = arq_obj.GetWrapper(); (*ras)->m_replyRAS.SetTag(H225_RasMessage::e_admissionConfirm); H225_AdmissionConfirm & acf = (*ras)->m_replyRAS; CopyCryptoTokens(lcf, acf); return true; } } return false; } bool NeighborPolicy::OnRequest(LocationRequest & lrq_obj) { RasMsg *ras = lrq_obj.GetWrapper(); List::iterator iter = find_if(m_neighbors.begin(), m_neighbors.end(), bind2nd(mem_fun(&Neighbor::IsAcceptable), ras)); Neighbor *requester = (iter != m_neighbors.end()) ? *iter : 0; int hopCount = 0; if (requester) if (requester->ForwardLRQ() < 0) return false; else if (requester->ForwardLRQ() > 0) hopCount = 1; H225_LocationRequest & lrq = (*ras)->m_recvRAS; if (lrq.HasOptionalField(H225_LocationRequest::e_hopCount)) { hopCount = lrq.m_hopCount - 1; if (hopCount) lrq.m_hopCount = hopCount; } if (!hopCount) return false; if (requester && !requester->ForwardResponse()) { LRQForwarder functor(lrq_obj); LRQRequester request(functor); if (request.Send(m_neighbors, requester)) { (*ras)->m_replyRAS.SetTag(H225_RasMessage::e_requestInProgress); H225_RequestInProgress & rip = (*ras)->m_replyRAS; rip.m_requestSeqNum = ras->GetSeqNum(); rip.m_delay = m_neighborTimeout; if (H225_NonStandardParameter *params = ras->GetNonStandardParam()) { PString data = params->m_data.AsString() + ":" + PString(request.GetReqNumber()); rip.IncludeOptionalField(H225_RequestInProgress::e_nonStandardData); rip.m_nonStandardData.m_data.SetValue(data); } return true; } } else { LRQSender functor(lrq_obj); LRQRequester request(functor); if (request.Send(m_neighbors, requester)) { if (H225_LocationConfirm *lcf = request.WaitForDestination(m_neighborTimeout)) { Route route(m_name, lcf->m_callSignalAddress); route.m_routeId = request.GetNeighborUsed(); route.m_flags |= Route::e_toNeighbor; lrq_obj.AddRoute(route); (*ras)->m_replyRAS.SetTag(H225_RasMessage::e_locationConfirm); H225_LocationConfirm & nlcf = (*ras)->m_replyRAS; CopyCryptoTokens(lcf, nlcf); return true; } } } return false; } bool NeighborPolicy::OnRequest(SetupRequest & setup_obj) { LRQSender functor(setup_obj); LRQRequester request(functor); if (request.Send(m_neighbors)) { if (H225_LocationConfirm *lcf = request.WaitForDestination(m_neighborTimeout)) { Route route(m_name, lcf->m_callSignalAddress); route.m_routeId = request.GetNeighborUsed(); route.m_flags |= Route::e_toNeighbor; setup_obj.AddRoute(route); CopyCryptoTokens(lcf, setup_obj.GetRequest()); return true; } } return false; } bool NeighborPolicy::OnRequest(FacilityRequest & facility_obj) { LRQSender functor(facility_obj); LRQRequester request(functor); if (request.Send(m_neighbors)) { if (H225_LocationConfirm *lcf = request.WaitForDestination(m_neighborTimeout)) { Route route(m_name, lcf->m_callSignalAddress); route.m_routeId = request.GetNeighborUsed(); route.m_flags |= Route::e_toNeighbor; facility_obj.AddRoute(route); CopyCryptoTokens(lcf, facility_obj.GetRequest()); return true; } } return false; } namespace { SimpleCreator NeighborPolicyCreator("neighbor"); } } // end of namespace Routing