Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(networking): adding API to perform sybil attack check #1573

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
Draft
3 changes: 3 additions & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions sn_networking/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ libp2p = { version = "0.53", features = [
"yamux",
"websocket",
] }
num = "0.4.1"
prometheus-client = { version = "0.22", optional = true }
rand = { version = "~0.8.5", features = ["small_rng"] }
rayon = "1.8.0"
Expand Down
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 @@
.payment_received();
}
SwarmCmd::GetLocalRecord { key, sender } => {
// TODO: eclipse content if sybil was set, if sybil xorname set is close to the key ....?

Check notice

Code scanning / devskim

A "TODO" or similar was left in source code, possibly indicating incomplete functionality Note

Suspicious comment

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

Check notice

Code scanning / devskim

A "TODO" or similar was left in source code, possibly indicating incomplete functionality Note

Suspicious comment

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

Check notice

Code scanning / devskim

A "TODO" or similar was left in source code, possibly indicating incomplete functionality Note

Suspicious comment

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 @@ -64,6 +64,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 @@ -184,6 +185,7 @@ pub struct NetworkBuilder {
metrics_registry: Option<Registry>,
#[cfg(feature = "open-metrics")]
metrics_server_port: u16,
sybil: Option<XorName>,
}

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

Expand All @@ -224,6 +227,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 @@ -487,6 +494,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 @@ -535,6 +543,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
37 changes: 30 additions & 7 deletions sn_networking/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ mod record_store;
mod record_store_api;
mod replication_fetcher;
mod spends;
mod sybil;
pub mod target_arch;
mod transfers;
mod transport;
Expand All @@ -42,7 +43,7 @@ pub use self::{
transfers::{get_raw_signed_spends_from_record, get_signed_spend_from_record},
};

use self::{cmd::SwarmCmd, error::Result};
use self::{cmd::SwarmCmd, error::Result, sybil::check_for_sybil_attack};
use backoff::{Error as BackoffError, ExponentialBackoff};
use futures::future::select_all;
use libp2p::{
Expand All @@ -55,7 +56,7 @@ use rand::Rng;
use sn_protocol::{
error::Error as ProtocolError,
messages::{ChunkProof, Cmd, Nonce, Query, QueryResponse, Request, Response},
storage::{RecordType, RetryStrategy},
storage::{ChunkAddress, RecordType, RetryStrategy},
NetworkAddress, PrettyPrintKBucketKey, PrettyPrintRecordKey,
};
use sn_transfers::{MainPubkey, NanoTokens, PaymentQuote, QuotingMetrics};
Expand All @@ -64,13 +65,15 @@ use std::{
path::PathBuf,
sync::Arc,
};
use tokio::sync::{
mpsc::{self, Sender},
oneshot,
use tokio::{
sync::{
mpsc::{self, Sender},
oneshot,
},
time::Duration,
};

use tokio::time::Duration;
use tracing::trace;
use xor_name::XorName;

/// The type of quote for a selected payee.
pub type PayeeQuote = (PeerId, MainPubkey, PaymentQuote);
Expand Down Expand Up @@ -812,6 +815,26 @@ impl Network {
Ok(closest_peers.into_iter().cloned().collect())
}

/// Using a random address, check if there is a sybil attack around it
pub async fn perform_sybil_attack_check(&self) {
let random_addr = {
let mut rng = rand::thread_rng();
let cid = XorName::random(&mut rng);
NetworkAddress::from_chunk_address(ChunkAddress::new(cid))
};

match self.get_closest_peers(&random_addr, true).await {
Ok(closest_peers) => {
if check_for_sybil_attack(&closest_peers, random_addr.as_kbucket_key(), &vec![])
.await
{
info!(">>> Sybil attack detected around addr: {random_addr}");
}
}
Err(err) => error!(">>> Failed to get closes peer to check for sybil attack: {err:?}"),
}
}

/// Send a `Request` to the provided set of peers and wait for their responses concurrently.
/// If `get_all_responses` is true, we wait for the responses from all the peers.
/// NB TODO: Will return an error if the request timeouts.
Expand Down