105 lines
3.5 KiB
Diff
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);
|
|
+ }
|
|
}
|