Skip to content

⛵️ Available - Crystal Domain Name System Resolver

License

Notifications You must be signed in to change notification settings

636f7374/durian.cr

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Durian.cr - Domain Name System Resolver

Description

  • Because Crystal Domain Name Resolver uses C.getaddrinfo, It seems to have serious problems.
  • Of course, Crystal official is always busy, it will not help you solve these problems.
    • Thanks to rdp for the help, this made me sure that the problem was caused by C.getaddrinfo.
  • Then I discovered the CrDNS repository, but it too broken, so I gave up the idea.
    • I started looking at many documents and started researching how to build a DNS resolver.
    • It took me some time to make it, it's not troublesome, it's not easy.
  • That's it, Thanks for using, If you encounter any problems, please let me know.

Features

  • If sending fails, it will try to resend through the next DNS server.
  • It supports Querying / Receiving multiple DNS record Types.
    • AAAA
    • A
    • NS
    • PTR
    • SOA
    • TXT
    • MX
    • CNAME
    • DNAME
    • SRV
  • It supports TCP and UDP protocols DNS server.
  • It does not contain any C.getaddrinfo.
  • It supports simple DNS caching (non-LRUCache).
    • (tapCount + updatedAt) custom Cache.
  • You can send / receive packets via Resolver.
    • or you can process packets via Packet.from_io, Packet.to_io.
  • ...

Tips

  • If the connection fails or there is no response packet, it will try to use the next server.
  • C.getaddrinfo is incompatible with green threads, It may cause your program to pause.
    • C.getaddrinfo is too bad, you should not use it in green thread.
    • (libuv uv_getaddrinfo, libevent evdns_getaddrinfo) is too complicated, you may encounter many problems.

Next

  • Support Alias & Mapping and Special DNS Server.
  • Support response packet to_io operation.
  • More exception handling.
  • Support DNS server features.
  • Better performance, Better DNS cache.
  • Supported DNS over TLS (DoT) feature.

Usage

  • Client | Http - Testing DNS resolution for IP availability.
require "durian"

servers = [] of Durian::Resolver::Server
servers << Durian::Resolver::Server.new ipAddress: Socket::IPAddress.new("8.8.8.8", 53_i32), protocol: Durian::Protocol::UDP
servers << Durian::Resolver::Server.new ipAddress: Socket::IPAddress.new("1.1.1.1", 53_i32), protocol: Durian::Protocol::UDP

buffer = uninitialized UInt8[4096_i32]
resolver = Durian::Resolver.new servers
resolver.ip_cache = Durian::Cache::IPAddress.new

begin
  socket = Durian::TCPSocket.connect "www.example.com", 80_i32, resolver, 5_i32
  socket.read_timeout = 5_i32
  socket.write_timeout = 5_i32
rescue
  abort "Connect Failed"
end

begin
  socket << "GET / HTTP/1.1\r\nHost: www.example.com\r\nConnection: close\r\n\r\n"
rescue
  abort "Write Failed"
end

begin
  length = socket.read buffer.to_slice
rescue
  abort "Read Failed"
end

STDOUT.puts [length, String.new buffer.to_slice[0_i32, length]]
  • Client | Query - A similar React Proc usage.
require "durian"

servers = [] of Durian::Resolver::Server
servers << Durian::Resolver::Server.new ipAddress: Socket::IPAddress.new("8.8.8.8", 53_i32), protocol: Durian::Protocol::UDP
servers << Durian::Resolver::Server.new ipAddress: Socket::IPAddress.new("1.1.1.1", 53_i32), protocol: Durian::Protocol::UDP

resolver = Durian::Resolver.new servers
resolver.record_cache = Durian::Cache::Record.new

resolver.resolve "google.com", [Durian::RecordFlag::A, Durian::RecordFlag::AAAA] do |response|
  STDOUT.puts [:Google, Time.utc, response]
end

resolver.resolve "twitter.com", Durian::RecordFlag::SOA do |response|
  STDOUT.puts [:Twitter, Time.utc, response]
end

resolver.resolve "facebook.com", [Durian::RecordFlag::A, Durian::RecordFlag::AAAA] do |response|
  STDOUT.puts [:FaceBook, Time.utc, response]
end

resolver.resolve "twitter.com", Durian::RecordFlag::SOA do |response|
  STDOUT.puts [:Twitter, Time.utc, response]
end

resolver.run
  • Client | Packet - from_io, to_io usage.
require "durian"

buffer = uninitialized UInt8[4096_i32]

request = Durian::Packet.new Durian::Protocol::UDP, Durian::Packet::QRFlag::Query
request.add_query "www.example.com", Durian::RecordFlag::A

_request = IO::Memory.new request.to_slice
STDOUT.puts [:Request, Durian::Packet.from_io Durian::Protocol::UDP, _request]

udp_socket = UDPSocket.new
udp_socket.connect Socket::IPAddress.new "8.8.8.8", 53_i32
udp_socket.send _request.to_slice
length, ip_address = udp_socket.receive buffer.to_slice

_response = IO::Memory.new buffer.to_slice[0_i32, length]
STDOUT.puts [:Response, Durian::Packet.from_io Durian::Protocol::UDP, _response]

Used as Shard

Add this to your application's shard.yml:

dependencies:
  durian:
    github: 636f7374/durian.cr

Installation

$ git clone https://github.com/636f7374/durian.cr.git

Development

$ make test

References

Related

Credit

Contributors

Name Creator Maintainer Contributor
636f7374
rdp
teknomunk
ilmanzo
yunixon
z64

License

  • MIT License