diff --git a/configs/example.toml b/configs/example.toml index 65048ff5..4aa834dd 100644 --- a/configs/example.toml +++ b/configs/example.toml @@ -196,6 +196,19 @@ bpf = true # ] +# The krb5kdc sampler attaches user space probes to the krb5kdc binary distributed as part +# of MIT kerberos. It will interpret the krb5_error_codes for the functions as well and export +# the number of calls to each ticket processing function and its result. Specifically it will +# attach to: finish_process_as_req, finish_dispatch_cache, and process_tgs_request. +[samplers.krb5kdc] +# Controls whether to use this sampler +# enabled = true + +# Path to the krb5kdc binary to probe +# path = "/usr/sbin/krb5kdc" + + + # The memory sampler provides telemetry for system memory utilization [samplers.memory] # Controls whether to use this sampler diff --git a/docs/METRICS.md b/docs/METRICS.md index 5091e9b7..530d8e1b 100644 --- a/docs/METRICS.md +++ b/docs/METRICS.md @@ -150,6 +150,26 @@ Provides system-wide telemetry for IRQs * `interrupt/tlb_shootdowns` - interrupts caused to trigger TLB shootdowns * `interrupt/total` - total interrupts +## Krb5kdc + +Provides telemetry to track MIT kerberos ticket requests served by the krb5kdc +binary. This is accomplished by attaching user space probes to the following +functions: finish_process_as_req, finish_dispatch_cache and process_tgs_req. +Each function exports a call count that is broken down by the resulting +[error code](https://github.com/krb5/krb5-test/blob/master/src/lib/krb5/error_tables/krb5_err.et). +Since there is a very large list of possible error codes, the first 30 error +codes are exported. All other error code values are exported as UNKNOWN. + +Each error code is reformatted to better fit metric naming standards: +"KRB5KDC_ERR_BAD_PVNO" -> "bad_pvno" + +* `krb5kdc/finish_process_as_req/{ERROR_CODE}` - count of finish_process_as_req + calls by error +* `krb5kdc/finish_dispatch_cache/{ERROR_CODE}` - count of finish_dispatch_cache + calls by error +* `krb5kdc/process_tgs_req/{ERROR_CODE}` - count of process_tgs_req calls by + error + ## Memory Provides telemetry around memory usage, transparent huge-pages, huge-pages, diff --git a/src/config/samplers.rs b/src/config/samplers.rs index 2e270b9a..218062a8 100644 --- a/src/config/samplers.rs +++ b/src/config/samplers.rs @@ -9,6 +9,7 @@ use samplers::disk::DiskConfig; use samplers::ext4::Ext4Config; use samplers::http::HttpConfig; use samplers::interrupt::InterruptConfig; +use samplers::krb5kdc::Krb5kdcConfig; use samplers::memcache::MemcacheConfig; use samplers::memory::MemoryConfig; use samplers::network::NetworkConfig; @@ -37,7 +38,7 @@ pub struct Samplers { #[serde(default)] interrupt: InterruptConfig, #[serde(default)] - usercall: UsercallConfig, + krb5kdc: Krb5kdcConfig, #[serde(default)] memcache: MemcacheConfig, #[serde(default)] @@ -61,6 +62,8 @@ pub struct Samplers { #[serde(default)] udp: UdpConfig, #[serde(default)] + usercall: UsercallConfig, + #[serde(default)] xfs: XfsConfig, } @@ -85,8 +88,8 @@ impl Samplers { &self.interrupt } - pub fn usercall(&self) -> &UsercallConfig { - &self.usercall + pub fn krb5kdc(&self) -> &Krb5kdcConfig { + &self.krb5kdc } pub fn memcache(&self) -> &MemcacheConfig { @@ -133,6 +136,10 @@ impl Samplers { &self.udp } + pub fn usercall(&self) -> &UsercallConfig { + &self.usercall + } + pub fn xfs(&self) -> &XfsConfig { &self.xfs } diff --git a/src/main.rs b/src/main.rs index d39eb730..372389c9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -80,7 +80,7 @@ fn main() -> Result<(), Box> { Ext4::spawn(common.clone()); Http::spawn(common.clone()); Interrupt::spawn(common.clone()); - Usercall::spawn(common.clone()); + Krb5kdc::spawn(common.clone()); Memcache::spawn(common.clone()); Memory::spawn(common.clone()); PageCache::spawn(common.clone()); @@ -92,6 +92,7 @@ fn main() -> Result<(), Box> { Softnet::spawn(common.clone()); Tcp::spawn(common.clone()); Udp::spawn(common.clone()); + Usercall::spawn(common.clone()); Xfs::spawn(common); #[cfg(feature = "push_kafka")] diff --git a/src/samplers/krb5kdc/bpf.c b/src/samplers/krb5kdc/bpf.c new file mode 100644 index 00000000..2a25a23e --- /dev/null +++ b/src/samplers/krb5kdc/bpf.c @@ -0,0 +1,341 @@ +// Copyright 2021 Twitter, Inc. +// Licensed under the Apache License, Version 2.0 +// http://www.apache.org/licenses/LICENSE-2.0 + +// krb_error_codes are an old format and translated into a platform appropriate +// format to be passed around on the stack. This is why the krb_error_codes are +// matched at an offset. +// https://github.com/heimdal/MKShim/blob/964a930dfee5942efb8364ac07997ab5b2480033/Kerberos/krb5.h#L2457 + +#include + +struct key_t { + char c[80]; +}; + +// Section for function count probe: finish_process_as_req + +BPF_HASH(counts_finish_process_as_req, struct key_t); + +int count_finish_process_as_req(struct pt_regs *ctx) { + + u64 match_val = PT_REGS_PARM2(ctx); + u64 zero = 0, *count; + + if (match_val == 0) { + struct key_t key = {.c = "NONE"}; + count = counts_finish_process_as_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638913) { + struct key_t key = {.c = "NAME_EXP"}; + count = counts_finish_process_as_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638914) { + struct key_t key = {.c = "SERVICE_EXP"}; + count = counts_finish_process_as_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638915) { + struct key_t key = {.c = "BAD_PVNO"}; + count = counts_finish_process_as_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638916) { + struct key_t key = {.c = "C_OLD_MAST_KVNO"}; + count = counts_finish_process_as_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638917) { + struct key_t key = {.c = "S_OLD_MAST_KVNO"}; + count = counts_finish_process_as_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638918) { + struct key_t key = {.c = "C_PRINCIPAL_UNKNOWN"}; + count = counts_finish_process_as_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638919) { + struct key_t key = {.c = "S_PRINCIPAL_UNKNOWN"}; + count = counts_finish_process_as_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638920) { + struct key_t key = {.c = "PRINCIPAL_NOT_UNIQUE"}; + count = counts_finish_process_as_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638921) { + struct key_t key = {.c = "NULL_KEY"}; + count = counts_finish_process_as_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638922) { + struct key_t key = {.c = "CANNOT_POSTDATE"}; + count = counts_finish_process_as_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638923) { + struct key_t key = {.c = "NEVER_VALID"}; + count = counts_finish_process_as_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638924) { + struct key_t key = {.c = "POLICY"}; + count = counts_finish_process_as_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638925) { + struct key_t key = {.c = "BADOPTION"}; + count = counts_finish_process_as_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638926) { + struct key_t key = {.c = "ETYPE_NOSUPP"}; + count = counts_finish_process_as_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638927) { + struct key_t key = {.c = "SUMTYPE_NOSUPP"}; + count = counts_finish_process_as_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638928) { + struct key_t key = {.c = "PADATA_TYPE_NOSUPP"}; + count = counts_finish_process_as_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638929) { + struct key_t key = {.c = "TRTYPE_NOSUPP"}; + count = counts_finish_process_as_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638930) { + struct key_t key = {.c = "CLIENT_REVOKED"}; + count = counts_finish_process_as_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638931) { + struct key_t key = {.c = "SERVICE_REVOKED"}; + count = counts_finish_process_as_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638932) { + struct key_t key = {.c = "TGT_REVOKED"}; + count = counts_finish_process_as_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638933) { + struct key_t key = {.c = "CLIENT_NOTYET"}; + count = counts_finish_process_as_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638934) { + struct key_t key = {.c = "SERVICE_NOTYET"}; + count = counts_finish_process_as_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638935) { + struct key_t key = {.c = "KEY_EXP"}; + count = counts_finish_process_as_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638936) { + struct key_t key = {.c = "PREAUTH_FAILED"}; + count = counts_finish_process_as_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638937) { + struct key_t key = {.c = "PREAUTH_REQUIRED"}; + count = counts_finish_process_as_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638938) { + struct key_t key = {.c = "SERVER_NOMATCH"}; + count = counts_finish_process_as_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638939) { + struct key_t key = {.c = "MUST_USE_USER2USER"}; + count = counts_finish_process_as_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638940) { + struct key_t key = {.c = "PATH_NOT_ACCEPTED"}; + count = counts_finish_process_as_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638941) { + struct key_t key = {.c = "SVC_UNAVAILABLE"}; + count = counts_finish_process_as_req.lookup_or_init(&key, &zero); + } else { + struct key_t key = {.c = "UNKNOWN"}; + count = counts_finish_process_as_req.lookup_or_init(&key, &zero); + } + + (*count)++; + + return 0; +} + +// Section for function count probe: finish_dispatch_cache + +BPF_HASH(counts_finish_dispatch_cache, struct key_t); + +int count_finish_dispatch_cache(struct pt_regs *ctx) { + + u64 match_val = PT_REGS_PARM2(ctx); + u64 zero = 0, *count; + + if (match_val == 0) { + struct key_t key = {.c = "NONE"}; + count = counts_finish_dispatch_cache.lookup_or_init(&key, &zero); + } else if (match_val == 2529638913) { + struct key_t key = {.c = "NAME_EXP"}; + count = counts_finish_dispatch_cache.lookup_or_init(&key, &zero); + } else if (match_val == 2529638914) { + struct key_t key = {.c = "SERVICE_EXP"}; + count = counts_finish_dispatch_cache.lookup_or_init(&key, &zero); + } else if (match_val == 2529638915) { + struct key_t key = {.c = "BAD_PVNO"}; + count = counts_finish_dispatch_cache.lookup_or_init(&key, &zero); + } else if (match_val == 2529638916) { + struct key_t key = {.c = "C_OLD_MAST_KVNO"}; + count = counts_finish_dispatch_cache.lookup_or_init(&key, &zero); + } else if (match_val == 2529638917) { + struct key_t key = {.c = "S_OLD_MAST_KVNO"}; + count = counts_finish_dispatch_cache.lookup_or_init(&key, &zero); + } else if (match_val == 2529638918) { + struct key_t key = {.c = "C_PRINCIPAL_UNKNOWN"}; + count = counts_finish_dispatch_cache.lookup_or_init(&key, &zero); + } else if (match_val == 2529638919) { + struct key_t key = {.c = "S_PRINCIPAL_UNKNOWN"}; + count = counts_finish_dispatch_cache.lookup_or_init(&key, &zero); + } else if (match_val == 2529638920) { + struct key_t key = {.c = "PRINCIPAL_NOT_UNIQUE"}; + count = counts_finish_dispatch_cache.lookup_or_init(&key, &zero); + } else if (match_val == 2529638921) { + struct key_t key = {.c = "NULL_KEY"}; + count = counts_finish_dispatch_cache.lookup_or_init(&key, &zero); + } else if (match_val == 2529638922) { + struct key_t key = {.c = "CANNOT_POSTDATE"}; + count = counts_finish_dispatch_cache.lookup_or_init(&key, &zero); + } else if (match_val == 2529638923) { + struct key_t key = {.c = "NEVER_VALID"}; + count = counts_finish_dispatch_cache.lookup_or_init(&key, &zero); + } else if (match_val == 2529638924) { + struct key_t key = {.c = "POLICY"}; + count = counts_finish_dispatch_cache.lookup_or_init(&key, &zero); + } else if (match_val == 2529638925) { + struct key_t key = {.c = "BADOPTION"}; + count = counts_finish_dispatch_cache.lookup_or_init(&key, &zero); + } else if (match_val == 2529638926) { + struct key_t key = {.c = "ETYPE_NOSUPP"}; + count = counts_finish_dispatch_cache.lookup_or_init(&key, &zero); + } else if (match_val == 2529638927) { + struct key_t key = {.c = "SUMTYPE_NOSUPP"}; + count = counts_finish_dispatch_cache.lookup_or_init(&key, &zero); + } else if (match_val == 2529638928) { + struct key_t key = {.c = "PADATA_TYPE_NOSUPP"}; + count = counts_finish_dispatch_cache.lookup_or_init(&key, &zero); + } else if (match_val == 2529638929) { + struct key_t key = {.c = "TRTYPE_NOSUPP"}; + count = counts_finish_dispatch_cache.lookup_or_init(&key, &zero); + } else if (match_val == 2529638930) { + struct key_t key = {.c = "CLIENT_REVOKED"}; + count = counts_finish_dispatch_cache.lookup_or_init(&key, &zero); + } else if (match_val == 2529638931) { + struct key_t key = {.c = "SERVICE_REVOKED"}; + count = counts_finish_dispatch_cache.lookup_or_init(&key, &zero); + } else if (match_val == 2529638932) { + struct key_t key = {.c = "TGT_REVOKED"}; + count = counts_finish_dispatch_cache.lookup_or_init(&key, &zero); + } else if (match_val == 2529638933) { + struct key_t key = {.c = "CLIENT_NOTYET"}; + count = counts_finish_dispatch_cache.lookup_or_init(&key, &zero); + } else if (match_val == 2529638934) { + struct key_t key = {.c = "SERVICE_NOTYET"}; + count = counts_finish_dispatch_cache.lookup_or_init(&key, &zero); + } else if (match_val == 2529638935) { + struct key_t key = {.c = "KEY_EXP"}; + count = counts_finish_dispatch_cache.lookup_or_init(&key, &zero); + } else if (match_val == 2529638936) { + struct key_t key = {.c = "PREAUTH_FAILED"}; + count = counts_finish_dispatch_cache.lookup_or_init(&key, &zero); + } else if (match_val == 2529638937) { + struct key_t key = {.c = "PREAUTH_REQUIRED"}; + count = counts_finish_dispatch_cache.lookup_or_init(&key, &zero); + } else if (match_val == 2529638938) { + struct key_t key = {.c = "SERVER_NOMATCH"}; + count = counts_finish_dispatch_cache.lookup_or_init(&key, &zero); + } else if (match_val == 2529638939) { + struct key_t key = {.c = "MUST_USE_USER2USER"}; + count = counts_finish_dispatch_cache.lookup_or_init(&key, &zero); + } else if (match_val == 2529638940) { + struct key_t key = {.c = "PATH_NOT_ACCEPTED"}; + count = counts_finish_dispatch_cache.lookup_or_init(&key, &zero); + } else if (match_val == 2529638941) { + struct key_t key = {.c = "SVC_UNAVAILABLE"}; + count = counts_finish_dispatch_cache.lookup_or_init(&key, &zero); + } else { + struct key_t key = {.c = "UNKNOWN"}; + count = counts_finish_dispatch_cache.lookup_or_init(&key, &zero); + } + + (*count)++; + + return 0; +} + +// Section for function count probe: process_tgs_req + +BPF_HASH(counts_process_tgs_req, struct key_t); + +int count_process_tgs_req(struct pt_regs *ctx) { + + u64 match_val = PT_REGS_RC(ctx); + u64 zero = 0, *count; + + if (match_val == 0) { + struct key_t key = {.c = "NONE"}; + count = counts_process_tgs_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638913) { + struct key_t key = {.c = "NAME_EXP"}; + count = counts_process_tgs_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638914) { + struct key_t key = {.c = "SERVICE_EXP"}; + count = counts_process_tgs_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638915) { + struct key_t key = {.c = "BAD_PVNO"}; + count = counts_process_tgs_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638916) { + struct key_t key = {.c = "C_OLD_MAST_KVNO"}; + count = counts_process_tgs_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638917) { + struct key_t key = {.c = "S_OLD_MAST_KVNO"}; + count = counts_process_tgs_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638918) { + struct key_t key = {.c = "C_PRINCIPAL_UNKNOWN"}; + count = counts_process_tgs_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638919) { + struct key_t key = {.c = "S_PRINCIPAL_UNKNOWN"}; + count = counts_process_tgs_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638920) { + struct key_t key = {.c = "PRINCIPAL_NOT_UNIQUE"}; + count = counts_process_tgs_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638921) { + struct key_t key = {.c = "NULL_KEY"}; + count = counts_process_tgs_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638922) { + struct key_t key = {.c = "CANNOT_POSTDATE"}; + count = counts_process_tgs_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638923) { + struct key_t key = {.c = "NEVER_VALID"}; + count = counts_process_tgs_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638924) { + struct key_t key = {.c = "POLICY"}; + count = counts_process_tgs_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638925) { + struct key_t key = {.c = "BADOPTION"}; + count = counts_process_tgs_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638926) { + struct key_t key = {.c = "ETYPE_NOSUPP"}; + count = counts_process_tgs_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638927) { + struct key_t key = {.c = "SUMTYPE_NOSUPP"}; + count = counts_process_tgs_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638928) { + struct key_t key = {.c = "PADATA_TYPE_NOSUPP"}; + count = counts_process_tgs_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638929) { + struct key_t key = {.c = "TRTYPE_NOSUPP"}; + count = counts_process_tgs_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638930) { + struct key_t key = {.c = "CLIENT_REVOKED"}; + count = counts_process_tgs_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638931) { + struct key_t key = {.c = "SERVICE_REVOKED"}; + count = counts_process_tgs_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638932) { + struct key_t key = {.c = "TGT_REVOKED"}; + count = counts_process_tgs_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638933) { + struct key_t key = {.c = "CLIENT_NOTYET"}; + count = counts_process_tgs_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638934) { + struct key_t key = {.c = "SERVICE_NOTYET"}; + count = counts_process_tgs_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638935) { + struct key_t key = {.c = "KEY_EXP"}; + count = counts_process_tgs_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638936) { + struct key_t key = {.c = "PREAUTH_FAILED"}; + count = counts_process_tgs_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638937) { + struct key_t key = {.c = "PREAUTH_REQUIRED"}; + count = counts_process_tgs_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638938) { + struct key_t key = {.c = "SERVER_NOMATCH"}; + count = counts_process_tgs_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638939) { + struct key_t key = {.c = "MUST_USE_USER2USER"}; + count = counts_process_tgs_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638940) { + struct key_t key = {.c = "PATH_NOT_ACCEPTED"}; + count = counts_process_tgs_req.lookup_or_init(&key, &zero); + } else if (match_val == 2529638941) { + struct key_t key = {.c = "SVC_UNAVAILABLE"}; + count = counts_process_tgs_req.lookup_or_init(&key, &zero); + } else { + struct key_t key = {.c = "UNKNOWN"}; + count = counts_process_tgs_req.lookup_or_init(&key, &zero); + } + + (*count)++; + + return 0; +} diff --git a/src/samplers/krb5kdc/config.rs b/src/samplers/krb5kdc/config.rs new file mode 100644 index 00000000..1b8647f7 --- /dev/null +++ b/src/samplers/krb5kdc/config.rs @@ -0,0 +1,78 @@ +// Copyright 2021 Twitter, Inc. +// Licensed under the Apache License, Version 2.0 +// http://www.apache.org/licenses/LICENSE-2.0 + +use serde_derive::Deserialize; +use strum::IntoEnumIterator; + +use crate::config::SamplerConfig; + +use super::stat::*; + +#[derive(Debug, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct Krb5kdcConfig { + #[serde(default)] + bpf: bool, + #[serde(default)] + enabled: bool, + #[serde(default)] + interval: Option, + #[serde(default)] + percentiles: Vec, + #[serde(default = "default_statistics")] + statistics: Vec, + #[serde(default)] + path: String, +} + +impl Default for Krb5kdcConfig { + fn default() -> Self { + Self { + bpf: Default::default(), + enabled: Default::default(), + interval: Default::default(), + percentiles: crate::common::default_percentiles(), + statistics: default_statistics(), + path: Default::default(), + } + } +} + +impl Krb5kdcConfig { + pub fn path(&self) -> String { + self.path.clone() + } +} + +fn default_statistics() -> Vec { + Krb5kdcStatistic::iter().collect() +} + +impl SamplerConfig for Krb5kdcConfig { + type Statistic = Krb5kdcStatistic; + + fn bpf(&self) -> bool { + self.bpf + } + + fn enabled(&self) -> bool { + self.enabled + } + + fn interval(&self) -> Option { + self.interval + } + + fn percentiles(&self) -> &[f64] { + &self.percentiles + } + + fn statistics(&self) -> Vec<::Statistic> { + let mut enabled = Vec::new(); + for statistic in self.statistics.iter() { + enabled.push(*statistic); + } + enabled + } +} diff --git a/src/samplers/krb5kdc/mod.rs b/src/samplers/krb5kdc/mod.rs new file mode 100644 index 00000000..1abac631 --- /dev/null +++ b/src/samplers/krb5kdc/mod.rs @@ -0,0 +1,208 @@ +// Copyright 2021 Twitter, Inc. +// Licensed under the Apache License, Version 2.0 +// http://www.apache.org/licenses/LICENSE-2.0 + +use async_trait::async_trait; + +use std::sync::{Arc, Mutex}; +use std::time::Instant; + +use crate::common::bpf::BPF; +use crate::config::SamplerConfig; +use crate::samplers::{Common, Sampler}; + +#[cfg(feature = "bpf")] +use crate::common::bpf::bpf_hash_char_to_map; +#[cfg(feature = "bpf")] +use std::collections::HashMap; + +mod config; +mod stat; + +pub use config::Krb5kdcConfig; +pub use stat::Krb5kdcStatistic; + +#[allow(dead_code)] +pub struct Krb5kdc { + bpf: Option>>, + bpf_last: Arc>, + common: Common, + statistics: Vec, + path: String, +} + +impl Krb5kdc { + fn init_bpf(&mut self) -> Result<(), anyhow::Error> { + #[cfg(feature = "bpf")] + { + let code = include_str!("bpf.c"); + let mut bpf = bcc::BPF::new(code)?; + + if let Err(err) = bcc::Uprobe::new() + .handler("count_finish_process_as_req") + .binary(self.path.clone()) + .symbol("finish_process_as_req") + .attach(&mut bpf) + { + if self.common.config().fault_tolerant() { + warn!("krb5kdc unable to attach probe to function finish_process_as_req"); + } else { + Err(err)?; + } + } + + if let Err(err) = bcc::Uprobe::new() + .handler("count_finish_dispatch_cache") + .binary(self.path.clone()) + .symbol("finish_dispatch_cache") + .attach(&mut bpf) + { + if self.common.config().fault_tolerant() { + warn!("krb5kdc unable to attach probe to function finish_dispatch_cache"); + } else { + Err(err)?; + } + } + + if let Err(err) = bcc::Uretprobe::new() + .handler("count_process_tgs_req") + .binary(self.path.clone()) + .symbol("process_tgs_req") + .attach(&mut bpf) + { + if self.common.config().fault_tolerant() { + warn!("krb5kdc unable to attach probe to function process_tgs_req"); + } else { + Err(err)?; + } + } + + self.bpf = Some(Arc::new(Mutex::new(BPF { inner: bpf }))); + } + Ok(()) + } +} + +#[async_trait] +impl Sampler for Krb5kdc { + type Statistic = Krb5kdcStatistic; + + fn new(common: Common) -> Result { + let fault_tolerant = common.config.general().fault_tolerant(); + let statistics = common.config().samplers().krb5kdc().statistics(); + let path = common.config().samplers().krb5kdc().path(); + let mut sampler = Self { + bpf: None, + bpf_last: Arc::new(Mutex::new(Instant::now())), + common, + statistics, + path, + }; + + if let Err(e) = sampler.init_bpf() { + error!("{}", e); + if !fault_tolerant { + return Err(e); + } + } + + if sampler.sampler_config().enabled() { + sampler.register(); + } + + Ok(sampler) + } + + fn spawn(common: Common) { + if common.config().samplers().krb5kdc().enabled() { + match Self::new(common.clone()) { + Ok(mut sampler) => { + common.runtime().spawn(async move { + loop { + let _ = sampler.sample().await; + } + }); + } + Err(e) => { + if !common.config.fault_tolerant() { + fatal!("failed to initialize krb5kdc sampler {}", e); + } else { + error!("failed to initialize krb5kdc sampler {}", e); + } + } + } + } + } + + fn common(&self) -> &Common { + &self.common + } + + fn common_mut(&mut self) -> &mut Common { + &mut self.common + } + + fn sampler_config(&self) -> &dyn SamplerConfig { + self.common.config().samplers().krb5kdc() + } + + async fn sample(&mut self) -> Result<(), std::io::Error> { + if let Some(ref mut delay) = self.delay() { + delay.tick().await; + } + + if !self.sampler_config().enabled() { + return Ok(()); + } + + #[cfg(feature = "bpf")] + if let Some(ref bpf) = self.bpf { + let bpf = bpf.lock().unwrap(); + let mut table_map = HashMap::new(); + + table_map.insert( + "counts_finish_process_as_req", + bpf_hash_char_to_map( + &(*bpf) + .inner + .table("counts_finish_process_as_req") + .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?, + ), + ); + + table_map.insert( + "counts_finish_dispatch_cache", + bpf_hash_char_to_map( + &(*bpf) + .inner + .table("counts_finish_dispatch_cache") + .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?, + ), + ); + + table_map.insert( + "counts_process_tgs_req", + bpf_hash_char_to_map( + &(*bpf) + .inner + .table("counts_process_tgs_req") + .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?, + ), + ); + + for stat in self.statistics.iter() { + if let Some(entry_map) = table_map.get(stat.bpf_table()) { + let val = entry_map.get(stat.bpf_entry()).unwrap_or(&0); + self.metrics() + .record_counter(stat, Instant::now(), *val) + .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?; + } else { + self.metrics() + .record_counter(stat, Instant::now(), 0) + .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?; + } + } + } + Ok(()) + } +} diff --git a/src/samplers/krb5kdc/stat.rs b/src/samplers/krb5kdc/stat.rs new file mode 100644 index 00000000..fd9adf46 --- /dev/null +++ b/src/samplers/krb5kdc/stat.rs @@ -0,0 +1,526 @@ +// Copyright 2021 Twitter, Inc. +// Licensed under the Apache License, Version 2.0 +// http://www.apache.org/licenses/LICENSE-2.0 + +use core::convert::TryFrom; +use core::str::FromStr; + +use rustcommon_metrics::*; +use serde_derive::{Deserialize, Serialize}; +use strum::ParseError; +use strum_macros::{EnumIter, EnumString, IntoStaticStr}; + +#[derive( + Clone, + Copy, + Debug, + Deserialize, + EnumIter, + EnumString, + Eq, + IntoStaticStr, + PartialEq, + Hash, + Serialize, +)] +#[serde(deny_unknown_fields, try_from = "&str", into = "&str")] +pub enum Krb5kdcStatistic { + #[strum(serialize = "krb5kdc/finish_process_as_req/unknown")] + FinishProcessAsReqUnknown, + + #[strum(serialize = "krb5kdc/finish_process_as_req/none")] + FinishProcessAsReqNone, + + #[strum(serialize = "krb5kdc/finish_process_as_req/name_exp")] + FinishProcessAsReqNameExp, + + #[strum(serialize = "krb5kdc/finish_process_as_req/service_exp")] + FinishProcessAsReqServiceExp, + + #[strum(serialize = "krb5kdc/finish_process_as_req/bad_pvno")] + FinishProcessAsReqBadPvno, + + #[strum(serialize = "krb5kdc/finish_process_as_req/c_old_mast_kvno")] + FinishProcessAsReqCOldMastKvno, + + #[strum(serialize = "krb5kdc/finish_process_as_req/s_old_mast_kvno")] + FinishProcessAsReqSOldMastKvno, + + #[strum(serialize = "krb5kdc/finish_process_as_req/c_principal_unknown")] + FinishProcessAsReqCPrincipalUnknown, + + #[strum(serialize = "krb5kdc/finish_process_as_req/s_principal_unknown")] + FinishProcessAsReqSPrincipalUnknown, + + #[strum(serialize = "krb5kdc/finish_process_as_req/principal_not_unique")] + FinishProcessAsReqPrincipalNotUnique, + + #[strum(serialize = "krb5kdc/finish_process_as_req/null_key")] + FinishProcessAsReqNullKey, + + #[strum(serialize = "krb5kdc/finish_process_as_req/cannot_postdate")] + FinishProcessAsReqCannotPostdate, + + #[strum(serialize = "krb5kdc/finish_process_as_req/never_valid")] + FinishProcessAsReqNeverValid, + + #[strum(serialize = "krb5kdc/finish_process_as_req/policy")] + FinishProcessAsReqPolicy, + + #[strum(serialize = "krb5kdc/finish_process_as_req/badoption")] + FinishProcessAsReqBadoption, + + #[strum(serialize = "krb5kdc/finish_process_as_req/etype_nosupp")] + FinishProcessAsReqEtypeNosupp, + + #[strum(serialize = "krb5kdc/finish_process_as_req/sumtype_nosupp")] + FinishProcessAsReqSumtypeNosupp, + + #[strum(serialize = "krb5kdc/finish_process_as_req/padata_type_nosupp")] + FinishProcessAsReqPadataTypeNosupp, + + #[strum(serialize = "krb5kdc/finish_process_as_req/trtype_nosupp")] + FinishProcessAsReqTrtypeNosupp, + + #[strum(serialize = "krb5kdc/finish_process_as_req/client_revoked")] + FinishProcessAsReqClientRevoked, + + #[strum(serialize = "krb5kdc/finish_process_as_req/service_revoked")] + FinishProcessAsReqServiceRevoked, + + #[strum(serialize = "krb5kdc/finish_process_as_req/tgt_revoked")] + FinishProcessAsReqTgtRevoked, + + #[strum(serialize = "krb5kdc/finish_process_as_req/client_notyet")] + FinishProcessAsReqClientNotyet, + + #[strum(serialize = "krb5kdc/finish_process_as_req/service_notyet")] + FinishProcessAsReqServiceNotyet, + + #[strum(serialize = "krb5kdc/finish_process_as_req/key_exp")] + FinishProcessAsReqKeyExp, + + #[strum(serialize = "krb5kdc/finish_process_as_req/preauth_failed")] + FinishProcessAsReqPreauthFailed, + + #[strum(serialize = "krb5kdc/finish_process_as_req/preauth_required")] + FinishProcessAsReqPreauthRequired, + + #[strum(serialize = "krb5kdc/finish_process_as_req/server_nomatch")] + FinishProcessAsReqServerNomatch, + + #[strum(serialize = "krb5kdc/finish_process_as_req/must_use_user2user")] + FinishProcessAsReqMustUseUser2user, + + #[strum(serialize = "krb5kdc/finish_process_as_req/path_not_accepted")] + FinishProcessAsReqPathNotAccepted, + + #[strum(serialize = "krb5kdc/finish_process_as_req/svc_unavailable")] + FinishProcessAsReqSvcUnavailable, + + #[strum(serialize = "krb5kdc/finish_dispatch_cache/unknown")] + FinishDispatchCacheUnknown, + + #[strum(serialize = "krb5kdc/finish_dispatch_cache/none")] + FinishDispatchCacheNone, + + #[strum(serialize = "krb5kdc/finish_dispatch_cache/name_exp")] + FinishDispatchCacheNameExp, + + #[strum(serialize = "krb5kdc/finish_dispatch_cache/service_exp")] + FinishDispatchCacheServiceExp, + + #[strum(serialize = "krb5kdc/finish_dispatch_cache/bad_pvno")] + FinishDispatchCacheBadPvno, + + #[strum(serialize = "krb5kdc/finish_dispatch_cache/c_old_mast_kvno")] + FinishDispatchCacheCOldMastKvno, + + #[strum(serialize = "krb5kdc/finish_dispatch_cache/s_old_mast_kvno")] + FinishDispatchCacheSOldMastKvno, + + #[strum(serialize = "krb5kdc/finish_dispatch_cache/c_principal_unknown")] + FinishDispatchCacheCPrincipalUnknown, + + #[strum(serialize = "krb5kdc/finish_dispatch_cache/s_principal_unknown")] + FinishDispatchCacheSPrincipalUnknown, + + #[strum(serialize = "krb5kdc/finish_dispatch_cache/principal_not_unique")] + FinishDispatchCachePrincipalNotUnique, + + #[strum(serialize = "krb5kdc/finish_dispatch_cache/null_key")] + FinishDispatchCacheNullKey, + + #[strum(serialize = "krb5kdc/finish_dispatch_cache/cannot_postdate")] + FinishDispatchCacheCannotPostdate, + + #[strum(serialize = "krb5kdc/finish_dispatch_cache/never_valid")] + FinishDispatchCacheNeverValid, + + #[strum(serialize = "krb5kdc/finish_dispatch_cache/policy")] + FinishDispatchCachePolicy, + + #[strum(serialize = "krb5kdc/finish_dispatch_cache/badoption")] + FinishDispatchCacheBadoption, + + #[strum(serialize = "krb5kdc/finish_dispatch_cache/etype_nosupp")] + FinishDispatchCacheEtypeNosupp, + + #[strum(serialize = "krb5kdc/finish_dispatch_cache/sumtype_nosupp")] + FinishDispatchCacheSumtypeNosupp, + + #[strum(serialize = "krb5kdc/finish_dispatch_cache/padata_type_nosupp")] + FinishDispatchCachePadataTypeNosupp, + + #[strum(serialize = "krb5kdc/finish_dispatch_cache/trtype_nosupp")] + FinishDispatchCacheTrtypeNosupp, + + #[strum(serialize = "krb5kdc/finish_dispatch_cache/client_revoked")] + FinishDispatchCacheClientRevoked, + + #[strum(serialize = "krb5kdc/finish_dispatch_cache/service_revoked")] + FinishDispatchCacheServiceRevoked, + + #[strum(serialize = "krb5kdc/finish_dispatch_cache/tgt_revoked")] + FinishDispatchCacheTgtRevoked, + + #[strum(serialize = "krb5kdc/finish_dispatch_cache/client_notyet")] + FinishDispatchCacheClientNotyet, + + #[strum(serialize = "krb5kdc/finish_dispatch_cache/service_notyet")] + FinishDispatchCacheServiceNotyet, + + #[strum(serialize = "krb5kdc/finish_dispatch_cache/key_exp")] + FinishDispatchCacheKeyExp, + + #[strum(serialize = "krb5kdc/finish_dispatch_cache/preauth_failed")] + FinishDispatchCachePreauthFailed, + + #[strum(serialize = "krb5kdc/finish_dispatch_cache/preauth_required")] + FinishDispatchCachePreauthRequired, + + #[strum(serialize = "krb5kdc/finish_dispatch_cache/server_nomatch")] + FinishDispatchCacheServerNomatch, + + #[strum(serialize = "krb5kdc/finish_dispatch_cache/must_use_user2user")] + FinishDispatchCacheMustUseUser2user, + + #[strum(serialize = "krb5kdc/finish_dispatch_cache/path_not_accepted")] + FinishDispatchCachePathNotAccepted, + + #[strum(serialize = "krb5kdc/finish_dispatch_cache/svc_unavailable")] + FinishDispatchCacheSvcUnavailable, + + #[strum(serialize = "krb5kdc/process_tgs_req/unknown")] + ProcessTgsReqUnknown, + + #[strum(serialize = "krb5kdc/process_tgs_req/none")] + ProcessTgsReqNone, + + #[strum(serialize = "krb5kdc/process_tgs_req/name_exp")] + ProcessTgsReqNameExp, + + #[strum(serialize = "krb5kdc/process_tgs_req/service_exp")] + ProcessTgsReqServiceExp, + + #[strum(serialize = "krb5kdc/process_tgs_req/bad_pvno")] + ProcessTgsReqBadPvno, + + #[strum(serialize = "krb5kdc/process_tgs_req/c_old_mast_kvno")] + ProcessTgsReqCOldMastKvno, + + #[strum(serialize = "krb5kdc/process_tgs_req/s_old_mast_kvno")] + ProcessTgsReqSOldMastKvno, + + #[strum(serialize = "krb5kdc/process_tgs_req/c_principal_unknown")] + ProcessTgsReqCPrincipalUnknown, + + #[strum(serialize = "krb5kdc/process_tgs_req/s_principal_unknown")] + ProcessTgsReqSPrincipalUnknown, + + #[strum(serialize = "krb5kdc/process_tgs_req/principal_not_unique")] + ProcessTgsReqPrincipalNotUnique, + + #[strum(serialize = "krb5kdc/process_tgs_req/null_key")] + ProcessTgsReqNullKey, + + #[strum(serialize = "krb5kdc/process_tgs_req/cannot_postdate")] + ProcessTgsReqCannotPostdate, + + #[strum(serialize = "krb5kdc/process_tgs_req/never_valid")] + ProcessTgsReqNeverValid, + + #[strum(serialize = "krb5kdc/process_tgs_req/policy")] + ProcessTgsReqPolicy, + + #[strum(serialize = "krb5kdc/process_tgs_req/badoption")] + ProcessTgsReqBadoption, + + #[strum(serialize = "krb5kdc/process_tgs_req/etype_nosupp")] + ProcessTgsReqEtypeNosupp, + + #[strum(serialize = "krb5kdc/process_tgs_req/sumtype_nosupp")] + ProcessTgsReqSumtypeNosupp, + + #[strum(serialize = "krb5kdc/process_tgs_req/padata_type_nosupp")] + ProcessTgsReqPadataTypeNosupp, + + #[strum(serialize = "krb5kdc/process_tgs_req/trtype_nosupp")] + ProcessTgsReqTrtypeNosupp, + + #[strum(serialize = "krb5kdc/process_tgs_req/client_revoked")] + ProcessTgsReqClientRevoked, + + #[strum(serialize = "krb5kdc/process_tgs_req/service_revoked")] + ProcessTgsReqServiceRevoked, + + #[strum(serialize = "krb5kdc/process_tgs_req/tgt_revoked")] + ProcessTgsReqTgtRevoked, + + #[strum(serialize = "krb5kdc/process_tgs_req/client_notyet")] + ProcessTgsReqClientNotyet, + + #[strum(serialize = "krb5kdc/process_tgs_req/service_notyet")] + ProcessTgsReqServiceNotyet, + + #[strum(serialize = "krb5kdc/process_tgs_req/key_exp")] + ProcessTgsReqKeyExp, + + #[strum(serialize = "krb5kdc/process_tgs_req/preauth_failed")] + ProcessTgsReqPreauthFailed, + + #[strum(serialize = "krb5kdc/process_tgs_req/preauth_required")] + ProcessTgsReqPreauthRequired, + + #[strum(serialize = "krb5kdc/process_tgs_req/server_nomatch")] + ProcessTgsReqServerNomatch, + + #[strum(serialize = "krb5kdc/process_tgs_req/must_use_user2user")] + ProcessTgsReqMustUseUser2user, + + #[strum(serialize = "krb5kdc/process_tgs_req/path_not_accepted")] + ProcessTgsReqPathNotAccepted, + + #[strum(serialize = "krb5kdc/process_tgs_req/svc_unavailable")] + ProcessTgsReqSvcUnavailable, +} + +impl Krb5kdcStatistic { + pub fn bpf_table(self) -> &'static str { + match self { + Self::FinishProcessAsReqUnknown => "counts_finish_process_as_req", + Self::FinishProcessAsReqNone => "counts_finish_process_as_req", + Self::FinishProcessAsReqNameExp => "counts_finish_process_as_req", + Self::FinishProcessAsReqServiceExp => "counts_finish_process_as_req", + Self::FinishProcessAsReqBadPvno => "counts_finish_process_as_req", + Self::FinishProcessAsReqCOldMastKvno => "counts_finish_process_as_req", + Self::FinishProcessAsReqSOldMastKvno => "counts_finish_process_as_req", + Self::FinishProcessAsReqCPrincipalUnknown => "counts_finish_process_as_req", + Self::FinishProcessAsReqSPrincipalUnknown => "counts_finish_process_as_req", + Self::FinishProcessAsReqPrincipalNotUnique => "counts_finish_process_as_req", + Self::FinishProcessAsReqNullKey => "counts_finish_process_as_req", + Self::FinishProcessAsReqCannotPostdate => "counts_finish_process_as_req", + Self::FinishProcessAsReqNeverValid => "counts_finish_process_as_req", + Self::FinishProcessAsReqPolicy => "counts_finish_process_as_req", + Self::FinishProcessAsReqBadoption => "counts_finish_process_as_req", + Self::FinishProcessAsReqEtypeNosupp => "counts_finish_process_as_req", + Self::FinishProcessAsReqSumtypeNosupp => "counts_finish_process_as_req", + Self::FinishProcessAsReqPadataTypeNosupp => "counts_finish_process_as_req", + Self::FinishProcessAsReqTrtypeNosupp => "counts_finish_process_as_req", + Self::FinishProcessAsReqClientRevoked => "counts_finish_process_as_req", + Self::FinishProcessAsReqServiceRevoked => "counts_finish_process_as_req", + Self::FinishProcessAsReqTgtRevoked => "counts_finish_process_as_req", + Self::FinishProcessAsReqClientNotyet => "counts_finish_process_as_req", + Self::FinishProcessAsReqServiceNotyet => "counts_finish_process_as_req", + Self::FinishProcessAsReqKeyExp => "counts_finish_process_as_req", + Self::FinishProcessAsReqPreauthFailed => "counts_finish_process_as_req", + Self::FinishProcessAsReqPreauthRequired => "counts_finish_process_as_req", + Self::FinishProcessAsReqServerNomatch => "counts_finish_process_as_req", + Self::FinishProcessAsReqMustUseUser2user => "counts_finish_process_as_req", + Self::FinishProcessAsReqPathNotAccepted => "counts_finish_process_as_req", + Self::FinishProcessAsReqSvcUnavailable => "counts_finish_process_as_req", + + Self::FinishDispatchCacheUnknown => "counts_finish_dispatch_cache", + Self::FinishDispatchCacheNone => "counts_finish_dispatch_cache", + Self::FinishDispatchCacheNameExp => "counts_finish_dispatch_cache", + Self::FinishDispatchCacheServiceExp => "counts_finish_dispatch_cache", + Self::FinishDispatchCacheBadPvno => "counts_finish_dispatch_cache", + Self::FinishDispatchCacheCOldMastKvno => "counts_finish_dispatch_cache", + Self::FinishDispatchCacheSOldMastKvno => "counts_finish_dispatch_cache", + Self::FinishDispatchCacheCPrincipalUnknown => "counts_finish_dispatch_cache", + Self::FinishDispatchCacheSPrincipalUnknown => "counts_finish_dispatch_cache", + Self::FinishDispatchCachePrincipalNotUnique => "counts_finish_dispatch_cache", + Self::FinishDispatchCacheNullKey => "counts_finish_dispatch_cache", + Self::FinishDispatchCacheCannotPostdate => "counts_finish_dispatch_cache", + Self::FinishDispatchCacheNeverValid => "counts_finish_dispatch_cache", + Self::FinishDispatchCachePolicy => "counts_finish_dispatch_cache", + Self::FinishDispatchCacheBadoption => "counts_finish_dispatch_cache", + Self::FinishDispatchCacheEtypeNosupp => "counts_finish_dispatch_cache", + Self::FinishDispatchCacheSumtypeNosupp => "counts_finish_dispatch_cache", + Self::FinishDispatchCachePadataTypeNosupp => "counts_finish_dispatch_cache", + Self::FinishDispatchCacheTrtypeNosupp => "counts_finish_dispatch_cache", + Self::FinishDispatchCacheClientRevoked => "counts_finish_dispatch_cache", + Self::FinishDispatchCacheServiceRevoked => "counts_finish_dispatch_cache", + Self::FinishDispatchCacheTgtRevoked => "counts_finish_dispatch_cache", + Self::FinishDispatchCacheClientNotyet => "counts_finish_dispatch_cache", + Self::FinishDispatchCacheServiceNotyet => "counts_finish_dispatch_cache", + Self::FinishDispatchCacheKeyExp => "counts_finish_dispatch_cache", + Self::FinishDispatchCachePreauthFailed => "counts_finish_dispatch_cache", + Self::FinishDispatchCachePreauthRequired => "counts_finish_dispatch_cache", + Self::FinishDispatchCacheServerNomatch => "counts_finish_dispatch_cache", + Self::FinishDispatchCacheMustUseUser2user => "counts_finish_dispatch_cache", + Self::FinishDispatchCachePathNotAccepted => "counts_finish_dispatch_cache", + Self::FinishDispatchCacheSvcUnavailable => "counts_finish_dispatch_cache", + + Self::ProcessTgsReqUnknown => "counts_process_tgs_req", + Self::ProcessTgsReqNone => "counts_process_tgs_req", + Self::ProcessTgsReqNameExp => "counts_process_tgs_req", + Self::ProcessTgsReqServiceExp => "counts_process_tgs_req", + Self::ProcessTgsReqBadPvno => "counts_process_tgs_req", + Self::ProcessTgsReqCOldMastKvno => "counts_process_tgs_req", + Self::ProcessTgsReqSOldMastKvno => "counts_process_tgs_req", + Self::ProcessTgsReqCPrincipalUnknown => "counts_process_tgs_req", + Self::ProcessTgsReqSPrincipalUnknown => "counts_process_tgs_req", + Self::ProcessTgsReqPrincipalNotUnique => "counts_process_tgs_req", + Self::ProcessTgsReqNullKey => "counts_process_tgs_req", + Self::ProcessTgsReqCannotPostdate => "counts_process_tgs_req", + Self::ProcessTgsReqNeverValid => "counts_process_tgs_req", + Self::ProcessTgsReqPolicy => "counts_process_tgs_req", + Self::ProcessTgsReqBadoption => "counts_process_tgs_req", + Self::ProcessTgsReqEtypeNosupp => "counts_process_tgs_req", + Self::ProcessTgsReqSumtypeNosupp => "counts_process_tgs_req", + Self::ProcessTgsReqPadataTypeNosupp => "counts_process_tgs_req", + Self::ProcessTgsReqTrtypeNosupp => "counts_process_tgs_req", + Self::ProcessTgsReqClientRevoked => "counts_process_tgs_req", + Self::ProcessTgsReqServiceRevoked => "counts_process_tgs_req", + Self::ProcessTgsReqTgtRevoked => "counts_process_tgs_req", + Self::ProcessTgsReqClientNotyet => "counts_process_tgs_req", + Self::ProcessTgsReqServiceNotyet => "counts_process_tgs_req", + Self::ProcessTgsReqKeyExp => "counts_process_tgs_req", + Self::ProcessTgsReqPreauthFailed => "counts_process_tgs_req", + Self::ProcessTgsReqPreauthRequired => "counts_process_tgs_req", + Self::ProcessTgsReqServerNomatch => "counts_process_tgs_req", + Self::ProcessTgsReqMustUseUser2user => "counts_process_tgs_req", + Self::ProcessTgsReqPathNotAccepted => "counts_process_tgs_req", + Self::ProcessTgsReqSvcUnavailable => "counts_process_tgs_req", + } + } + + pub fn bpf_entry(self) -> &'static str { + match self { + Self::FinishProcessAsReqUnknown => "UNKNOWN", + Self::FinishProcessAsReqNone => "NONE", + Self::FinishProcessAsReqNameExp => "NAME_EXP", + Self::FinishProcessAsReqServiceExp => "SERVICE_EXP", + Self::FinishProcessAsReqBadPvno => "BAD_PVNO", + Self::FinishProcessAsReqCOldMastKvno => "C_OLD_MAST_KVNO", + Self::FinishProcessAsReqSOldMastKvno => "S_OLD_MAST_KVNO", + Self::FinishProcessAsReqCPrincipalUnknown => "C_PRINCIPAL_UNKNOWN", + Self::FinishProcessAsReqSPrincipalUnknown => "S_PRINCIPAL_UNKNOWN", + Self::FinishProcessAsReqPrincipalNotUnique => "PRINCIPAL_NOT_UNIQUE", + Self::FinishProcessAsReqNullKey => "NULL_KEY", + Self::FinishProcessAsReqCannotPostdate => "CANNOT_POSTDATE", + Self::FinishProcessAsReqNeverValid => "NEVER_VALID", + Self::FinishProcessAsReqPolicy => "POLICY", + Self::FinishProcessAsReqBadoption => "BADOPTION", + Self::FinishProcessAsReqEtypeNosupp => "ETYPE_NOSUPP", + Self::FinishProcessAsReqSumtypeNosupp => "SUMTYPE_NOSUPP", + Self::FinishProcessAsReqPadataTypeNosupp => "PADATA_TYPE_NOSUPP", + Self::FinishProcessAsReqTrtypeNosupp => "TRTYPE_NOSUPP", + Self::FinishProcessAsReqClientRevoked => "CLIENT_REVOKED", + Self::FinishProcessAsReqServiceRevoked => "SERVICE_REVOKED", + Self::FinishProcessAsReqTgtRevoked => "TGT_REVOKED", + Self::FinishProcessAsReqClientNotyet => "CLIENT_NOTYET", + Self::FinishProcessAsReqServiceNotyet => "SERVICE_NOTYET", + Self::FinishProcessAsReqKeyExp => "KEY_EXP", + Self::FinishProcessAsReqPreauthFailed => "PREAUTH_FAILED", + Self::FinishProcessAsReqPreauthRequired => "PREAUTH_REQUIRED", + Self::FinishProcessAsReqServerNomatch => "SERVER_NOMATCH", + Self::FinishProcessAsReqMustUseUser2user => "MUST_USE_USER2USER", + Self::FinishProcessAsReqPathNotAccepted => "PATH_NOT_ACCEPTED", + Self::FinishProcessAsReqSvcUnavailable => "SVC_UNAVAILABLE", + + Self::FinishDispatchCacheUnknown => "UNKNOWN", + Self::FinishDispatchCacheNone => "NONE", + Self::FinishDispatchCacheNameExp => "NAME_EXP", + Self::FinishDispatchCacheServiceExp => "SERVICE_EXP", + Self::FinishDispatchCacheBadPvno => "BAD_PVNO", + Self::FinishDispatchCacheCOldMastKvno => "C_OLD_MAST_KVNO", + Self::FinishDispatchCacheSOldMastKvno => "S_OLD_MAST_KVNO", + Self::FinishDispatchCacheCPrincipalUnknown => "C_PRINCIPAL_UNKNOWN", + Self::FinishDispatchCacheSPrincipalUnknown => "S_PRINCIPAL_UNKNOWN", + Self::FinishDispatchCachePrincipalNotUnique => "PRINCIPAL_NOT_UNIQUE", + Self::FinishDispatchCacheNullKey => "NULL_KEY", + Self::FinishDispatchCacheCannotPostdate => "CANNOT_POSTDATE", + Self::FinishDispatchCacheNeverValid => "NEVER_VALID", + Self::FinishDispatchCachePolicy => "POLICY", + Self::FinishDispatchCacheBadoption => "BADOPTION", + Self::FinishDispatchCacheEtypeNosupp => "ETYPE_NOSUPP", + Self::FinishDispatchCacheSumtypeNosupp => "SUMTYPE_NOSUPP", + Self::FinishDispatchCachePadataTypeNosupp => "PADATA_TYPE_NOSUPP", + Self::FinishDispatchCacheTrtypeNosupp => "TRTYPE_NOSUPP", + Self::FinishDispatchCacheClientRevoked => "CLIENT_REVOKED", + Self::FinishDispatchCacheServiceRevoked => "SERVICE_REVOKED", + Self::FinishDispatchCacheTgtRevoked => "TGT_REVOKED", + Self::FinishDispatchCacheClientNotyet => "CLIENT_NOTYET", + Self::FinishDispatchCacheServiceNotyet => "SERVICE_NOTYET", + Self::FinishDispatchCacheKeyExp => "KEY_EXP", + Self::FinishDispatchCachePreauthFailed => "PREAUTH_FAILED", + Self::FinishDispatchCachePreauthRequired => "PREAUTH_REQUIRED", + Self::FinishDispatchCacheServerNomatch => "SERVER_NOMATCH", + Self::FinishDispatchCacheMustUseUser2user => "MUST_USE_USER2USER", + Self::FinishDispatchCachePathNotAccepted => "PATH_NOT_ACCEPTED", + Self::FinishDispatchCacheSvcUnavailable => "SVC_UNAVAILABLE", + + Self::ProcessTgsReqUnknown => "UNKNOWN", + Self::ProcessTgsReqNone => "NONE", + Self::ProcessTgsReqNameExp => "NAME_EXP", + Self::ProcessTgsReqServiceExp => "SERVICE_EXP", + Self::ProcessTgsReqBadPvno => "BAD_PVNO", + Self::ProcessTgsReqCOldMastKvno => "C_OLD_MAST_KVNO", + Self::ProcessTgsReqSOldMastKvno => "S_OLD_MAST_KVNO", + Self::ProcessTgsReqCPrincipalUnknown => "C_PRINCIPAL_UNKNOWN", + Self::ProcessTgsReqSPrincipalUnknown => "S_PRINCIPAL_UNKNOWN", + Self::ProcessTgsReqPrincipalNotUnique => "PRINCIPAL_NOT_UNIQUE", + Self::ProcessTgsReqNullKey => "NULL_KEY", + Self::ProcessTgsReqCannotPostdate => "CANNOT_POSTDATE", + Self::ProcessTgsReqNeverValid => "NEVER_VALID", + Self::ProcessTgsReqPolicy => "POLICY", + Self::ProcessTgsReqBadoption => "BADOPTION", + Self::ProcessTgsReqEtypeNosupp => "ETYPE_NOSUPP", + Self::ProcessTgsReqSumtypeNosupp => "SUMTYPE_NOSUPP", + Self::ProcessTgsReqPadataTypeNosupp => "PADATA_TYPE_NOSUPP", + Self::ProcessTgsReqTrtypeNosupp => "TRTYPE_NOSUPP", + Self::ProcessTgsReqClientRevoked => "CLIENT_REVOKED", + Self::ProcessTgsReqServiceRevoked => "SERVICE_REVOKED", + Self::ProcessTgsReqTgtRevoked => "TGT_REVOKED", + Self::ProcessTgsReqClientNotyet => "CLIENT_NOTYET", + Self::ProcessTgsReqServiceNotyet => "SERVICE_NOTYET", + Self::ProcessTgsReqKeyExp => "KEY_EXP", + Self::ProcessTgsReqPreauthFailed => "PREAUTH_FAILED", + Self::ProcessTgsReqPreauthRequired => "PREAUTH_REQUIRED", + Self::ProcessTgsReqServerNomatch => "SERVER_NOMATCH", + Self::ProcessTgsReqMustUseUser2user => "MUST_USE_USER2USER", + Self::ProcessTgsReqPathNotAccepted => "PATH_NOT_ACCEPTED", + Self::ProcessTgsReqSvcUnavailable => "SVC_UNAVAILABLE", + } + } +} + +impl Statistic for Krb5kdcStatistic { + fn name(&self) -> &str { + (*self).into() + } + + fn source(&self) -> Source { + Source::Counter + } +} + +impl TryFrom<&str> for Krb5kdcStatistic { + type Error = ParseError; + + fn try_from(s: &str) -> Result { + Krb5kdcStatistic::from_str(s) + } +} diff --git a/src/samplers/mod.rs b/src/samplers/mod.rs index d6367f17..0865ade0 100644 --- a/src/samplers/mod.rs +++ b/src/samplers/mod.rs @@ -20,6 +20,7 @@ pub mod disk; pub mod ext4; pub mod http; pub mod interrupt; +pub mod krb5kdc; pub mod memcache; pub mod memory; pub mod network; @@ -39,6 +40,7 @@ pub use disk::Disk; pub use ext4::Ext4; pub use http::Http; pub use interrupt::Interrupt; +pub use krb5kdc::Krb5kdc; pub use memcache::Memcache; pub use memory::Memory; pub use network::Network;