From bd3e737adf2039078c1e64ef0a14b0bb7fd4a1e2 Mon Sep 17 00:00:00 2001
From: firealarmss <99303085+firealarmss@users.noreply.github.com>
Date: Sat, 15 Jun 2024 05:35:24 -0500
Subject: [PATCH] REST Additions and added NAK reasons (#56)
* Initial work for a peer whitelist/blacklist
* Remove forgotten debug log
* Remove extra line
* Use a dedicated file for white/blacklists
* Add support to REST for managing the peer white/blacklist
* Fix line spaces
* Move to one example file
* Add support for disconnecting a peer via the REST API; Add NAK reason for a peer ACL violation and for a peer reset; Add a REST endpoint for getting the current mode of peer ACL
---
src/common/lookups/PeerListLookup.cpp | 8 +++
src/common/lookups/PeerListLookup.h | 3 ++
src/common/network/BaseNetwork.h | 2 +
src/fne/network/FNENetwork.cpp | 53 +++++++++++++++++---
src/fne/network/FNENetwork.h | 3 ++
src/fne/network/RESTAPI.cpp | 72 +++++++++++++++++++++++++++
src/fne/network/RESTAPI.h | 4 ++
src/fne/network/RESTDefines.h | 2 +
src/host/network/Network.cpp | 6 +++
9 files changed, 147 insertions(+), 6 deletions(-)
diff --git a/src/common/lookups/PeerListLookup.cpp b/src/common/lookups/PeerListLookup.cpp
index c26119f6..2222ee05 100644
--- a/src/common/lookups/PeerListLookup.cpp
+++ b/src/common/lookups/PeerListLookup.cpp
@@ -155,6 +155,14 @@ void PeerListLookup::setEnabled(bool enabled)
m_enabled = enabled;
}
+///
+/// Gets whether the lookup is enabled.
+///
+bool PeerListLookup::getEnabled() const
+{
+ return m_enabled;
+}
+
///
/// Finds a table entry in this lookup table.
///
diff --git a/src/common/lookups/PeerListLookup.h b/src/common/lookups/PeerListLookup.h
index f13461cf..f324d2bf 100644
--- a/src/common/lookups/PeerListLookup.h
+++ b/src/common/lookups/PeerListLookup.h
@@ -72,6 +72,9 @@ namespace lookups
/// Sets whether the lookup is enabled.
void setEnabled(bool enabled);
+ /// Gets whether the lookup is enabled.
+ bool getEnabled() const;
+
/// Finds a table entry in this lookup table.
uint32_t find(uint32_t id) override;
diff --git a/src/common/network/BaseNetwork.h b/src/common/network/BaseNetwork.h
index dcb3e443..15bf1219 100644
--- a/src/common/network/BaseNetwork.h
+++ b/src/common/network/BaseNetwork.h
@@ -145,6 +145,8 @@ namespace network
NET_CONN_NAK_FNE_UNAUTHORIZED,
NET_CONN_NAK_BAD_CONN_STATE,
NET_CONN_NAK_INVALID_CONFIG_DATA,
+ NET_CONN_NAK_PEER_RESET,
+ NET_CONN_NAK_PEER_ACL,
NET_CONN_NAK_FNE_MAX_CONN,
diff --git a/src/fne/network/FNENetwork.cpp b/src/fne/network/FNENetwork.cpp
index 0fe19c45..b0b9dbd3 100644
--- a/src/fne/network/FNENetwork.cpp
+++ b/src/fne/network/FNENetwork.cpp
@@ -637,35 +637,42 @@ void* FNENetwork::threadedNetworkRx(void* arg)
delete[] in;
// validate hash
- bool valid = false;
+ bool validHash = false;
if (req->length - 8U == 32U) {
- valid = true;
+ validHash = true;
for (uint8_t i = 0; i < 32U; i++) {
if (hash[i] != out[i]) {
- valid = false;
+ validHash = false;
break;
}
}
}
// check if the peer is (not)whitelisted or blacklisted
+ bool validAcl = true;
if (!network->m_peerListLookup->isPeerAllowed(peerId)) {
if (network->m_peerListLookup->getMode() == lookups::PeerListLookup::BLACKLIST) {
LogWarning(LOG_NET, "PEER %u is blacklisted", peerId);
} else {
LogWarning(LOG_NET, "PEER %u is not whitelisted", peerId);
}
- valid = false;
+ validAcl = false;
}
- if (valid) {
+ if (validHash && validAcl) {
connection->connectionState(NET_STAT_WAITING_CONFIG);
network->writePeerACK(peerId);
LogInfoEx(LOG_NET, "PEER %u RPTK ACK, completed the login exchange", peerId);
}
else {
LogWarning(LOG_NET, "PEER %u RPTK NAK, failed the login exchange", peerId);
- network->writePeerNAK(peerId, TAG_REPEATER_AUTH, NET_CONN_NAK_FNE_UNAUTHORIZED);
+
+ if (!validAcl) {
+ network->writePeerNAK(peerId, TAG_REPEATER_AUTH, NET_CONN_NAK_PEER_ACL);
+ } else {
+ network->writePeerNAK(peerId, TAG_REPEATER_AUTH, NET_CONN_NAK_FNE_UNAUTHORIZED);
+ }
+
network->erasePeer(peerId);
}
@@ -1217,6 +1224,34 @@ bool FNENetwork::erasePeer(uint32_t peerId)
return false;
}
+///
+/// Helper to reset a peer connection.
+///
+///
+///
+bool FNENetwork::resetPeer(uint32_t peerId)
+{
+ if (peerId > 0 && (m_peers.find(peerId) != m_peers.end())) {
+ FNEPeerConnection* connection = m_peers[peerId];
+ if (connection != nullptr) {
+ sockaddr_storage addr = connection->socketStorage();
+ uint32_t addrLen = connection->sockStorageLen();
+
+ LogInfoEx(LOG_NET, "PEER %u (%s) resetting peer connection", peerId, connection->identity().c_str());
+
+ writePeerNAK(peerId, TAG_REPEATER_LOGIN, NET_CONN_NAK_PEER_RESET, addr, addrLen);
+
+ delete connection;
+ erasePeer(peerId);
+
+ return true;
+ }
+ }
+
+ LogWarning(LOG_NET, "PEER %u reset failed; peer not found.", peerId);
+ return false;
+}
+
///
/// Helper to resolve the peer ID to its identity string.
///
@@ -1738,6 +1773,12 @@ void FNENetwork::logPeerNAKReason(uint32_t peerId, const char* tag, NET_CONN_NAK
case NET_CONN_NAK_FNE_MAX_CONN:
LogWarning(LOG_NET, "PEER %u NAK %s, reason = %u; FNE has reached maximum permitted connections", peerId, tag, (uint16_t)reason);
break;
+ case NET_CONN_NAK_PEER_RESET:
+ LogWarning(LOG_NET, "PEER %u master NAK; FNE Called for a connection reset", peerId, tag, (uint16_t)reason);
+ break;
+ case NET_CONN_NAK_PEER_ACL:
+ LogWarning(LOG_NET, "PEER %u NAK %s, reason = %u; ACL Rejection", peerId, tag, (uint16_t)reason);
+ break;
case NET_CONN_NAK_GENERAL_FAILURE:
default:
diff --git a/src/fne/network/FNENetwork.h b/src/fne/network/FNENetwork.h
index 05ae37ca..35f58acf 100644
--- a/src/fne/network/FNENetwork.h
+++ b/src/fne/network/FNENetwork.h
@@ -259,6 +259,9 @@ namespace network
/// Closes connection to the network.
void close() override;
+ ///
+ bool resetPeer(uint32_t peerId);
+
private:
friend class DiagNetwork;
friend class fne::TagDMRData;
diff --git a/src/fne/network/RESTAPI.cpp b/src/fne/network/RESTAPI.cpp
index a046a1b6..ba27dfc8 100644
--- a/src/fne/network/RESTAPI.cpp
+++ b/src/fne/network/RESTAPI.cpp
@@ -571,6 +571,7 @@ void RESTAPI::initializeEndpoints()
m_dispatcher.match(FNE_GET_PEER_QUERY).get(REST_API_BIND(RESTAPI::restAPI_GetPeerQuery, this));
m_dispatcher.match(FNE_GET_PEER_COUNT).get(REST_API_BIND(RESTAPI::restAPI_GetPeerCount, this));
+ m_dispatcher.match(FNE_PUT_PEER_RESET).put(REST_API_BIND(RESTAPI::restAPI_PutPeerReset, this));
m_dispatcher.match(FNE_GET_RID_QUERY).get(REST_API_BIND(RESTAPI::restAPI_GetRIDQuery, this));
m_dispatcher.match(FNE_PUT_RID_ADD).put(REST_API_BIND(RESTAPI::restAPI_PutRIDAdd, this));
@@ -586,6 +587,7 @@ void RESTAPI::initializeEndpoints()
m_dispatcher.match(FNE_PUT_PEER_ADD).put(REST_API_BIND(RESTAPI::restAPI_PutPeerAdd, this));
m_dispatcher.match(FNE_PUT_PEER_DELETE).put(REST_API_BIND(RESTAPI::restAPI_PutPeerDelete, this));
m_dispatcher.match(FNE_GET_PEER_COMMIT).get(REST_API_BIND(RESTAPI::restAPI_GetPeerCommit, this));
+ m_dispatcher.match(FNE_GET_PEER_MODE).get(REST_API_BIND(RESTAPI::restAPI_GetPeerMode, this));
m_dispatcher.match(FNE_GET_FORCE_UPDATE).get(REST_API_BIND(RESTAPI::restAPI_GetForceUpdate, this));
@@ -873,6 +875,35 @@ void RESTAPI::restAPI_GetPeerCount(const HTTPPayload& request, HTTPPayload& repl
reply.payload(response);
}
+///
+///
+///
+///
+///
+///
+void RESTAPI::restAPI_PutPeerReset(const HTTPPayload& request, HTTPPayload& reply, const RequestMatch& match)
+{
+ if (!validateAuth(request, reply)) {
+ return;
+ }
+
+ json::object req = json::object();
+ if (!parseRequestBody(request, reply, req)) {
+ return;
+ }
+
+ errorPayload(reply, "OK", HTTPPayload::OK);
+
+ if (!req["peerId"].is()) {
+ errorPayload(reply, "peerId was not a valid integer");
+ return;
+ }
+
+ uint32_t peerId = req["peerId"].get();
+
+ m_network->resetPeer(peerId);
+}
+
///
///
///
@@ -1273,6 +1304,47 @@ void RESTAPI::restAPI_GetPeerCommit(const HTTPPayload& request, HTTPPayload& rep
reply.payload(response);
}
+///
+///
+///
+///
+///
+///
+void RESTAPI::restAPI_GetPeerMode(const HTTPPayload& request, HTTPPayload& reply, const RequestMatch& match)
+{
+ if (!validateAuth(request, reply)) {
+ return;
+ }
+
+ json::object response = json::object();
+ setResponseDefaultStatus(response);
+
+ lookups::PeerListLookup::Mode mode = m_peerListLookup->getMode();
+ bool enabled = m_peerListLookup->getEnabled();
+
+ std::string modeStr;
+
+ if (enabled) {
+ switch (mode) {
+ case lookups::PeerListLookup::WHITELIST:
+ modeStr = "WHITELIST";
+ break;
+ case lookups::PeerListLookup::BLACKLIST:
+ modeStr = "BLACKLIST";
+ break;
+ default:
+ modeStr = "UNKNOWN";
+ break;
+ }
+ }
+ else {
+ modeStr = "DISABLED";
+ }
+
+ response["mode"].set(modeStr);
+ reply.payload(response);
+}
+
///
///
///
diff --git a/src/fne/network/RESTAPI.h b/src/fne/network/RESTAPI.h
index 4729edb1..516715f8 100644
--- a/src/fne/network/RESTAPI.h
+++ b/src/fne/network/RESTAPI.h
@@ -106,6 +106,8 @@ private:
void restAPI_GetPeerQuery(const HTTPPayload& request, HTTPPayload& reply, const network::rest::RequestMatch& match);
///
void restAPI_GetPeerCount(const HTTPPayload& request, HTTPPayload& reply, const network::rest::RequestMatch& match);
+ ///
+ void restAPI_PutPeerReset(const HTTPPayload& request, HTTPPayload& reply, const network::rest::RequestMatch& match);
///
void restAPI_GetRIDQuery(const HTTPPayload& request, HTTPPayload& reply, const network::rest::RequestMatch& match);
@@ -133,6 +135,8 @@ private:
void restAPI_PutPeerDelete(const HTTPPayload& request, HTTPPayload& reply, const network::rest::RequestMatch& match);
///
void restAPI_GetPeerCommit(const HTTPPayload& request, HTTPPayload& reply, const network::rest::RequestMatch& match);
+ ///
+ void restAPI_GetPeerMode(const HTTPPayload& request, HTTPPayload& reply, const network::rest::RequestMatch& match);
///
void restAPI_GetForceUpdate(const HTTPPayload& request, HTTPPayload& reply, const network::rest::RequestMatch& match);
diff --git a/src/fne/network/RESTDefines.h b/src/fne/network/RESTDefines.h
index 51696957..061c6acf 100644
--- a/src/fne/network/RESTDefines.h
+++ b/src/fne/network/RESTDefines.h
@@ -22,6 +22,7 @@
#define FNE_GET_PEER_QUERY "/peer/query"
#define FNE_GET_PEER_COUNT "/peer/count"
+#define FNE_PUT_PEER_RESET "/peer/reset"
#define FNE_GET_RID_QUERY "/rid/query"
#define FNE_PUT_RID_ADD "/rid/add"
@@ -37,6 +38,7 @@
#define FNE_PUT_PEER_ADD "/peer/add"
#define FNE_PUT_PEER_DELETE "/peer/delete"
#define FNE_GET_PEER_COMMIT "/peer/commit"
+#define FNE_GET_PEER_MODE "/peer/mode"
#define FNE_GET_FORCE_UPDATE "/force-update"
diff --git a/src/host/network/Network.cpp b/src/host/network/Network.cpp
index 9a1f7851..df810557 100644
--- a/src/host/network/Network.cpp
+++ b/src/host/network/Network.cpp
@@ -541,6 +541,12 @@ void Network::clock(uint32_t ms)
case NET_CONN_NAK_FNE_MAX_CONN:
LogWarning(LOG_NET, "PEER %u master NAK; FNE has reached maximum permitted connections, remotePeerId = %u", m_peerId, rtpHeader.getSSRC());
break;
+ case NET_CONN_NAK_PEER_RESET:
+ LogWarning(LOG_NET, "PEER %u master NAK; FNE Called for a connection reset, remotePeerId = %u", m_peerId, rtpHeader.getSSRC());
+ break;
+ case NET_CONN_NAK_PEER_ACL:
+ LogWarning(LOG_NET, "PEER %u master NAK; ACL Rejection, remotePeerId = %u", m_peerId, rtpHeader.getSSRC());
+ break;
case NET_CONN_NAK_GENERAL_FAILURE:
default: