#dns-server #dns #middleware #tokio #domains #dns-query #non-icann

any-dns

Lightweight DNS server with Middleware support for non-ICANN domains

10 releases

new 0.3.0 Nov 5, 2024
0.2.5 Nov 4, 2024
0.2.4 Feb 19, 2024
0.1.2 Feb 4, 2024
0.1.1 Jan 28, 2024

#2118 in Network programming

Download history 3/week @ 2024-08-27 2/week @ 2024-09-17 23/week @ 2024-09-24 3/week @ 2024-10-01 2/week @ 2024-10-08 1/week @ 2024-10-15 1/week @ 2024-10-22 72/week @ 2024-10-29

78 downloads per month

MIT license

24KB
521 lines

any-dns

Crates.io Version

Lightweight DNS server with Middleware support for non-ICANN domains made in Rust. Tokio Async only.

Example

Regular DNS Build server listening on 0.0.0.0:53 and forward queries to 8.8.8.8:53.

use std::error::Error;
use any_dns::Builder;


#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    println!("Listening on 0.0.0.0:53. Waiting for Ctrl-C...");

    let anydns = Builder::new()
        .icann_resolver("8.8.8.8:53".parse()?)
        .build()
        .await?;

    anydns.wait_on_ctrl_c().await;
    println!("Got it! Exiting...");
    anydns.stop();

    Ok(())
}

Test: nslookup example.com 127.0.0.1

Custom Handler Resolve any.dns to an IP.

use any_dns::{DnsSocket, Builder, CustomHandler, CustomHandlerError};
use async_trait::async_trait;
use simple_dns::{Packet, ResourceRecord};


/**
 * Create Custom handler
*/
#[derive(Clone, Debug)]
struct MyHandler {}

#[async_trait] // <-- Don't forget
impl CustomHandler for MyHandler {
    // `lookup` is called for every dns query
    async fn lookup(&mut self, query: &Vec<u8>, socket: DnsSocket) -> Result<Vec<u8>, CustomHandlerError> {
        // Parse query with any dns library
        let packet = Packet::parse(query).unwrap();
        let question = packet.questions.get(0).expect("Valid query");

        let is_any_dot_dns = question.qname.to_string() == "any.dns" && question.qtype == QTYPE::TYPE(TYPE::A);
        if is_any_dot_dns {
            Ok(self.construct_reply(query)) // Reply with A record IP
        } else {
            Err(CustomHandlerError::Unhandled) // Fallback to ICANN
        }        
    }
}


#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    println!("Listening on 0.0.0.0:53. Waiting for Ctrl-C...");
    let handler = MyHandler {};
    let anydns = Builder::new()
        .handler(handler) // Add the handler here.
        .icann_resolver("8.8.8.8:53".parse().unwrap())
        .build()
        .await?;

    anydns.wait_on_ctrl_c().await;
    println!("Got it! Exiting...");
    anydns.stop();

    Ok(())
}

Test: nslookup any.dns 127.0.0.1

Logs

anydns uses the tracing crate for logs. Set the environment variable RUST_LOG=any_dns=trace to see them.

Dependencies

~4–10MB
~101K SLoC