Skip to content

Commit

Permalink
Reworking README for 2.0 release.
Browse files Browse the repository at this point in the history
  • Loading branch information
ioquatix committed Apr 9, 2017
1 parent 22ce3c8 commit 4c5796e
Show file tree
Hide file tree
Showing 8 changed files with 324 additions and 59 deletions.
60 changes: 21 additions & 39 deletions README.md
@@ -1,24 +1,15 @@
# RubyDNS

**RubyDNS 2.0 which was developed and based on Celluloid is [currently being reworked](https://github.com/socketry/socketry-dns)**

[![Gitter](https://badges.gitter.im/Join+Chat.svg)](https://gitter.im/ioquatix/rubydns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)

RubyDNS is a high-performance DNS server which can be easily integrated into other projects or used as a stand-alone daemon. By default it uses rule-based pattern matching. Results can be hard-coded, computed, fetched from a remote DNS server or fetched from a local cache, depending on requirements.

[![RubyDNS Introduction](http://img.youtube.com/vi/B9ygq0xh3HQ/maxresdefault.jpg)](https://www.youtube.com/watch?v=B9ygq0xh3HQ&feature=youtu.be&hd=1 "RubyDNS Introduction")

In addition, RubyDNS includes a high-performance asynchronous DNS resolver built on top of [Celluloid][1]. This module can be used by itself in client applications without using the full RubyDNS server stack.

For examples and documentation please see the main [project page][2].

[1]: https://celluloid.io
[2]: http://www.codeotaku.com/projects/rubydns/

[![Build Status](https://travis-ci.org/ioquatix/rubydns.svg)](https://travis-ci.org/ioquatix/rubydns)
[![Code Climate](https://codeclimate.com/github/ioquatix/rubydns.svg)](https://codeclimate.com/github/ioquatix/rubydns)
[![Coverage Status](https://coveralls.io/repos/ioquatix/rubydns/badge.svg)](https://coveralls.io/r/ioquatix/rubydns)

[![RubyDNS Introduction](http://img.youtube.com/vi/B9ygq0xh3HQ/maxresdefault.jpg)](https://www.youtube.com/watch?v=B9ygq0xh3HQ&feature=youtu.be&hd=1 "RubyDNS Introduction")

## Installation

Add this line to your application's Gemfile:
Expand All @@ -35,15 +26,19 @@ Or install it yourself as:

## Usage

This is copied from `test/examples/test-dns-2.rb`. It has been simplified slightly.
There are [lots of examples available](examples/README.md) in the `examples/` directory.

### Basic DNS Server

Here is the code from `examples/basic-dns.rb`:

```ruby
#!/usr/bin/env ruby
require 'rubydns'

INTERFACES = [
[:udp, "0.0.0.0", 5300],
[:tcp, "0.0.0.0", 5300]
[:tcp, "0.0.0.0", 5300],
]

IN = Resolv::DNS::Resource::IN
Expand All @@ -53,7 +48,7 @@ UPSTREAM = RubyDNS::Resolver.new([[:udp, "8.8.8.8", 53], [:tcp, "8.8.8.8", 53]])

# Start the RubyDNS server
RubyDNS::run_server(:listen => INTERFACES) do
match(/test\.mydomain\.org/, IN::A) do |transaction|
match(%r{test.local}, IN::A) do |transaction|
transaction.respond!("10.0.0.80")
end

Expand All @@ -64,9 +59,9 @@ RubyDNS::run_server(:listen => INTERFACES) do
end
```

Start the server using `./test.rb`. You can then test it using dig:
Start the server using `RUBYOPT=-w ./examples/basic-dns.rb`. You can then test it using dig:

$ dig @localhost -p 5300 test.mydomain.org
$ dig @localhost -p 5300 test.local
$ dig @localhost -p 5300 google.com

### File Handle Limitations
Expand All @@ -84,19 +79,22 @@ class MyServer < RubyDNS::Server
end
end

# Use the RubyDNS infrastructure for running the daemon:
# If asynchronous is true, it will return immediately, otherwise, it will block the current thread until Ctrl-C is pressed (SIGINT).
RubyDNS::run_server(asynchronous: false, server_class: MyServer)

# Directly instantiate the celluloid supervisor:
supervisor = MyServer.supervise
supervisor.actors.first.run
Async::Reactor.run do
task = MyServer.run

# ... do other things

# Shut down the server:
task.stop
end
```

This is the best way to integrate with other projects.

## Performance

**Due to changes in the underlying code, there have been some very minor performance regressions. The numbers below will be updated in due course.**

We welcome additional benchmarks and feedback regarding RubyDNS performance. To check the current performance results, consult the [travis build job output](https://travis-ci.org/ioquatix/rubydns).

### Server
Expand All @@ -123,22 +121,6 @@ These benchmarks are included in the unit tests.

DNSSEC is currently not supported and is [unlikely to be supported in the future](http://sockpuppet.org/blog/2015/01/15/against-dnssec/).

## Examples

### How to respond with something other than what was requested

```ruby
# Full code in examples/cname.rb

RubyDNS::run_server do
# Match request for IN A resource records...
match(//, IN::A) do |transaction|
# And return an IN CNAME record:
transaction.respond!(Name.create('foo.bar'), resource_class: IN::CNAME)
end
end
```

## Contributing

1. Fork it
Expand Down
24 changes: 24 additions & 0 deletions examples/basic-dns.rb
@@ -0,0 +1,24 @@
#!/usr/bin/env ruby
require 'rubydns'

INTERFACES = [
[:udp, "0.0.0.0", 5300],
[:tcp, "0.0.0.0", 5300],
]

IN = Resolv::DNS::Resource::IN

# Use upstream DNS for name resolution.
UPSTREAM = RubyDNS::Resolver.new([[:udp, "8.8.8.8", 53], [:tcp, "8.8.8.8", 53]])

# Start the RubyDNS server
RubyDNS::run_server(:listen => INTERFACES) do
match(%r{test.local}, IN::A) do |transaction|
transaction.respond!("10.0.0.80")
end

# Default DNS handler
otherwise do |transaction|
transaction.passthrough!(UPSTREAM)
end
end
4 changes: 2 additions & 2 deletions examples/cname.rb
Expand Up @@ -14,12 +14,12 @@
UPSTREAM = RubyDNS::Resolver.new([[:udp, "8.8.8.8", 53], [:tcp, "8.8.8.8", 53]])

RubyDNS::run_server(:listen => INTERFACES) do
# How to respond to something other than what was requested.
match(//, IN::A) do |transaction|
transaction.respond!(Name.create('foo.bar'), resource_class: IN::CNAME)
end

#passthrough
otherwise do |transaction|
transaction.passthrough!(UPSTREAM)
end
end
end
25 changes: 25 additions & 0 deletions examples/simple.rb
@@ -0,0 +1,25 @@
#!/usr/bin/env ruby
require 'rubydns'

INTERFACES = [
[:udp, '0.0.0.0', 5300],
[:tcp, '0.0.0.0', 5300]
]

Name = Resolv::DNS::Name
IN = Resolv::DNS::Resource::IN

# Use upstream DNS for name resolution.
UPSTREAM = RubyDNS::Resolver.new([[:udp, '8.8.8.8', 53], [:tcp, '8.8.8.8', 53]])

# Start the RubyDNS server
RubyDNS.run_server(listen: INTERFACES) do
match(/test.mydomain.org/, IN::A) do |transaction|
transaction.respond!('10.0.0.80')
end

# Default DNS handler
otherwise do |transaction|
transaction.passthrough!(UPSTREAM)
end
end
82 changes: 82 additions & 0 deletions examples/soa-dns.rb
@@ -0,0 +1,82 @@
#!/usr/bin/env ruby

# Copyright, 2009, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

require 'rubygems'
require 'rubydns'

$R = Resolv::DNS.new
Name = Resolv::DNS::Name
IN = Resolv::DNS::Resource::IN

RubyDNS.run_server(listen: [[:udp, '0.0.0.0', 5400]]) do
# SOA Record
# dig @localhost -p 5400 SOA mydomain.org
match('mydomain.org', IN::SOA) do |transaction|
#
# For more details about these headers please see:
# http://www.ripe.net/ripe/docs/ripe-203.html
#

transaction.respond!(
Name.create('ns.mydomain.org.'), # Master Name
Name.create('admin.mydomain.org.'), # Responsible Name
File.mtime(__FILE__).to_i, # Serial Number
1200, # Refresh Time
900, # Retry Time
3_600_000, # Maximum TTL / Expiry Time
172_800 # Minimum TTL
)

transaction.append!(transaction.question, IN::NS, section: :authority)
end

# Default NS record
# dig @localhost -p 5400 mydomain.org NS
match('mydomain.org', IN::NS) do |transaction|
transaction.respond!(Name.create('ns.mydomain.org.'))
end

# For this exact address record, return an IP address
# dig @localhost -p 5400 CNAME bob.mydomain.org
match(/([^.]+).mydomain.org/, IN::CNAME) do |transaction|
transaction.respond!(Name.create('www.mydomain.org'))
transaction.append!('www.mydomain.org', IN::A)
end

match('80.0.0.10.in-addr.arpa', IN::PTR) do |transaction|
transaction.respond!(Name.create('www.mydomain.org.'))
end

match('www.mydomain.org', IN::A) do |transaction|
transaction.respond!('10.0.0.80')
end

match('ns.mydomain.org', IN::A) do |transaction|
transaction.respond!('10.0.0.10')
end

# Default DNS handler
otherwise do |transaction|
# Non-Existant Domain
transaction.fail!(:NXDomain)
end
end
83 changes: 83 additions & 0 deletions examples/test-dns-1.rb
@@ -0,0 +1,83 @@
#!/usr/bin/env ruby

# Copyright, 2009, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

require 'rubygems'
require 'rubydns'
require 'rubydns/system'

# You can specify other DNS servers easily
# $R = Resolv::DNS.new(:nameserver => ["xx.xx.1.1", "xx.xx.2.2"])

R = RubyDNS::Resolver.new(RubyDNS::System.nameservers)
Name = Resolv::DNS::Name
IN = Resolv::DNS::Resource::IN
INTERFACES = [
[:udp, '0.0.0.0', 5300],
[:tcp, '0.0.0.0', 5300],
# [:udp, '::0', 5300],
# [:tcp, '::0', 5300],
]

RubyDNS.run_server(listen: INTERFACES) do
# % dig +nocmd +noall +answer @localhost ANY dev.mydomain.org
# dev.mydomain.org. 16000 IN A 10.0.0.80
# dev.mydomain.org. 16000 IN MX 10 mail.mydomain.org.
match(/dev.mydomain.org/, IN::ANY) do |transaction|
transaction.append_question!

[IN::A, IN::CNAME, IN::MX].each do |resource_class|
logger.debug "Appending query for #{resource_class}..."
transaction.append!(transaction.name, resource_class)
end
end

# For this exact address record, return an IP address
match('dev.mydomain.org', IN::A) do |transaction|
transaction.respond!('10.0.0.80')
end

match('80.0.0.10.in-addr.arpa', IN::PTR) do |transaction|
transaction.respond!(Name.create('dev.mydomain.org.'))
end

match('dev.mydomain.org', IN::MX) do |transaction|
transaction.respond!(10, Name.create('mail.mydomain.org.'))
end

match(/^test([0-9]+).mydomain.org$/, IN::A) do |transaction, match_data|
offset = match_data[1].to_i

if offset > 0 && offset < 10
logger.info "Responding with address #{'10.0.0.' + (90 + offset).to_s}..."
transaction.respond!('10.0.0.' + (90 + offset).to_s)
else
logger.info "Address out of range: #{offset}!"
false
end
end

# Default DNS handler
otherwise do |transaction|
logger.info 'Passing DNS request upstream...'
transaction.passthrough!(R)
end
end

0 comments on commit 4c5796e

Please sign in to comment.