Crate rsdns

source ·
Expand description

rsdns is a DNS client library.

rsdns provides an API to directly communicate with DNS servers using its own implementation of the DNS protocol. It strives to be minimal and fast.

§Notable Features

  • Minimal API
  • Three independent asynchronous clients for different async runtimes: tokio, async-std and smol
  • An independent blocking client implemented with std::net
  • Zero memory allocations when parsing records with no variable size fields (e.g. A, AAAA)
  • Sockets can be bound to network interfaces by name (requires SO_BINDTODEVICE support from the underlying OS)
  • Minimal set of dependencies

§Library Structure

rsdns is built from two major parts: message parsing and clients.

The message parsing part is the core of rsdns. It is generic and is suitable for any type of client that you may choose. It can be used even without an rsdns client at all, if you have DNS messages obtained by other means. This part is always present and cannot be disabled. See the message::reader module for more details.

The clients part is comprised of four independent implementations of the client API. Usually an application will use only one of those. See the clients module for more information.

§Crate Features

rsdns has several crate features which enable different functionalities:

  1. net-tokio - enables the clients::tokio module
  2. net-async-std - enables the clients::async_std module
  3. net-smol - enables the clients::smol module
  4. net-std - enables the clients::std module
  5. socket2 - together with net-tokio enables bind-to-device support (currently on Linux only)

Note that none of the features is enabled by default. The clients module exists only if one of the net-* features is enabled.


The following function retrieves A records using rsdns’s asynchronous tokio::Client. To retrieve a different type of record, or use a different asynchronous client, use the relevant types from records::data and clients modules respectively.

This is a very simplified example of the available API. In a real application initialization of the Client object would be done once for many DNS queries. Also, please note that a full application requires tokio runtime initialization, which is out of rsdns scope. See the tokio documentation for details.

use rsdns::records::{data::A, Class};
use rsdns::clients::{tokio::Client, ClientConfig};

async fn get_a_records(qname: &str) -> Result<Vec<A>, Box<dyn Error>> {
    // use Google's Public DNS recursor as nameserver
    let nameserver = SocketAddr::from_str("")?;

    // default client configuration; specify nameserver address only
    let config = ClientConfig::with_nameserver(nameserver);

    // create tokio Client
    let mut client = Client::new(config).await?;

    // issue an A query
    let rrset = client.query_rrset::<A>(qname, Class::IN).await?;


The same function using rsdns’s synchronous std::Client.

use rsdns::records::{data::A, Class};
use rsdns::clients::{std::Client, ClientConfig};

fn get_a_records(qname: &str) -> Result<Vec<A>, Box<dyn Error>> {
    let nameserver = SocketAddr::from_str("")?;
    let mut client = Client::new(ClientConfig::with_nameserver(nameserver))?;
    let rrset = client.query_rrset::<A>(qname, Class::IN)?;



Type Aliases§