feat(api, web): enhance MikroTik integration and IP hit tracking
- 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:
@@ -118,18 +118,34 @@ nft_add_chunk() {
|
||||
}
|
||||
}
|
||||
|
||||
# Ensure inet set exists with interval + counter (recreate if missing counter).
|
||||
# Ensure inet set exists. Prefer per-element counters; many kernels reject
|
||||
# `counter` on interval sets — fall back to plain interval (no per-IP hits).
|
||||
# Caller must delete referencing chains before recreating a set.
|
||||
ensure_nft_set() {
|
||||
local table=$1 name=$2 setname=$3
|
||||
local def
|
||||
def=$(nft -a list set "$table" "$name" "$setname" 2>/dev/null || true)
|
||||
def=$(nft list set "$table" "$name" "$setname" 2>/dev/null || true)
|
||||
if [[ -n "$def" ]] && [[ "$def" == *"counter"* ]]; then
|
||||
return 0
|
||||
fi
|
||||
if [[ -n "$def" ]]; then
|
||||
# Upgrade path: drop old set without counters (chain must already be gone).
|
||||
nft delete set "$table" "$name" "$setname" 2>>"$LOG_FILE" || true
|
||||
fi
|
||||
nft add set "$table" "$name" "$setname" '{ type ipv4_addr; flags interval; counter; }' 2>>"$LOG_FILE"
|
||||
if nft add set "$table" "$name" "$setname" '{ type ipv4_addr; flags interval; counter; }' 2>>"$LOG_FILE"; then
|
||||
return 0
|
||||
fi
|
||||
# Set may still exist if delete failed — try plain create only if missing.
|
||||
if nft list set "$table" "$name" "$setname" >/dev/null 2>&1; then
|
||||
log "nft: keep existing set $setname (no per-element counter)"
|
||||
return 0
|
||||
fi
|
||||
if nft add set "$table" "$name" "$setname" '{ type ipv4_addr; flags interval; }' 2>>"$LOG_FILE"; then
|
||||
log "nft: set $setname without counter (interval+counter unsupported)"
|
||||
return 0
|
||||
fi
|
||||
log "nft: failed to create set $setname"
|
||||
return 1
|
||||
}
|
||||
|
||||
collect_nft_stats() {
|
||||
@@ -214,10 +230,13 @@ apply_nft() {
|
||||
for p in "${ALLOW[@]+"${ALLOW[@]}"}"; do [[ "$p" == *:* ]] && continue; allow_v4+=("$p"); done
|
||||
|
||||
nft list table "$table" "$name" >/dev/null 2>&1 || nft add table "$table" "$name"
|
||||
# Drop chain first so sets can be deleted/recreated (upgrade to counters).
|
||||
# Stats were already captured by the caller before apply_nft.
|
||||
nft delete chain "$table" "$name" input 2>/dev/null || true
|
||||
ensure_nft_set "$table" "$name" deny_v4
|
||||
ensure_nft_set "$table" "$name" allow_v4
|
||||
nft flush set "$table" "$name" deny_v4
|
||||
nft flush set "$table" "$name" allow_v4
|
||||
nft flush set "$table" "$name" deny_v4 2>>"$LOG_FILE" || true
|
||||
nft flush set "$table" "$name" allow_v4 2>>"$LOG_FILE" || true
|
||||
|
||||
local batch=() chunk=64
|
||||
for p in "${deny_v4[@]}"; do
|
||||
@@ -232,7 +251,6 @@ apply_nft() {
|
||||
done
|
||||
((${#batch[@]})) && nft_add_chunk "$table" "$name" allow_v4 "${batch[@]}"
|
||||
|
||||
nft delete chain "$table" "$name" input 2>/dev/null || true
|
||||
# Unified chain: deny → allow → default_action
|
||||
if [[ "$DEFAULT_ACTION" == "drop" ]]; then
|
||||
nft add chain "$table" "$name" input '{ type filter hook input priority 0; policy drop; }'
|
||||
@@ -255,16 +273,23 @@ apply_nft() {
|
||||
ensure_ipset_counters() {
|
||||
local name=$1
|
||||
if ! ipset list "$name" >/dev/null 2>&1; then
|
||||
ipset create "$name" hash:net family inet counters
|
||||
return
|
||||
if ipset create "$name" hash:net family inet counters 2>>"$LOG_FILE"; then
|
||||
return 0
|
||||
fi
|
||||
ipset create "$name" hash:net family inet 2>>"$LOG_FILE" || {
|
||||
log "ipset: failed to create $name"
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
fi
|
||||
# Recreate once if set has no packet counters (Header lacks "counters").
|
||||
local header
|
||||
header=$(ipset list "$name" 2>/dev/null | head -n 5 || true)
|
||||
if [[ "$header" != *"counters"* && "$header" != *"packet"* ]]; then
|
||||
ipset destroy "$name" 2>>"$LOG_FILE" || true
|
||||
ipset create "$name" hash:net family inet counters
|
||||
if [[ "$header" == *"counters"* ]]; then
|
||||
return 0
|
||||
fi
|
||||
# Cannot safely destroy while iptables may reference the set — leave as-is.
|
||||
log "ipset: $name has no counters (leave existing; per-IP hits unavailable)"
|
||||
}
|
||||
|
||||
apply_ipset() {
|
||||
@@ -324,11 +349,11 @@ if [[ -f "$HASH_FILE" && "$(tr -d '\r\n' <"$HASH_FILE")" == "$HASH" && -n "$HASH
|
||||
if [[ "$KERNEL_METHOD" == "nft" ]]; then
|
||||
APPLIED=$(nft list set inet evofw deny_v4 2>/dev/null | grep -cE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' || true)
|
||||
local_allow=$(nft list set inet evofw allow_v4 2>/dev/null | grep -cE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' || true)
|
||||
APPLIED=$((APPLIED + local_allow))
|
||||
APPLIED=$((${APPLIED:-0} + ${local_allow:-0}))
|
||||
elif [[ "$KERNEL_METHOD" == "ipset" ]]; then
|
||||
APPLIED=$(ipset list evofw_deny_v4 2>/dev/null | awk '/^[0-9]/{c++} END{print c+0}')
|
||||
local_allow=$(ipset list evofw_allow_v4 2>/dev/null | awk '/^[0-9]/{c++} END{print c+0}')
|
||||
APPLIED=$((APPLIED + local_allow))
|
||||
APPLIED=$((${APPLIED:-0} + ${local_allow:-0}))
|
||||
fi
|
||||
send_report
|
||||
exit 0
|
||||
|
||||
Reference in New Issue
Block a user