Skip to main content

bindizr_dns/
lib.rs

1pub(crate) mod acl;
2pub(crate) mod address;
3pub(crate) mod nsupdate;
4pub(crate) mod soa;
5pub use bindizr_core::dns::txt;
6pub mod xfr;
7
8use std::{io::ErrorKind, net::SocketAddr, time::Duration};
9
10use acl::SecondaryAcl;
11pub(crate) use bindizr_core::{config, log_error, log_info, log_warn, model};
12pub(crate) use bindizr_service as service;
13use domain::base::iana::Rtype;
14use tokio::{
15    net::{TcpListener, TcpStream, UdpSocket},
16    time::timeout,
17};
18
19const TCP_IDLE_TIMEOUT: Duration = Duration::from_secs(30);
20
21enum QueryRoute {
22    Nsupdate,
23    Soa,
24    Xfr,
25    Other(Rtype),
26}
27
28pub async fn initialize() {
29    xfr::initialize().await;
30
31    let bindizr_config = config::get_bindizr_config();
32    let listen_addr = SocketAddr::new(
33        bindizr_config.dns.listen_addr,
34        bindizr_config.dns.listen_port,
35    );
36
37    let secondary_acl = acl::secondary_acl_from_config();
38    let tcp_secondary_acl = secondary_acl.clone();
39
40    tokio::spawn(async move {
41        if let Err(e) = run_tcp_server(listen_addr, tcp_secondary_acl).await {
42            log_error!("DNS TCP server error: {}", e);
43        }
44    });
45
46    tokio::spawn(async move {
47        if let Err(e) = run_udp_server(listen_addr, secondary_acl).await {
48            log_error!("DNS UDP server error: {}", e);
49        }
50    });
51}
52
53async fn run_tcp_server(
54    listen_addr: SocketAddr,
55    secondary_acl: SecondaryAcl,
56) -> Result<(), String> {
57    let listener = TcpListener::bind(listen_addr)
58        .await
59        .map_err(|e| format!("Failed to bind DNS TCP listener on {}: {}", listen_addr, e))?;
60
61    log_info!("DNS TCP server listening on {}", listen_addr);
62
63    loop {
64        match listener.accept().await {
65            Ok((stream, client_addr)) => {
66                let allowed = secondary_acl.clone();
67                tokio::spawn(async move {
68                    if let Err(e) = handle_tcp_connection(stream, client_addr, allowed).await {
69                        log_error!("DNS TCP connection error from {}: {}", client_addr, e);
70                    }
71                });
72            }
73            Err(e) => {
74                log_error!("Failed to accept DNS TCP connection: {}", e);
75            }
76        }
77    }
78}
79
80async fn handle_tcp_connection(
81    mut stream: TcpStream,
82    client_addr: SocketAddr,
83    secondary_acl: SecondaryAcl,
84) -> Result<(), String> {
85    loop {
86        let query_data = match timeout(TCP_IDLE_TIMEOUT, xfr::wire::read_tcp_message(&mut stream))
87            .await
88        {
89            Ok(Ok(query_data)) => query_data,
90            Ok(Err(xfr::error::XfrError::IoError(e))) if e.kind() == ErrorKind::UnexpectedEof => {
91                break;
92            }
93            Ok(Err(e)) => return Err(format!("Failed to read DNS TCP message: {}", e)),
94            Err(_) => {
95                log_info!(
96                    "Closing idle DNS TCP connection from {} after {:?}",
97                    client_addr,
98                    TCP_IDLE_TIMEOUT
99                );
100                break;
101            }
102        };
103
104        handle_tcp_query(&mut stream, client_addr, &secondary_acl, &query_data).await?;
105    }
106
107    Ok(())
108}
109
110async fn handle_tcp_query(
111    stream: &mut TcpStream,
112    client_addr: SocketAddr,
113    secondary_acl: &SecondaryAcl,
114    query_data: &[u8],
115) -> Result<(), String> {
116    match classify_query_route(query_data) {
117        Ok(QueryRoute::Nsupdate) => {
118            nsupdate::handle_tcp_nsupdate(stream, query_data, client_addr).await?;
119        }
120        Ok(QueryRoute::Soa) => {
121            soa::handle_tcp_soa(stream, client_addr, query_data)
122                .await
123                .map_err(|e| format!("Failed to handle SOA TCP query: {}", e))?;
124        }
125        Ok(QueryRoute::Xfr) => {
126            xfr::handle_tcp_query(stream, client_addr, secondary_acl, query_data)
127                .await
128                .map_err(|e| format!("Failed to handle XFR TCP query: {}", e))?;
129        }
130        Ok(QueryRoute::Other(qtype)) => {
131            log_info!(
132                "Ignoring non-XFR DNS TCP query from {} (qtype={:?})",
133                client_addr,
134                qtype
135            );
136        }
137        Err(e) => {
138            log_warn!("Failed to parse DNS TCP query from {}: {}", client_addr, e);
139        }
140    }
141
142    Ok(())
143}
144
145async fn run_udp_server(
146    listen_addr: SocketAddr,
147    secondary_acl: SecondaryAcl,
148) -> Result<(), String> {
149    let socket = UdpSocket::bind(listen_addr)
150        .await
151        .map_err(|e| format!("Failed to bind DNS UDP socket on {}: {}", listen_addr, e))?;
152
153    log_info!("DNS UDP server listening on {}", listen_addr);
154
155    let mut buf = vec![0u8; 65535];
156
157    loop {
158        let (len, client_addr) = match socket.recv_from(&mut buf).await {
159            Ok(v) => v,
160            Err(e) => {
161                log_error!("Failed to receive DNS UDP packet: {}", e);
162                continue;
163            }
164        };
165
166        let query_data = &buf[..len];
167
168        match classify_query_route(query_data) {
169            Ok(QueryRoute::Nsupdate) => {
170                if let Err(e) =
171                    nsupdate::handle_udp_nsupdate(&socket, query_data, client_addr).await
172                {
173                    log_error!("NSUPDATE UDP handler failed for {}: {}", client_addr, e);
174                }
175            }
176            Ok(QueryRoute::Soa) => {
177                if let Err(e) = soa::handle_udp_soa(&socket, client_addr, query_data).await {
178                    log_warn!("Failed to handle SOA UDP query from {}: {}", client_addr, e);
179                }
180            }
181            Ok(QueryRoute::Xfr) => {
182                if let Err(e) = xfr::handle_udp_query(client_addr, &secondary_acl, query_data).await
183                {
184                    log_warn!("Failed to handle XFR UDP query from {}: {}", client_addr, e);
185                }
186            }
187            Ok(QueryRoute::Other(_)) => {}
188            Err(_) => {}
189        }
190    }
191}
192
193fn classify_query_route(query_data: &[u8]) -> Result<QueryRoute, String> {
194    if nsupdate::is_nsupdate(query_data) {
195        return Ok(QueryRoute::Nsupdate);
196    }
197
198    let (_zone_name, qtype, _client_serial, _query_id) =
199        xfr::wire::parse_query(query_data).map_err(|e| e.to_string())?;
200
201    if qtype == Rtype::SOA {
202        Ok(QueryRoute::Soa)
203    } else if xfr::is_xfr_query_type(qtype) {
204        Ok(QueryRoute::Xfr)
205    } else {
206        Ok(QueryRoute::Other(qtype))
207    }
208}