Skip to content

Commit

Permalink
draft: node-mgr and node args to run as sybil nodes eclipsing a speci…
Browse files Browse the repository at this point in the history
…fied xorname
  • Loading branch information
bochaco committed Apr 8, 2024
1 parent 0522e65 commit cdd9b5e
Show file tree
Hide file tree
Showing 9 changed files with 86 additions and 5 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions sn_networking/src/cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,8 @@ impl SwarmDriver {
.payment_received();
}
SwarmCmd::GetLocalRecord { key, sender } => {
// TODO: eclipse content if sybil was set, if sybil xorname set is close to the key ....?

cmd_string = "GetLocalRecord";
let record = self
.swarm
Expand All @@ -379,6 +381,8 @@ impl SwarmDriver {
sender,
quorum,
} => {
// TODO: eclipse content if sybil was set, if sybil xorname set is close to the key ....?

cmd_string = "PutRecord";
let record_key = PrettyPrintRecordKey::from(&record.key).into_owned();
trace!(
Expand Down Expand Up @@ -431,6 +435,8 @@ impl SwarmDriver {
}
}
SwarmCmd::PutLocalRecord { record } => {
// TODO: eclipse content if sybil was set, if sybil xorname set is close to the key ....?

cmd_string = "PutLocalRecord";
let key = record.key.clone();
let record_key = PrettyPrintRecordKey::from(&key);
Expand Down
10 changes: 10 additions & 0 deletions sn_networking/src/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ use std::{
use tokio::sync::{mpsc, oneshot};
use tokio::time::Duration;
use tracing::warn;
use xor_name::XorName;

/// Interval over which we check for the farthest record we _should_ be holding
/// based upon our knowledge of the CLOSE_GROUP
Expand Down Expand Up @@ -185,6 +186,7 @@ pub struct NetworkBuilder {
metrics_registry: Option<Registry>,
#[cfg(feature = "open-metrics")]
metrics_server_port: u16,
sybil: Option<XorName>,
}

impl NetworkBuilder {
Expand All @@ -200,6 +202,7 @@ impl NetworkBuilder {
metrics_registry: None,
#[cfg(feature = "open-metrics")]
metrics_server_port: 0,
sybil: None,
}
}

Expand All @@ -225,6 +228,10 @@ impl NetworkBuilder {
self.metrics_server_port = port;
}

pub fn set_sybil_mode(&mut self, sybil: Option<XorName>) {
self.sybil = sybil;
}

/// Creates a new `SwarmDriver` instance, along with a `Network` handle
/// for sending commands and an `mpsc::Receiver<NetworkEvent>` for receiving
/// network events. It initializes the swarm, sets up the transport, and
Expand Down Expand Up @@ -488,6 +495,7 @@ impl NetworkBuilder {
replication_fetcher,
#[cfg(feature = "open-metrics")]
network_metrics,
sybil: self.sybil,
cmd_receiver: swarm_cmd_receiver,
event_sender: network_event_sender,
pending_get_closest_peers: Default::default(),
Expand Down Expand Up @@ -536,6 +544,8 @@ pub struct SwarmDriver {
#[allow(unused)]
pub(crate) network_metrics: NetworkMetrics,

sybil: Option<XorName>,

cmd_receiver: mpsc::Receiver<SwarmCmd>,
event_sender: mpsc::Sender<NetworkEvent>, // Use `self.send_event()` to send a NetworkEvent.

Expand Down
19 changes: 19 additions & 0 deletions sn_node/src/bin/safenode/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,15 @@ struct Opt {
#[clap(long)]
local: bool,

/// Set to have the node to act as sybil node eclipsing a specified CID/address.
///
/// A hex-encoded xorname shall be provided to eclipse the content at such address
/// by dropping any provider record, as well as queries, targeting such address.
/// This can be used for testing sybil defense and detection using an address which belongs to
/// only test content so real users content is not affected.
#[clap(long, name = "CID's xorname")]
sybil: Option<String>,

#[cfg(feature = "open-metrics")]
/// Specify the port for the OpenMetrics server.
///
Expand Down Expand Up @@ -173,6 +182,15 @@ fn main() -> Result<()> {

info!("Node started with initial_peers {bootstrap_peers:?}");

let sybil = opt.sybil.map(|xorname_str| {
let bytes = hex::decode(xorname_str).unwrap();
let mut arr = [0u8; xor_name::XOR_NAME_LEN];
arr.copy_from_slice(&bytes);
let xorname = xor_name::XorName(arr);
info!("Running as sybil node to eclipse XorName: {xorname}");
xorname
});

// Create a tokio runtime per `run_node` attempt, this ensures
// any spawned tasks are closed before we would attempt to run
// another process with these args.
Expand All @@ -185,6 +203,7 @@ fn main() -> Result<()> {
bootstrap_peers,
opt.local,
root_dir,
sybil,
);
#[cfg(feature = "open-metrics")]
let mut node_builder = node_builder;
Expand Down
6 changes: 6 additions & 0 deletions sn_node/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ use tokio::{
sync::{broadcast, mpsc::Receiver},
task::{spawn, JoinHandle},
};
use xor_name::XorName;

/// Interval to trigger replication of all records to all peers.
/// This is the max time it should take. Minimum interval at any ndoe will be half this
Expand All @@ -63,6 +64,7 @@ pub struct NodeBuilder {
initial_peers: Vec<Multiaddr>,
local: bool,
root_dir: PathBuf,
sybil: Option<XorName>,
#[cfg(feature = "open-metrics")]
metrics_server_port: u16,
}
Expand All @@ -75,13 +77,15 @@ impl NodeBuilder {
initial_peers: Vec<Multiaddr>,
local: bool,
root_dir: PathBuf,
sybil: Option<XorName>,
) -> Self {
Self {
keypair,
addr,
initial_peers,
local,
root_dir,
sybil,
#[cfg(feature = "open-metrics")]
metrics_server_port: 0,
}
Expand Down Expand Up @@ -135,6 +139,8 @@ impl NodeBuilder {
#[cfg(feature = "open-metrics")]
network_builder.metrics_server_port(self.metrics_server_port);

network_builder.set_sybil_mode(self.sybil);

let (network, network_event_receiver, swarm_driver) = network_builder.build_node()?;
let node_events_channel = NodeEventsChannel::default();
let (node_cmds, _) = broadcast::channel(10);
Expand Down
2 changes: 2 additions & 0 deletions sn_node_manager/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ clap = { version = "4.4.6", features = ["derive", "env"] }
colored = "2.0.4"
color-eyre = "~0.6"
dirs-next = "2.0.0"
hex = "0.4.3"
indicatif = { version = "0.17.5", features = ["tokio"] }
libp2p = { version = "0.53", features = [] }
libp2p-identity = { version = "0.2.7", features = ["rand"] }
Expand All @@ -54,6 +55,7 @@ tracing = { version = "~0.1.26" }
prost = { version = "0.9" }
tonic = { version = "0.6.2" }
uuid = { version = "1.5.0", features = ["v4"] }
xor_name = "5.0.0"

[target.'cfg(any(target_os = "linux", target_os = "macos"))'.dependencies]
nix = { version = "0.27.1", features = ["fs", "user"] }
Expand Down
10 changes: 10 additions & 0 deletions sn_node_manager/src/bin/cli/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,14 @@ pub enum SubCmd {
/// The number of nodes to run.
#[clap(long, default_value_t = DEFAULT_NODE_COUNT)]
count: u16,
/// Set to have the node/s joining to act as sybil nodes eclipsing a specified CID/address.
///
/// A hex-encoded xorname shall be provided to have nodes to eclipse the content at such address
/// by dropping any provider record, as well as queries, targeting such address.
/// This can be used for testing sybil defense and detection using an address which belongs to
/// only test content so real users content is not affected.
#[clap(long, name = "CID's xorname")]
sybil: Option<String>,
/// Path to a faucet binary
///
/// The path and version arguments are mutually exclusive.
Expand Down Expand Up @@ -647,6 +655,7 @@ async fn main() -> Result<()> {
SubCmd::Join {
build,
count,
sybil,
faucet_path,
faucet_version,
interval,
Expand All @@ -658,6 +667,7 @@ async fn main() -> Result<()> {
cmd::local::join(
build,
count,
sybil,
faucet_path,
faucet_version,
interval,
Expand Down
20 changes: 17 additions & 3 deletions sn_node_manager/src/cmd/local.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@ use sn_service_management::{
control::ServiceController, get_local_node_registry_path, NodeRegistry,
};
use std::path::PathBuf;
use xor_name::XOR_NAME_LEN;

pub async fn join(
build: bool,
count: u16,
sybil: Option<String>,
faucet_path: Option<PathBuf>,
faucet_version: Option<String>,
interval: u64,
Expand All @@ -32,9 +34,19 @@ pub async fn join(
peers: PeersArgs,
skip_validation: bool,
) -> Result<(), Report> {
println!("=================================================");
println!(" Joining Local Network ");
println!("=================================================");
let sybil = sybil.map(|xorname_str| {
let bytes = hex::decode(xorname_str).unwrap();
let mut arr = [0u8; XOR_NAME_LEN];
arr.copy_from_slice(&bytes);
xor_name::XorName(arr)
});

println!("====================================================");
println!(" Joining Local Network ");
if let Some(xorname) = sybil {
println!("** WITH SYBIL NODE/s TO ECLIPSE XorName: {xorname} **");
}
println!("====================================================");

let local_node_reg_path = &get_local_node_registry_path()?;
let mut local_node_registry = NodeRegistry::load(local_node_reg_path)?;
Expand Down Expand Up @@ -71,6 +83,7 @@ pub async fn join(
interval,
join: true,
node_count: count,
sybil,
peers,
safenode_bin_path: node_path,
skip_validation,
Expand Down Expand Up @@ -159,6 +172,7 @@ pub async fn run(
join: false,
interval,
node_count: count,
sybil: None,
peers: None,
safenode_bin_path: node_path,
skip_validation,
Expand Down
16 changes: 14 additions & 2 deletions sn_node_manager/src/local.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ pub trait Launcher {
&self,
rpc_socket_addr: SocketAddr,
bootstrap_peers: Vec<Multiaddr>,
sybil: Option<xor_name::XorName>,
) -> Result<()>;
fn wait(&self, delay: u64);
}
Expand Down Expand Up @@ -68,6 +69,7 @@ impl Launcher for LocalSafeLauncher {
&self,
rpc_socket_addr: SocketAddr,
bootstrap_peers: Vec<Multiaddr>,
sybil: Option<xor_name::XorName>,
) -> Result<()> {
let mut args = Vec::new();
if bootstrap_peers.is_empty() {
Expand All @@ -81,6 +83,10 @@ impl Launcher for LocalSafeLauncher {
args.push("--local".to_string());
args.push("--rpc".to_string());
args.push(rpc_socket_addr.to_string());
if let Some(xorname) = sybil {
args.push("--sybil".to_string());
args.push(hex::encode(xorname));
}

Command::new(self.safenode_bin_path.clone())
.args(args)
Expand Down Expand Up @@ -165,6 +171,7 @@ pub struct LocalNetworkOptions {
pub join: bool,
pub interval: u64,
pub node_count: u16,
pub sybil: Option<xor_name::XorName>,
pub peers: Option<Vec<Multiaddr>>,
pub safenode_bin_path: PathBuf,
pub skip_validation: bool,
Expand Down Expand Up @@ -203,6 +210,7 @@ pub async fn run_network(
number,
genesis: true,
interval: options.interval,
sybil: None,
rpc_socket_addr,
bootstrap_peers: vec![],
},
Expand Down Expand Up @@ -230,6 +238,7 @@ pub async fn run_network(
number,
genesis: false,
interval: options.interval,
sybil: options.sybil,
rpc_socket_addr,
bootstrap_peers: bootstrap_peers.clone(),
},
Expand Down Expand Up @@ -277,6 +286,7 @@ pub struct RunNodeOptions {
pub number: u16,
pub genesis: bool,
pub interval: u64,
pub sybil: Option<xor_name::XorName>,
pub rpc_socket_addr: SocketAddr,
pub bootstrap_peers: Vec<Multiaddr>,
}
Expand All @@ -290,6 +300,7 @@ pub async fn run_node(
launcher.launch_node(
run_options.rpc_socket_addr,
run_options.bootstrap_peers.clone(),
run_options.sybil,
)?;
launcher.wait(run_options.interval);

Expand Down Expand Up @@ -417,9 +428,9 @@ mod tests {
let rpc_socket_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 13000);
mock_launcher
.expect_launch_node()
.with(eq(rpc_socket_addr), eq(vec![]))
.with(eq(rpc_socket_addr), eq(vec![]), eq(None))
.times(1)
.returning(|_, _| Ok(()));
.returning(|_, _, _| Ok(()));
mock_launcher
.expect_wait()
.with(eq(100))
Expand Down Expand Up @@ -459,6 +470,7 @@ mod tests {
number: 1,
genesis: true,
interval: 100,
sybil: None,
rpc_socket_addr,
bootstrap_peers: vec![],
},
Expand Down

0 comments on commit cdd9b5e

Please sign in to comment.