v0.7.1 · aggiornata · GitHub

API / Pacchetti

Percorso di importazione: github.com/lenny-ts/caddy-analyzer/pkg/*. Go 1.25+. Per il flusso dei dati attraverso questi pacchetti, consulta Architettura.

parser — JSON Caddy → struct Go

Analizza una riga JSON in *LogEntry (richiesta gestita) o *OperationalEntry (log senza request).

import "github.com/lenny-ts/caddy-analyzer/pkg/parser"

entry, err := parser.Parse(line)
switch v := entry.(type) {
case *parser.LogEntry:       // v.Method, v.URI, v.Status, v.RemoteIP, v.UserAgent
case *parser.OperationalEntry: // v.Level, v.Logger, v.Msg, v.Extra
}
Tipo chiaveCampi
LogEntryMethod, URI, Host, RemoteIP, Status, Size, Duration, UserAgent, Referer, ForwardedFor
OperationalEntryLevel, Logger, Msg, Extra map[string]json.RawMessage

analysis — filtraggio + rilevamento in 26 categorie

import "github.com/lenny-ts/caddy-analyzer/pkg/analysis"
import "github.com/lenny-ts/caddy-analyzer/pkg/types"

eng := analysis.New(types.Filters{From: time.Now().Add(-1*time.Hour), Status: []string{"500"}})
det := analysis.NewDetector(10) // uaRotation
eng.SetDetector(det)

// per line:
if eng.MatchEntry(entry) { // respects all Filters (ip, country, asn, grep, bot, etc.)
    eng.Process(entry)     // counters + detector + histogram
}
stats := eng.Finalize() // computes P50/P95/RPS
topIPs := eng.TopN(10, types.TopFieldIP)
suspicious := stats.SuspiciousIPs // grouped by IP with MITRE tags

Euristiche comportamentali: ua_rotation ≥10, object_enumeration ≥10 IDs/template, beaconing CV<0.25. Esporta Sigma: det.ExportSigmaInfo().

enrich — GeoIP

import "github.com/lenny-ts/caddy-analyzer/pkg/enrich"

geo, err := enrich.NewGeoIP("") // auto-discovers mmdb in 7 paths + auto-downloads GeoLite2
if err == nil { defer geo.Close() }
info := geo.Lookup("203.0.113.18") // -> CountryCode, CountryName, ASN
code, _ := enrich.CountryCodeFromName("Italy") // "IT"

Cache: 50K LRU, TTL 24h (configurabile tramite Configurazione). Variante asincrona: NewGeoIPAsync.

blocklist — trie CIDR

import "github.com/lenny-ts/caddy-analyzer/pkg/blocklist"

mgr := blocklist.NewManager("~/.cache/caddy-analyzer/blocklists")
mgr.Refresh(context.Background()) // download 8 feeds
hit := mgr.Contains("198.51.100.23") // O(1) via cidranger.PCTrie
sources := mgr.ListSources() // name, URL, count, age, status

Aggiunta personalizzata: mgr.AddSource(blocklist.Source{Name:"My",URL:"https://…/list.txt"}). TTL cache 7d.

guard — firewall

import "github.com/lenny-ts/caddy-analyzer/pkg/guard"
import "github.com/lenny-ts/caddy-analyzer/pkg/guard/firewall"

backend, _ := firewall.Detect(guard.LevelInfo) // auto → hybrid/docker/iptables/nftables
g := guard.New(guard.Config{
  Limit: 100, Window: time.Minute, Duration: 10*time.Minute,
  Blocker: backend, GeoIP: geo, BlocklistMgr: mgr,
  NeverBlock: []string{"10.0.0.0/8"},
  OnAudit: func(a guard.AuditEntry){ /* log */ },
})
// per log line:
if g.Evaluate(entry) == guard.BlockNow { /* iptables BLOCK */ }
// periodic:
blocked := g.Tick() // expires, subnet/cred-stuffing/rps checks

Lo stato persiste in /var/lib/caddy-analyzer/blocked.json. Consulta Architettura → flusso dei dati per vedere dove si colloca guard.

reader — acquisizione da sorgenti multiple

import "github.com/lenny-ts/caddy-analyzer/pkg/reader"

src, _ := reader.ParseSource("docker://caddy")
r, _ := reader.FromSource(src, true /*follow*/) // → LogReader (file/docker/k8s/journalctl/stdin)
for line := range r.Lines() { entry, _ := parser.Parse(line) }

Unisce stdout+stderr di Docker, segue la rotazione dei file tramite controllo inode, espande i glob tramite expandPaths.

output — table / json / csv / html

import "github.com/lenny-ts/caddy-analyzer/pkg/output"

output.Report(stats, output.FormatTable, false /*defang*/, nil)
output.Report(stats, output.FormatHTML, true, os.Stdout) // standalone dark HTML

types — struct condivise

import "github.com/lenny-ts/caddy-analyzer/pkg/types"

var f types.Filters // --ip, --country, --asn, --grep, --level, --ops-only, Top, Format, ...
stats := &types.Stats{} // histogram 1000 buckets, TopN, SuspiciousIPs
entry.EffectiveClientIP(trustForwarded) // last public XFF or RemoteIP
Vedi anche
Architettura — come parser → analysis/enrich → guard/blocklist → output interagiscono. Contribuire — test/lint e dove aggiungere un nuovo rilevamento o feed.