Compare commits

...

3 Commits

Author SHA1 Message Date
1ea4715b59 Explain usage in README 2024-08-24 18:04:00 +02:00
daa9bb04af Add logging 2024-08-24 18:01:55 +02:00
d7c8e9cde5 Provide human readable error messages 2024-08-24 15:17:47 +02:00
4 changed files with 93 additions and 10 deletions

44
Cargo.lock generated
View File

@ -75,6 +75,12 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "anyhow"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
[[package]]
name = "async-trait"
version = "0.1.81"
@ -205,10 +211,13 @@ checksum = "a7993efb860416547839c115490d4951c6d0f8ec04a3594d9dd99d50ed7ec170"
name = "dhcpv6stateless"
version = "0.1.0"
dependencies = [
"anyhow",
"clap",
"dhcproto",
"env_logger",
"hex",
"ipnetwork",
"log",
"pnet",
"tokio",
]
@ -225,6 +234,29 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "env_filter"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab"
dependencies = [
"log",
"regex",
]
[[package]]
name = "env_logger"
version = "0.11.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d"
dependencies = [
"anstream",
"anstyle",
"env_filter",
"humantime",
"log",
]
[[package]]
name = "form_urlencoded"
version = "1.2.1"
@ -321,6 +353,12 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "humantime"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "idna"
version = "0.2.3"
@ -375,6 +413,12 @@ version = "0.2.158"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
[[package]]
name = "log"
version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]]
name = "matches"
version = "0.1.10"

View File

@ -4,9 +4,12 @@ version = "0.1.0"
edition = "2021"
[dependencies]
anyhow = "1.0.86"
clap = { version = "4.5.16", features = ["derive"] }
dhcproto = "0.12.0"
env_logger = "0.11.5"
hex = "0.4.3"
ipnetwork = "0.20.0"
log = "0.4.22"
pnet = "0.35.0"
tokio = { version = "1.39.3", features = ["macros", "net", "rt-multi-thread"] }

View File

@ -2,6 +2,18 @@
This -thing- is doing a DHCPv6 INFORMATION-REQUEST, waits for a response and displays it.
## Usage
Pass the interface name as the first parameter:
```
dhcpv6stateless wlp3s0
```
## Logging
Logging is handled by [Rust env_logger](https://docs.rs/env_logger/latest/env_logger/).
## References
- <https://datatracker.ietf.org/doc/html/rfc8415#section-6.1>

View File

@ -1,3 +1,7 @@
use anyhow::{
Context,
Result,
};
use clap::Parser;
use dhcproto::{
Decodable,
@ -13,6 +17,12 @@ use dhcproto::{
},
};
use ipnetwork;
use log::{
debug,
log_enabled,
info,
Level,
};
use pnet;
use std::net::SocketAddrV6;
use tokio::net::UdpSocket;
@ -30,14 +40,16 @@ struct Cli {
}
#[tokio::main]
async fn main() {
async fn main() -> Result<()>{
env_logger::init();
let cli = Cli::parse();
let all_interfaces = pnet::datalink::interfaces();
let selected_interface = all_interfaces
.iter()
.find(|i| i.name == cli.interface)
.expect(format!("No interface found with name: {}", cli.interface).as_str());
.with_context(|| format!("No interface found with name: {}", cli.interface))?;
let ipv6_addresses = selected_interface.ips
.iter()
@ -50,10 +62,14 @@ async fn main() {
// Just take the first address found on the interface
let selected_address = ipv6_link_local_addresses.next()
.expect("No IPv6 link local address assigned to this interface");
.context("No IPv6 link local address assigned to this interface")?;
let socket_addr = SocketAddrV6::new(selected_address.ip(), DHCP_CLIENT_PORT, 0, selected_interface.index.clone());
let sock = UdpSocket::bind(socket_addr).await.unwrap();
let sock = UdpSocket::bind(socket_addr).await
.context("Unable to bind UDP socket")?;
info!("Listening on {}", sock.local_addr()
.context("Failed to fetch address socket bound to")?);
let remote_addr = SocketAddrV6::new(ALL_DHCP_RELAY_AGENTS_AND_SERVERS.parse().unwrap(), DHCP_RELAY_AGENT_AND_SERVER_PORT, 0, selected_interface.index.clone());
@ -70,20 +86,28 @@ async fn main() {
let mut msg_buf = Vec::new();
let mut msg_encoder = Encoder::new(&mut msg_buf);
msg.encode(&mut msg_encoder).unwrap(); // Serializes msg to msg_buf
msg.encode(&mut msg_encoder)
.context("Unable to serialize DHCP options for message to send")?; // Serializes msg to msg_buf
sock.send_to(&msg_buf, remote_addr).await.unwrap();
sock.send_to(&msg_buf, remote_addr).await
.context("Failed to send DHCPv6 INFORMATION-REQUEST message")?;
loop {
let mut recv_buf = [0; 1024];
let (len, recv_addr) = sock.recv_from(&mut recv_buf).await.unwrap();
let recv_msg = Message::decode(&mut Decoder::new(&recv_buf)).unwrap();
let (len, recv_addr) = sock.recv_from(&mut recv_buf).await
.context("Failed to receive DHCPv6 response")?;
let recv_msg = Message::decode(&mut Decoder::new(&recv_buf))
.context("Unable to parse DHCPv6 response message")?;
if recv_msg.xid() == msg.xid() {
println!("{:?} bytes received from {:?}", len, recv_addr);
println!("{}", &recv_buf[..len].escape_ascii().to_string());
info!("{:?} bytes received from {:?}", len, recv_addr);
if log_enabled!(Level::Debug) {
debug!("Received packet: {}", hex::encode(&recv_buf[..len]));
}
println!("{}", &recv_msg);
break;
}
}
Ok(())
}