feat(api, web): enhance MikroTik integration and IP hit tracking
Build and Push EvoFirewall Docker Image / build-and-push (push) Successful in 1m54s
Build and Push EvoFirewall Docker Image / create-release (push) Skipped

- Updated the `evofw-firewall.sh` script to improve the handling of NFT sets, ensuring compatibility with kernel limitations on counters and enhancing logging for better diagnostics.
- Introduced a new presence mode for MikroTik, allowing for real-time tracking of IP hits with updated last seen timestamps and packet counts.
- Enhanced the API to support the new presence mode, updating the database interactions to reflect the changes in how IP hits are recorded.
- Updated the agent detail view to display sync windows for MikroTik, providing clearer insights into blocked IPs and their activity.
- Improved documentation to reflect the new features and changes in the MikroTik handling process, ensuring clarity for users and developers.

These changes significantly enhance the monitoring capabilities and user experience for agents, particularly those using MikroTik devices.
This commit is contained in:
Denozordec
2026-08-07 14:46:06 +07:00
parent 4ee78032c4
commit ee3429b747
8 changed files with 237 additions and 54 deletions
+40 -2
View File
@@ -36,16 +36,28 @@ export function deleteStatsSamplesForAgent(db: Db, agentId: string) {
export type IpHitInput = { ip: string; packets: number }
export type UpsertIpBlockStatsOptions = {
/**
* MikroTik EVOFW_HITS presence: always refresh last_seen;
* packets += 1 per report (sync-window sightings).
* Linux keeps absolute counter deltas (default).
*/
mode?: 'absolute' | 'presence'
}
/**
* Upsert per-IP drop counters. Agent reports absolute kernel counters;
* CP accumulates deltas (mirrors totalPacketsDropped logic).
* Upsert per-IP drop counters.
* - absolute (Linux): agent reports kernel counters; CP accumulates deltas.
* - presence (MikroTik): each report sighting → last_seen=now, packets+=1.
*/
export function upsertIpBlockStats(
db: Db,
agentId: string,
hits: IpHitInput[],
now = new Date().toISOString(),
opts: UpsertIpBlockStatsOptions = {},
) {
const mode = opts.mode ?? 'absolute'
for (const hit of hits) {
const ip = hit.ip.trim()
if (!ip) continue
@@ -61,6 +73,32 @@ export function upsertIpBlockStats(
)
.get()
if (mode === 'presence') {
if (!existing) {
db.insert(agentIpBlockStats)
.values({
id: crypto.randomUUID(),
agentId,
ip,
packets: 1,
lastReportedPackets: 1,
firstSeenAt: now,
lastSeenAt: now,
})
.run()
continue
}
db.update(agentIpBlockStats)
.set({
packets: (existing.packets ?? 0) + 1,
lastReportedPackets: (existing.lastReportedPackets ?? 0) + 1,
lastSeenAt: now,
})
.where(eq(agentIpBlockStats.id, existing.id))
.run()
continue
}
if (!existing) {
db.insert(agentIpBlockStats)
.values({