1use std::sync::atomic::{AtomicU64, Ordering};
15use std::sync::Arc;
16
17#[cfg(feature = "tokio-runtime")]
22use crate::security::ssrf::IpClass;
23
24#[derive(Debug, Default, Clone)]
26pub struct SecurityMetrics {
27 inner: Arc<SecurityMetricsInner>,
28}
29
30#[derive(Debug, Default)]
31struct SecurityMetricsInner {
32 #[cfg_attr(not(feature = "tokio-runtime"), allow(dead_code))]
38 ssrf_blocked_private: AtomicU64,
39 #[cfg_attr(not(feature = "tokio-runtime"), allow(dead_code))]
40 ssrf_blocked_loopback: AtomicU64,
41 #[cfg_attr(not(feature = "tokio-runtime"), allow(dead_code))]
42 ssrf_blocked_link_local: AtomicU64,
43 #[cfg_attr(not(feature = "tokio-runtime"), allow(dead_code))]
44 ssrf_blocked_multicast: AtomicU64,
45 #[cfg_attr(not(feature = "tokio-runtime"), allow(dead_code))]
46 ssrf_blocked_reserved: AtomicU64,
47 dotfile_denied: AtomicU64,
53}
54
55impl SecurityMetrics {
56 pub fn new() -> Self {
58 Self::default()
59 }
60
61 #[cfg(feature = "tokio-runtime")]
63 pub fn record_ssrf_block(&self, class: IpClass) {
64 let counter = match class {
65 IpClass::Private => &self.inner.ssrf_blocked_private,
66 IpClass::Loopback => &self.inner.ssrf_blocked_loopback,
67 IpClass::LinkLocal => &self.inner.ssrf_blocked_link_local,
68 IpClass::Multicast => &self.inner.ssrf_blocked_multicast,
69 IpClass::Reserved | IpClass::Public => &self.inner.ssrf_blocked_reserved,
70 };
71 counter.fetch_add(1, Ordering::Relaxed);
72 }
73
74 #[cfg(feature = "tokio-runtime")]
76 pub fn ssrf_blocked_total(&self, class: IpClass) -> u64 {
77 let counter = match class {
78 IpClass::Private => &self.inner.ssrf_blocked_private,
79 IpClass::Loopback => &self.inner.ssrf_blocked_loopback,
80 IpClass::LinkLocal => &self.inner.ssrf_blocked_link_local,
81 IpClass::Multicast => &self.inner.ssrf_blocked_multicast,
82 IpClass::Reserved | IpClass::Public => &self.inner.ssrf_blocked_reserved,
83 };
84 counter.load(Ordering::Relaxed)
85 }
86
87 pub fn record_dotfile_deny(&self) {
89 self.inner.dotfile_denied.fetch_add(1, Ordering::Relaxed);
90 }
91
92 pub fn dotfile_denied_total(&self) -> u64 {
94 self.inner.dotfile_denied.load(Ordering::Relaxed)
95 }
96}