Durian.cr - Domain Name System Resolver
Description
- Because Crystal Domain Name Resolver uses
C.getaddrinfo
, It seems to have serious problems.- This may cause the program to Freeze, so I created this repository.
- 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
.
- Thanks to rdp for the help, this made me sure that the problem was caused by
- 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
.
- or you can process packets via
- ...
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
, libeventevdns_getaddrinfo
) is too complicated, you may encounter many problems.
Next
- [X] 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.
- [X] 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
- StackOverflow | How to convert a string or integer to binary in Ruby?
- StackOverflow | Requesting A and AAAA records in single DNS query
- StackOverflow | Example of DNS Compression Pointer Offset > than 12 bytes
- StackOverflow | why libuv do DNS request by multiple thread
- Official | DNS_HEADER structure
- Official | The Saga of Concurrent DNS in Python, and the Defeat of the Wicked Mutex Troll
- Official | Help understanding DNS packet data
- Official | Ietf - RFC 1035
- Official | Docs.rs::hyper_trust_dns_connector
- Official | libuv provides asynchronous variants of getaddrinfo and getnameinfo
- Blogs | Adventures in Rust: Futures and Tokio
- Blogs | Cocoa: Asynchronous Host name lookups
- Blogs | Using DNS with Libevent: high and low-level functionality
- Blogs | The problem with libresolv
- Blogs | The problem with getaddrinfo
- Blogs | What does getaddrinfo do?
- Blogs | A warm welcome to DNS
- Document | DNS Query Message Format
- Docuemnt | Protocol and Format
- Document | Binary Numbers
- Document | DNS Message Header and Question Section Format
- Document | DNS Name Notation and Message Compression Technique
- Github Gist | DNS Query Code in C with linux sockets
- Github Gist | getaddrinfo.strace
- Source Code | posix/getaddrinfo.c
- Source Code | DNS header for C | 0x00sec
- ...
Related
- #8480 | blocking call in one fiber can cause IO timeouts in others
- #4816 | Add Resolv class to standard library
- #2660 | Fix/Implement own DNS resolver
- #4236 | Configurable DNS resolvers
- #2829 | DNS threaded resolver
- #2745 | Don't use libevent's getaddrinfo, use C's getaddrinfo
- #8376 | Some TCPSocket connections will cause HTTP::Server accept (freeze | blocking | hangs | waiting)?
- ...
Credit
Contributors
|Name|Creator|Maintainer|Contributor| |:---:|:---:|:---:|:---:| |**636f7374|√|√|| |rdp|||√| |teknomunk|||√| |ilmanzo|||√| |yunixon|||√| |z64**|||√|
License
- MIT License