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;
|
||||
|
||||
|
||||
/// 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 {
|
||||
addr: [u8; 6],
|
||||
}
|
||||
|
||||
|
||||
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))
|
||||
.collect::<Result<Vec<u8>, _>>()
|
||||
.and_then(|parts| {
|
||||
.collect();
|
||||
match split {
|
||||
Ok(parts) => {
|
||||
let mut addr = [0u8; 6];
|
||||
if parts.len() == 6 {
|
||||
addr.copy_from_slice(&parts[..6]);
|
||||
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] {
|
||||
&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::net;
|
||||
use mac;
|
||||
|
||||
|
||||
/// Magic packet for a specific MAC address
|
||||
pub struct MagicPacket<'a> {
|
||||
mac: &'a mac::MacAddress,
|
||||
}
|
||||
|
||||
|
||||
impl<'a> MagicPacket<'a> {
|
||||
|
||||
/// Create a new magic packet the given MAC address
|
||||
pub fn new(mac: &'a mac::MacAddress) -> Self {
|
||||
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> {
|
||||
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> {
|
||||
let socket = net::UdpSocket::bind("0.0.0.0:0")?;
|
||||
socket.set_broadcast(true)?;
|
||||
|
|
15
src/main.rs
15
src/main.rs
|
@ -1,9 +1,22 @@
|
|||
use std::env;
|
||||
|
||||
mod mac;
|
||||
mod magic;
|
||||
|
||||
|
||||
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);
|
||||
println!("Sending magic packet to {}", mac);
|
||||
packet.send().unwrap();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue