SentrySentry
Referência

API — sentry-core

Referência da API pública do sentry-core: modelo de domínio, sinais, traits de plugin, rules engine, policy, pipeline e trackers

API — sentry-core

sentry-core é a crate de contratos: modelo de domínio, traits de plugin, rules engine, heurísticas e trackers. É pura — sem I/O, sem HTTP, sem DB — e declara #![forbid(unsafe_code)]. Toda crate de plugin depende apenas dela.

Modelo de domínio — módulo event

Event

Event é o evento normalizado, agnóstico de protocolo, que flui por todo o pipeline. Campos comuns ficam no struct; detalhes de protocolo ficam em protocol: ProtocolData.

pub struct Event {
    pub id: Uuid,
    pub timestamp: DateTime<Utc>,
    pub source: SourceKind,
    pub transport: Transport,
    pub client_ip: IpAddr,
    pub geo: Option<GeoInfo>,
    pub asn: Option<u32>,
    /* ... bytes, duração, reputação, bot ... */
    pub protocol: ProtocolData,
}

Acessores que fazem pattern-match no payload — heurísticas e regras usam-nos para optar por lógica de um protocolo sem assumir que todo evento é HTTP:

MétodoRetorna
http() / http_mut()Option<&HttpData>
tcp()Option<&TcpData>
tls()Option<&TlsData>
syslog()Option<&SyslogData>
is_http() / protocol_kind()bool / ProtocolKind

Event::new cria com id/timestamp novos; Event::canonical_ip normaliza IPv4-mapeado-em-IPv6 (::ffff:a.b.c.d) para IPv4 puro — o mesmo cliente vira uma única chave em blocos, storage e CLI.

ProtocolData

ProtocolData é o enum que torna o Event extensível. Adicionar um protocolo = uma variante nova + helper em impl Event + atualizar protocol_kind().

VariantePayload
Http(HttpData)Requisição HTTP/1.x ou HTTP/2
Tcp(TcpData)Stream TCP não-HTTP (captura, edge-tcp)
Udp(UdpData)Datagrama UDP (UdpData, decodifica DNS quando reconhece)
TlsHandshake(TlsData)Telemetria de ClientHello (SNI/JA3/JA4)
Syslog(SyslogData)Mensagem RFC 5424/3164
Raw(RawData)Fallback (RawData)

HttpData, UploadInfo e enums menores

HttpData carrega method/scheme/host/path/query/status/user_agent/headers/cookies/body/uploads. body só é populado por fontes inline e volta ao cap de captura após o pipeline. UploadInfo é metadado de upload (F10) — conteúdo nunca persiste; UploadKind classifica por magic bytes (Text/Image/Archive/Executable/Pdf/Unknown).

Outros tipos do módulo: TcpData (flags, payload reassemblado, fingerprint SYN, syn_count de rajada), TcpFlags, TcpStage, TlsData (sni/ja3/ja4/cipher/version/alpn), SyslogData, SourceKind, Transport, HttpMethod, GeoInfo e ReputationInfo. RawEvent é o que a trait Source emite, antes do enriquecimento; into_event promove para Event.

Sinais e vereditos — módulo analysis

Signal e SignalKind

Signal é a unidade de detecção — o "porquê" do score:

pub struct Signal {
    pub kind: SignalKind,
    pub weight: u8,
    pub detail: Option<String>,
}

SignalKind é o catálogo fechado de detecções. Pesos default (a config [scorer.weights] sobrescreve por chave, exceto posture_advisory, que é travado em 0):

SinalPeso defaultEmitido por
Log4Shell80heurística
Rce (cmd injection)70heurística
SqlInjection60heurística
UploadPolyglot60UPLOAD_POLYGLOT_WEIGHT
Lfi50heurística
KnownBadIp50KNOWN_BAD_IP_WEIGHT
UploadExecutable50UPLOAD_EXECUTABLE_WEIGHT
Xss45heurística
SuspiciousLoginSuccess45SUSPICIOUS_LOGIN_SUCCESS_WEIGHT
BadCrawler40heurística
PathTraversal40heurística
CredentialStuffing40CREDENTIAL_STUFFING_WEIGHT
AuthBruteForce35AUTH_BRUTE_FORCE_WEIGHT
ScanBehavior35SCAN_BEHAVIOR_WEIGHT
SpoofedBot35SPOOFED_BOT_WEIGHT
SensitivePath30heurística
TcpScanner30heurística
UploadTypeMismatch30UPLOAD_TYPE_MISMATCH_WEIGHT
UploadDisallowed30UPLOAD_DISALLOWED_WEIGHT
DirectoryBruteForce30DIRECTORY_BRUTE_FORCE_WEIGHT
RandomScan25RANDOM_SCAN_WEIGHT
UploadFlood25UPLOAD_FLOOD_WEIGHT
ProtocolViolation25PROTOCOL_VIOLATION_WEIGHT (schemas sobrescrevem por policy)
VpnProxy20VPN_PROXY_WEIGHT
TlsSniMismatch20TLS_SNI_MISMATCH_WEIGHT
UploadOversize20UPLOAD_OVERSIZE_WEIGHT
ScanAttackCorrelation20SCAN_ATTACK_CORRELATION_WEIGHT
TorExitNode15TOR_EXIT_NODE_WEIGHT
MethodNotAllowed10RouteValidator
SuspiciousUA (UA vazio)10heurística
PromiscuousScanner10PROMISCUOUS_SCANNER_WEIGHT
UnknownRoute8RouteValidator
AnomalousPayload25[ai] signal_weight (default)
LlmMaliciousdinâmicoscore × confidence do LLM
ExternalReputationescaladoabuseConfidenceScore do provider
RuleHit100/50/30short-circuit de regra, por verdict
PostureAdvisory0 (travado)postura web, nunca reavalia o visitante

Verdict, RiskLevel, AnalysisResult e Decision

Verdict é a ação recomendada: Allow / RateLimit / Challenge / Block / Quarantine. RiskLevel agrupa o score 0–100 em cinco níveis fixos (from_score: Info 0–9, Low 10–29, Medium 30–49, High 50–74, Critical 75+).

AnalysisResult é a detecção (score + sinais + verdict pré-policy); Decision é a resposta final após policy, com override_reason e log_level opcional. RuleLogLevel controla a verbosidade de console de eventos short-circuitados (silent|info|warn|error).

Traits de plugin

Source

Implementada por toda origem de dados (source.rs):

#[async_trait]
pub trait Source: Send + Sync {
    fn name(&self) -> &'static str;
    async fn stream(&self) -> Result<mpsc::Receiver<RawEvent>>;
    async fn shutdown(&self) -> Result<()> { Ok(()) }
}

A origem é aberta dentro de stream, que devolve o receiver de um canal limitado; fechar o sender sinaliza fim de stream. Helpers do módulo: event_channel (sizing padrão) e send_or_log (push com throttle de log por fonte quando o canal enche).

Action, ActionContext e ActionDispatch

Implementada por toda resposta (action.rs):

#[async_trait]
pub trait Action: Send + Sync {
    fn name(&self) -> &'static str;
    async fn execute(&self, evt: &Event, decision: &Decision) -> Result<()>;
    async fn execute_with_context(&self, evt: &Event, decision: &Decision, ctx: &ActionContext) -> Result<()>;
    fn applies_to(&self, decision: &Decision) -> bool;
    fn dispatch(&self) -> ActionDispatch;
}

Implementações devem ser idempotentes (replay pós-restart é no-op, não erro). ActionContext carrega o incident_id para alertas bidirecionais (F4.5). ActionDispatch decide onde a action roda: Inline (contenção local, hot path) ou Deferred (default; I/O de rede vai para workers postergados).

ChallengeProvider

Abstração provider-agnostic de edge (challenge.rs) — espelha o LlmProvider:

#[async_trait]
pub trait ChallengeProvider: Send + Sync {
    fn name(&self) -> &'static str;
    async fn apply(&self, ip: IpAddr, verdict: Verdict, opts: &EdgeOptions) -> Result<()>;
}

