aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main.rs78
1 files changed, 74 insertions, 4 deletions
diff --git a/src/main.rs b/src/main.rs
index 777ae9e..9c68ec1 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,8 +1,10 @@
use rsdsl_dnsd::error::{Error, Result};
+use std::cell::RefCell;
use std::fs::{self, File};
use std::net::{IpAddr, SocketAddr, UdpSocket};
use std::path::Path;
+use std::str::FromStr;
use std::sync::{Arc, RwLock};
use std::thread;
use std::time::{Duration, SystemTime};
@@ -10,8 +12,9 @@ use std::time::{Duration, SystemTime};
use byteorder::{ByteOrder, NetworkEndian as NE};
use bytes::Bytes;
use dns_message_parser::question::{QType, Question};
-use dns_message_parser::rr::{A, RR};
+use dns_message_parser::rr::{Class, A, PTR, RR};
use dns_message_parser::{Dns, DomainName, Flags, Opcode, RCode};
+use ipnet::IpNet;
use notify::event::{AccessKind, AccessMode, CreateKind};
use notify::{Event, EventKind, RecursiveMode, Watcher};
use rsdsl_dhcp4d::lease::Lease;
@@ -139,10 +142,18 @@ fn handle_query(
let questions = msg.questions.clone();
+ let ptr_nx = RefCell::new(false);
+
let (lan, fwd): (_, Vec<Question>) =
msg.questions.into_iter().partition(|q| {
match is_dhcp_known(&usable_name(domain, &q.domain_name), leases.clone()) {
- Ok(known) => known,
+ Ok(known) => {
+ if q.q_type == QType::PTR && !known {
+ *ptr_nx.borrow_mut() = true;
+ }
+
+ known
+ }
Err(e) => {
println!("can't read dhcp config, ignoring {}: {}", q.domain_name, e);
false
@@ -153,6 +164,13 @@ fn handle_query(
msg.questions = fwd
.into_iter()
.filter(|q| q.domain_name.to_string().matches('.').count() >= 2)
+ .filter(|q| {
+ !IpNet::from_str("10.128.0.0/16").unwrap().contains(
+ &usable_name(domain, &q.domain_name)
+ .parse_arpa_name()
+ .expect("can't parse arpa name"),
+ )
+ })
.collect();
let lan_resp = lan.into_iter().filter_map(|q| {
@@ -177,12 +195,52 @@ fn handle_query(
println!("{} dhcp {}", raddr, answer);
Some(answer)
+ } else if q.q_type == QType::PTR {
+ let lease = dhcp_lease(&hostname, u8::MAX, leases.clone())
+ .unwrap()
+ .unwrap();
+
+ let name = match lease.hostname.map(|name| {
+ name + "."
+ + &domain
+ .as_ref()
+ .map(|domain| domain.to_utf8())
+ .unwrap_or(String::new())
+ }) {
+ Some(name) => name,
+ None => {
+ *ptr_nx.borrow_mut() = true;
+ return None;
+ }
+ };
+
+ let lease_ttl = match lease.expires.duration_since(SystemTime::now()) {
+ Ok(v) => v,
+ Err(_) => {
+ *ptr_nx.borrow_mut() = true;
+ return None;
+ }
+ };
+
+ let answer = RR::PTR(PTR {
+ domain_name: q.domain_name,
+ ttl: lease_ttl.as_secs() as u32,
+ class: Class::IN,
+ ptr_d_name: name.parse().expect("can't parse hostname"),
+ });
+
+ println!("{} dhcp {}", raddr, answer);
+ Some(answer)
} else {
None
}
});
- let mut rcode = RCode::NoError;
+ let mut rcode = if *ptr_nx.borrow() {
+ RCode::NXDomain
+ } else {
+ RCode::NoError
+ };
let mut resp_answers = Vec::new();
let mut resp_authorities = Vec::new();
@@ -251,7 +309,19 @@ fn handle_query(
}
fn find_lease(hostname: &Name, mut leases: impl Iterator<Item = Lease>) -> Option<Lease> {
- leases.find(|lease| lease.hostname.clone().map(|name| name + ".") == Some(hostname.to_utf8()))
+ leases.find(|lease| {
+ if Name::from_str("in-addr.arpa.")
+ .unwrap()
+ .zone_of(&hostname.base_name())
+ {
+ IpNet::new(lease.address.into(), 32).unwrap()
+ == hostname
+ .parse_arpa_name()
+ .expect("can't parse arpa hostname")
+ } else {
+ lease.hostname.clone().map(|name| name + ".") == Some(hostname.to_utf8())
+ }
+ })
}
fn dhcp_lease(