Skip to main content

cmr_core/
policy.rs

1//! Router security and routing policy.
2
3use serde::{Deserialize, Serialize};
4
5/// Global security posture.
6#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
7#[serde(rename_all = "kebab-case")]
8pub enum SecurityLevel {
9    /// Strict defaults for untrusted internet peers.
10    #[default]
11    Strict,
12    /// Balanced defaults for mixed deployments.
13    Balanced,
14    /// Trusted peers where performance matters most.
15    Trusted,
16}
17
18/// Throughput and anti-flood policy.
19#[derive(Clone, Debug, Serialize, Deserialize)]
20pub struct ThroughputPolicy {
21    /// Max inbound messages per peer per minute.
22    pub per_peer_messages_per_minute: u32,
23    /// Max inbound bytes per peer per minute.
24    pub per_peer_bytes_per_minute: u64,
25    /// Max total inbound messages per minute.
26    pub global_messages_per_minute: u32,
27    /// Max total inbound bytes per minute.
28    pub global_bytes_per_minute: u64,
29    /// Max forwarding fanout produced by one accepted message.
30    pub max_forward_actions: usize,
31}
32
33/// Spam and semantic match policy.
34#[derive(Clone, Debug, Serialize, Deserialize)]
35pub struct SpamPolicy {
36    /// Minimum intrinsic dependence accepted for untrusted payloads.
37    pub min_intrinsic_dependence: f64,
38    /// Maximum raw Section 3.2 match distance for forwarding gates.
39    pub max_match_distance: f64,
40    /// Estimator order for intrinsic-dependence checks.
41    pub intrinsic_dependence_order: i64,
42}
43
44/// Identity/trust and reputation policy.
45#[derive(Clone, Debug, Serialize, Deserialize)]
46pub struct TrustPolicy {
47    /// Minimum score required to accept traffic from a peer.
48    pub min_reputation_score: f64,
49    /// Require signatures from known peers that already have a shared key.
50    pub require_signatures_from_known_peers: bool,
51    /// Reject signed messages when no key exists for the immediate sender.
52    pub reject_signed_without_known_key: bool,
53    /// Allow unsigned messages from unknown peers.
54    pub allow_unsigned_from_unknown_peers: bool,
55    /// Max outbound/inbound byte ratio before throttling peer.
56    pub max_outbound_inbound_ratio: f64,
57    /// Automatic key-exchange method for unknown peers.
58    #[serde(default)]
59    pub auto_key_exchange_mode: AutoKeyExchangeMode,
60}
61
62/// Automatic first-contact key-exchange method.
63#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
64#[serde(rename_all = "kebab-case")]
65pub enum AutoKeyExchangeMode {
66    /// Initiate RSA key exchange.
67    #[default]
68    Rsa,
69    /// Initiate Diffie-Hellman key exchange.
70    Dh,
71}
72
73/// Content safety policy.
74#[derive(Clone, Debug, Serialize, Deserialize)]
75pub struct ContentPolicy {
76    /// Max full message size.
77    pub max_message_bytes: usize,
78    /// Max body size.
79    pub max_body_bytes: usize,
80    /// Max header hop count.
81    pub max_header_ids: usize,
82    /// Allow non-text/binary payloads.
83    pub allow_binary_payloads: bool,
84    /// Drop likely executable payloads unless peer is trusted.
85    pub block_executable_magic: bool,
86}
87
88/// Full router policy.
89#[derive(Clone, Debug, Serialize, Deserialize)]
90pub struct RoutingPolicy {
91    /// High-level security posture.
92    pub security_level: SecurityLevel,
93    /// Throughput controls.
94    pub throughput: ThroughputPolicy,
95    /// Spam controls.
96    pub spam: SpamPolicy,
97    /// Trust controls.
98    pub trust: TrustPolicy,
99    /// Content controls.
100    pub content: ContentPolicy,
101    /// Max messages retained in cache.
102    pub cache_max_messages: usize,
103    /// Max bytes retained in cache.
104    pub cache_max_bytes: usize,
105}
106
107impl RoutingPolicy {
108    /// Default policy for a chosen security level.
109    #[must_use]
110    pub fn for_level(level: SecurityLevel) -> Self {
111        match level {
112            SecurityLevel::Strict => Self {
113                security_level: level,
114                throughput: ThroughputPolicy {
115                    per_peer_messages_per_minute: 240,
116                    per_peer_bytes_per_minute: 8 * 1024 * 1024,
117                    global_messages_per_minute: 20_000,
118                    global_bytes_per_minute: 512 * 1024 * 1024,
119                    max_forward_actions: 64,
120                },
121                spam: SpamPolicy {
122                    min_intrinsic_dependence: 0.02,
123                    max_match_distance: 500.0,
124                    intrinsic_dependence_order: 8,
125                },
126                trust: TrustPolicy {
127                    min_reputation_score: -20.0,
128                    require_signatures_from_known_peers: true,
129                    reject_signed_without_known_key: true,
130                    allow_unsigned_from_unknown_peers: true,
131                    max_outbound_inbound_ratio: 1.8,
132                    auto_key_exchange_mode: AutoKeyExchangeMode::Rsa,
133                },
134                content: ContentPolicy {
135                    max_message_bytes: 4 * 1024 * 1024,
136                    max_body_bytes: 2 * 1024 * 1024,
137                    max_header_ids: 1024,
138                    allow_binary_payloads: true,
139                    block_executable_magic: true,
140                },
141                cache_max_messages: 200_000,
142                cache_max_bytes: 2 * 1024 * 1024 * 1024,
143            },
144            SecurityLevel::Balanced => Self {
145                security_level: level,
146                throughput: ThroughputPolicy {
147                    per_peer_messages_per_minute: 600,
148                    per_peer_bytes_per_minute: 16 * 1024 * 1024,
149                    global_messages_per_minute: 40_000,
150                    global_bytes_per_minute: 1024 * 1024 * 1024,
151                    max_forward_actions: 128,
152                },
153                spam: SpamPolicy {
154                    min_intrinsic_dependence: 0.01,
155                    max_match_distance: 700.0,
156                    intrinsic_dependence_order: 8,
157                },
158                trust: TrustPolicy {
159                    min_reputation_score: -40.0,
160                    require_signatures_from_known_peers: true,
161                    reject_signed_without_known_key: false,
162                    allow_unsigned_from_unknown_peers: true,
163                    max_outbound_inbound_ratio: 2.5,
164                    auto_key_exchange_mode: AutoKeyExchangeMode::Rsa,
165                },
166                content: ContentPolicy {
167                    max_message_bytes: 8 * 1024 * 1024,
168                    max_body_bytes: 4 * 1024 * 1024,
169                    max_header_ids: 2048,
170                    allow_binary_payloads: true,
171                    block_executable_magic: true,
172                },
173                cache_max_messages: 400_000,
174                cache_max_bytes: 4 * 1024 * 1024 * 1024,
175            },
176            SecurityLevel::Trusted => Self {
177                security_level: level,
178                throughput: ThroughputPolicy {
179                    per_peer_messages_per_minute: 6_000,
180                    per_peer_bytes_per_minute: 128 * 1024 * 1024,
181                    global_messages_per_minute: 200_000,
182                    global_bytes_per_minute: 8 * 1024 * 1024 * 1024,
183                    max_forward_actions: 512,
184                },
185                spam: SpamPolicy {
186                    min_intrinsic_dependence: 0.0,
187                    max_match_distance: 800.0,
188                    intrinsic_dependence_order: 8,
189                },
190                trust: TrustPolicy {
191                    min_reputation_score: -80.0,
192                    require_signatures_from_known_peers: false,
193                    reject_signed_without_known_key: false,
194                    allow_unsigned_from_unknown_peers: true,
195                    max_outbound_inbound_ratio: 4.0,
196                    auto_key_exchange_mode: AutoKeyExchangeMode::Rsa,
197                },
198                content: ContentPolicy {
199                    max_message_bytes: 16 * 1024 * 1024,
200                    max_body_bytes: 12 * 1024 * 1024,
201                    max_header_ids: 4096,
202                    allow_binary_payloads: true,
203                    block_executable_magic: false,
204                },
205                cache_max_messages: 1_000_000,
206                cache_max_bytes: 16 * 1024 * 1024 * 1024,
207            },
208        }
209    }
210}
211
212impl Default for RoutingPolicy {
213    fn default() -> Self {
214        Self::for_level(SecurityLevel::Strict)
215    }
216}