ChallengeAction é a única Action que os providers de edge exigem: ela filtra os vereditos Block/Challenge/RateLimit (pula Allow/Quarantine) e delega ao provider. EdgeMode é o sabor (block/js_challenge/managed_challenge/rate_limit) e EdgeOptions carrega TTL + modo preferido. Novo provider de edge (AWS WAF, Fastly…) = implementar a trait + um braço em daemon::build_challenge_action.

Providers de IA (crate sentry-ai)

LlmProvider

Contrato de classificação por LLM (llm.rs):

#[async_trait]
pub trait LlmProvider: Send + Sync {
    fn name(&self) -> &'static str;
    fn model_id(&self) -> &str;
    async fn classify(&self, req: ClassifyRequest) -> anyhow::Result<ClassifyResponse>;
    async fn explain(&self, req: ExplainRequest) -> anyhow::Result<String>;
}

Adapters embarcados: OpenRouterProvider (default, SENTRY_LLM_KEY), OllamaProvider (local, sem chave) e MockLlmProvider. ClassifyResponse traz verdict, score, confidence e uso de tokens.

IpLookupProvider

Lookup externo de reputação por IP (F7.5, lookup.rs):

#[async_trait]
pub trait IpLookupProvider: Send + Sync {
    fn name(&self) -> &'static str;
    async fn check(&self, ip: IpAddr) -> Result<IpLookupResult, String>;
}

AbuseIpDbLookup implementa GET /api/v2/check; o score retornado escala o peso do sinal ExternalReputation. O fork assíncrono do daemon só consulta a "banda cinza" (score acima do trigger, verdict ≠ Block), com cache e quota.

ThreatModel

O modelo local clássico fica atrás de ThreatModel — implementado por OnnxThreatModel quando a feature onnx está ligada. Detalhes de treino/export em IA.

Rules engine — módulo rules

Rule, RuleSet e SharedRuleSet

pub struct Rule {
    pub id: RuleId,
    pub priority: i32,      // menor = avaliado antes
    pub enabled: bool,
    pub match_: RuleMatch,
    pub action: RuleAction,
    pub ttl: Option<Duration>,
    pub source: RuleSource,
    /* tags, log_level, created_at */
}

Rule é avaliada na fast-path, antes de heurísticas e IA. RuleSet indexa regras por IP/ASN/país para lookup rápido; SharedRuleSet é o handle Arc<RwLock<>> que o hot-reload troca a quente (shared()).

RuleAction e RuleSource

RuleAction: Allow (bypass total) > Block/Challenge/RateLimit (short-circuit) > Log/Tag (anota e continua). RuleSource registra a origem (config/db/cloudflare_sync/feed/auto_learned/default_pack).

RuleMatch

RuleMatch é a condição declarativa, combinável com All/Any/Not: Ip(cidr), Asn, Country, Path{op, pattern}, Method, Header{name, op}, UserAgent, Query, Body, UploadFilename, Protocol, TlsFingerprint{ja3, ja4}, TlsSni, Ja3In(set), Reputation(tier), BotVerified, Status, Rate{count, per_secs, scope}, Time.

DSL

O texto do match = "..." no TOML é compilado por dsl::parse (recursive-descent, AND/OR/NOT/parênteses) em um RuleMatch. Erro de digitação falha em tempo de carga, não em runtime. rules_from_config compila cada [[rules.custom]] independentemente — uma expressão inválida pula só aquela regra. ReputationTier (malicious/tor/vpn_proxy/promiscuous/authorized) alimenta Reputation(tier).

Política — módulo policy

VerdictPolicy

VerdictPolicy é o mapeamento configurável detecção→ação. O default preserva o histórico (Info/Low→Allow, Medium→RateLimit, High→Challenge, Critical→Block); cada nível é remapeável no TOML e [[policy.override]] força verdict por DSL — o primeiro override que casa vence e popula Decision.override_reason.

pub fn from_config(cfg: &PolicyConfig) -> Result<Self>;
pub fn decide(&self, level: RiskLevel, evt: &Event) -> (Verdict, Option<String>);

Pipeline — módulo pipeline

Pipeline

Pipeline orquestra regras → heurísticas → rotas → scorer → policy → escalada. Construção por builders encadeados:

