wip
This commit is contained in:
+4
-2
@@ -12,8 +12,9 @@ pub enum WError {
|
|||||||
InvalidConfigDir(String),
|
InvalidConfigDir(String),
|
||||||
ConfigDirInitError(String),
|
ConfigDirInitError(String),
|
||||||
ConfigFileFormatError(String),
|
ConfigFileFormatError(String),
|
||||||
UdpSocketBindError(String),
|
UdpSocketBindError(std::io::Error),
|
||||||
InvalidCommandString(String),
|
InvalidCommandString(String),
|
||||||
|
FfiFailed(String),
|
||||||
|
|
||||||
DaemonSocketBindError(std::io::Error),
|
DaemonSocketBindError(std::io::Error),
|
||||||
DaemonConnectionReadError(std::io::Error),
|
DaemonConnectionReadError(std::io::Error),
|
||||||
@@ -32,8 +33,9 @@ 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::UdpSocketBindError(s) => format!("{}", s),
|
WError::UdpSocketBindError(e) => format!("Couldn't bind and send udp packet because {}", e),
|
||||||
WError::InvalidCommandString(s) => format!("Command string '{}' is unknown", s),
|
WError::InvalidCommandString(s) => format!("Command string '{}' is unknown", s),
|
||||||
|
WError::FfiFailed(s) => format!("FFI invocation failed {}", s),
|
||||||
|
|
||||||
WError::DaemonCommandError(s) => format!("Failed to execute command {}", s),
|
WError::DaemonCommandError(s) => format!("Failed to execute command {}", s),
|
||||||
WError::DaemonCommandExecutionError(output) => format!(
|
WError::DaemonCommandExecutionError(output) => format!(
|
||||||
|
|||||||
+2
-1
@@ -1,7 +1,8 @@
|
|||||||
|
mod arp;
|
||||||
mod config;
|
mod config;
|
||||||
mod daemon;
|
mod daemon;
|
||||||
mod error;
|
mod error;
|
||||||
mod ifaddrs;
|
mod netif;
|
||||||
mod mac;
|
mod mac;
|
||||||
mod wolz;
|
mod wolz;
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,9 @@ use std::ffi::{CStr, c_uchar};
|
|||||||
use std::net::Ipv4Addr;
|
use std::net::Ipv4Addr;
|
||||||
use std::os::raw::{c_char, c_int, c_uint, c_ushort, c_void};
|
use std::os::raw::{c_char, c_int, c_uint, c_ushort, c_void};
|
||||||
|
|
||||||
|
use crate::error::{WError, WResult};
|
||||||
|
use crate::mac::Mac;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
struct IfAddrs {
|
struct IfAddrs {
|
||||||
ifa_next: *mut IfAddrs,
|
ifa_next: *mut IfAddrs,
|
||||||
@@ -57,12 +60,12 @@ struct LinkAddress {
|
|||||||
mac: [u8; 6],
|
mac: [u8; 6],
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct NetworkInterface {
|
struct NetworkInterface {
|
||||||
pub name: String,
|
name: String,
|
||||||
pub ip: Ipv4Addr,
|
ip: Ipv4Addr,
|
||||||
pub _netmask: Ipv4Addr,
|
_netmask: Ipv4Addr,
|
||||||
pub broadcast: Ipv4Addr,
|
broadcast: Ipv4Addr,
|
||||||
pub _mac: [u8; 6],
|
_mac: [u8; 6],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NetworkInterface {
|
impl NetworkInterface {
|
||||||
@@ -77,15 +80,52 @@ impl NetworkInterface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_network_interfaces() -> Vec<NetworkInterface> {
|
pub struct LocalNetwork {
|
||||||
|
pub source_ip_hint: Ipv4Addr,
|
||||||
|
pub subnet_broadcast: Ipv4Addr,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_local_networks() -> WResult<Vec<LocalNetwork>> {
|
||||||
|
let mut networks = Vec::new();
|
||||||
|
let interfaces = get_network_interfaces()?;
|
||||||
|
let mut unique_broadcast_addresses = Vec::new();
|
||||||
|
for i in &interfaces {
|
||||||
|
if unique_broadcast_addresses.contains(&i.broadcast) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// man systemd.net-naming-scheme
|
||||||
|
// Only broadcast to local network
|
||||||
|
let iname = &i.name;
|
||||||
|
if iname.starts_with("en") || iname.starts_with("wl") || iname.starts_with("eth") {
|
||||||
|
unique_broadcast_addresses.push(i.broadcast);
|
||||||
|
let local_network = LocalNetwork {
|
||||||
|
source_ip_hint: i.ip,
|
||||||
|
subnet_broadcast: i.broadcast,
|
||||||
|
};
|
||||||
|
networks.push(local_network);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(networks)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn find_local_networks_with_mac(mac: Mac) -> WResult<Vec<LocalNetwork>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_network_interfaces() -> WResult<Vec<NetworkInterface>> {
|
||||||
let mut network_addresses = HashMap::new();
|
let mut network_addresses = HashMap::new();
|
||||||
let mut link_addresses = HashMap::new();
|
let mut link_addresses = HashMap::new();
|
||||||
let mut addrs: *mut IfAddrs = std::ptr::null_mut();
|
let mut addrs: *mut IfAddrs = std::ptr::null_mut();
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
if getifaddrs(&mut addrs) != 0 {
|
let stat = getifaddrs(&mut addrs);
|
||||||
eprintln!("getifaddrs failed");
|
if stat != 0 {
|
||||||
return Vec::new();
|
return Err(WError::FfiFailed(format!(
|
||||||
|
"Failed to call libc:getifaddrs, returned {}",
|
||||||
|
stat
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut cur = addrs;
|
let mut cur = addrs;
|
||||||
@@ -133,7 +173,7 @@ pub fn get_network_interfaces() -> Vec<NetworkInterface> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
network_interfaces
|
Ok(network_interfaces)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculate_broadcast_address(ip: Ipv4Addr, netmask: Ipv4Addr) -> Ipv4Addr {
|
fn calculate_broadcast_address(ip: Ipv4Addr, netmask: Ipv4Addr) -> Ipv4Addr {
|
||||||
+31
-37
@@ -1,7 +1,11 @@
|
|||||||
use std::net::UdpSocket;
|
use std::net::UdpSocket;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::Config, daemon, error::{WError, WResult}, ifaddrs::{self},
|
arp,
|
||||||
|
config::Config,
|
||||||
|
error::{WError, WResult},
|
||||||
|
mac::Mac,
|
||||||
|
netif::{self, LocalNetwork},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct Wolz {
|
pub struct Wolz {
|
||||||
@@ -38,55 +42,45 @@ impl Wolz {
|
|||||||
let mut magic_bytes = [0u8; 102];
|
let mut magic_bytes = [0u8; 102];
|
||||||
mac.copy_magic_bytes(&mut magic_bytes);
|
mac.copy_magic_bytes(&mut magic_bytes);
|
||||||
|
|
||||||
let interfaces = ifaddrs::get_network_interfaces();
|
let networks = netif::get_local_networks()?;
|
||||||
let mut sent_addresses = Vec::new();
|
if networks.len() == 0 {
|
||||||
for i in &interfaces {
|
println!("Refusing to send WoL packets. Are you connected to any network?");
|
||||||
if sent_addresses.contains(&i.broadcast) {
|
return Ok(());
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// man systemd.net-naming-scheme
|
for n in &networks {
|
||||||
// Only broadcast to local network
|
try_send_magic_bytes(&magic_bytes, &mac, n);
|
||||||
let iname = &i.name;
|
|
||||||
if iname.starts_with("en") || iname.starts_with("wl") || iname.starts_with("eth") {
|
|
||||||
let send_addr = format!("{}:0", i.ip);
|
|
||||||
let broadcast_addr = format!("{}:9", i.broadcast);
|
|
||||||
match try_send_magic_bytes(&magic_bytes, &send_addr, &broadcast_addr) {
|
|
||||||
Ok(()) => {
|
|
||||||
println!("Sent magic pkt {} -> {} for Mac {}", send_addr, broadcast_addr, mac);
|
|
||||||
sent_addresses.push(i.broadcast);
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
println!(
|
|
||||||
"Unable to send magic pkt {} -> {} for Mac {}, because {}",
|
|
||||||
send_addr, broadcast_addr, mac, e
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if sent_addresses.len() == 0 {
|
|
||||||
println!("Did not send to any address, are you connected to local network?");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn shut_down(&self, mac_or_nick: &str) -> WResult<()> {
|
pub fn shut_down(&self, mac_or_nick: &str) -> WResult<()> {
|
||||||
|
let mac = self.config.get_mac(mac_or_nick)?;
|
||||||
|
let ip_from_arp = netif::find_local_networks_with_mac(mac)?;
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_send_magic_bytes(magic_bytes: &[u8; 102], send_addr: &str, broadcast_addr: &str) -> WResult<()> {
|
fn try_send_magic_bytes(magic_bytes: &[u8; 102], mac: &Mac, local_network: &LocalNetwork) {
|
||||||
let socket = UdpSocket::bind(&send_addr)
|
let send_addr = format!("{}:0", local_network.source_ip_hint);
|
||||||
.map_err(|e| WError::UdpSocketBindError(format!("couldn't bind to socket because {}", e)))?;
|
let broadcast_addr = format!("{}:9", local_network.subnet_broadcast);
|
||||||
socket
|
match send_magic_bytes(&magic_bytes, &send_addr, &broadcast_addr) {
|
||||||
.set_broadcast(true)
|
Ok(()) => {
|
||||||
.map_err(|e| WError::UdpSocketBindError(format!("couldn't set broadcast because {}", e)))?;
|
println!("Sent magic pkt {} -> {} for Mac {}", send_addr, broadcast_addr, mac);
|
||||||
|
}
|
||||||
|
Err(e) => println!(
|
||||||
|
"Unable to send magic pkt {} -> {} for Mac {}, because {}",
|
||||||
|
send_addr, broadcast_addr, mac, e
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_magic_bytes(magic_bytes: &[u8; 102], send_addr: &str, broadcast_addr: &str) -> WResult<()> {
|
||||||
|
let socket = UdpSocket::bind(&send_addr).map_err(WError::UdpSocketBindError)?;
|
||||||
|
socket.set_broadcast(true).map_err(WError::UdpSocketBindError)?;
|
||||||
socket
|
socket
|
||||||
.send_to(magic_bytes, &broadcast_addr)
|
.send_to(magic_bytes, &broadcast_addr)
|
||||||
.map_err(|e| WError::UdpSocketBindError(format!("couldn't send data because {}", e)))?;
|
.map_err(WError::UdpSocketBindError)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user