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 chiave | Campi |
|---|---|
LogEntry | Method, URI, Host, RemoteIP, Status, Size, Duration, UserAgent, Referer, ForwardedFor |
OperationalEntry | Level, 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