aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/error.rs4
-rw-r--r--src/main.rs64
2 files changed, 52 insertions, 16 deletions
diff --git a/src/error.rs b/src/error.rs
index e013a67..975e08d 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -4,6 +4,8 @@ use thiserror::Error;
#[derive(Debug, Error)]
pub enum Error {
+ #[error("no domain name servers")]
+ NoDns,
#[error("no ia_pd")]
NoIAPD,
#[error("no ia_pd status code")]
@@ -14,6 +16,8 @@ pub enum Error {
NoServerId,
#[error("incomplete transmission")]
PartialSend,
+ #[error("too few domain name servers (got {0}, need at least 2)")]
+ TooFewDns(usize),
#[error("parse address: {0}")]
AddrParse(#[from] net::AddrParseError),
diff --git a/src/main.rs b/src/main.rs
index fa37461..30edfe5 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,7 +1,7 @@
use std::ffi::CString;
use std::fs::File;
use std::mem::MaybeUninit;
-use std::net::{SocketAddr, SocketAddrV6};
+use std::net::{Ipv6Addr, SocketAddr, SocketAddrV6};
use std::os::fd::AsRawFd;
use std::str::FromStr;
use std::sync::{Arc, Mutex};
@@ -151,6 +151,18 @@ fn handle_response(
_ => unreachable!(),
};
+ let dnss = match opts
+ .get(OptionCode::DomainNameServers)
+ .ok_or(Error::NoDns)?
+ {
+ DhcpOption::DomainNameServers(dnss) => dnss,
+ _ => unreachable!(),
+ };
+
+ if dnss.len() < 2 {
+ return Err(Error::TooFewDns(dnss.len()));
+ }
+
match *state {
State::Solicit(ref client_id) => {
let mut request = Message::new_with_id(MessageType::Request, msg.xid());
@@ -160,7 +172,7 @@ fn handle_response(
opts.insert(DhcpOption::ServerId(server_id.clone()));
opts.insert(DhcpOption::IAPD(ia_pd.clone()));
opts.insert(DhcpOption::ORO(ORO {
- opts: vec![OptionCode::AftrName],
+ opts: vec![OptionCode::AftrName, OptionCode::DomainNameServers],
}));
let mut request_buf = Vec::new();
@@ -169,16 +181,18 @@ fn handle_response(
send_to_exact(sock, &request_buf, &remote.into())?;
println!(
- " <- [{}] advertise pd {}/{} valid {} pref {}, aftr {}",
+ " <- [{}] advertise pd {}/{} valid {} pref {}, dns1 {}, dns2 {}, aftr {}",
remote,
ia_prefix.prefix_ip,
ia_prefix.prefix_len,
ia_prefix.valid_lifetime,
ia_prefix.preferred_lifetime,
+ dnss[0],
+ dnss[1],
aftr.map(|v| v.to_utf8()).unwrap_or("unset".into())
);
println!(
- " -> [{}] request 0/{} pd {} aftr",
+ " -> [{}] request 0/{} pd {}, dns, aftr",
remote, MAX_ATTEMPTS, ia_pd.id
);
@@ -223,17 +237,31 @@ fn handle_response(
_ => unreachable!(),
};
+ let dnss = match opts
+ .get(OptionCode::DomainNameServers)
+ .ok_or(Error::NoDns)?
+ {
+ DhcpOption::DomainNameServers(dnss) => dnss,
+ _ => unreachable!(),
+ };
+
+ if dnss.len() < 2 {
+ return Err(Error::TooFewDns(dnss.len()));
+ }
+
match *state {
State::Request(ref client_id, ..) => {
let aftr = aftr.map(|v| v.to_utf8());
println!(
- " <- [{}] reply pd {}/{} valid {} pref {}, aftr {}",
+ " <- [{}] reply pd {}/{} valid {} pref {}, dns1 {}, dns2 {}, aftr {}",
remote,
ia_prefix.prefix_ip,
ia_prefix.prefix_len,
ia_prefix.valid_lifetime,
ia_prefix.preferred_lifetime,
+ dnss[0],
+ dnss[1],
aftr.clone().unwrap_or("unset".into())
);
*state = State::Active(
@@ -245,15 +273,17 @@ fn handle_response(
ia_pd.t1,
);
- update_pdconfig(ia_prefix, &aftr);
+ update_pdconfig(ia_prefix, dnss, &aftr);
}
State::Renew(ref client_id, ..) => {
let aftr = aftr.map(|v| v.to_utf8());
println!(
- " <- [{}] reply renew pd {}, aftr {}",
+ " <- [{}] reply renew pd {}, dns1 {}, dns2 {}, aftr {}",
remote,
ia_pd.id,
+ dnss[0],
+ dnss[1],
aftr.clone().unwrap_or("unset".into())
);
*state = State::Active(
@@ -302,7 +332,7 @@ fn tick(sock: &Socket, state: Arc<Mutex<State>>) -> Result<()> {
opts: Default::default(),
}));
opts.insert(DhcpOption::ORO(ORO {
- opts: vec![OptionCode::AftrName],
+ opts: vec![OptionCode::AftrName, OptionCode::DomainNameServers],
}));
let mut solicit_buf = Vec::new();
@@ -310,7 +340,7 @@ fn tick(sock: &Socket, state: Arc<Mutex<State>>) -> Result<()> {
send_to_exact(sock, &solicit_buf, &dst.into())?;
- println!(" -> [{}] solicit pd 1 aftr", dst);
+ println!(" -> [{}] solicit pd 1, dns, aftr", dst);
Ok(())
}
State::Request(ref client_id, ref server_id, xid, dst, ref ia_pd, n) => {
@@ -328,7 +358,7 @@ fn tick(sock: &Socket, state: Arc<Mutex<State>>) -> Result<()> {
opts.insert(DhcpOption::ServerId(server_id.clone()));
opts.insert(DhcpOption::IAPD(ia_pd.clone()));
opts.insert(DhcpOption::ORO(ORO {
- opts: vec![OptionCode::AftrName],
+ opts: vec![OptionCode::AftrName, OptionCode::DomainNameServers],
}));
let mut request_buf = Vec::new();
@@ -337,7 +367,7 @@ fn tick(sock: &Socket, state: Arc<Mutex<State>>) -> Result<()> {
send_to_exact(sock, &request_buf, &dst.into())?;
println!(
- " -> [{}] request {}/{} pd {} aftr",
+ " -> [{}] request {}/{} pd {}, dns, aftr",
dst, n, MAX_ATTEMPTS, ia_pd.id
);
@@ -374,7 +404,7 @@ fn tick(sock: &Socket, state: Arc<Mutex<State>>) -> Result<()> {
opts.insert(DhcpOption::ServerId(server_id.clone()));
opts.insert(DhcpOption::IAPD(ia_pd.clone()));
opts.insert(DhcpOption::ORO(ORO {
- opts: vec![OptionCode::AftrName],
+ opts: vec![OptionCode::AftrName, OptionCode::DomainNameServers],
}));
let mut renew_buf = Vec::new();
@@ -383,7 +413,7 @@ fn tick(sock: &Socket, state: Arc<Mutex<State>>) -> Result<()> {
send_to_exact(sock, &renew_buf, &dst.into())?;
println!(
- " -> [{}] renew {}/{} pd {} aftr",
+ " -> [{}] renew {}/{} pd {}, dns, aftr",
dst, n, MAX_ATTEMPTS, ia_pd.id
);
@@ -408,8 +438,8 @@ fn send_to_exact(sock: &Socket, buf: &[u8], dst: &SockAddr) -> Result<()> {
}
}
-fn update_pdconfig(ia_prefix: &IAPrefix, aftr: &Option<String>) {
- match write_pdconfig(ia_prefix, aftr) {
+fn update_pdconfig(ia_prefix: &IAPrefix, dnss: &[Ipv6Addr], aftr: &Option<String>) {
+ match write_pdconfig(ia_prefix, dnss, aftr) {
Ok(_) => println!("<-> write pd config to {}", rsdsl_pd_config::LOCATION),
Err(e) => println!(
"<-> can't write pd config to {}: {}",
@@ -419,12 +449,14 @@ fn update_pdconfig(ia_prefix: &IAPrefix, aftr: &Option<String>) {
}
}
-fn write_pdconfig(ia_prefix: &IAPrefix, aftr: &Option<String>) -> Result<()> {
+fn write_pdconfig(ia_prefix: &IAPrefix, dnss: &[Ipv6Addr], aftr: &Option<String>) -> Result<()> {
let pdconfig = PdConfig {
prefix: ia_prefix.prefix_ip,
len: ia_prefix.prefix_len,
validlft: ia_prefix.valid_lifetime,
preflft: ia_prefix.preferred_lifetime,
+ dns1: dnss[0], // Bounds checked by packet handler.
+ dns2: dnss[1], // Bounds checked by packet handler.
aftr: aftr.clone(),
};