Track tcp/udp dports via deny_port_hits, expose aggregate and per-IP ports in UI; install-link re-run refreshes nft rules. Co-authored-by: Cursor <cursoragent@cursor.com>
7.6 KiB
Agents
Short install (рекомендуется)
В UI /agents → Добавить агента:
- Создаётся агент со статусом Invited (сразу виден в таблице) + install-ссылка.
- Скопируйте one-liner (колонка Install или Sheet):
Linux:
curl -fsSL https://<cp>/agent-install/<id> | bash
MikroTik:
/tool fetch url="https://<cp>/agent-install/<id>" dst-path=evofw-install.rsc; /import file-name=evofw-install.rsc
- После enroll статус станет Pending — одобрите агента (Approve).
- Approved — агент синхронизирует политику.
Повторный запуск той же install-ссылки на хосте, где агент уже стоит: обновляет sync-скрипт / timer (или MikroTik scheduler) и пересоздаёт nft rules (в т.ч. deny_port_hits), без повторного enroll — CLIENT_ID/token сохраняются. Сбрасывается last_hash, затем сразу force sync. Полный переустановки с новым токеном: EVOFW_INSTALL_FORCE=1 (Linux).
API (auth): POST /api/v1/install-links { "name": "web-01", "platform": "linux" | "mikrotik" }.
Linux (legacy one-liner)
curl -fsSL https://<cp>/v1/agent/install.sh | \
EVOFW_CP_URL=https://<cp> \
EVOFW_SEED=<seed> \
EVOFW_CLIENT_NAME="web-01" \
bash
Создаёт нового агента со статусом Pending (без Invited).
Файлы: /etc/evofw/agent.conf, /usr/local/sbin/evofw-firewall.sh, timer evofw-firewall.timer (default 1min).
Install сам ставит зависимости через apt/dnf/yum/apk: curl, jq (или python3), nftables/iptables(+ipset). Планировщик: systemd timer если есть /run/systemd/system, иначе ставит cron/cronie и пишет crontab. Значения в agent.conf всегда в single quotes (имена с пробелами безопасны). Sync при статусе pending завершается с exit 0 (pending approval), чтобы systemd timer не был failed.
Если /etc/evofw/agent.conf уже есть — install переходит в update: скачивает свежий sync-script + uninstall.sh, перезаписывает unit/timer, оставляет токен. EVOFW_INSTALL_FORCE=1 — полный re-enroll (новый токен; для уже Approved install-link обычно не сработает).
Uninstall (Linux):
curl -fsSL https://<cp>/v1/agent/uninstall.sh | bash
# или локально после install:
sudo /usr/local/sbin/evofw-uninstall.sh
Backend auto-detect: nft → ipset → iptables.
Whitelist: nft chain policy drop + allow set. Blacklist: policy accept + deny set.
Per-IP blocked stats (Linux)
Linux agent reports optional ip_hits in POST /v1/agent/apply-report:
- nft: tries set
deny_v4withflags interval; counter;. If the kernel rejects counters on interval sets, falls back to plain interval (aggregate Traffic ↓ still works; per-IP empty). - Upgrade path: on install-link re-run,
last_hashis cleared once so sets/chain can be recreated (chain deleted before set replace) — обновляет и port-hit правила. - ipset: prefers
hash:net … counterson create; existing sets without counters are left as-is. - Payload: only entries with
packets > 0, top 200 by packets. - Control plane:
agent_ip_block_stats, accumulates deltas of absolute kernel counters (как Traffic ↓). После flush set/chain (policy apply) CP сбрасывает per-IP baseline (last_reported), иначе вторая эпоха счётчиков теряется (Traffic растёт, Blocked IPs — нет). GET /api/v1/agents/:id/blocked-ips, reset viaPOST …/stats/reset.- UI: agent detail → Blocked IPs. Sum of Blocked IPs ≈ Traffic ↓ для deny (при default accept); default-drop / allow в Traffic считаются отдельно.
IPv6 skipped.
Destination ports (Linux nft)
На nft агент ведёт dynamic set deny_port_hits (ipv4_addr . inet_proto . inet_service, timeout 1h, counter):
- Deny rule для tcp/udp:
update @deny_port_hits { ip saddr . meta l4proto . th dport }+ drop; прочие протоколы — plain drop. - В
apply-report: optionalport_hitstop 500{ ip, port, protocol, packets }. - CP:
agent_port_block_stats(absolute deltas). Set не flush’ится на каждый policy apply (элементы живут по timeout) — baseline не сбрасывается при Traffic flush. GET /api/v1/agents/:id/blocked-ports— aggregate top 50 портов; вblocked-ipsу каждого IP —portstop 5.- UI: Top ports + колонка Ports в Blocked IPs (только
platform=linux). - ipset/iptables:
port_hits: []. MikroTik — без port hits. - Чтобы подтянуть правила на уже установленном агенте: re-run install one-liner (см. выше).
IPv6 skipped.
MikroTik (RouterOS 7.21+)
В UI /agents → Добавить агента → platform MikroTik. Скопируйте one-liner:
/tool fetch url="https://<cp>/agent-install/<id>" dst-path=evofw-install.rsc; /import file-name=evofw-install.rsc
Или короткий slug: https://<cp>/<slug>.
Install RSC:
- Enroll (с
install_link_id→ агент Invited → Pending). - Создаёт filter-правила
evofw-*в начале цепочекinput/forward(place-before) и address-listEVOFW_DENY/EVOFW_ALLOW/ dynamicEVOFW_HITS. - Scheduler
evofw-syncкаждую минуту:GET /v1/agent/policy(JSON) → rebuild deny/allow + report (+ip_hitsиз HITS). Не использует/importогромного.rsc.
Лог: /log print where message~"evofw". Ручной sync: /system script run evofw-sync.
Traffic ↓/↑ в UI — сумма packets с evofw-deny-drop-* / evofw-allow-* / evofw-default-drop-* (накопительно, пока правила не пересозданы re-install).
Per-IP / Blocked IPs (MikroTik)
Цепочка deny: hit → drop (семантика drop/allow/default как раньше):
evofw-deny-hit-input/forward—add-src-to-address-list→EVOFW_HITS,address-list-timeout=1h(passthrough).evofw-deny-drop-input/forward—dropпоEVOFW_DENY.
В EVOFW_HITS попадают реальные src /32. Policy rebuild не чистит HITS (только DENY/ALLOW). Sync шлёт top-200 в ip_hits; CP mode presence: last_seen обновляется, пока IP в HITS; packets (Hits) увеличивается только при первом появлении или повторном входе после исчезновения из списка (~>2.5 мин без report), а не на каждый sync.
UI: agent detail → Blocked IPs (колонка Hits).
Default action задаётся на агенте (default_action: accept | drop):
- accept — пакет вне deny/allow пропускается
- drop — пакет вне deny/allow отбрасывается (forward)
Цепочка: deny-hit → deny-drop → allow-accept → default. Наборы несут только правила deny/allow, без exclusive mode.
Force sync
sudo rm -f /var/lib/evofw/last_hash
sudo /usr/local/sbin/evofw-firewall.sh