shutdown WIP
This commit is contained in:
Generated
+4
@@ -12,3 +12,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "wolz-lib"
|
name = "wolz-lib"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wolzd"
|
||||||
|
version = "0.0.1"
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
[package]
|
||||||
|
name = "wolzd"
|
||||||
|
version = "0.0.1"
|
||||||
|
edition = "2024"
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
use std::{fmt::Display, process::Output};
|
||||||
|
|
||||||
|
pub type DResult<T> = Result<T, DError>;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) enum DError {
|
||||||
|
InvalidRequest(String),
|
||||||
|
TcpBindError(std::io::Error),
|
||||||
|
ConnectionReadError(std::io::Error),
|
||||||
|
CommandError(String),
|
||||||
|
CommandExecutionError(Output),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for DError {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
DError::CommandError(s) => write!(f, "Failed to execute command {}", s),
|
||||||
|
DError::CommandExecutionError(output) => {
|
||||||
|
writeln!(f, "Exit Code : {}", output.status.code().unwrap())?;
|
||||||
|
writeln!(f, "Stdout : {}", String::from_utf8_lossy(&output.stdout))?;
|
||||||
|
writeln!(f, "Stderr : {}", String::from_utf8_lossy(&output.stderr))
|
||||||
|
},
|
||||||
|
DError::TcpBindError(e) => write!(f, "Failed to create tcp listener {}", e),
|
||||||
|
DError::ConnectionReadError(e) => write!(f, "Error while reading from the socket {}", e),
|
||||||
|
DError::InvalidRequest(s) => write!(f, "Command '{}' in request is invalid, dropping it", s),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
mod error;
|
||||||
|
|
||||||
|
use crate::error::{DError, DResult};
|
||||||
|
use std::{
|
||||||
|
io::Read,
|
||||||
|
net::{TcpListener, TcpStream},
|
||||||
|
process::{Command, Stdio},
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn main() -> DResult<()> {
|
||||||
|
let address = "0.0.0.0:21367";
|
||||||
|
let listener = TcpListener::bind(address).map_err(DError::TcpBindError)?;
|
||||||
|
println!("Listening on {}", address);
|
||||||
|
for mut stream in listener.incoming() {
|
||||||
|
match &mut stream {
|
||||||
|
Ok(stream) => {
|
||||||
|
if let Err(e) = handle_connection(stream) {
|
||||||
|
eprintln!("Failed to handle request {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => eprintln!("{}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_connection(stream: &mut TcpStream) -> DResult<()> {
|
||||||
|
// TODO: Slowloris
|
||||||
|
stream
|
||||||
|
.set_read_timeout(Some(Duration::from_secs(5)))
|
||||||
|
.map_err(DError::ConnectionReadError)?;
|
||||||
|
let command = read_command(stream)?;
|
||||||
|
match command.as_str() {
|
||||||
|
"shutdown" => execute_shutdown_command(),
|
||||||
|
_ => Err(DError::InvalidRequest(command)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn execute_shutdown_command() -> DResult<()> {
|
||||||
|
let mut shutdown_cmd = build_shutdown_cmd();
|
||||||
|
shutdown_cmd.stdout(Stdio::piped());
|
||||||
|
shutdown_cmd.stderr(Stdio::piped());
|
||||||
|
|
||||||
|
let output = shutdown_cmd.output().map_err(|e| DError::CommandError(e.to_string()))?;
|
||||||
|
let status_code = output
|
||||||
|
.status
|
||||||
|
.code()
|
||||||
|
.ok_or(DError::CommandError("No exit code returned!".to_string()))?;
|
||||||
|
|
||||||
|
if status_code != 0 {
|
||||||
|
return Err(DError::CommandExecutionError(output));
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_command(stream: &mut TcpStream) -> DResult<String> {
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
let read = stream.read_to_end(&mut buf).map_err(DError::ConnectionReadError)?;
|
||||||
|
let command = String::from_utf8_lossy(&buf[..read]).to_string();
|
||||||
|
Ok(command)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_shutdown_cmd() -> Command {
|
||||||
|
let mut cmd = Command::new("systemctl");
|
||||||
|
cmd.arg("-k");
|
||||||
|
cmd.arg("poweroff");
|
||||||
|
|
||||||
|
cmd
|
||||||
|
}
|
||||||
@@ -11,7 +11,7 @@ pub enum WError {
|
|||||||
InvalidConfigDir(String),
|
InvalidConfigDir(String),
|
||||||
ConfigDirInitError(String),
|
ConfigDirInitError(String),
|
||||||
ConfigFileFormatError(String),
|
ConfigFileFormatError(String),
|
||||||
UdpSocketError(String),
|
UdpSocketBindError(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for WError {
|
impl Display for WError {
|
||||||
@@ -24,7 +24,7 @@ impl Display for WError {
|
|||||||
WError::InvalidConfigDir(s) => format!("{}", s),
|
WError::InvalidConfigDir(s) => format!("{}", s),
|
||||||
WError::ConfigDirInitError(s) => format!("{}", s),
|
WError::ConfigDirInitError(s) => format!("{}", s),
|
||||||
WError::ConfigFileFormatError(s) => format!("{}", s),
|
WError::ConfigFileFormatError(s) => format!("{}", s),
|
||||||
WError::UdpSocketError(s) => format!("{}", s),
|
WError::UdpSocketBindError(s) => format!("{}", s),
|
||||||
};
|
};
|
||||||
|
|
||||||
write!(f, "{}", to_write)
|
write!(f, "{}", to_write)
|
||||||
|
|||||||
@@ -68,9 +68,16 @@ impl Nick {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) struct IpV4 {
|
||||||
|
original_string: String,
|
||||||
|
ip: [u8; 4],
|
||||||
|
port: u32,
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) enum Device {
|
pub(crate) enum Device {
|
||||||
Mac(Mac),
|
Mac(Mac),
|
||||||
Nick(Nick),
|
Nick(Nick),
|
||||||
|
IpV4(IpV4),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Device {
|
impl Device {
|
||||||
|
|||||||
@@ -21,13 +21,16 @@ impl Wolz {
|
|||||||
mac.copy_magic_bytes(&mut magic_bytes);
|
mac.copy_magic_bytes(&mut magic_bytes);
|
||||||
|
|
||||||
let socket = UdpSocket::bind("0.0.0.0:0")
|
let socket = UdpSocket::bind("0.0.0.0:0")
|
||||||
.map_err(|e| WError::UdpSocketError(format!("couldn't bind to socket because {}", e)))?;
|
.map_err(|e| WError::UdpSocketBindError(format!("couldn't bind to socket because {}", e)))?;
|
||||||
socket.set_broadcast(true)
|
socket.set_broadcast(true)
|
||||||
.map_err(|e| WError::UdpSocketError(format!("couldn't set broadcast because {}", e)))?;
|
.map_err(|e| WError::UdpSocketBindError(format!("couldn't set broadcast because {}", e)))?;
|
||||||
socket
|
socket
|
||||||
.send_to(&magic_bytes, "255.255.255.255:9")
|
.send_to(&magic_bytes, "255.255.255.255:9")
|
||||||
.map_err(|e| WError::UdpSocketError(format!("couldn't send data because {}", e)))?;
|
.map_err(|e| WError::UdpSocketBindError(format!("couldn't send data because {}", e)))?;
|
||||||
println!("Magic packet sent to 255.255.255.255:9 for Mac {:}", mac);
|
println!("Magic packet sent to 255.255.255.255:9 for Mac {:}", mac);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn shutdown(&self, ip_or_nick: &str) -> WResult<()> {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user