dns v1.6.1

extendable non blocking DNS for crystal lang

DNS

CI

Non-blocking extendable DNS client for crystal lang.

With built in support for UDP, TLS, HTTPS and mDNS resolvers.

Installation

  1. Add the dependency to your shard.yml:

    dependencies:
      dns:
        github: spider-gazelle/dns
    
  2. Run shards install

Usage

A simple query

require "dns"

responses = DNS.query(
  "www.google.com",
  {
    DNS::RecordType::A,
    DNS::RecordType::AAAA,
  }
)

ips = responses.map(&.ip_address)

How to configure custom resolvers (secure from prying eyes)

require "dns"
require "dns/resolver/https"

DNS.default_resolver = DNS::Resolver::HTTPS.new(["https://1.1.1.1/dns-query"])

# or just for some routes
DNS.resolvers[/.+\.com\.au$/i] = DNS::Resolver::HTTPS.new(["https://1.1.1.1/dns-query"])

# there is a built in resolver to use mDNS for *.local routes

# if you'd prefer to use the system resolver for A and AAAA records
DNS.default_resolver = DNS::Resolver::System.new(
  # uses the fallback resolver for other DNS records
  fallback: Resolver::UDP.new
)

# for the TLS resolver you need to specify a domain name for the returned TLS certificate
DNS.default_resolver = DNS::Resolver::TLS.new({
  "8.8.8.8" => "dns.google",
})

# or maybe you don't want to use the system defined DNS servers
DNS.default_resolver = DNS::Resolver::UDP.new(["1.1.1.1", "8.8.8.8"])

# it's also possible to create your own resolvers implementing the abstract method in `DNS::Resolver`

By default, the library will attempt to obtain the DNS servers configured on your host. That is using:

  • /etc/resolv.conf on linux / nix* systems
  • Win32 API calls on Windows
  • SystemConfiguration framework on MacOS

NOTE:: currently it does not check if DNS over HTTPS is configured on either Mac or Windows (future work)

If DNS discovery is unsuccessful it falls back to using ["1.1.1.1", "8.8.8.8"].

# to customise the fallback servers
DNS::Servers.fallback = ["192.168.0.1"]

Resolver behaviour

The UDP resolver is modelled on the behaviour of unix getaddrinfo:

  • queries are retransmitted with an exponential backoff and failed over across the configured nameservers, rather than failing on a single dropped packet
  • a persistently unresponsive nameserver is demoted to the end of the list so later queries prefer healthy servers
  • resolv.conf options are honoured: timeout: (default 2s, clamped 1..30), attempts: (default 3, clamped 1..5) and ndots: (default 1, clamped 0..15). The base timeout can also be set globally with DNS.timeout.
  • an EDNS0 OPT record is sent advertising a 1232 byte UDP payload (DNS Flag Day 2020), and truncated (TC) responses are transparently refetched over TCP
# tune the base (initial) per-try timeout; backoff doubles it each attempt
DNS.timeout = 1.second

Shared UDP source port

All UDP queries are sent from a single, long-lived source port per address family (a process-wide DNS::Resolver::UDP::SharedSocket) rather than opening a fresh socket per query. A background fiber demultiplexes responses back to each waiting query by transaction id.

Reusing one source port trades some of the source-port entropy recommended by RFC 5452 for connection reuse, so every response is strictly validated before it is accepted: the transaction id (a CSPRNG value) must be outstanding, the QR bit must be set, the source address must match the queried server, and the echoed question must match the request. This is appropriate for a stub resolver talking to a trusted recursive resolver. If you operate over an untrusted path, prefer the TLS or HTTPS resolvers.

Other things to note:

  • IPv6 is supported and handled transparently
  • a DNS cache is maintained and used based on TTL of responses
  • DNS servers may return results of expected future queries, these results are cached
  • force all DNS lookups to occur via this library: require "dns/ext/addrinfo"

Contributing

  1. Fork it (https://github.com/spider-gazelle/dns/fork)
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create a new Pull Request

Contributors

Repository

dns

Owner
Statistic
  • 16
  • 2
  • 0
  • 12
  • 0
  • 9 days ago
  • October 22, 2024
License

MIT License

Links
Synced at

Wed, 17 Jun 2026 11:18:48 GMT

Languages