aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHimbeerserverDE <himbeerserverde@gmail.com>2023-08-22 15:36:43 +0200
committerHimbeerserverDE <himbeerserverde@gmail.com>2023-08-22 15:36:43 +0200
commit56c65f4e3a5fabb21af79f2ff90dd048a4bf2192 (patch)
tree1e5cf10284a38f68a14554735a7dfa9b212acf31 /src
parent2d0cf7bac6b602abd1fc44826e8d65802f6ea8c9 (diff)
serve the local search domain
can be configured at /data/dnsd.domain (noeol)
Diffstat (limited to 'src')
-rw-r--r--src/error.rs2
-rw-r--r--src/main.rs50
2 files changed, 41 insertions, 11 deletions
diff --git a/src/error.rs b/src/error.rs
index 94318d8..8bc2225 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -16,6 +16,8 @@ pub enum Error {
DnsEncode(#[from] dns_message_parser::EncodeError),
#[error("notify: {0}")]
Notify(#[from] notify::Error),
+ #[error("trust_dns_proto: {0}")]
+ TrustDnsProto(#[from] trust_dns_proto::error::ProtoError),
}
pub type Result<T> = std::result::Result<T, Error>;
diff --git a/src/main.rs b/src/main.rs
index dfe4ed9..5b57f88 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -11,7 +11,7 @@ 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::{Dns, Flags, Opcode, RCode};
+use dns_message_parser::{Dns, DomainName, Flags, Opcode, RCode};
use notify::event::{AccessKind, AccessMode, CreateKind};
use notify::{Event, EventKind, RecursiveMode, Watcher};
use rsdsl_dhcp4d::lease::Lease;
@@ -93,6 +93,20 @@ fn main() -> Result<()> {
Err(e) => println!("{}", e),
});
+ let domain = match fs::read_to_string("/data/dnsd.domain") {
+ Ok(v) => match Name::from_utf8(v) {
+ Ok(w) => Some(w),
+ Err(e) => {
+ println!("can't get search domain: {}", e);
+ None
+ }
+ },
+ Err(e) => {
+ println!("can't get search domain: {}", e);
+ None
+ }
+ };
+
let sock = UdpSocket::bind("[::]:53")?;
loop {
@@ -100,17 +114,21 @@ fn main() -> Result<()> {
let (n, raddr) = sock.recv_from(&mut buf)?;
let buf = &buf[..n];
+ let domain2 = domain.clone();
let sock2 = sock.try_clone()?;
let buf = buf.to_vec();
let leases3 = leases.clone();
- thread::spawn(move || match handle_query(sock2, &buf, raddr, leases3) {
- Ok(_) => {}
- Err(e) => println!("can't handle query from {}: {}", raddr, e),
- });
+ thread::spawn(
+ move || match handle_query(&domain2, sock2, &buf, raddr, leases3) {
+ Ok(_) => {}
+ Err(e) => println!("can't handle query from {}: {}", raddr, e),
+ },
+ );
}
}
fn handle_query(
+ domain: &Option<Name>,
sock: UdpSocket,
buf: &[u8],
raddr: SocketAddr,
@@ -123,10 +141,7 @@ fn handle_query(
let (lan, fwd): (_, Vec<Question>) =
msg.questions.into_iter().partition(|q| {
- match is_dhcp_known(
- &Name::from_utf8(q.domain_name.to_string()).expect("not a valid UTF-8 domain name"),
- leases.clone(),
- ) {
+ match is_dhcp_known(&usable_name(domain, &q.domain_name), leases.clone()) {
Ok(known) => known,
Err(e) => {
println!("can't read dhcp config, ignoring {}: {}", q.domain_name, e);
@@ -141,8 +156,7 @@ fn handle_query(
.collect();
let lan_resp = lan.into_iter().filter_map(|q| {
- let hostname =
- Name::from_utf8(q.domain_name.to_string()).expect("not a valid UTF-8 domain name");
+ let hostname = usable_name(domain, &q.domain_name);
if q.q_type == QType::A {
let net_id = subnet_id(&raddr.ip());
@@ -276,3 +290,17 @@ fn subnet_id(addr: &IpAddr) -> u8 {
IpAddr::V6(v6) => NE::read_u16(&v6.octets()[6..8]) as u8,
}
}
+
+fn usable_name(domain: &Option<Name>, name: &DomainName) -> Name {
+ let as_name = Name::from_utf8(name.to_string()).expect("not a valid UTF-8 domain name");
+
+ match domain {
+ Some(domain) if domain.zone_of(&as_name) => {
+ let mut labels = as_name.iter();
+
+ labels.nth_back(domain.iter().len() - 1);
+ Name::from_labels(labels).expect("labels became invalid by removing the domain")
+ }
+ _ => as_name,
+ }
+}