diff --git a/configs/fne-config.example.yml b/configs/fne-config.example.yml index 429b4ada..d7f17812 100644 --- a/configs/fne-config.example.yml +++ b/configs/fne-config.example.yml @@ -87,6 +87,30 @@ master: # Flag indicating whether or not verbose debug logging is enabled. debug: false + # Flag indicating whether or not DMR traffic will be passed. + allowDMRTraffic: true + # Flag indicating whether or not P25 traffic will be passed. + allowP25Traffic: true + # Flag indicating whether or not P25 Phase 2 traffic will be passed. + allowP25P2Traffic: false + # Flag indicating whether or not NXDN traffic will be passed. + allowNXDNTraffic: true + # Flag indicating whether or not analog traffic will be passed. + allowAnalogTraffic: false + + # Maximum number of concurrent packet processing workers. + workers: 16 + + # Flag indicating whether or not master endpoint networking is encrypted. + encrypted: false + # AES-256 32-byte Preshared Key + # (This field *must* be 32 hex bytes in length or 64 characters + # 0 - 9, A - F.) + presharedKey: "000102030405060708090A0B0C0D0E0F000102030405060708090A0B0C0D0E0F" + + # Flag indicating whether or not peer pinging will be reported. + reportPeerPing: true + # # High Availability # @@ -109,7 +133,7 @@ master: # jitterBuffer: # Flag indicating whether the adaptive jitter buffer is enabled by default for all peers. - enabled: false + enable: false # Default maximum buffer size in frames (range: 2-8 frames). # Larger values provide more reordering capability but add latency. # Recommended: 4 frames for most networks, 6-8 for high-jitter links (satellite, cellular). @@ -125,9 +149,6 @@ master: # Flag indicating whether or not calls start/end events from a upstream peer will be logged. logUpstreamCallStartEnd: true - # Maximum number of concurrent packet processing workers. - workers: 16 - # Maximum permitted connections (hard maximum is 250 peers). connectionLimit: 100 @@ -142,10 +163,21 @@ master: # spanning tree updates.) spanningTreeFastReconnect: true - # Console patch status registry configuration. + # Delay from when a call on a parrot TG ends to when the playback starts (in milliseconds). + parrotDelay: 2000 + # Flag indicating whether or not a parrot TG call will generate a grant demand. + parrotGrantDemand: true + # Flag indicating whether or not a parrot TG call will only be sent to the originating peer. + parrotOnlyToOrginiatingPeer: false + # Source ID to override parrot TG calls with (0 for no override). + parrotOverrideSrcId: 0 + + # + # Console patch status registry configuration + # patchStatus: # Flag indicating whether or not console patch status publishing is enabled. - enabled: true + enable: true # Default TTL, in seconds, for console patch status updates that do not specify one. defaultTtlSeconds: 15 # Minimum accepted TTL, in seconds, for console patch status updates. @@ -153,62 +185,64 @@ master: # Maximum accepted TTL, in seconds, for console patch status updates. maxTtlSeconds: 300 - # Flag indicating whether or not peer pinging will be reported. - reportPeerPing: true - - # Flag indicating whether or not master endpoint networking is encrypted. - encrypted: false - # AES-256 32-byte Preshared Key - # (This field *must* be 32 hex bytes in length or 64 characters - # 0 - 9, A - F.) - presharedKey: "000102030405060708090A0B0C0D0E0F000102030405060708090A0B0C0D0E0F" - - # Flag indicating whether or not DMR traffic will be passed. - allowDMRTraffic: true - # Flag indicating whether or not P25 traffic will be passed. - allowP25Traffic: true - # Flag indicating whether or not P25 Phase 2 traffic will be passed. - allowP25P2Traffic: false - # Flag indicating whether or not NXDN traffic will be passed. - allowNXDNTraffic: true - # Flag indicating whether or not analog traffic will be passed. - allowAnalogTraffic: false - - # Flag indicating whether packet data will be passed. - disablePacketData: false - # Flag indicating whether verbose dumping of data packets is enabled. - dumpPacketData: false - # Flag indicating whether verbose logging of data packet operations is enabled. - verbosePacketData: false + # + # Packet data configuration + # + packetData: + # Flag P25 packet data to every peer using the broadcast behavior + # instead of routing it to the subscriber's learned location. + # (This should be set to true if conventional and trunked data registration is not being used.) + broadcast: false - # Delay from when a call on a parrot TG ends to when the playback starts (in milliseconds). - parrotDelay: 2000 - # Flag indicating whether or not a parrot TG call will generate a grant demand. - parrotGrantDemand: true - # Flag indicating whether or not a parrot TG call will only be sent to the originating peer. - parrotOnlyToOrginiatingPeer: false - # Source ID to override parrot TG calls with (0 for no override). - parrotOverrideSrcId: 0 + # + # Dynamic IP Allocation + # + ipPool: + # Starting IP address for dynamic IP allocation pool + startAddress: 192.168.1.10 + # Ending IP address for dynamic IP allocation pool + endAddress: 192.168.1.200 + + # Flag indicating whether packet data will be passed. + disablePacketData: false + # Flag indicating whether verbose dumping of data packets is enabled. + dumpPacketData: false + # Flag indicating whether verbose logging of data packet operations is enabled. + verbosePacketData: false - # Flag indicating whether or not P25 OTAR KMF services are enabled. - kmfServicesEnabled: false - # Port number to listen on for P25 OTAR KMF services. - kmfOtarPort: 64414 - # P25 OTAR KMF RSI - kmfRsi: 9999999 - # Flag indicating whether or not P25 OTAR KMF services will allow RID 0 (broadcast) key requests. - # NOTE: This is used for peer key requests (NOT OTAR REQUESTS). - kmfAllowRID0: false - # Flag indicating whether or not P25 OTAR KMF services will encrypt peer-based key requests. - kmfEncKeyRequest: false - # AES-256 32-byte Preshared Key for peer-based key requests - # (This field *must* be 32 hex bytes in length or 64 characters - # 0 - 9, A - F.) - kmfPresharedKey: "000102030405060708090A0B0C0D0E0F000102030405060708090A0B0C0D0E0F" - # Flag indicating whether or not P25 OTAR KMF services will allow a warm start rekey request. - kmfWarmStart: true - # Flag indicating whether or not verbose debug logging for P25 OTAR KMF services is enabled. - kmfDebug: false + # + # Key Management Facility (KMF) configuration + # + kmf: + # Flag indicating whether or not P25 OTAR KMF services are enabled. + enable: false + # Port number to listen on for P25 OTAR KMF services. + otarPort: 64414 + # P25 OTAR KMF RSI + rsi: 9999999 + + # Flag indicating whether or not P25 OTAR KMF services will allow RID 0 (broadcast) key requests. + # NOTE: This is used for peer key requests (NOT OTAR REQUESTS). + allowRID0: false + # Flag indicating whether or not the source LLID should be forged to the PDU LLID if it is set + # to the default value of 1. + # (This is bad practice and should only be used for testing in controlled environments. This is indicative of + # the KMF parameters not being programmed into the subscriber correctly (like for example the codeplug + # carrying a Individual OTAR Radio ID of 1).) + forgeSrcLLId: false + + # Flag indicating whether or not P25 OTAR KMF services will encrypt peer-based key requests. + encKeyRequest: false + # AES-256 32-byte Preshared Key for peer-based key requests + # (This field *must* be 32 hex bytes in length or 64 characters + # 0 - 9, A - F.) + presharedKey: "000102030405060708090A0B0C0D0E0F000102030405060708090A0B0C0D0E0F" + + # Flag indicating whether or not P25 OTAR KMF services will allow a warm start rekey request. + warmStart: true + + # Flag indicating whether or not verbose debug logging for P25 OTAR KMF services is enabled. + debug: false # Amount of time in seconds for a call collision to last before switching over the source of a call. callCollisionTimeout: 5 @@ -490,12 +524,3 @@ vtun: # Example: # args: "limit=1024 flows=1024 target=5ms interval=100ms ecn=1" args: "" - - # - # P25 SNDCP Dynamic IP Allocation - # - sndcp: - # Starting IP address for dynamic IP allocation pool - startAddress: 192.168.1.10 - # Ending IP address for dynamic IP allocation pool - endAddress: 192.168.1.200 diff --git a/src/fne/HostFNE.cpp b/src/fne/HostFNE.cpp index b4091383..794a6bf3 100644 --- a/src/fne/HostFNE.cpp +++ b/src/fne/HostFNE.cpp @@ -577,7 +577,10 @@ bool HostFNE::createMasterNetwork() bool verbose = masterConf["verbose"].as(false); bool packetDump = masterConf["packetDump"].as(false); bool debug = masterConf["debug"].as(false); - bool kmfDebug = masterConf["kmfDebug"].as(false); + + yaml::Node kmfConf = masterConf["kmf"]; + bool kmfDebug = kmfConf["debug"].as(false); + uint16_t workerCnt = (uint16_t)masterConf["workers"].as(16U); // clamp worker thread count properly @@ -640,19 +643,18 @@ bool HostFNE::createMasterNetwork() } bool parrotGrantDemand = masterConf["parrotGrantDemand"].as(true); - LogInfo("Network Parameters"); + LogInfo("System Parameters"); LogInfo(" Identity: %s", identity.c_str()); LogInfo(" Peer ID: %u", id); LogInfo(" Address: %s", address.c_str()); LogInfo(" Traffic Port: %u", port); LogInfo(" Metadata Port: %u", port + 1U); + LogInfo(" Allow DMR Traffic: %s", m_dmrEnabled ? "yes" : "no"); LogInfo(" Allow P25 Traffic: %s", m_p25Enabled ? "yes" : "no"); LogInfo(" Allow P25 Phase 2 Traffic: %s", m_p25P2Enabled ? "yes" : "no"); LogInfo(" Allow NXDN Traffic: %s", m_nxdnEnabled ? "yes" : "no"); LogInfo(" Allow Analog Traffic: %s", m_analogEnabled ? "yes" : "no"); - LogInfo(" Parrot Repeat Delay: %u ms", parrotDelay); - LogInfo(" Parrot Grant Demand: %s", parrotGrantDemand ? "yes" : "no"); LogInfo(" Worker Threads: %u", workerCnt); @@ -672,15 +674,13 @@ bool HostFNE::createMasterNetwork() LogInfo(" Debug: yes"); } - if (kmfDebug) { - LogInfo(" P25 OTAR KMF Services Debug: yes"); - } - // initialize traffic networking m_network = new TrafficNetwork(this, address, port, id, password, identity, debug, kmfDebug, verbose, reportPeerPing, m_dmrEnabled, m_p25Enabled, m_p25P2Enabled, m_nxdnEnabled, m_analogEnabled, parrotDelay, parrotGrantDemand, m_allowActivityTransfer, m_allowDiagnosticTransfer, m_pingTime, m_updateLookupTime, workerCnt); + yaml::Node vtunConf = m_conf["vtun"]; + m_network->setPacketDataOptions(vtunConf); m_network->setOptions(masterConf, true); m_network->setPacketDump(packetDump); diff --git a/src/fne/network/P25OTARService.cpp b/src/fne/network/P25OTARService.cpp index e08c11b7..13692bfa 100644 --- a/src/fne/network/P25OTARService.cpp +++ b/src/fne/network/P25OTARService.cpp @@ -882,11 +882,17 @@ UInt8Array P25OTARService::processKMM(const uint8_t* data, uint32_t len, uint32_ return nullptr; } + // if configured to forge the source LLID, forge it, if it is set to the default value of 1 + if (m_network->m_kmfForgeSrcLLId && frame->getSrcLLId() == 1U) { + frame->setSrcLLId(llId); + } + // AACA-D 7.4: validate addressing, MN/MAC coupling, authentication and // anti-replay state before executing message-specific behavior if (frame->getDstLLId() != m_network->m_kmfRsi || frame->getSrcLLId() == 0U || (llId != 0U && frame->getSrcLLId() != llId)) { - LogWarning(LOG_P25, P25_KMM_STR ", invalid source/destination RSI, llid = %u, srcLlId = %u, dstLlId = %u", llId, frame->getSrcLLId(), frame->getDstLLId()); + LogWarning(LOG_P25, P25_KMM_STR ", invalid source/destination RSI, llId = %u, srcLlId = %u, dstLlId = %u, kmfRSI = %u", llId, frame->getSrcLLId(), frame->getDstLLId(), + m_network->m_kmfRsi); return nullptr; } diff --git a/src/fne/network/TrafficNetwork.cpp b/src/fne/network/TrafficNetwork.cpp index 826ac5f7..11af7273 100644 --- a/src/fne/network/TrafficNetwork.cpp +++ b/src/fne/network/TrafficNetwork.cpp @@ -91,9 +91,11 @@ TrafficNetwork::TrafficNetwork(HostFNE* host, const std::string& address, uint16 m_kmfServicesEnabled(false), m_kmfRsi(P25DEF::KMF_DEFAULT_RSI), m_kmfAllowRID0(false), + m_kmfForgeSrcLLId(false), m_kmfEncKeyRequest(false), m_kmfPresharedKey(nullptr), m_kmfWarmStart(true), + m_kmfDebug(kmfDebug), m_ridLookup(nullptr), m_ridAliasLookup(nullptr), m_tidLookup(nullptr), @@ -170,13 +172,14 @@ TrafficNetwork::TrafficNetwork(HostFNE* host, const std::string& address, uint16 m_healthTaskEnqueueFailures(0U), m_metadataUpdateMutex(), m_metadataUpdateState(), + m_packetDataBroadcast(false), + m_sndcpStartAddr(__IP_FROM_STR("10.10.1.10")), + m_sndcpEndAddr(__IP_FROM_STR("10.10.1.254")), m_disablePacketData(false), m_dumpPacketData(false), m_verbosePacketData(false), m_vtunQueueMaxFrames(128U), m_vtunQueueMaxBytes(262144U), - m_sndcpStartAddr(__IP_FROM_STR("10.10.1.10")), - m_sndcpEndAddr(__IP_FROM_STR("10.10.1.254")), m_logDenials(false), m_logUpstreamCallStartEnd(true), m_reportPeerPing(reportPeerPing), @@ -254,72 +257,27 @@ void TrafficNetwork::setOptions(yaml::Node& conf, bool printOptions) m_softConnLimit = MAX_HARD_CONN_CAP; } - m_enableSpanningTree = conf["enableSpanningTree"].as(true); - - if (!m_enableSpanningTree) { - LogWarning(LOG_MASTER, "WARNING: Disabling the peer spanning tree is not recommended! This can cause network loops and other issues in a multi-peer FNE network."); - } - - m_logSpanningTreeChanges = conf["logSpanningTreeChanges"].as(false); - m_spanningTreeFastReconnect = conf["spanningTreeFastReconnect"].as(true); - - yaml::Node patchStatusConf = conf["patchStatus"]; - m_patchStatusEnabled = patchStatusConf["enabled"].as(true); - uint32_t patchStatusDefaultTtl = patchStatusConf["defaultTtlSeconds"].as(PatchStatusRegistry::DEFAULT_TTL_SECONDS); - uint32_t patchStatusMinTtl = patchStatusConf["minTtlSeconds"].as(PatchStatusRegistry::MIN_TTL_SECONDS); - uint32_t patchStatusMaxTtl = patchStatusConf["maxTtlSeconds"].as(PatchStatusRegistry::MAX_TTL_SECONDS); - m_patchStatusRegistry.configure(patchStatusDefaultTtl, patchStatusMinTtl, patchStatusMaxTtl); - // always force disable ADJ_STS_BCAST to neighbor FNE peers if the all option // is enabled if (m_disallowAdjStsBcast) { m_disallowExtAdjStsBcast = true; } - yaml::Node metricsConf = conf["metrics"]; - m_enableMetrics = metricsConf["enable"].as(false); - m_metricsLogRawData = metricsConf["logRawData"].as(false); - - yaml::Node influxConf = metricsConf["influx"]; - m_enableInfluxDB = influxConf["enable"].as(false); - m_influxServerAddress = influxConf["serverAddress"].as("127.0.0.1"); - m_influxServerPort = influxConf["serverPort"].as(8086U); - m_influxServerToken = influxConf["serverToken"].as(); - m_influxOrg = influxConf["org"].as("dvm"); - m_influxBucket = influxConf["bucket"].as("dvm"); - if (m_enableInfluxDB) { - m_influxServer = influxdb::ServerInfo(m_influxServerAddress, m_influxServerPort, m_influxOrg, m_influxServerToken, m_influxBucket); - } - - yaml::Node sqliteConf = metricsConf["sqlite"]; - m_enableSQLite = sqliteConf["enable"].as(false); - m_sqliteDBFile = sqliteConf["file"].as("metrics.db"); - m_sqlitePruneAfterDays = sqliteConf["pruneAfterDays"].as(30U); - m_sqlitePruneIntervalMinutes = sqliteConf["pruneIntervalMinutes"].as(60U); - - if (m_sqlitePruneAfterDays == 0U) { - m_sqlitePruneIntervalMinutes = 0U; - } else if (m_sqlitePruneIntervalMinutes > 0U && m_sqlitePruneIntervalMinutes < 5U) { - LogWarning(LOG_MASTER, "SQLite prune interval is too low (%u minutes), clamping to 5 minutes.", m_sqlitePruneIntervalMinutes); - m_sqlitePruneIntervalMinutes = 5U; - } - - TrafficNetwork::MetricsLogging::initialize(this); - - if (m_enableInfluxDB && m_enableSQLite) { - LogWarning(LOG_MASTER, "Both InfluxDB and SQLite metrics logging are enabled. This could cause performance penalties, are you sure?"); - } + // High Availability (HA) configuration + yaml::Node& haParams = conf["ha"]; + m_advertisedHAAddress = haParams["advertisedWANAddress"].as(); + m_advertisedHAPort = (uint16_t)haParams["advertisedWANPort"].as(TRAFFIC_DEFAULT_PORT); + m_haEnabled = haParams["enable"].as(false); - m_parrotOnlyOriginating = conf["parrotOnlyToOrginiatingPeer"].as(false); - m_parrotOverrideSrcId = conf["parrotOverrideSrcId"].as(0U); - if (m_parrotOverrideSrcId > 0U && m_parrotOverrideSrcId > 16777200U) { - LogWarning(LOG_MASTER, "Parrot Override Source ID %u is out of valid range (1 - 16777200), disabling override.", m_parrotOverrideSrcId); - m_parrotOverrideSrcId = 0U; + if (m_haEnabled) { + uint32_t ipAddr = __IP_FROM_STR(m_advertisedHAAddress); + HAParameters params = HAParameters(m_peerId, ipAddr, m_advertisedHAPort); + m_peerReplicaHAParams.push_back(params); } // jitter buffer configuration yaml::Node jitterConf = conf["jitterBuffer"]; - m_jitterBufferEnabled = jitterConf["enabled"].as(false); + m_jitterBufferEnabled = jitterConf["enable"].as(false); m_jitterMaxSize = (uint16_t)jitterConf["defaultMaxSize"].as(DEFAULT_JITTER_MAX_SIZE); m_jitterMaxWait = jitterConf["defaultMaxWait"].as(DEFAULT_JITTER_MAX_WAIT); @@ -333,10 +291,63 @@ void TrafficNetwork::setOptions(yaml::Node& conf, bool printOptions) if (m_jitterMaxWait > MAX_JITTER_MAX_WAIT) m_jitterMaxWait = MAX_JITTER_MAX_WAIT; + // Spanning tree configuration + m_enableSpanningTree = conf["enableSpanningTree"].as(true); + + if (!m_enableSpanningTree) { + LogWarning(LOG_MASTER, "WARNING: Disabling the peer spanning tree is not recommended! This can cause network loops and other issues in a multi-peer FNE network."); + } + + m_logSpanningTreeChanges = conf["logSpanningTreeChanges"].as(false); + m_spanningTreeFastReconnect = conf["spanningTreeFastReconnect"].as(true); + + m_parrotOnlyOriginating = conf["parrotOnlyToOrginiatingPeer"].as(false); + m_parrotOverrideSrcId = conf["parrotOverrideSrcId"].as(0U); + if (m_parrotOverrideSrcId > 0U && m_parrotOverrideSrcId > 16777200U) { + LogWarning(LOG_MASTER, "Parrot Override Source ID %u is out of valid range (1 - 16777200), disabling override.", m_parrotOverrideSrcId); + m_parrotOverrideSrcId = 0U; + } + + // Console patch status registry configuration + yaml::Node patchStatusConf = conf["patchStatus"]; + m_patchStatusEnabled = patchStatusConf["enable"].as(true); + uint32_t patchStatusDefaultTtl = patchStatusConf["defaultTtlSeconds"].as(PatchStatusRegistry::DEFAULT_TTL_SECONDS); + uint32_t patchStatusMinTtl = patchStatusConf["minTtlSeconds"].as(PatchStatusRegistry::MIN_TTL_SECONDS); + uint32_t patchStatusMaxTtl = patchStatusConf["maxTtlSeconds"].as(PatchStatusRegistry::MAX_TTL_SECONDS); + m_patchStatusRegistry.configure(patchStatusDefaultTtl, patchStatusMinTtl, patchStatusMaxTtl); + + // Packet data configuration + yaml::Node packetDataConf = conf["packetData"]; + m_packetDataBroadcast = packetDataConf["broadcast"].as(false); + + m_sndcpStartAddr = __IP_FROM_STR("10.10.1.10"); + m_sndcpEndAddr = __IP_FROM_STR("10.10.1.254"); + + yaml::Node& ipPool = packetDataConf["ipPool"]; + if (ipPool.size() > 0U) { + std::string startAddrStr = ipPool["startAddress"].as("10.10.1.10"); + std::string endAddrStr = ipPool["endAddress"].as("10.10.1.254"); + m_sndcpStartAddr = __IP_FROM_STR(startAddrStr); + m_sndcpEndAddr = __IP_FROM_STR(endAddrStr); + + if (m_sndcpStartAddr == 0U || m_sndcpEndAddr == 0U || m_sndcpStartAddr > m_sndcpEndAddr) { + LogWarning(LOG_MASTER, "Invalid IP pool address range (%s - %s), using defaults", + startAddrStr.c_str(), endAddrStr.c_str()); + m_sndcpStartAddr = __IP_FROM_STR("10.10.1.10"); + m_sndcpEndAddr = __IP_FROM_STR("10.10.1.254"); + } + } + + m_disablePacketData = packetDataConf["disablePacketData"].as(false); + m_dumpPacketData = packetDataConf["dumpPacketData"].as(false); + m_verbosePacketData = packetDataConf["verbosePacketData"].as(false); + + // KMF (Key Management Facility) configuration + yaml::Node kmfConf = conf["kmf"]; #if defined(ENABLE_SSL) - m_kmfServicesEnabled = conf["kmfServicesEnabled"].as(false); - m_kmfRsi = conf["kmfRsi"].as(P25DEF::KMF_DEFAULT_RSI); - uint16_t kmfOtarPort = conf["kmfOtarPort"].as(64414U); + m_kmfServicesEnabled = kmfConf["enable"].as(false); + m_kmfRsi = kmfConf["rsi"].as(P25DEF::KMF_DEFAULT_RSI); + uint16_t kmfOtarPort = kmfConf["otarPort"].as(64414U); if (m_kmfServicesEnabled) { if (!m_p25OTARService->open(m_address, kmfOtarPort)) { m_kmfServicesEnabled = false; @@ -348,13 +359,14 @@ void TrafficNetwork::setOptions(yaml::Node& conf, bool printOptions) m_kmfServicesEnabled = false; LogWarning(LOG_MASTER, "FNE is compiled without OpenSSL support, KMF services are unavailable."); #endif // ENABLE_SSL - m_kmfAllowRID0 = conf["kmfAllowRID0"].as(false); - m_kmfWarmStart = conf["kmfWarmStart"].as(true); + m_kmfAllowRID0 = kmfConf["allowRID0"].as(false); + m_kmfForgeSrcLLId = kmfConf["forgeSrcLLId"].as(false); + m_kmfWarmStart = kmfConf["warmStart"].as(true); // scope is intentional { - bool encrypted = conf["kmfEncKeyRequest"].as(false); - std::string key = conf["kmfPresharedKey"].as(); + bool encrypted = kmfConf["encKeyRequest"].as(false); + std::string key = kmfConf["presharedKey"].as(); if (!key.empty()) { if (key.size() == 32) { // bryanb: shhhhhhh....dirty nasty hacks @@ -394,49 +406,6 @@ void TrafficNetwork::setOptions(yaml::Node& conf, bool printOptions) m_restrictPVCallToRegOnly = conf["restrictPrivateCallToRegOnly"].as(false); m_filterTerminators = conf["filterTerminators"].as(true); - m_disablePacketData = conf["disablePacketData"].as(false); - m_dumpPacketData = conf["dumpPacketData"].as(false); - m_verbosePacketData = conf["verbosePacketData"].as(false); - - // SNDCP IP allocation configuration - m_sndcpStartAddr = __IP_FROM_STR("10.10.1.10"); - m_sndcpEndAddr = __IP_FROM_STR("10.10.1.254"); - m_vtunQueueMaxFrames = 128U; - m_vtunQueueMaxBytes = 262144U; - yaml::Node& vtun = conf["vtun"]; - if (vtun.size() > 0U) { - yaml::Node& queue = vtun["queue"]; - if (queue.size() > 0U) { - m_vtunQueueMaxFrames = queue["maxFrames"].as(128U); - m_vtunQueueMaxBytes = queue["maxBytes"].as(262144U); - - if (m_vtunQueueMaxFrames == 0U) { - LogWarning(LOG_MASTER, "VTUN queue maxFrames is 0, clamping to 1"); - m_vtunQueueMaxFrames = 1U; - } - - if (m_vtunQueueMaxBytes == 0U) { - LogWarning(LOG_MASTER, "VTUN queue maxBytes is 0, clamping to 512"); - m_vtunQueueMaxBytes = 512U; - } - } - - yaml::Node& sndcp = vtun["sndcp"]; - if (sndcp.size() > 0U) { - std::string startAddrStr = sndcp["startAddress"].as("10.10.1.10"); - std::string endAddrStr = sndcp["endAddress"].as("10.10.1.254"); - m_sndcpStartAddr = __IP_FROM_STR(startAddrStr); - m_sndcpEndAddr = __IP_FROM_STR(endAddrStr); - - if (m_sndcpStartAddr > m_sndcpEndAddr) { - LogWarning(LOG_MASTER, "SNDCP start address (%s) is greater than end address (%s), using defaults", - startAddrStr.c_str(), endAddrStr.c_str()); - m_sndcpStartAddr = __IP_FROM_STR("10.10.1.10"); - m_sndcpEndAddr = __IP_FROM_STR("10.10.1.254"); - } - } - } - m_logDenials = conf["logDenials"].as(false); m_logUpstreamCallStartEnd = conf["logUpstreamCallStartEnd"].as(true); @@ -456,57 +425,136 @@ void TrafficNetwork::setOptions(yaml::Node& conf, bool printOptions) } } - yaml::Node& haParams = conf["ha"]; - m_advertisedHAAddress = haParams["advertisedWANAddress"].as(); - m_advertisedHAPort = (uint16_t)haParams["advertisedWANPort"].as(TRAFFIC_DEFAULT_PORT); - m_haEnabled = haParams["enable"].as(false); + // Metrics configuration + yaml::Node metricsConf = conf["metrics"]; + m_enableMetrics = metricsConf["enable"].as(false); + m_metricsLogRawData = metricsConf["logRawData"].as(false); - if (m_haEnabled) { - uint32_t ipAddr = __IP_FROM_STR(m_advertisedHAAddress); - HAParameters params = HAParameters(m_peerId, ipAddr, m_advertisedHAPort); - m_peerReplicaHAParams.push_back(params); + yaml::Node influxConf = metricsConf["influx"]; + m_enableInfluxDB = influxConf["enable"].as(false); + m_influxServerAddress = influxConf["serverAddress"].as("127.0.0.1"); + m_influxServerPort = influxConf["serverPort"].as(8086U); + m_influxServerToken = influxConf["serverToken"].as(); + m_influxOrg = influxConf["org"].as("dvm"); + m_influxBucket = influxConf["bucket"].as("dvm"); + if (m_enableInfluxDB) { + m_influxServer = influxdb::ServerInfo(m_influxServerAddress, m_influxServerPort, m_influxOrg, m_influxServerToken, m_influxBucket); + } + + yaml::Node sqliteConf = metricsConf["sqlite"]; + m_enableSQLite = sqliteConf["enable"].as(false); + m_sqliteDBFile = sqliteConf["file"].as("metrics.db"); + m_sqlitePruneAfterDays = sqliteConf["pruneAfterDays"].as(30U); + m_sqlitePruneIntervalMinutes = sqliteConf["pruneIntervalMinutes"].as(60U); + + if (m_sqlitePruneAfterDays == 0U) { + m_sqlitePruneIntervalMinutes = 0U; + } else if (m_sqlitePruneIntervalMinutes > 0U && m_sqlitePruneIntervalMinutes < 5U) { + LogWarning(LOG_MASTER, "SQLite prune interval is too low (%u minutes), clamping to 5 minutes.", m_sqlitePruneIntervalMinutes); + m_sqlitePruneIntervalMinutes = 5U; + } + + TrafficNetwork::MetricsLogging::initialize(this); + + if (m_enableInfluxDB && m_enableSQLite) { + LogWarning(LOG_MASTER, "Both InfluxDB and SQLite metrics logging are enabled. This could cause performance penalties, are you sure?"); } if (printOptions) { + LogInfo(" Log Traffic Denials: %s", m_logDenials ? "yes" : "no"); + LogInfo(" Log Upstream Call Start/End Events: %s", m_logUpstreamCallStartEnd ? "yes" : "no"); LogInfo(" Maximum Permitted Connections: %u", m_softConnLimit); - LogInfo(" Enable Peer Spanning Tree: %s", m_enableSpanningTree ? "yes" : "no"); - LogInfo(" Log Spanning Tree Changes: %s", m_logSpanningTreeChanges ? "yes" : "no"); - LogInfo(" Spanning Tree Allow Fast Reconnect: %s", m_spanningTreeFastReconnect ? "yes" : "no"); - LogInfo(" Console Patch Status Enabled: %s", m_patchStatusEnabled ? "yes" : "no"); - if (m_patchStatusEnabled) { - LogInfo(" Console Patch Status Default TTL: %us", m_patchStatusRegistry.defaultTtlSeconds()); - LogInfo(" Console Patch Status Minimum TTL: %us", m_patchStatusRegistry.minTtlSeconds()); - LogInfo(" Console Patch Status Maximum TTL: %us", m_patchStatusRegistry.maxTtlSeconds()); + + LogInfo(" Call Collision Timeout: %us", m_callCollisionTimeout); + if (m_callCollisionTimeout == 0U) { + LogWarning(LOG_MASTER, "Call Collisions are disabled because the call collision timeout is set to 0 seconds. This is not recommended, and can cause undesired behavior."); } + LogInfo(" Restrict grant response by affiliation: %s", m_restrictGrantToAffOnly ? "yes" : "no"); + LogInfo(" Restrict private call to registered units: %s", m_restrictPVCallToRegOnly ? "yes" : "no"); LogInfo(" Disable adjacent site broadcasts to any peers: %s", m_disallowAdjStsBcast ? "yes" : "no"); if (m_disallowAdjStsBcast) { LogWarning(LOG_MASTER, "NOTICE: All P25 ADJ_STS_BCAST messages will be blocked and dropped!"); } - LogInfo(" Disable Packet Data: %s", m_disablePacketData ? "yes" : "no"); - LogInfo(" Dump Packet Data: %s", m_dumpPacketData ? "yes" : "no"); - LogInfo(" VTUN Queue Max Frames: %u", m_vtunQueueMaxFrames); - LogInfo(" VTUN Queue Max Bytes: %u", m_vtunQueueMaxBytes); LogInfo(" Disable P25 ADJ_STS_BCAST to neighbor peers: %s", m_disallowExtAdjStsBcast ? "yes" : "no"); LogInfo(" Disable P25 Radio Monitor to any peers: %s", m_disallowRadioMonitor ? "yes" : "no"); - LogInfo(" Disable P25 TDULC call termination broadcasts to any peers: %s", m_disallowCallTerm ? "yes" : "no"); LogInfo(" Allow conventional sites to override affiliation and receive all traffic: %s", m_allowConvSiteAffOverride ? "yes" : "no"); + LogInfo(" Disallow In-Call Control Feedback: %s", m_disallowInCallCtrl ? "yes" : "no"); LogInfo(" Enable RID In-Call Control: %s", m_enableRIDInCallCtrl ? "yes" : "no"); - LogInfo(" Disallow In-Call Control Requests: %s", m_disallowInCallCtrl ? "yes" : "no"); LogInfo(" Reject Unknown RIDs: %s", m_rejectUnknownRID ? "yes" : "no"); - LogInfo(" Log Traffic Denials: %s", m_logDenials ? "yes" : "no"); - LogInfo(" Log Upstream Call Start/End Events: %s", m_logUpstreamCallStartEnd ? "yes" : "no"); + LogInfo(" Disable P25 TDULC call termination broadcasts to any peers: %s", m_disallowCallTerm ? "yes" : "no"); LogInfo(" Mask Outbound Traffic Peer ID: %s", m_maskOutboundPeerID ? "yes" : "no"); if (m_maskOutboundPeerIDForNonPL) { LogInfo(" Mask Outbound Traffic Peer ID for Non-Peer Link: yes"); } - LogInfo(" Call Collision Timeout: %us", m_callCollisionTimeout); - if (m_callCollisionTimeout == 0U) { - LogWarning(LOG_MASTER, "Call Collisions are disabled because the call collision timeout is set to 0 seconds. This is not recommended, and can cause undesired behavior."); - } - LogInfo(" Restrict grant response by affiliation: %s", m_restrictGrantToAffOnly ? "yes" : "no"); - LogInfo(" Restrict private call to registered units: %s", m_restrictPVCallToRegOnly ? "yes" : "no"); LogInfo(" Traffic Terminators Filtered by Destination ID: %s", m_filterTerminators ? "yes" : "no"); LogInfo(" Disallow Unit-to-Unit: %s", m_disallowU2U ? "yes" : "no"); + + LogInfo("High Availability Parameters"); + LogInfo(" High Availability Enabled: %s", m_haEnabled ? "yes" : "no"); + if (m_haEnabled) { + LogInfo(" Advertised HA WAN IP: %s", m_advertisedHAAddress.c_str()); + LogInfo(" Advertised HA WAN Port: %u", m_advertisedHAPort); + } + + LogInfo("Adaptive Jitter Buffer Parameters"); + LogInfo(" Global Jitter Buffer Enabled: %s", m_jitterBufferEnabled ? "yes" : "no"); + if (m_jitterBufferEnabled) { + LogInfo(" Global Jitter Buffer Default Max Size: %u frames", m_jitterMaxSize); + LogInfo(" Global Jitter Buffer Default Max Wait: %u microseconds", m_jitterMaxWait); + } + + LogInfo("Spanning Tree Parameters"); + LogInfo(" Enable Peer Spanning Tree: %s", m_enableSpanningTree ? "yes" : "no"); + LogInfo(" Log Spanning Tree Changes: %s", m_logSpanningTreeChanges ? "yes" : "no"); + LogInfo(" Spanning Tree Allow Fast Reconnect: %s", m_spanningTreeFastReconnect ? "yes" : "no"); + + LogInfo("Parrot Service Parameters"); + LogInfo(" Parrot Repeat Delay: %u ms", m_parrotDelay); + LogInfo(" Parrot Grant Demand: %s", m_parrotGrantDemand ? "yes" : "no"); + LogInfo(" Parrot Repeat to Only Originating Peer: %s", m_parrotOnlyOriginating ? "yes" : "no"); + if (m_parrotOverrideSrcId != 0U) { + LogInfo(" Parrot Repeat Source ID Override: %u", m_parrotOverrideSrcId); + } + + LogInfo("Console Patch Status Parameters"); + LogInfo(" Console Patch Status Enabled: %s", m_patchStatusEnabled ? "yes" : "no"); + if (m_patchStatusEnabled) { + LogInfo(" Console Patch Status Default TTL: %us", m_patchStatusRegistry.defaultTtlSeconds()); + LogInfo(" Console Patch Status Minimum TTL: %us", m_patchStatusRegistry.minTtlSeconds()); + LogInfo(" Console Patch Status Maximum TTL: %us", m_patchStatusRegistry.maxTtlSeconds()); + } + + LogInfo("Packet Data Parameters"); + LogInfo(" Packet Data Broadcast: %s", m_packetDataBroadcast ? "yes" : "no"); + LogInfo(" IP Pool Size: %u", m_sndcpEndAddr - m_sndcpStartAddr + 1U); + LogInfo(" Disable Packet Data: %s", m_disablePacketData ? "yes" : "no"); + LogInfo(" Dump Packet Data: %s", m_dumpPacketData ? "yes" : "no"); + LogInfo(" VTUN Queue Max Frames: %u", m_vtunQueueMaxFrames); + LogInfo(" VTUN Queue Max Bytes: %u", m_vtunQueueMaxBytes); + + LogInfo("Key Management Facility Parameters"); + LogInfo(" OTAR KMF Services Enabled: %s", m_kmfServicesEnabled ? "yes" : "no"); + LogInfo(" OTAR KMF RSI: %u", m_kmfRsi); + LogInfo(" OTAR KMF Listening Address: %s", m_address.c_str()); + LogInfo(" OTAR KMF Listening Port: %u", kmfOtarPort); + LogInfo(" OTAR KMF Allow RID 0 Requests: %s", m_kmfAllowRID0 ? "yes" : "no"); + if (m_kmfAllowRID0) { + LogWarning(LOG_P25, "We are configured to allow RID 0 peer key requests, this is a security risk and shouldn't be used outside of testing environments."); + } + LogInfo(" OTAR KMF Forge Source LLID: %s", m_kmfForgeSrcLLId ? "yes" : "no"); + if (m_kmfForgeSrcLLId) { + LogWarning(LOG_P25, "We are configured to forge the source LLID on KMM packets, this is a security risk and shouldn't be used outside of testing environments."); + } + LogInfo(" OTAR KMF Warm Start Requests Allowed: %s", m_kmfWarmStart ? "yes" : "no"); + LogInfo(" OTAR KMF Peer Request Encrypted: %s", m_kmfEncKeyRequest ? "yes" : "no"); + if (!m_encryptedTrafficConn && !m_kmfEncKeyRequest) { + LogWarning(LOG_MASTER, "Peers can make key requests, but the encrypted traffic connection is not enabled and KMF requests are not encrypted! Key requests will be sent in the clear."); + } + if (m_kmfDebug) { + LogInfo(" OTAR KMF Services Debug: yes"); + } + + LogInfo("Metrics Reporting Parameters"); LogInfo(" Metrics Reporting Enabled: %s", m_enableMetrics ? "yes" : "no"); LogInfo(" Metrics Log Raw TSBK/CSBK/RCCH: %s", m_metricsLogRawData ? "yes" : "no"); LogInfo(" InfluxDB Reporting Enabled: %s", m_enableInfluxDB ? "yes" : "no"); @@ -530,29 +578,28 @@ void TrafficNetwork::setOptions(yaml::Node& conf, bool printOptions) LogWarning(LOG_MASTER, "SQLite Metrics pruning is disabled. This can result in extremely large database files depending on system traffic."); } } - LogInfo(" Global Jitter Buffer Enabled: %s", m_jitterBufferEnabled ? "yes" : "no"); - if (m_jitterBufferEnabled) { - LogInfo(" Global Jitter Buffer Default Max Size: %u frames", m_jitterMaxSize); - LogInfo(" Global Jitter Buffer Default Max Wait: %u microseconds", m_jitterMaxWait); - } - LogInfo(" Parrot Repeat to Only Originating Peer: %s", m_parrotOnlyOriginating ? "yes" : "no"); - if (m_parrotOverrideSrcId != 0U) { - LogInfo(" Parrot Repeat Source ID Override: %u", m_parrotOverrideSrcId); - } - LogInfo(" P25 OTAR KMF Services Enabled: %s", m_kmfServicesEnabled ? "yes" : "no"); - LogInfo(" P25 OTAR KMF RSI: %u", m_kmfRsi); - LogInfo(" P25 OTAR KMF Listening Address: %s", m_address.c_str()); - LogInfo(" P25 OTAR KMF Listening Port: %u", kmfOtarPort); - LogInfo(" P25 KMF Allow RID 0 Requests: %s", m_kmfAllowRID0 ? "yes" : "no"); - LogInfo(" P25 KMF Warm Start Requests Allowed: %s", m_kmfWarmStart ? "yes" : "no"); - LogInfo(" P25 KMF Peer Request Encrypted: %s", m_kmfEncKeyRequest ? "yes" : "no"); - if (!m_encryptedTrafficConn && !m_kmfEncKeyRequest) { - LogWarning(LOG_MASTER, "Peers can make key requests, but the encrypted traffic connection is not enabled and KMF requests are not encrypted! Key requests will be sent in the clear."); + } +} + +/* Helper to set packet-data configuration options. */ + +void TrafficNetwork::setPacketDataOptions(yaml::Node& conf) +{ + m_vtunQueueMaxFrames = 128U; + m_vtunQueueMaxBytes = 262144U; + + yaml::Node& queue = conf["queue"]; + if (queue.size() > 0U) { + m_vtunQueueMaxFrames = queue["maxFrames"].as(128U); + m_vtunQueueMaxBytes = queue["maxBytes"].as(262144U); + + if (m_vtunQueueMaxFrames == 0U) { + LogWarning(LOG_MASTER, "VTUN queue maxFrames is 0, clamping to 1"); + m_vtunQueueMaxFrames = 1U; } - LogInfo(" High Availability Enabled: %s", m_haEnabled ? "yes" : "no"); - if (m_haEnabled) { - LogInfo(" Advertised HA WAN IP: %s", m_advertisedHAAddress.c_str()); - LogInfo(" Advertised HA WAN Port: %u", m_advertisedHAPort); + if (m_vtunQueueMaxBytes == 0U) { + LogWarning(LOG_MASTER, "VTUN queue maxBytes is 0, clamping to 512"); + m_vtunQueueMaxBytes = 512U; } } } diff --git a/src/fne/network/TrafficNetwork.h b/src/fne/network/TrafficNetwork.h index 6debba59..09cd0210 100644 --- a/src/fne/network/TrafficNetwork.h +++ b/src/fne/network/TrafficNetwork.h @@ -210,6 +210,11 @@ namespace network * @param printOptions Flag indicating whether or not options should be printed to log. */ void setOptions(yaml::Node& conf, bool printOptions); + /** + * @brief Sets packet-data options from the top-level VTUN configuration. + * @param conf VTUN configuration node. + */ + void setPacketDataOptions(yaml::Node& conf); /** * @brief Gets the current status of the network. @@ -375,9 +380,11 @@ namespace network bool m_kmfServicesEnabled; uint32_t m_kmfRsi; bool m_kmfAllowRID0; + bool m_kmfForgeSrcLLId; bool m_kmfEncKeyRequest; uint8_t* m_kmfPresharedKey; bool m_kmfWarmStart; + bool m_kmfDebug; lookups::RadioIdLookup* m_ridLookup; lookups::RadioAliasLookup* m_ridAliasLookup; @@ -502,6 +509,9 @@ namespace network std::mutex m_metadataUpdateMutex; std::unordered_map m_metadataUpdateState; + bool m_packetDataBroadcast; + uint32_t m_sndcpStartAddr; + uint32_t m_sndcpEndAddr; bool m_disablePacketData; bool m_dumpPacketData; bool m_verbosePacketData; @@ -509,9 +519,6 @@ namespace network uint32_t m_vtunQueueMaxFrames; uint32_t m_vtunQueueMaxBytes; - uint32_t m_sndcpStartAddr; - uint32_t m_sndcpEndAddr; - bool m_logDenials; bool m_logUpstreamCallStartEnd; bool m_reportPeerPing; diff --git a/src/fne/network/callhandler/packetdata/P25PacketData.cpp b/src/fne/network/callhandler/packetdata/P25PacketData.cpp index 47824069..4b798e72 100644 --- a/src/fne/network/callhandler/packetdata/P25PacketData.cpp +++ b/src/fne/network/callhandler/packetdata/P25PacketData.cpp @@ -71,7 +71,8 @@ P25PacketData::P25PacketData(TrafficNetwork* network, TagP25Data* tag, bool debu m_bindingRegistry(), m_locationRegistry(CONVENTIONAL_LOCATION_MAX_AGE_MS), m_dataLinkManager(), - m_conventionalDataService(m_bindingRegistry, m_dataLinkManager), + m_conventionalDataService(m_bindingRegistry, m_dataLinkManager, + ConventionalRegistrationPolicy { false, 0U, [this](uint32_t llId, uint32_t) { return allocateIPAddress(llId); } }), m_scepService(m_bindingRegistry), m_debug(debug) { @@ -677,9 +678,10 @@ void P25PacketData::dispatch(uint32_t peerId) if (status->assembler.getAuxiliaryES()) sap = status->assembler.dataHeader.getEXSAP(); - // the peer is the only channel identity carried at this boundary -- preserve - // unknown channel fields as zero until peer metadata supplies them, a - // registration establishes location only after the binding is accepted + // The peer is the only channel identity carried at this boundary. Remember + // any valid inbound PDU so DLD OTAR can return KMMs without conventional + // packet-data registration (TIA-102.AACA makes DLD registration optional). + // Registration PDUs establish location only after the binding is accepted. if (sap != PDUSAP::CONV_DATA_REG && m_locationRegistry.learnFromInbound()) { uint32_t inboundLlId = status->assembler.getExtendedAddress() ? status->assembler.dataHeader.getSrcLLId() : status->assembler.dataHeader.getLLId(); @@ -923,7 +925,7 @@ void P25PacketData::dispatchToFNE(uint32_t peerId) uint32_t dstId = status->assembler.dataHeader.getLLId(); std::vector routes; - bool groupDelivery = dstId == WUID_ALL; + bool groupDelivery = dstId == WUID_ALL || m_network->m_packetDataBroadcast; if (groupDelivery) { std::vector availablePeers; for (const auto& peer : m_network->m_peers) @@ -1006,7 +1008,7 @@ bool P25PacketData::dispatchUserFrameToFNE(DataHeader& dataHeader, bool extended uint32_t dstId = dataHeader.getLLId(); std::vector routes; - if (dstId == WUID_ALL) { + if (dstId == WUID_ALL || m_network->m_packetDataBroadcast) { std::vector availablePeers; for (const auto& peer : m_network->m_peers) availablePeers.push_back(peer.first);