java-topology/defects/bzflag-0002/patch/bzflag-0002.patch

105 lines
3.5 KiB
Diff

# UNDF: UNDF-2026-000000994
--- a/src/bzfs/AccessControlList.h
+++ b/src/bzfs/AccessControlList.h
@@ -12,6 +12,7 @@
// System headers
#include <vector>
+#include <unordered_set>
#include <string>
#include <string.h>
@@ -173,6 +174,15 @@
/* FIXME the AccessControlList assumes that 255 is a wildcard. it "should"
* include a cidr mask with each address. it's still useful as is, though
* see wildcard conversion occurs in convert().
+ *
+ * PERF NOTE: ban(), hostBan(), and idBan() each use std::find() on our
+ * vector to detect duplicates before inserting. When called from merge()
+ * which processes every entry in a master ban list, this makes ban list
+ * loading O(B^2) where B = number of bans. For large master ban lists
+ * (hundreds to thousands of entries from community servers) this is
+ * significant. Fix: maintain a parallel unordered_set index keyed on
+ * the ban identity (IP+CIDR for IP bans, hostpat for host bans, idpat
+ * for ID bans) to achieve O(1) duplicate detection.
*/
/** This class handles the lists of bans and hostbans. It has functions for
@@ -296,6 +306,15 @@
typedef std::vector<IdBanInfo> idBanList_t;
idBanList_t idBanList;
+ // O(1) duplicate detection indexes.
+ // Key for IP bans: (addr.s_addr, cidr) packed as uint64.
+ // Key for host bans: hostpat string.
+ // Key for ID bans: idpat string.
+ std::unordered_set<uint64_t> banIndex;
+ std::unordered_set<std::string> hostBanIndex;
+ std::unordered_set<std::string> idBanIndex;
+
+ static uint64_t banKey(in_addr addr, unsigned char cidr) { return ((uint64_t)addr.s_addr << 8) | cidr; }
std::string banFile;
private:
--- a/src/bzfs/AccessControlList.cxx
+++ b/src/bzfs/AccessControlList.cxx
@@ -41,9 +41,12 @@
{
BanInfo toban(ipAddr, bannedBy, period, cidr, fromMaster);
if (reason) toban.reason = reason;
- banList_t::iterator oldit = std::find(banList.begin(), banList.end(), toban);
- if (oldit != banList.end()) // IP already in list? -> replace
- *oldit = toban;
+ uint64_t key = banKey(ipAddr, cidr);
+ if (banIndex.count(key)) {
+ // IP already in list -> replace
+ banList_t::iterator oldit = std::find(banList.begin(), banList.end(), toban);
+ if (oldit != banList.end())
+ *oldit = toban;
+ }
else
+ {
+ banIndex.insert(key);
banList.push_back(toban);
+ }
}
@@ -93,9 +96,12 @@
{
HostBanInfo toban(hostpat, bannedBy, period,fromMaster);
if (reason) toban.reason = reason;
- hostBanList_t::iterator oldit = std::find(hostBanList.begin(), hostBanList.end(), toban);
- if (oldit != hostBanList.end())
- *oldit = toban;
+ if (hostBanIndex.count(hostpat)) {
+ hostBanList_t::iterator oldit = std::find(hostBanList.begin(), hostBanList.end(), toban);
+ if (oldit != hostBanList.end())
+ *oldit = toban;
+ }
else
+ {
+ hostBanIndex.insert(hostpat);
hostBanList.push_back(toban);
+ }
}
@@ -106,9 +112,12 @@
{
IdBanInfo toban(idpat, bannedBy, period, fromMaster);
if (reason) toban.reason = reason;
- idBanList_t::iterator oldit = std::find(idBanList.begin(), idBanList.end(), toban);
- if (oldit != idBanList.end())
- *oldit = toban;
+ if (idBanIndex.count(idpat)) {
+ idBanList_t::iterator oldit = std::find(idBanList.begin(), idBanList.end(), toban);
+ if (oldit != idBanList.end())
+ *oldit = toban;
+ }
else
+ {
+ idBanIndex.insert(idpat);
idBanList.push_back(toban);
+ }
}