Operare
Rotația logului
Daemonul gestionează ambele pattern-uri uzuale de rotație:
- Rotate-and-rename (access logul este redenumit, un fișier nou îi ia locul). Detectat prin schimbarea inode/device pe calea monitorizată.
- Copytruncate (conținutul fișierului este copiat în altă parte, apoi originalul este truncat la zero). Detectat prin
tell() > stat().
În ambele cazuri, daemonul redeschide fișierul de la început și scrie info reopen after rotate dev=… ino=… (rotate-and-rename) sau info truncate file shrank (copytruncate) pe stderr.
Dacă lipsesc intrări în jurul rotației, verifică configurația uneltei de rotație:
- Pe OpenBSD,
newsyslogare rotație standard rotate-and-rename — fără configurare specială necesară. - Pe Linux,
logrotateia mai bine default-ul (rotație + SIGHUP către serverul web) decât modulcopytruncate. Ambele funcționează, dar rotate-and-rename este mai ieftin și nu pierde linii.
Scriptul rc.d (OpenBSD)
Variantă minimă /etc/rc.d/abusive_http_watch:
#!/bin/ksh
daemon="/usr/local/sbin/abusive_http_watch"
daemon_flags="/var/www/logs/access.log"
daemon_user="_www"
. /etc/rc.d/rc.subr
rc_bg=YES
rc_reload=NO
rc_cmd $1Apoi:
doas rcctl enable abusive_http_watch
doas rcctl start abusive_http_watch
doas rcctl check abusive_http_watchPe Linux cu systemd, vezi documentația distribuției; o unitate simplă Type=simple care arată către /usr/local/sbin/abusive_http_watch cu aceleași argumente este suficientă.
Evenimente syslog
Daemonul emite o clasă de evenimente — added — când un IP nou depășește pragul de hit-uri. Format:
<syslog-tag>[<pid>]: added ip=<ip> path=<cale-blocklist>Exemplu:
abusive_http_watch[12345]: added ip=198.51.100.42 path=/var/www/run/abusive_http_hostsPrin syslog.conf, rutează către un fișier propriu pentru review:
local0.notice /var/log/abusive_http.logÎmpreună cu ABUSIVE_SYSLOG_FACILITY=local0, rezultă un audit log curat al fiecărui IP blocat.
Semnale de monitoring
Pentru monitoring automat, doi indicatori sunt utili:
- Rata de creștere a blocklistei —
wc -l /var/www/run/abusive_http_hostsîn timp. Pe un server web public, ar trebui să crească constant (de la câteva IP-uri pe zi la multe pe oră, în funcție de expunere). O linie plată de 24h pe un site public sugerează că daemonul nu rulează sau citește logul greșit. - Sănătatea procesului —
pgrep -f abusive_http_watchar trebui să returneze mereu exact un PID. Alertă la zero.
Pentru setupuri Prometheus, un mic exporter care doar wc -luiește fișierul de blocklistă și expune numărul ca gauge este suficient. Fără endpoint de metrici în daemonul însuși — by design, pentru a-l ține fără dependențe.
Troubleshooting
Fișierul de blocklistă rămâne gol
Cauze posibile, în ordinea probabilității:
- Daemonul citește fișierul greșit. Pornește în foreground cu
ABUSIVE_DEBUG=1. Verifică să loghezestart following dev=… ino=…pentru calea așteptată. Dacă nu, corectează argumentul. - Nu există trafic real de atac. Improbabil pe un server web public, dar posibil intern. Rulează cu
ABUSIVE_DEBUG=1și caută linii[dbg] ip=…fără un[dbg] token matchcorespunzător. - Whitelist-ul înghite totul. Verifică
/etc/abusive_http_whitelist— o intrare CIDR/0greșită pune tot internetul pe whitelist. Scoate și restartează. - Pragul de hit-uri prea mare. Coboară
ABUSIVE_MIN_HITSde test la1și observă comportamentul.
Blocklista crește, dar firewallul nu blochează
Daemonul scrie fișierul. Firewallul trebuie instruit să-l citească. Verifică:
- Cronul reîncarcă tabelul
pf/ setulnftablesla fiecare câteva minute (daemonul nu cheamăpfctlel însuși). - Regula de firewall care referă tabelul este în chain-ul potrivit și
quickîndeajuns ca să prindă înainte de regulilepassulterioare.
Utilizatori legitimi sunt blocați
Adaugă IP-ul lor public sau range-ul CIDR la /etc/abusive_http_whitelist. Daemonul recitește whitelist-ul la fiecare linie — schimbările prind în câteva secunde.
Pentru a scoate un singur IP din blocklista existentă, editează direct fișierul și reîncarcă tabelul de firewall. Daemonul nu are nevoie de restart — va reintroduce IP-ul doar dacă utilizatorul lovește din nou tokenuri.
Daemonul crash-uiește după rotația logului
Nu ar trebui să se întâmple cu gestionarea de rotație descrisă mai sus. Dacă totuși da, rulează în foreground cu ABUSIVE_DEBUG=1, declanșează o rotație și înregistrează stderr. Trimite logul înregistrat prin pagina de
Contact — acesta este un bug real pe care vrem să-l reparăm.
Shutdown curat
Daemonul prinde SIGTERM și se termină curat după iterația curentă:
doas rcctl stop abusive_http_watchLoghează [info] TERM received, exiting, închide handle-ul fișierului de log, face flush la toate scrierile în așteptare și iese cu status 0. Fără corupere de stare, chiar și pe un log foarte folosit.