MétodoLiga
with_configruleset compartilhado + rotas + scorer + policy
configure_uploadsinspeção de corpo/uploads (F10)
with_trustnever-ban/blacklist/shadow (F7.2)
with_rate_limiterbackend p/ condições Rate
with_offenderescalada de reincidentes
with_scan_tracker / with_behavior_tracker / with_correlation_trackerdetectores comportamentais
with_bot_verifierverificação rDNS de bots (F7.10)

Métodos de execução e hot-reload: process (síncrono, retorna ProcessedEvent), rescore_from (re-integra sinais de forks AI/LLM/lookup — só eleva, nunca rebaixa), observe_response (fila de sinais de resposta por-IP, F3.9.1), swap_rules / swap_routes, prune_pending.

RouteValidator e RouteDef

RouteValidator valida rotas conhecidas: path fora da lista → UnknownRoute; método não suportado → MethodNotAllowed. RouteDef aceita templates (/users/{id}, trailing /*); RouteValidator::merge une config ∪ DB (dedupe por path, config vence).

Trackers de estado

Todos são por-IP com janelas deslizantes e história limitada; o daemon faz prune periódico.

TrackerArquivoO que detecta
OffenderTrackeroffender.rsReincidentes: strikes por janela; record_and_escalate só sobe o verdict na escada RateLimit→Challenge→Block
ScanTrackerscan.rs4xx em rajada: ≥N paths distintos → RandomScan; ≥N 4xx → ScanBehavior
BehaviorTrackerbehavior.rsForça bruta em login, credential stuffing (UAs distintos), wordlist 404, sucesso suspeito pós-falhas
CorrelationTrackercorrelation.rsScan de outro IP no mesmo /24, /64 ou ASN pouco antes do ataque → ScanAttackCorrelation
BotVerifierbotverify.rsCache rDNS de crawlers (Verified/Spoofed/Unknown); DNS injetado via BotDnsResolver, fluxo puro em verify_with
BlockTableblocks.rsTabela compartilhada de IPs bloqueados com TTL opcional; fast-path da edge nega antes do pipeline (is_blocked, seed, reload)
TrustSet / SharedTrustSettrust.rsProxies confiáveis, never-ban, blacklist e shadow-list do [real_ip]; ranges Cloudflare embutidos (cloudflare_ranges)

Config — módulo config

SentryConfig é o schema tipado do sentry.toml (serde; a carga com figment + overlay SENTRY_ vive no CLI). Cada seção tem seu struct (CoreConfig, EdgeConfig, UploadsConfig, PolicyConfig, …), todos reexportados na raiz da crate. A referência completa de chaves e defaults vive na seção Configuração — aqui fica só o contrato: o tipo de action é o enum ActionKind, não string, então erro de digitação falha na carga.

Heurísticas — módulo heuristics

Heuristic e HeuristicEngine

pub trait Heuristic: Send + Sync {
    fn name(&self) -> &'static str;
    fn gate_bit(&self) -> Option<u8> { None }
    fn analyze(&self, evt: &Event, text: &DecodedHttp<'_>) -> Vec<Signal>;
}

Heuristic é um detector de regex; HeuristicEngine roda todos (analyze). Performance (F5): um autômato Aho-Corasick de literais-gatilho (gate) antecipa as regex — tráfego limpo custa uma passada SIMD. As famílias embarcadas: SqlInjection, Xss, PathTraversal, Lfi, Log4Shell, CmdInjection, SensitivePath, BadCrawler, EmptyUserAgent, TcpScanner + as de upload (F10, com gate_bit() = None porque operam sobre corpo, não texto de path).

DecodedHttp

DecodedHttp carrega o path e a query URL-decodificados (%27→', +/%20→espaço) computados uma vez por evento, mais multipart/urlecoded parseados. Ao escrever nova heurística, analise text.path/text.query — nunca http.path cru, senão payloads encodados fazem bypass. (O decode acontece no helper interno http_text.)

reload_dataset_lists

pub fn reload_dataset_lists(user_agents: &[String], paths: &[String]);

reload_dataset_lists mescla literais de datasets DB-backed (user_agent/path) nos gates do prefilter via ArcSwap — hot-reload sem restart (F7.7).

On this page