Fix: add pruneOutOfSubnetData() to auto-remove contaminated device/flow records after every collection cycle
This commit is contained in:
1 parent
b6bd0f42f6
commit
ab5bb1fd11
1 file changed
+69
-1
+69
-1
@@ -2,6 +2,7 @@
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Pruning process for BackOne MongoDB data retention.
|
||||
// Removes telemetry records older than 30 days to conserve database space.
|
||||
// Also removes device/flow records that are outside the agent's configured subnet.
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
const mongoose = require('mongoose');
|
||||
@@ -31,6 +32,73 @@ async function pruneOldData() {
|
||||
console.error(`[Collector] [Retention] ✗ Failed to prune ${name}: ${err.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Also prune out-of-subnet data
|
||||
await pruneOutOfSubnetData();
|
||||
}
|
||||
|
||||
module.exports = { pruneOldData };
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Subnet-based cleanup: remove devices/flows that are outside the agent's
|
||||
// configured allowed_subnets. Runs after every collection cycle automatically.
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
function _ipToLong(ip) {
|
||||
return ip.split('.').reduce((acc, o) => (acc << 8) + parseInt(o, 10), 0) >>> 0;
|
||||
}
|
||||
|
||||
function _ipMatchesSubnets(ip, subnets) {
|
||||
if (!ip || ip.includes(':')) return false; // skip IPv6
|
||||
if (!subnets || subnets.length === 0) return true; // no restriction
|
||||
return subnets.some(s => {
|
||||
if (s.includes('/')) {
|
||||
try {
|
||||
const [r, b] = s.split('/');
|
||||
const bits = parseInt(b, 10);
|
||||
if (isNaN(bits) || bits < 0 || bits > 32) return false;
|
||||
const mask = bits === 0 ? 0 : (~0 << (32 - bits)) >>> 0;
|
||||
return (_ipToLong(ip) & mask) === (_ipToLong(r) & mask);
|
||||
} catch { return false; }
|
||||
}
|
||||
return ip.startsWith(s + '.') || ip === s;
|
||||
});
|
||||
}
|
||||
|
||||
async function pruneOutOfSubnetData() {
|
||||
try {
|
||||
const db = mongoose.connection.db;
|
||||
const agents = await db.collection('agent_registry')
|
||||
.find({ allowed_subnets: { $exists: true, $not: { $size: 0 } } })
|
||||
.toArray();
|
||||
|
||||
for (const agent of agents) {
|
||||
const uuid = agent.uuid;
|
||||
const subnets = (agent.allowed_subnets || []).map(s => s.trim()).filter(Boolean);
|
||||
if (subnets.length === 0) continue;
|
||||
|
||||
// devicestats
|
||||
const devIps = await db.collection('devicestats').distinct('ip_address', { agent_uuid: uuid });
|
||||
const badDevIps = devIps.filter(ip => !_ipMatchesSubnets(ip, subnets));
|
||||
if (badDevIps.length > 0) {
|
||||
const r1 = await db.collection('devicestats').deleteMany({ agent_uuid: uuid, ip_address: { $in: badDevIps } });
|
||||
const r2 = await db.collection('deviceappstats').deleteMany({ agent_uuid: uuid, ip_address: { $in: badDevIps } });
|
||||
if (r1.deletedCount + r2.deletedCount > 0) {
|
||||
console.log(`[Collector] [Subnet] ${uuid}: removed ${r1.deletedCount} device + ${r2.deletedCount} deviceapp records (${badDevIps.length} bad IPs)`);
|
||||
}
|
||||
}
|
||||
|
||||
// flows
|
||||
const flowIps = await db.collection('flows').distinct('src_ip', { agent_uuid: uuid });
|
||||
const badFlowIps = flowIps.filter(ip => !_ipMatchesSubnets(ip, subnets));
|
||||
if (badFlowIps.length > 0) {
|
||||
const r = await db.collection('flows').deleteMany({ agent_uuid: uuid, src_ip: { $in: badFlowIps } });
|
||||
if (r.deletedCount > 0) {
|
||||
console.log(`[Collector] [Subnet] ${uuid}: removed ${r.deletedCount} flow records (${badFlowIps.length} bad IPs)`);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('[Collector] [Subnet] pruneOutOfSubnetData error:', err.message);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { pruneOldData, pruneOutOfSubnetData };
|
||||
Reference in new issue
Block a user