Compare commits
7 Commits
c0b462d8ac
...
22c5fd4832
Author | SHA1 | Date |
---|---|---|
|
22c5fd4832 | |
|
60dd1f72dc | |
|
823cfc2593 | |
|
989a6eb0e6 | |
|
ff8316895a | |
|
cc9f630dbc | |
|
e3e4c39f21 |
|
@ -0,0 +1,19 @@
|
||||||
|
//! Send Wake-on-LAN magic packets to wake sleeping machines
|
||||||
|
//!
|
||||||
|
//! This create provides a library and command-line interface for building
|
||||||
|
//! wake-on-LAN magic packets and sending them to network destinations.
|
||||||
|
//!
|
||||||
|
//! # Examples
|
||||||
|
//!
|
||||||
|
//! Basic usage:
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! use wakeonlan::{mac, magic};
|
||||||
|
//!
|
||||||
|
//! let mac = mac::MacAddress::from_string("aa:bb:cc:dd:ee:ff").unwrap();
|
||||||
|
//! let packet = magic::MagicPacket::new(&mac);
|
||||||
|
//! packet.send().unwrap();
|
||||||
|
//! ```
|
||||||
|
|
||||||
|
pub mod mac;
|
||||||
|
pub mod magic;
|
94
src/mac.rs
94
src/mac.rs
|
@ -1,24 +1,108 @@
|
||||||
|
//! MAC address parsing
|
||||||
|
//!
|
||||||
|
//! This module provides tools for parsing and using MAC addresses. MAC
|
||||||
|
//! addresses are used as physical device addresses in Ethernet and other
|
||||||
|
//! layer-2 networking protocols.
|
||||||
|
|
||||||
|
use std::error;
|
||||||
|
use std::fmt;
|
||||||
use std::num;
|
use std::num;
|
||||||
|
|
||||||
|
|
||||||
|
/// Error returned when attempting to parse a MAC address
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ParseError {
|
||||||
|
/// The input contained an invalid numeric value
|
||||||
|
Value(num::ParseIntError),
|
||||||
|
|
||||||
|
/// The input was not correctly formatted
|
||||||
|
Format,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl From<num::ParseIntError> for ParseError {
|
||||||
|
fn from(e: num::ParseIntError) -> Self {
|
||||||
|
ParseError::Value(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl fmt::Display for ParseError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match *self {
|
||||||
|
ParseError::Value(ref e) => e.fmt(f),
|
||||||
|
ParseError::Format => write!(f, "Invalid MAC address format"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl error::Error for ParseError {
|
||||||
|
fn cause(&self) -> Option<&error::Error> {
|
||||||
|
match *self {
|
||||||
|
ParseError::Value(ref e) => Some(e),
|
||||||
|
ParseError::Format => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// MAC address
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct MacAddress {
|
pub struct MacAddress {
|
||||||
addr: [u8; 6],
|
addr: [u8; 6],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl MacAddress {
|
impl MacAddress {
|
||||||
pub fn from_string(s: &str) -> Result<Self, num::ParseIntError> {
|
|
||||||
s.split(":")
|
/// Parse a MAC address from a string
|
||||||
|
///
|
||||||
|
/// This method parses a 48-bit MAC address from a standard string of
|
||||||
|
/// six hexadecimal octets separated by colons or hyphens.
|
||||||
|
pub fn from_string(s: &str) -> Result<Self, ParseError> {
|
||||||
|
let split: Result<Vec<_>, _> = s.split(|c| c == ':' || c == '-')
|
||||||
.map(|b| u8::from_str_radix(b, 16))
|
.map(|b| u8::from_str_radix(b, 16))
|
||||||
.collect::<Result<Vec<u8>, _>>()
|
.collect();
|
||||||
.and_then(|parts| {
|
match split {
|
||||||
|
Ok(parts) => {
|
||||||
let mut addr = [0u8; 6];
|
let mut addr = [0u8; 6];
|
||||||
|
if parts.len() == 6 {
|
||||||
addr.copy_from_slice(&parts[..6]);
|
addr.copy_from_slice(&parts[..6]);
|
||||||
Ok(MacAddress { addr })
|
Ok(MacAddress { addr })
|
||||||
})
|
} else {
|
||||||
|
Err(ParseError::Format)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(e) => Err(ParseError::from(e)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the MAC address as an array of bytes
|
||||||
pub fn as_bytes(&self) -> &[u8; 6] {
|
pub fn as_bytes(&self) -> &[u8; 6] {
|
||||||
&self.addr
|
&self.addr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl fmt::Display for MacAddress {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
let s = self.addr.iter()
|
||||||
|
.map(|b| format!("{:x}", b))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(":");
|
||||||
|
write!(f, "{}", s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_mac_from_string() {
|
||||||
|
let mac = MacAddress::from_string("a:bb:cc:dd:ee:ff").unwrap();
|
||||||
|
assert_eq!(&[0xa, 0xbb, 0xcc, 0xdd, 0xee, 0xff], mac.as_bytes());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
15
src/magic.rs
15
src/magic.rs
|
@ -1,22 +1,37 @@
|
||||||
|
//! Wake-On-LAN Magic Packets
|
||||||
|
//!
|
||||||
|
//! This module contains tools for creating and sending WOL magic packets.
|
||||||
|
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::net;
|
use std::net;
|
||||||
use mac;
|
use mac;
|
||||||
|
|
||||||
|
|
||||||
|
/// Magic packet for a specific MAC address
|
||||||
pub struct MagicPacket<'a> {
|
pub struct MagicPacket<'a> {
|
||||||
mac: &'a mac::MacAddress,
|
mac: &'a mac::MacAddress,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl<'a> MagicPacket<'a> {
|
impl<'a> MagicPacket<'a> {
|
||||||
|
|
||||||
|
/// Create a new magic packet the given MAC address
|
||||||
pub fn new(mac: &'a mac::MacAddress) -> Self {
|
pub fn new(mac: &'a mac::MacAddress) -> Self {
|
||||||
MagicPacket { mac }
|
MagicPacket { mac }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Send the magic packet
|
||||||
|
///
|
||||||
|
/// This method sends the magic packet to the default destination: the
|
||||||
|
/// subnet-directed broadcast on UDP port 9.
|
||||||
pub fn send(&self) -> io::Result<usize> {
|
pub fn send(&self) -> io::Result<usize> {
|
||||||
self.send_to("255.255.255.255:9")
|
self.send_to("255.255.255.255:9")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Send the magic packet to a specific destination
|
||||||
|
///
|
||||||
|
/// This method sends the magic packet to the given destination address
|
||||||
|
/// and UDP port.
|
||||||
pub fn send_to<A: net::ToSocketAddrs>(&self, addr: A) -> io::Result<usize> {
|
pub fn send_to<A: net::ToSocketAddrs>(&self, addr: A) -> io::Result<usize> {
|
||||||
let socket = net::UdpSocket::bind("0.0.0.0:0")?;
|
let socket = net::UdpSocket::bind("0.0.0.0:0")?;
|
||||||
socket.set_broadcast(true)?;
|
socket.set_broadcast(true)?;
|
||||||
|
|
15
src/main.rs
15
src/main.rs
|
@ -1,9 +1,22 @@
|
||||||
|
use std::env;
|
||||||
|
|
||||||
mod mac;
|
mod mac;
|
||||||
mod magic;
|
mod magic;
|
||||||
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mac = mac::MacAddress::from_string("0c:9d:92:0e:3a:41").unwrap();
|
let mut args = env::args();
|
||||||
|
args.next();
|
||||||
|
for arg in args {
|
||||||
|
let mac = match mac::MacAddress::from_string(&arg) {
|
||||||
|
Ok(m) => m,
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("Invalid address: {} ({})", &arg, e);
|
||||||
|
continue;
|
||||||
|
},
|
||||||
|
};
|
||||||
let packet = magic::MagicPacket::new(&mac);
|
let packet = magic::MagicPacket::new(&mac);
|
||||||
|
println!("Sending magic packet to {}", mac);
|
||||||
packet.send().unwrap();
|
packet.send().unwrap();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue