rubydns 0.8.1 → 0.8.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +6 -2
- data/README.md +37 -1
- data/lib/rubydns/handler.rb +20 -10
- data/lib/rubydns/server.rb +10 -5
- data/lib/rubydns/transaction.rb +4 -0
- data/lib/rubydns/version.rb +1 -1
- data/lib/rubydns.rb +4 -0
- data/rubydns.gemspec +1 -1
- data/test/examples/dropping-dns.rb +0 -4
- data/test/examples/fortune-dns.rb +0 -2
- data/test/examples/geoip-dns.rb +1 -5
- data/test/examples/wikipedia-dns.rb +0 -2
- data/test/performance/benchmark.rb +29 -0
- data/test/performance/bind9/generate-local.rb +25 -0
- data/test/performance/bind9/local.zone +5014 -0
- data/test/performance/bind9/named.conf +14 -0
- data/test/performance/million.rb +87 -0
- data/test/test_daemon.rb +24 -2
- data/test/test_passthrough.rb +1 -1
- data/test/test_resolver_performance.rb +2 -1
- data/test/test_server_performance.rb +134 -0
- data/test/test_slow_server.rb +1 -3
- data/test/test_truncation.rb +1 -3
- metadata +30 -20
- data/test/test_domains.txt +0 -185
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 204ba4e799634855d87e3a5b0d4969e17b7aafcf
|
4
|
+
data.tar.gz: 55f9a962495018de41eeb37656b61d2e9580e519
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9a08e54d3e38cb82e735a65750dae55452c94115d28a1ea115452069afacb6ac978645de0dd25a547c65168703249df4a6f5bbb75254e8a4d5b1e368db58229d
|
7
|
+
data.tar.gz: 18220b387aec7b2b145f1af7760947b08aee115ab87a8e04fdbc34d0d230c0d49a3396c0252b3e87bf94d956982bba1aa905106f368059db6c286fbb42c03924
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -8,7 +8,7 @@ For examples and documentation please see the main [project page][1].
|
|
8
8
|
|
9
9
|
[1]: http://www.codeotaku.com/projects/rubydns/
|
10
10
|
|
11
|
-
[![Build Status](https://travis-ci.org/ioquatix/rubydns.svg)](https://travis-ci.org/ioquatix/rubydns)
|
11
|
+
[![Build Status](https://travis-ci.org/ioquatix/rubydns.svg?branch=master)](https://travis-ci.org/ioquatix/rubydns)
|
12
12
|
[![Code Climate](https://codeclimate.com/github/ioquatix/rubydns.png)](https://codeclimate.com/github/ioquatix/rubydns)
|
13
13
|
|
14
14
|
## Installation
|
@@ -63,6 +63,10 @@ Start the server using `rvmsudo ./test.rb`. You can then test it using dig:
|
|
63
63
|
$ dig @localhost dev.mydomain.org
|
64
64
|
$ dig @localhost google.com
|
65
65
|
|
66
|
+
### File Handle Limitations
|
67
|
+
|
68
|
+
On some platforms (e.g. Mac OS X) the number of file descriptors is relatively low by default and should be increased by calling `ulimit -n 10000` before running tests or even before starting a server which expects a large number of concurrent incoming connections.
|
69
|
+
|
66
70
|
### Custom servers
|
67
71
|
|
68
72
|
It is possible to create and integrate your own custom servers.
|
@@ -79,12 +83,44 @@ It is possible to create and integrate your own custom servers.
|
|
79
83
|
|
80
84
|
This is the best way to integrate with other projects.
|
81
85
|
|
86
|
+
## Performance
|
87
|
+
|
88
|
+
We welcome additional benchmarks and feedback regarding RubyDNS performance.
|
89
|
+
|
90
|
+
### Server
|
91
|
+
|
92
|
+
The performance is on the same magnitude as `bind9` however `bind9` supports multiple CPUs and thus can scale more easily than RubyDNS using MRI. Some basic benchmarks resolving 1000 names concurrently, repeated 5 times, using `RubyDNS::Resolver` gives the following:
|
93
|
+
|
94
|
+
Testing server performance...
|
95
|
+
user system total real
|
96
|
+
RubyDNS::Server 1.040000 0.320000 1.360000 ( 6.469213)
|
97
|
+
Bind9 1.940000 0.120000 2.060000 ( 2.062983)
|
98
|
+
|
99
|
+
These benchmarks are included in the unit tests. To test bind9 performance, it must be installed and `which named` must return the executable.
|
100
|
+
|
101
|
+
### Resolver
|
102
|
+
|
103
|
+
The `RubyDNS::Resolver` is highly concurrent and can resolve individual names as fast as the built in `Resolv::DNS` resolver. Because the resolver is asynchronous, when dealing with multiple names, it can work more efficiently:
|
104
|
+
|
105
|
+
Comparing resolvers...
|
106
|
+
user system total real
|
107
|
+
RubyDNS::Resolver 0.020000 0.010000 0.030000 ( 0.280679)
|
108
|
+
Resolv::DNS 0.030000 0.010000 0.040000 ( 2.801773)
|
109
|
+
|
110
|
+
These benchmarks are included in the unit tests.
|
111
|
+
|
82
112
|
## Compatibility
|
83
113
|
|
84
114
|
### Migrating from RubyDNS 0.7.x to 0.8.x
|
85
115
|
|
86
116
|
The primary change is the removal of the dependency on `RExec` which was used for daemons and the addition of the testing dependency `process-daemon`. In order to create and run your own daemon, you may use `process-daemon` or another tool of your choice.
|
87
117
|
|
118
|
+
The transaction options are now conveniently available:
|
119
|
+
|
120
|
+
transaction.options[key] == transaction[key]
|
121
|
+
|
122
|
+
The remote peer address used to be available directly via `transaction[:peer]` but profiling revealed that the `EventMachine::Connection#get_peername` was moderately expensive. Therefore, the incoming connection is now available in `transaction[:connection]` and more specifically `transaction[:peer]` is no longer available and replaced by `transaction[:connection].peername` which gives `[ip_address, port]`.
|
123
|
+
|
88
124
|
### Migrating from RubyDNS 0.6.x to 0.7.x
|
89
125
|
|
90
126
|
The asynchronous deferred processing became the default and only method for processing requests in `0.7.0`. This simplifies the API but there were a few changes, notably the removal of `defer!` and the addition of `defer`. The reason for this was due to issues relating to deferred processing and the flow of control, which were confusing and introduced bugs in specific situations. Now, you can assume flow control through the entire block even with non-blocking functions.
|
data/lib/rubydns/handler.rb
CHANGED
@@ -22,20 +22,24 @@ require_relative 'message'
|
|
22
22
|
require_relative 'binary_string'
|
23
23
|
|
24
24
|
module RubyDNS
|
25
|
-
|
26
|
-
|
27
|
-
|
25
|
+
module Peername
|
26
|
+
# Available for both UDP and TCP connections, returns `[address, port]`.
|
27
|
+
def peername
|
28
|
+
Socket.unpack_sockaddr_in(self.get_peername).reverse
|
29
|
+
end
|
28
30
|
end
|
29
31
|
|
30
32
|
# Handling incoming UDP requests, which are single data packets, and pass them on to the given server.
|
31
33
|
module UDPHandler
|
34
|
+
include Peername
|
35
|
+
|
32
36
|
def initialize(server)
|
33
37
|
@server = server
|
34
38
|
end
|
35
39
|
|
36
40
|
# Process a packet of data with the given server. If an exception is thrown, a failure message will be sent back.
|
37
41
|
def self.process(server, data, options = {}, &block)
|
38
|
-
server.logger.debug "Receiving incoming query (#{data.bytesize} bytes)..."
|
42
|
+
server.logger.debug {"Receiving incoming query (#{data.bytesize} bytes)..."}
|
39
43
|
query = nil
|
40
44
|
|
41
45
|
begin
|
@@ -63,17 +67,20 @@ module RubyDNS
|
|
63
67
|
end
|
64
68
|
end
|
65
69
|
|
70
|
+
def peername
|
71
|
+
Socket.unpack_sockaddr_in(self.get_peername)
|
72
|
+
end
|
73
|
+
|
66
74
|
def receive_data(data)
|
67
|
-
|
68
|
-
options = {:peer => peer_ip}
|
75
|
+
options = {:connection => self}
|
69
76
|
|
70
77
|
UDPHandler.process(@server, data, options) do |answer|
|
71
78
|
data = answer.encode
|
72
79
|
|
73
|
-
@server.logger.debug "Writing response to client (#{data.bytesize} bytes) via UDP..."
|
80
|
+
@server.logger.debug {"Writing response to client (#{data.bytesize} bytes) via UDP..."}
|
74
81
|
|
75
82
|
if data.bytesize > UDP_TRUNCATION_SIZE
|
76
|
-
@server.logger.warn "Response via UDP was larger than #{UDP_TRUNCATION_SIZE}!"
|
83
|
+
@server.logger.warn {"Response via UDP was larger than #{UDP_TRUNCATION_SIZE}!"}
|
77
84
|
|
78
85
|
# Reencode data with truncation flag marked as true:
|
79
86
|
truncation_error = Resolv::DNS::Message.new(answer.id)
|
@@ -83,7 +90,8 @@ module RubyDNS
|
|
83
90
|
end
|
84
91
|
|
85
92
|
# We explicitly use the ip and port given, because we found that send_data was unreliable in a callback.
|
86
|
-
self.send_datagram(data, peer_ip, peer_port)
|
93
|
+
# self.send_datagram(data, peer_ip, peer_port)
|
94
|
+
self.send_data(data)
|
87
95
|
end
|
88
96
|
end
|
89
97
|
end
|
@@ -92,6 +100,8 @@ module RubyDNS
|
|
92
100
|
end
|
93
101
|
|
94
102
|
module TCPHandler
|
103
|
+
include Peername
|
104
|
+
|
95
105
|
def initialize(server)
|
96
106
|
@server = server
|
97
107
|
|
@@ -120,7 +130,7 @@ module RubyDNS
|
|
120
130
|
if (@buffer.size - @processed) >= @length
|
121
131
|
data = @buffer.string.byteslice(@processed, @length)
|
122
132
|
|
123
|
-
options = {:
|
133
|
+
options = {:connection => self}
|
124
134
|
|
125
135
|
UDPHandler.process(@server, data, options) do |answer|
|
126
136
|
data = answer.encode
|
data/lib/rubydns/server.rb
CHANGED
@@ -63,6 +63,8 @@ module RubyDNS
|
|
63
63
|
|
64
64
|
# Process an incoming DNS message. Returns a serialized message to be sent back to the client.
|
65
65
|
def process_query(query, options = {}, &block)
|
66
|
+
start_time = Time.now
|
67
|
+
|
66
68
|
# Setup answer
|
67
69
|
answer = Resolv::DNS::Message::new(query.id)
|
68
70
|
answer.qr = 1 # 0 = Query, 1 = Response
|
@@ -77,20 +79,23 @@ module RubyDNS
|
|
77
79
|
|
78
80
|
begin
|
79
81
|
query.question.each do |question, resource_class|
|
80
|
-
@logger.debug "Processing question #{question} #{resource_class}..."
|
82
|
+
@logger.debug {"[#{query.id}] Processing question #{question} #{resource_class}..."}
|
81
83
|
|
82
84
|
transaction = Transaction.new(self, query, question, resource_class, answer, options)
|
83
85
|
|
84
86
|
transaction.process
|
85
87
|
end
|
86
88
|
rescue
|
87
|
-
@logger.error "Exception thrown while processing #{transaction}!"
|
89
|
+
@logger.error {"[#{query.id}] Exception thrown while processing #{transaction}!"}
|
88
90
|
RubyDNS.log_exception(@logger, $!)
|
89
91
|
|
90
92
|
answer.rcode = Resolv::DNS::RCode::ServFail
|
91
93
|
end
|
92
|
-
|
94
|
+
|
93
95
|
yield answer
|
96
|
+
|
97
|
+
end_time = Time.now
|
98
|
+
@logger.debug {"[#{query.id}] Time to process request: #{end_time - start_time}s"}
|
94
99
|
end.resume
|
95
100
|
end
|
96
101
|
|
@@ -267,10 +272,10 @@ module RubyDNS
|
|
267
272
|
|
268
273
|
# Give a name and a record type, try to match a rule and use it for processing the given arguments.
|
269
274
|
def process(name, resource_class, *args)
|
270
|
-
@logger.debug "Searching for #{name} #{resource_class.name}"
|
275
|
+
@logger.debug {"Searching for #{name} #{resource_class.name}"}
|
271
276
|
|
272
277
|
@rules.each do |rule|
|
273
|
-
@logger.debug "Checking rule #{rule}..."
|
278
|
+
@logger.debug {"Checking rule #{rule}..."}
|
274
279
|
|
275
280
|
catch (:next) do
|
276
281
|
# If the rule returns true, we assume that it was successful and no further rules need to be evaluated.
|
data/lib/rubydns/transaction.rb
CHANGED
data/lib/rubydns/version.rb
CHANGED
data/lib/rubydns.rb
CHANGED
data/rubydns.gemspec
CHANGED
@@ -33,6 +33,6 @@ Gem::Specification.new do |spec|
|
|
33
33
|
spec.add_dependency("eventmachine", "~> 1.0.0")
|
34
34
|
|
35
35
|
spec.add_development_dependency "bundler", "~> 1.3"
|
36
|
-
spec.add_development_dependency "process-daemon", "~> 0.5.
|
36
|
+
spec.add_development_dependency "process-daemon", "~> 0.5.3"
|
37
37
|
spec.add_development_dependency "rake"
|
38
38
|
end
|
@@ -30,10 +30,6 @@ INTERFACES = [
|
|
30
30
|
]
|
31
31
|
|
32
32
|
class DroppingDaemon < Process::Daemon
|
33
|
-
# You can specify a specific directory to use for run-time information (pid, logs, etc):
|
34
|
-
# @@base_directory = File.expand_path("../", __FILE__)
|
35
|
-
# @@base_directory = "/var"
|
36
|
-
|
37
33
|
Name = Resolv::DNS::Name
|
38
34
|
IN = Resolv::DNS::Resource::IN
|
39
35
|
R = RubyDNS::Resolver.new(RubyDNS::System::nameservers)
|
data/test/examples/geoip-dns.rb
CHANGED
@@ -35,10 +35,6 @@ INTERFACES = [
|
|
35
35
|
# For more information, please see http://www.maxmind.com/en/geolite and http://geoip.rubyforge.org
|
36
36
|
|
37
37
|
class GeoIPDNSDaemon < Process::Daemon
|
38
|
-
# You can specify a specific directory to use for run-time information (pid, logs, etc):
|
39
|
-
# @@base_directory = File.expand_path("../", __FILE__)
|
40
|
-
# @@base_directory = "/var"
|
41
|
-
|
42
38
|
Name = Resolv::DNS::Name
|
43
39
|
IN = Resolv::DNS::Resource::IN
|
44
40
|
R = RubyDNS::Resolver.new(RubyDNS::System::nameservers)
|
@@ -48,7 +44,7 @@ class GeoIPDNSDaemon < Process::Daemon
|
|
48
44
|
RubyDNS::run_server(:listen => INTERFACES) do
|
49
45
|
match(//, IN::A) do |transaction|
|
50
46
|
location = nil
|
51
|
-
peer = transaction.options[:
|
47
|
+
peer = transaction.options[:connection].peername[0]
|
52
48
|
|
53
49
|
if peer
|
54
50
|
logger.debug "Looking up geographic information for peer #{peer}"
|
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'benchmark'
|
4
|
+
require 'rubydns'
|
5
|
+
|
6
|
+
Benchmark.bm(20) do |x|
|
7
|
+
DOMAINS = (1..1000).collect do |i|
|
8
|
+
"domain#{i}.local"
|
9
|
+
end
|
10
|
+
|
11
|
+
resolved = {}
|
12
|
+
|
13
|
+
x.report("RubyDNS::Resolver") do
|
14
|
+
resolver = RubyDNS::Resolver.new([[:udp, '127.0.0.1', 5300]])
|
15
|
+
|
16
|
+
# Number of requests remaining since this is an asynchronous event loop:
|
17
|
+
pending = DOMAINS.size
|
18
|
+
|
19
|
+
EventMachine::run do
|
20
|
+
DOMAINS.each do |domain|
|
21
|
+
resolver.addresses_for(domain) do |addresses|
|
22
|
+
resolved[domain] = addresses
|
23
|
+
|
24
|
+
EventMachine::stop if (pending -= 1) == 0
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
File.open("local.zone", "w") do |f|
|
4
|
+
f.write(DATA.read)
|
5
|
+
|
6
|
+
(1..5_000).each do |i|
|
7
|
+
f.puts "domain#{i} IN A #{69}.#{(i >> 16)%256}.#{(i >> 8)%256}.#{i%256}"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
__END__
|
12
|
+
;
|
13
|
+
; BIND data file for local loopback interface
|
14
|
+
;
|
15
|
+
$TTL 604800
|
16
|
+
@ IN SOA ns.local. postmaster.localhost (
|
17
|
+
2 ; Serial
|
18
|
+
604800 ; Refresh
|
19
|
+
86400 ; Retry
|
20
|
+
2419200 ; Expire
|
21
|
+
604800 ) ; Negative Cache TTL
|
22
|
+
;
|
23
|
+
local. IN NS ns.local.
|
24
|
+
ns.local. IN A 127.0.0.1
|
25
|
+
|