This commit is contained in:
2024-09-27 11:04:51 +02:00
commit 5eede690ca
11 changed files with 806 additions and 0 deletions

View File

@@ -0,0 +1,14 @@
[package]
name = "pause-spammer"
version = "0.1.0"
edition.workspace = true
[dependencies]
clap = { version = "4.5.18", features = ["derive"] }
humantime = "2.1.0"
pnet = "0.35.0"
tracing = "0.1.40"
tracing-subscriber = "0.3.18"
[lints]
workspace = true

View File

@@ -0,0 +1,73 @@
//! Ethernet PAUSE frame spammer.
use clap::Parser;
use pnet::datalink;
use pnet::datalink::Channel::Ethernet;
use pnet::packet::Packet;
use pnet::packet::ethernet::MutableEthernetPacket;
use pnet::util::MacAddr;
/// Command line options
#[derive(Debug, Parser)]
pub struct Cli {
#[arg(long)]
interface_name: String,
#[arg(long, default_value = "100ms")]
interval: humantime::Duration,
#[arg(long, default_value_t = u16::MAX)]
pause_time: u16,
}
fn main() {
tracing_subscriber::fmt::init();
let Cli {
interface_name,
interval,
pause_time,
} = Cli::parse();
// Find the network interface with the provided name
let interfaces = datalink::interfaces();
let interface = interfaces.iter().find(|iface| iface.name == interface_name).unwrap_or_else(|| {
panic!(
"No interface with name {interface_name} found in interfaces: {}",
interfaces.iter().map(|iface| iface.name.clone()).collect::<Vec<_>>().join(", ")
)
});
tracing::info!("Interface: {interface}");
// Create a new channel, dealing with layer 2 packets
let (mut tx, _rx) = match datalink::channel(interface, Default::default()) {
Ok(Ethernet(tx, rx)) => (tx, rx),
Ok(_) => panic!("Unhandled channel type"),
Err(err) => panic!("An error occurred when creating the datalink channel: {err}"),
};
loop {
// Create a PAUSE frame
let mut buffer = [0u8; 60]; // Minimum Ethernet frame size
let mut ethernet_packet = MutableEthernetPacket::new(&mut buffer).unwrap();
// Set Ethernet header
ethernet_packet.set_destination(MacAddr::new(0x01, 0x80, 0xC2, 0x00, 0x00, 0x01));
ethernet_packet.set_source(interface.mac.unwrap());
ethernet_packet.set_ethertype(pnet::packet::ethernet::EtherType::new(0x8808));
// Set PAUSE frame payload
// Payload format: [Opcode (2 bytes), Pause time (2 bytes)]
let mut pause_frame = [0u8; 4];
const PAUSE_OPCODE: u16 = 0x0001;
pause_frame[0..2].copy_from_slice(&PAUSE_OPCODE.to_be_bytes());
pause_frame[2..4].copy_from_slice(&pause_time.to_be_bytes());
ethernet_packet.set_payload(&pause_frame);
tracing::info!("Sending PAUSE frame {ethernet_packet:?} with pause time {pause_time}");
tx.send_to(ethernet_packet.packet(), None);
std::thread::sleep(interval.into());
}
}