diff --git a/src/common/Defines.h b/src/common/Defines.h index 56d6fb1e..1c70f498 100644 --- a/src/common/Defines.h +++ b/src/common/Defines.h @@ -108,7 +108,7 @@ typedef unsigned long long ulong64_t; #define __EXE_NAME__ "" #define VERSION_MAJOR "04" -#define VERSION_MINOR "11" +#define VERSION_MINOR "20" #define VERSION_REV "G" #define __NETVER__ "DVM_R" VERSION_MAJOR VERSION_REV VERSION_MINOR diff --git a/src/fne/network/RESTAPI.cpp b/src/fne/network/RESTAPI.cpp index 9c13b47a..4a366ed6 100644 --- a/src/fne/network/RESTAPI.cpp +++ b/src/fne/network/RESTAPI.cpp @@ -4,7 +4,7 @@ * GPLv2 Open Source. Use is subject to license terms. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * Copyright (C) 2024 Bryan Biedenkapp, N2PLL + * Copyright (C) 2024-2025 Bryan Biedenkapp, N2PLL * Copyright (C) 2024 Patrick McDonnell, W3AXL * */ @@ -222,6 +222,16 @@ json::object tgToJson(const TalkgroupRuleGroupVoice& groupVoice) } config["preferred"].set(preferreds); + json::array permittedRIDs = json::array(); + std::vector permittedRID = groupVoice.config().permittedRIDs(); + if (permittedRID.size() > 0) { + for (auto entry : permittedRID) { + uint32_t rid = entry; + permittedRIDs.push_back(json::value((double)rid)); + } + } + config["permittedRids"].set(permittedRIDs); + tg["config"].set(config); } @@ -445,6 +455,27 @@ TalkgroupRuleGroupVoice jsonToTG(json::object& req, HTTPPayload& reply) config.preferred(preferred); } + if (!configObj["permittedRids"].is()) { + errorPayload(reply, "TG configuration \"permittedRids\" was not a valid JSON array"); + LogDebug(LOG_REST, "TG configuration \"permittedRids\" was not a valid JSON array"); + return TalkgroupRuleGroupVoice(); + } + json::array permittedRIDs = configObj["permittedRids"].get(); + + std::vector permittedRID = groupVoice.config().permittedRIDs(); + if (permittedRIDs.size() > 0) { + for (auto entry : permittedRIDs) { + if (!entry.is()) { + errorPayload(reply, "TG configuration permitted RID value was not a valid number"); + LogDebug(LOG_REST, "TG configuration permitted RID value was not a valid number"); + return TalkgroupRuleGroupVoice(); + } + + permittedRID.push_back(entry.get()); + } + config.permittedRIDs(permittedRID); + } + groupVoice.config(config); } diff --git a/src/fne/network/callhandler/TagDMRData.cpp b/src/fne/network/callhandler/TagDMRData.cpp index 44583ce6..e5705e31 100644 --- a/src/fne/network/callhandler/TagDMRData.cpp +++ b/src/fne/network/callhandler/TagDMRData.cpp @@ -876,6 +876,16 @@ bool TagDMRData::validate(uint32_t peerId, data::NetData& data, uint32_t streamI return false; } + // peer always send list takes priority over any following affiliation rules + bool isAlwaysPeer = false; + std::vector alwaysSend = tg.config().alwaysSend(); + if (alwaysSend.size() > 0) { + auto it = std::find(alwaysSend.begin(), alwaysSend.end(), peerId); + if (it != alwaysSend.end()) { + isAlwaysPeer = true; // skip any following checks and always send traffic + } + } + // check the DMR slot number if (tg.source().tgSlot() != data.getSlotNo()) { // report error event to InfluxDB @@ -918,27 +928,30 @@ bool TagDMRData::validate(uint32_t peerId, data::NetData& data, uint32_t streamI return false; } - // does the TGID have a permitted RID list? - if (tg.config().permittedRIDs().size() > 0) { - // does the transmitting RID have permission? - std::vector permittedRIDs = tg.config().permittedRIDs(); - if (std::find(permittedRIDs.begin(), permittedRIDs.end(), data.getSrcId()) == permittedRIDs.end()) { - // report error event to InfluxDB - if (m_network->m_enableInfluxDB) { - influxdb::QueryBuilder() - .meas("call_error_event") - .tag("peerId", std::to_string(peerId)) - .tag("streamId", std::to_string(streamId)) - .tag("srcId", std::to_string(data.getSrcId())) - .tag("dstId", std::to_string(data.getDstId())) - .field("message", INFLUXDB_ERRSTR_RID_NOT_PERMITTED) - .timestamp(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()) - .request(m_network->m_influxServer); - } + // always peers can violate the rules...hurray + if (!isAlwaysPeer) { + // does the TGID have a permitted RID list? + if (tg.config().permittedRIDs().size() > 0) { + // does the transmitting RID have permission? + std::vector permittedRIDs = tg.config().permittedRIDs(); + if (std::find(permittedRIDs.begin(), permittedRIDs.end(), data.getSrcId()) == permittedRIDs.end()) { + // report error event to InfluxDB + if (m_network->m_enableInfluxDB) { + influxdb::QueryBuilder() + .meas("call_error_event") + .tag("peerId", std::to_string(peerId)) + .tag("streamId", std::to_string(streamId)) + .tag("srcId", std::to_string(data.getSrcId())) + .tag("dstId", std::to_string(data.getDstId())) + .field("message", INFLUXDB_ERRSTR_RID_NOT_PERMITTED) + .timestamp(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()) + .request(m_network->m_influxServer); + } - // report In-Call Control to the peer sending traffic - m_network->writePeerICC(peerId, streamId, NET_SUBFUNC::PROTOCOL_SUBFUNC_DMR, NET_ICC::REJECT_TRAFFIC, data.getDstId(), data.getSlotNo()); - return false; + // report In-Call Control to the peer sending traffic + m_network->writePeerICC(peerId, streamId, NET_SUBFUNC::PROTOCOL_SUBFUNC_DMR, NET_ICC::REJECT_TRAFFIC, data.getDstId(), data.getSlotNo()); + return false; + } } } } diff --git a/src/fne/network/callhandler/TagNXDNData.cpp b/src/fne/network/callhandler/TagNXDNData.cpp index ae674b37..d19dae20 100644 --- a/src/fne/network/callhandler/TagNXDNData.cpp +++ b/src/fne/network/callhandler/TagNXDNData.cpp @@ -682,6 +682,16 @@ bool TagNXDNData::validate(uint32_t peerId, lc::RTCH& lc, uint8_t messageType, u return false; } + // peer always send list takes priority over any following affiliation rules + bool isAlwaysPeer = false; + std::vector alwaysSend = tg.config().alwaysSend(); + if (alwaysSend.size() > 0) { + auto it = std::find(alwaysSend.begin(), alwaysSend.end(), peerId); + if (it != alwaysSend.end()) { + isAlwaysPeer = true; // skip any following checks and always send traffic + } + } + // is the TGID active? if (!tg.config().active()) { // report error event to InfluxDB @@ -702,27 +712,30 @@ bool TagNXDNData::validate(uint32_t peerId, lc::RTCH& lc, uint8_t messageType, u return false; } - // does the TGID have a permitted RID list? - if (tg.config().permittedRIDs().size() > 0) { - // does the transmitting RID have permission? - std::vector permittedRIDs = tg.config().permittedRIDs(); - if (std::find(permittedRIDs.begin(), permittedRIDs.end(), lc.getSrcId()) == permittedRIDs.end()) { - // report error event to InfluxDB - if (m_network->m_enableInfluxDB) { - influxdb::QueryBuilder() - .meas("call_error_event") - .tag("peerId", std::to_string(peerId)) - .tag("streamId", std::to_string(streamId)) - .tag("srcId", std::to_string(lc.getSrcId())) - .tag("dstId", std::to_string(lc.getDstId())) - .field("message", INFLUXDB_ERRSTR_RID_NOT_PERMITTED) - .timestamp(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()) - .request(m_network->m_influxServer); - } + // always peers can violate the rules...hurray + if (!isAlwaysPeer) { + // does the TGID have a permitted RID list? + if (tg.config().permittedRIDs().size() > 0) { + // does the transmitting RID have permission? + std::vector permittedRIDs = tg.config().permittedRIDs(); + if (std::find(permittedRIDs.begin(), permittedRIDs.end(), lc.getSrcId()) == permittedRIDs.end()) { + // report error event to InfluxDB + if (m_network->m_enableInfluxDB) { + influxdb::QueryBuilder() + .meas("call_error_event") + .tag("peerId", std::to_string(peerId)) + .tag("streamId", std::to_string(streamId)) + .tag("srcId", std::to_string(lc.getSrcId())) + .tag("dstId", std::to_string(lc.getDstId())) + .field("message", INFLUXDB_ERRSTR_RID_NOT_PERMITTED) + .timestamp(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()) + .request(m_network->m_influxServer); + } - // report In-Call Control to the peer sending traffic - m_network->writePeerICC(peerId, streamId, NET_SUBFUNC::PROTOCOL_SUBFUNC_NXDN, NET_ICC::REJECT_TRAFFIC, lc.getDstId()); - return false; + // report In-Call Control to the peer sending traffic + m_network->writePeerICC(peerId, streamId, NET_SUBFUNC::PROTOCOL_SUBFUNC_NXDN, NET_ICC::REJECT_TRAFFIC, lc.getDstId()); + return false; + } } } diff --git a/src/fne/network/callhandler/TagP25Data.cpp b/src/fne/network/callhandler/TagP25Data.cpp index a36b1bd2..fd73f2b7 100644 --- a/src/fne/network/callhandler/TagP25Data.cpp +++ b/src/fne/network/callhandler/TagP25Data.cpp @@ -1072,7 +1072,7 @@ bool TagP25Data::validate(uint32_t peerId, lc::LC& control, DUID::E duid, const skipRidCheck = true; } - LogDebug(LOG_NET, "P25, duid = $%02X, mfId = $%02X, lco = $%02X, srcId = %u, dstId = %u", duid, control.getMFId(), control.getLCO(), control.getSrcId(), control.getDstId()); + //LogDebug(LOG_NET, "P25, duid = $%02X, mfId = $%02X, lco = $%02X, srcId = %u, dstId = %u", duid, control.getMFId(), control.getLCO(), control.getSrcId(), control.getDstId()); // is the source ID a blacklisted ID? if (!skipRidCheck) { @@ -1249,6 +1249,16 @@ bool TagP25Data::validate(uint32_t peerId, lc::LC& control, DUID::E duid, const return false; } + // peer always send list takes priority over any following affiliation rules + bool isAlwaysPeer = false; + std::vector alwaysSend = tg.config().alwaysSend(); + if (alwaysSend.size() > 0) { + auto it = std::find(alwaysSend.begin(), alwaysSend.end(), peerId); + if (it != alwaysSend.end()) { + isAlwaysPeer = true; // skip any following checks and always send traffic + } + } + // is the TGID active? if (!tg.config().active()) { // report error event to InfluxDB @@ -1269,34 +1279,36 @@ bool TagP25Data::validate(uint32_t peerId, lc::LC& control, DUID::E duid, const return false; } - // does the TGID have a permitted RID list? - if (tg.config().permittedRIDs().size() > 0) { - // does the transmitting RID have permission? - std::vector permittedRIDs = tg.config().permittedRIDs(); - if (std::find(permittedRIDs.begin(), permittedRIDs.end(), control.getSrcId()) == permittedRIDs.end()) { - // report error event to InfluxDB - if (m_network->m_enableInfluxDB) { - influxdb::QueryBuilder() - .meas("call_error_event") - .tag("peerId", std::to_string(peerId)) - .tag("streamId", std::to_string(streamId)) - .tag("srcId", std::to_string(control.getSrcId())) - .tag("dstId", std::to_string(control.getDstId())) - .field("message", INFLUXDB_ERRSTR_RID_NOT_PERMITTED) - .timestamp(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()) - .request(m_network->m_influxServer); - } + // always peers can violate the rules...hurray + if (!isAlwaysPeer) { + // does the TGID have a permitted RID list? + if (tg.config().permittedRIDs().size() > 0) { + // does the transmitting RID have permission? + std::vector permittedRIDs = tg.config().permittedRIDs(); + if (std::find(permittedRIDs.begin(), permittedRIDs.end(), control.getSrcId()) == permittedRIDs.end()) { + // report error event to InfluxDB + if (m_network->m_enableInfluxDB) { + influxdb::QueryBuilder() + .meas("call_error_event") + .tag("peerId", std::to_string(peerId)) + .tag("streamId", std::to_string(streamId)) + .tag("srcId", std::to_string(control.getSrcId())) + .tag("dstId", std::to_string(control.getDstId())) + .field("message", INFLUXDB_ERRSTR_RID_NOT_PERMITTED) + .timestamp(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()) + .request(m_network->m_influxServer); + } - // report In-Call Control to the peer sending traffic - m_network->writePeerICC(peerId, streamId, NET_SUBFUNC::PROTOCOL_SUBFUNC_P25, NET_ICC::REJECT_TRAFFIC, control.getDstId()); - return false; + // report In-Call Control to the peer sending traffic + m_network->writePeerICC(peerId, streamId, NET_SUBFUNC::PROTOCOL_SUBFUNC_P25, NET_ICC::REJECT_TRAFFIC, control.getDstId()); + return false; + } } } return true; } - /* Helper to write a grant packet. */ bool TagP25Data::write_TSDU_Grant(uint32_t peerId, uint32_t srcId, uint32_t dstId, uint8_t serviceOptions, bool grp)