feat(core): implement ForwardingPolicy with rule-based allow/deny

Add ForwardingPolicy, ForwardingAction, ForwardingRule, and TargetPattern
types in config/forwarding.rs. Implement policy evaluation with first-match
wins semantics, principal and transport matching, CIDR and glob patterns.

Modify ServerHandler to check ForwardingPolicy before proxying in
channel_open_direct_tcpip. Reserved alknet-* destinations bypass policy.
Preserve existing behavior with default allow_all() policy.
This commit is contained in:
2026-06-07 14:47:44 +00:00
parent 92a307fd03
commit 9478e2911d
6 changed files with 503 additions and 41 deletions

View File

@@ -6,6 +6,7 @@ use russh::keys::ssh_key::HashAlg;
use crate::auth::identity::Identity;
use crate::auth::ServerAuthConfig;
use crate::config::forwarding::ForwardingPolicy;
pub struct AuthPolicy {
pub authorized_keys: std::collections::HashSet<russh::keys::PublicKey>,
@@ -212,41 +213,6 @@ impl Clone for AuthPolicy {
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum ForwardingAction {
Allow,
Deny,
}
#[derive(Debug, Clone)]
pub struct ForwardingRule {
pub action: ForwardingAction,
pub principals: Vec<String>,
pub transports: Vec<crate::server::handler::TransportKind>,
}
#[derive(Debug, Clone)]
pub struct ForwardingPolicy {
pub default: ForwardingAction,
pub rules: Vec<ForwardingRule>,
}
impl ForwardingPolicy {
pub fn allow_all() -> Self {
Self {
default: ForwardingAction::Allow,
rules: Vec::new(),
}
}
pub fn deny_all() -> Self {
Self {
default: ForwardingAction::Deny,
rules: Vec::new(),
}
}
}
#[derive(Debug, Clone)]
pub struct RateLimitConfig {
pub max_connections_per_ip: usize,
@@ -330,6 +296,7 @@ pub fn new_dynamic_config() -> (Arc<ArcSwap<DynamicConfig>>, ConfigReloadHandle)
#[cfg(test)]
mod tests {
use super::*;
use crate::config::forwarding::ForwardingAction;
#[test]
fn forwarding_policy_allow_all_default() {