summaryrefslogtreecommitdiffstats
path: root/src/transport/firewall.rs
blob: 7b0ec0de887c17546de25ee8c0a88147d81d9aed (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
//! The debug firewall (`/debug/firewall`, with `--debug-api`): drops messages from and
//! to peers, by node ID, to test partitions on a real swarm. It works at the bottom of
//! the node, in the paths layer (`transport::paths::Gate`), so it drops everything a
//! partition would: WHO and ME, PINGs and their PONGs, as well as the node's messages.

use std::collections::HashSet;
use std::sync::{RwLock, RwLockReadGuard};

use serde::{Deserialize, Serialize};

use crate::locks::RwLockExt;

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub(crate) struct FirewallRules {
    /// Messages from these peers are dropped before the application sees them.
    #[serde(default)]
    pub(crate) inbound: HashSet<String>,
    /// Messages to these peers are silently dropped, like a lossy network.
    #[serde(default)]
    pub(crate) outbound: HashSet<String>,
}

/// Uses a std lock: checks are tiny and the guard is never held across an await.
#[derive(Default)]
pub(crate) struct Firewall {
    rules: RwLock<FirewallRules>,
}

impl Firewall {
    fn read(&self) -> RwLockReadGuard<'_, FirewallRules> {
        self.rules.read_or_recover()
    }

    pub(crate) fn rules(&self) -> FirewallRules {
        self.read().clone()
    }

    pub(crate) fn set_rules(&self, rules: FirewallRules) {
        *self.rules.write_or_recover() = rules;
    }

    pub(crate) fn blocks_inbound(&self, peer: &str) -> bool {
        self.read().inbound.contains(peer)
    }

    pub(crate) fn blocks_outbound(&self, peer: &str) -> bool {
        self.read().outbound.contains(peer)
    }
}