From ae66c0e497b7790a9418c63918edbdbfaea55cc5 Mon Sep 17 00:00:00 2001 From: sakridge Date: Sun, 29 Mar 2020 14:44:25 -0700 Subject: [PATCH] Add repair message support to dos tool (#9090) --- Cargo.lock | 1 + core/src/serve_repair.rs | 2 +- dos/Cargo.toml | 1 + dos/src/main.rs | 192 ++++++++++++++++++++++++++++----------- 4 files changed, 141 insertions(+), 55 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c00221899..589ffe69f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4023,6 +4023,7 @@ dependencies = [ "solana-logger 1.2.0", "solana-net-utils 1.2.0", "solana-runtime 1.2.0", + "solana-sdk 1.2.0", ] [[package]] diff --git a/core/src/serve_repair.rs b/core/src/serve_repair.rs index bc887cf72..f4d56ebed 100644 --- a/core/src/serve_repair.rs +++ b/core/src/serve_repair.rs @@ -59,7 +59,7 @@ pub struct ServeRepairStats { /// Window protocol messages #[derive(Serialize, Deserialize, Debug)] -enum RepairProtocol { +pub enum RepairProtocol { WindowIndex(ContactInfo, u64, u64), HighestWindowIndex(ContactInfo, u64, u64), Orphan(ContactInfo, u64), diff --git a/dos/Cargo.toml b/dos/Cargo.toml index feda757c0..91f445d27 100644 --- a/dos/Cargo.toml +++ b/dos/Cargo.toml @@ -17,3 +17,4 @@ solana-core = { path = "../core", version = "1.2.0" } solana-logger = { path = "../logger", version = "1.2.0" } solana-net-utils = { path = "../net-utils", version = "1.2.0" } solana-runtime = { path = "../runtime", version = "1.2.0" } +solana-sdk = { path = "../sdk", version = "1.2.0" } diff --git a/dos/src/main.rs b/dos/src/main.rs index 84770150c..93c43e385 100644 --- a/dos/src/main.rs +++ b/dos/src/main.rs @@ -1,11 +1,95 @@ use clap::{value_t, value_t_or_exit, App, Arg}; use log::*; use rand::{thread_rng, Rng}; -use solana_core::gossip_service::discover_cluster; +use solana_core::contact_info::ContactInfo; +use solana_core::gossip_service::discover; +use solana_core::serve_repair::RepairProtocol; +use solana_sdk::pubkey::Pubkey; use std::net::{SocketAddr, UdpSocket}; use std::process::exit; use std::time::Instant; +fn run_dos( + nodes: &[ContactInfo], + iterations: usize, + entrypoint_addr: SocketAddr, + data_type: String, + data_size: usize, + mode: String, +) { + let mut target = None; + for node in nodes { + if node.gossip == entrypoint_addr { + target = match mode.as_str() { + "gossip" => Some(node.gossip), + "tvu" => Some(node.tvu), + "tvu_forwards" => Some(node.tvu_forwards), + "tpu" => Some(node.tpu), + "tpu_forwards" => Some(node.tpu_forwards), + "repair" => Some(node.repair), + "serve_repair" => Some(node.serve_repair), + &_ => panic!("Unknown mode"), + }; + break; + } + } + let target = target.expect("should have target"); + + info!("Targetting {}", target); + let socket = UdpSocket::bind("0.0.0.0:0").unwrap(); + + let mut data = Vec::new(); + + let source = thread_rng().gen_range(0, nodes.len()); + let mut contact = nodes[source].clone(); + contact.id = Pubkey::new_rand(); + match data_type.as_str() { + "repair_highest" => { + let slot = 100; + let req = RepairProtocol::WindowIndex(contact, slot, 0); + data = bincode::serialize(&req).unwrap(); + } + "repair_shred" => { + let slot = 100; + let req = RepairProtocol::HighestWindowIndex(contact, slot, 0); + data = bincode::serialize(&req).unwrap(); + } + "repair_orphan" => { + let slot = 100; + let req = RepairProtocol::Orphan(contact, slot); + data = bincode::serialize(&req).unwrap(); + } + "random" => { + data.resize(data_size, 0); + } + &_ => { + panic!("unknown data type"); + } + } + + let mut last_log = Instant::now(); + let mut count = 0; + let mut error_count = 0; + loop { + if data_type == "random" { + thread_rng().fill(&mut data[..]); + } + let res = socket.send_to(&data, target); + count += 1; + if res.is_err() { + error_count += 1; + } + if last_log.elapsed().as_secs() > 5 { + info!("count: {} errors: {}", count, error_count); + last_log = Instant::now(); + count = 0; + } + if iterations != 0 && count >= iterations { + break; + } + } +} + fn main() { solana_logger::setup(); let matches = App::new("crate") @@ -18,13 +102,6 @@ fn main() { .value_name("HOST:PORT") .help("Gossip entrypoint address. Usually :8001"), ) - .arg( - Arg::with_name("num_nodes") - .long("num_nodes") - .takes_value(true) - .value_name("NUM") - .help("Number of gossip nodes to look for."), - ) .arg( Arg::with_name("mode") .long("mode") @@ -44,10 +121,11 @@ fn main() { .help("Size of packet to dos with."), ) .arg( - Arg::with_name("random_data") - .long("random_data") - .takes_value(false) - .help("Use random data for each iteration."), + Arg::with_name("data_type") + .long("data_type") + .takes_value(true) + .value_name("DATA_TYPE") + .help("Type of data to send."), ) .get_matches(); @@ -58,58 +136,64 @@ fn main() { exit(1) }); } - let num_nodes = value_t!(matches, "num_nodes", usize).unwrap_or(1); let data_size = value_t!(matches, "data_size", usize).unwrap_or(128); - let random_data = matches.is_present("random_data"); let mode = value_t_or_exit!(matches, "mode", String); + let data_type = value_t_or_exit!(matches, "data_type", String); info!("Finding cluster entry: {:?}", entrypoint_addr); - let (nodes, _archivers) = discover_cluster(&entrypoint_addr, num_nodes).unwrap_or_else(|err| { - eprintln!("Failed to discover {} nodes: {:?}", num_nodes, err); + let (nodes, _archivers) = discover( + Some(&entrypoint_addr), + None, + Some(60), + None, + Some(&entrypoint_addr), + None, + ) + .unwrap_or_else(|err| { + eprintln!("Failed to discover {} node: {:?}", entrypoint_addr, err); exit(1); }); info!("done found {} nodes", nodes.len()); - let mut target = None; - for node in &nodes { - if node.gossip == entrypoint_addr { - target = match mode.as_str() { - "gossip" => Some(node.gossip), - "tvu" => Some(node.tvu), - "tvu_forwards" => Some(node.tvu_forwards), - "tpu" => Some(node.tpu), - "tpu_forwards" => Some(node.tpu_forwards), - "repair" => Some(node.repair), - "serve_repair" => Some(node.serve_repair), - &_ => panic!("Unknown mode"), - }; - break; - } - } - let target = target.expect("should have target"); + run_dos(&nodes, 0, entrypoint_addr, data_type, data_size, mode); +} - info!("Targetting {}", target); - let socket = UdpSocket::bind("0.0.0.0:0").unwrap(); - let mut data = vec![0u8; data_size]; - thread_rng().fill(&mut data[..]); - let mut last_log = Instant::now(); - let mut count = 0; - let mut error_count = 0; - loop { - if random_data { - thread_rng().fill(&mut data[..]); - } - let res = socket.send_to(&data, target); - count += 1; - if res.is_err() { - error_count += 1; - } - if last_log.elapsed().as_secs() > 5 { - info!("count: {} errors: {}", count, error_count); - last_log = Instant::now(); - count = 0; - } +#[cfg(test)] +pub mod test { + use super::*; + use solana_sdk::timing::timestamp; + + #[test] + fn test_dos() { + let nodes = [ContactInfo::new_localhost(&Pubkey::new_rand(), timestamp())]; + let entrypoint_addr = nodes[0].gossip.clone(); + run_dos( + &nodes, + 1, + entrypoint_addr, + "random".to_string(), + 10, + "tvu".to_string(), + ); + + run_dos( + &nodes, + 1, + entrypoint_addr, + "repair_highest".to_string(), + 10, + "repair".to_string(), + ); + + run_dos( + &nodes, + 1, + entrypoint_addr, + "repair_shred".to_string(), + 10, + "serve_repair".to_string(), + ); } }