rubydns 2.0.2 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/lib/rubydns/rule.rb +92 -0
- data/lib/rubydns/server.rb +76 -0
- data/lib/rubydns/version.rb +5 -20
- data/lib/rubydns.rb +29 -28
- data/license.md +37 -0
- data/readme.md +33 -0
- data/releases.md +8 -0
- data.tar.gz.sig +0 -0
- metadata +61 -108
- metadata.gz.sig +1 -0
- data/.gitignore +0 -26
- data/.rspec +0 -4
- data/.simplecov +0 -15
- data/.travis.yml +0 -13
- data/.yardopts +0 -1
- data/Gemfile +0 -13
- data/README.md +0 -167
- data/Rakefile +0 -6
- data/bin/rubydns-check +0 -374
- data/examples/Gemfile +0 -9
- data/examples/README.md +0 -137
- data/examples/basic-dns.rb +0 -24
- data/examples/cname.rb +0 -25
- data/examples/flakey-dns.rb +0 -72
- data/examples/fortune-dns.rb +0 -106
- data/examples/geoip-dns.rb +0 -115
- data/examples/simple.rb +0 -25
- data/examples/soa-dns.rb +0 -82
- data/examples/test-dns-1.rb +0 -83
- data/examples/test-dns-2.rb +0 -83
- data/examples/wikipedia-dns.rb +0 -121
- data/lib/rubydns/rule_based_server.rb +0 -180
- data/rubydns.gemspec +0 -28
- data/spec/rubydns/daemon_spec.rb +0 -114
- data/spec/rubydns/hosts.txt +0 -2
- data/spec/rubydns/injected_supervisor_spec.rb +0 -64
- data/spec/rubydns/passthrough_spec.rb +0 -85
- data/spec/rubydns/rules_spec.rb +0 -74
- data/spec/spec_helper.rb +0 -30
data/README.md
DELETED
@@ -1,167 +0,0 @@
|
|
1
|
-
# RubyDNS
|
2
|
-
|
3
|
-
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.
|
4
|
-
|
5
|
-
[](https://travis-ci.org/socketry/rubydns)
|
6
|
-
[](https://codeclimate.com/github/socketry/rubydns)
|
7
|
-
[](https://coveralls.io/r/socketry/rubydns)
|
8
|
-
[](https://gitter.im/socketry/rubydns)
|
9
|
-
|
10
|
-
[](https://www.youtube.com/watch?v=B9ygq0xh3HQ&feature=youtu.be&hd=1 "RubyDNS Introduction")
|
11
|
-
|
12
|
-
## Installation
|
13
|
-
|
14
|
-
Add this line to your application's Gemfile:
|
15
|
-
|
16
|
-
gem 'rubydns'
|
17
|
-
|
18
|
-
And then execute:
|
19
|
-
|
20
|
-
$ bundle
|
21
|
-
|
22
|
-
Or install it yourself as:
|
23
|
-
|
24
|
-
$ gem install rubydns
|
25
|
-
|
26
|
-
## Usage
|
27
|
-
|
28
|
-
There are [lots of examples available](examples/README.md) in the `examples/` directory.
|
29
|
-
|
30
|
-
### Basic DNS Server
|
31
|
-
|
32
|
-
Here is the code from `examples/basic-dns.rb`:
|
33
|
-
|
34
|
-
```ruby
|
35
|
-
#!/usr/bin/env ruby
|
36
|
-
require 'rubydns'
|
37
|
-
|
38
|
-
INTERFACES = [
|
39
|
-
[:udp, "0.0.0.0", 5300],
|
40
|
-
[:tcp, "0.0.0.0", 5300],
|
41
|
-
]
|
42
|
-
|
43
|
-
IN = Resolv::DNS::Resource::IN
|
44
|
-
|
45
|
-
# Use upstream DNS for name resolution.
|
46
|
-
UPSTREAM = RubyDNS::Resolver.new([[:udp, "8.8.8.8", 53], [:tcp, "8.8.8.8", 53]])
|
47
|
-
|
48
|
-
# Start the RubyDNS server
|
49
|
-
RubyDNS::run_server(INTERFACES) do
|
50
|
-
match(%r{test.local}, IN::A) do |transaction|
|
51
|
-
transaction.respond!("10.0.0.80")
|
52
|
-
end
|
53
|
-
|
54
|
-
# Default DNS handler
|
55
|
-
otherwise do |transaction|
|
56
|
-
transaction.passthrough!(UPSTREAM)
|
57
|
-
end
|
58
|
-
end
|
59
|
-
```
|
60
|
-
|
61
|
-
Start the server using `RUBYOPT=-w ./examples/basic-dns.rb`. You can then test it using dig:
|
62
|
-
|
63
|
-
$ dig @localhost -p 5300 test.local
|
64
|
-
$ dig @localhost -p 5300 google.com
|
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
|
-
|
70
|
-
### Custom Servers
|
71
|
-
|
72
|
-
It is possible to create and integrate your own custom servers, however this functionality has now moved to [`Async::DNS::Server`](https://github.com/socketry/async-dns).
|
73
|
-
|
74
|
-
```ruby
|
75
|
-
class MyServer < Async::DNS::Server
|
76
|
-
def process(name, resource_class, transaction)
|
77
|
-
transaction.fail!(:NXDomain)
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
Async::Reactor.run do
|
82
|
-
task = MyServer.new.run
|
83
|
-
|
84
|
-
# ... do other things, e.g. run specs/tests
|
85
|
-
|
86
|
-
# Shut down the server manually if required, otherwise it will run indefinitely.
|
87
|
-
# task.stop
|
88
|
-
end
|
89
|
-
```
|
90
|
-
|
91
|
-
This is the best way to integrate with other projects.
|
92
|
-
|
93
|
-
## Performance
|
94
|
-
|
95
|
-
**Due to changes in the underlying code, there have been some very minor performance regressions. The numbers below will be updated in due course.**
|
96
|
-
|
97
|
-
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).
|
98
|
-
|
99
|
-
### Server
|
100
|
-
|
101
|
-
The performance is on the same magnitude as `bind9`. Some basic benchmarks resolving 1000 names concurrently, repeated 5 times, using `RubyDNS::Resolver` gives the following:
|
102
|
-
|
103
|
-
user system total real
|
104
|
-
RubyDNS::Server 4.280000 0.450000 4.730000 ( 4.854862)
|
105
|
-
Bind9 4.970000 0.520000 5.490000 ( 5.541213)
|
106
|
-
|
107
|
-
These benchmarks are included in the unit tests. To test bind9 performance, it must be installed and `which named` must return the executable.
|
108
|
-
|
109
|
-
### Resolver
|
110
|
-
|
111
|
-
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:
|
112
|
-
|
113
|
-
user system total real
|
114
|
-
RubyDNS::Resolver 0.020000 0.010000 0.030000 ( 0.030507)
|
115
|
-
Resolv::DNS 0.070000 0.010000 0.080000 ( 1.465975)
|
116
|
-
|
117
|
-
These benchmarks are included in the unit tests.
|
118
|
-
|
119
|
-
### DNSSEC support
|
120
|
-
|
121
|
-
DNSSEC is currently not supported and is [unlikely to be supported in the future](http://sockpuppet.org/blog/2015/01/15/against-dnssec/).
|
122
|
-
|
123
|
-
## Contributing
|
124
|
-
|
125
|
-
1. Fork it
|
126
|
-
2. Create your feature branch (`git checkout -b my-new-feature`)
|
127
|
-
3. Commit your changes (`git commit -am 'Add some feature'`)
|
128
|
-
4. Push to the branch (`git push origin my-new-feature`)
|
129
|
-
5. Create new Pull Request
|
130
|
-
|
131
|
-
### Desired Features
|
132
|
-
|
133
|
-
* Support for more features of DNS such as zone transfer.
|
134
|
-
* Support reverse records more easily.
|
135
|
-
* Some kind of system level integration, e.g. registering a DNS server with the currently running system resolver.
|
136
|
-
|
137
|
-
## See Also
|
138
|
-
|
139
|
-
The majority of this gem is now implemented by `async-dns`.
|
140
|
-
|
141
|
-
- [async-io](https://github.com/socketry/async-io) — Asynchronous networking and sockets.
|
142
|
-
- [async-dns](https://github.com/socketry/async-dns) — Asynchronous DNS resolver and server.
|
143
|
-
- [async-rspec](https://github.com/socketry/async-rspec) — Shared contexts for running async specs.
|
144
|
-
|
145
|
-
## License
|
146
|
-
|
147
|
-
Released under the MIT license.
|
148
|
-
|
149
|
-
Copyright, 2017, by [Samuel G. D. Williams](http://www.codeotaku.com/samuel-williams).
|
150
|
-
|
151
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
152
|
-
of this software and associated documentation files (the "Software"), to deal
|
153
|
-
in the Software without restriction, including without limitation the rights
|
154
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
155
|
-
copies of the Software, and to permit persons to whom the Software is
|
156
|
-
furnished to do so, subject to the following conditions:
|
157
|
-
|
158
|
-
The above copyright notice and this permission notice shall be included in
|
159
|
-
all copies or substantial portions of the Software.
|
160
|
-
|
161
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
162
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
163
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
164
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
165
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
166
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
167
|
-
THE SOFTWARE.
|
data/Rakefile
DELETED
data/bin/rubydns-check
DELETED
@@ -1,374 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
# Copyright, 2009, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
3
|
-
#
|
4
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
-
# of this software and associated documentation files (the "Software"), to deal
|
6
|
-
# in the Software without restriction, including without limitation the rights
|
7
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
-
# copies of the Software, and to permit persons to whom the Software is
|
9
|
-
# furnished to do so, subject to the following conditions:
|
10
|
-
#
|
11
|
-
# The above copyright notice and this permission notice shall be included in
|
12
|
-
# all copies or substantial portions of the Software.
|
13
|
-
#
|
14
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
20
|
-
# THE SOFTWARE.
|
21
|
-
|
22
|
-
# Pulls down DNS data from old-dns
|
23
|
-
# rd-dns-check -s old-dns.mydomain.com -d mydomain.com. -f old-dns.yml
|
24
|
-
|
25
|
-
# Check data against old-dns
|
26
|
-
# rd-dns-check -s old-dns.mydomain.com -d mydomain.com. -c old-dns.yml
|
27
|
-
|
28
|
-
# Check data against new DNS server
|
29
|
-
# rd-dns-check -s 10.0.0.36 -d mydomain.com. -c old-dns.yml
|
30
|
-
|
31
|
-
require 'yaml'
|
32
|
-
require 'optparse'
|
33
|
-
require 'set'
|
34
|
-
|
35
|
-
class DNSRecord
|
36
|
-
def initialize(arr)
|
37
|
-
@record = arr
|
38
|
-
normalize
|
39
|
-
end
|
40
|
-
|
41
|
-
def normalize
|
42
|
-
@record[0] = @record[0].downcase
|
43
|
-
@record[1] = @record[1].upcase
|
44
|
-
@record[2] = @record[2].upcase
|
45
|
-
@record[3] = @record[3].downcase
|
46
|
-
end
|
47
|
-
|
48
|
-
def hostname
|
49
|
-
@record[0]
|
50
|
-
end
|
51
|
-
|
52
|
-
def klass
|
53
|
-
@record[1]
|
54
|
-
end
|
55
|
-
|
56
|
-
def type
|
57
|
-
@record[2]
|
58
|
-
end
|
59
|
-
|
60
|
-
def value
|
61
|
-
@record[3]
|
62
|
-
end
|
63
|
-
|
64
|
-
def is_address?
|
65
|
-
["A", "AAAA"].include?(type)
|
66
|
-
end
|
67
|
-
|
68
|
-
def is_cname?
|
69
|
-
return type == "CNAME"
|
70
|
-
end
|
71
|
-
|
72
|
-
def to_s
|
73
|
-
"#{hostname.ljust(50)} #{klass.rjust(4)} #{type.rjust(5)} #{value}"
|
74
|
-
end
|
75
|
-
|
76
|
-
def key
|
77
|
-
"#{hostname}:#{klass}:#{type}".downcase
|
78
|
-
end
|
79
|
-
|
80
|
-
def to_a
|
81
|
-
@record
|
82
|
-
end
|
83
|
-
|
84
|
-
def == other
|
85
|
-
return @record == other.to_a
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
def dig(dns_server, cmd, exclude = ["TXT", "HINFO", "SOA", "NS"])
|
90
|
-
records = []
|
91
|
-
|
92
|
-
IO.popen("dig @#{dns_server} +nottlid +nocmd +noall +answer " + cmd) do |p|
|
93
|
-
p.each do |line|
|
94
|
-
r = line.chomp.split(/\s/, 4)
|
95
|
-
|
96
|
-
next if exclude.include?(r[2])
|
97
|
-
|
98
|
-
records << DNSRecord.new(r)
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
return records
|
103
|
-
end
|
104
|
-
|
105
|
-
def retrieve_records(dns_server, dns_root)
|
106
|
-
return dig(dns_server, "#{dns_root} AXFR")
|
107
|
-
end
|
108
|
-
|
109
|
-
def resolve_hostname(dns_server, hostname)
|
110
|
-
return dig(dns_server, "#{hostname} A").first
|
111
|
-
end
|
112
|
-
|
113
|
-
def resolve_address(dns_server, address)
|
114
|
-
return dig(dns_server, "-x #{address}").first
|
115
|
-
end
|
116
|
-
|
117
|
-
def print_summary(records, errors, okay, &block)
|
118
|
-
puts "[ Summary ]".center(72, "=")
|
119
|
-
puts "Checked #{records.size} record(s). #{errors} errors."
|
120
|
-
if errors == 0
|
121
|
-
puts "Everything seemed okay."
|
122
|
-
else
|
123
|
-
puts "The following records are okay:"
|
124
|
-
okay.each do |r|
|
125
|
-
if block_given?
|
126
|
-
yield r
|
127
|
-
else
|
128
|
-
puts "".rjust(12) + r.to_s
|
129
|
-
end
|
130
|
-
end
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
# Resolve hostnames to IP address "A" or "AAAA" records.
|
135
|
-
# Works through CNAME records in order to find out the final
|
136
|
-
# address if possible. Checks for loops in CNAME records.
|
137
|
-
def resolve_addresses(records)
|
138
|
-
addresses = {}
|
139
|
-
cnames = {}
|
140
|
-
|
141
|
-
# Extract all hostname -> ip address mappings
|
142
|
-
records.each do |r|
|
143
|
-
if r.is_address?
|
144
|
-
addresses[r.hostname] = r
|
145
|
-
elsif r.is_cname?
|
146
|
-
cnames[r.hostname] = r
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
cnames.each do |hostname, r|
|
151
|
-
q = r
|
152
|
-
trail = []
|
153
|
-
failed = false
|
154
|
-
|
155
|
-
# Keep track of CNAME records to avoid loops
|
156
|
-
while q.is_cname?
|
157
|
-
trail << q
|
158
|
-
q = cnames[q.value] || addresses[q.value]
|
159
|
-
|
160
|
-
# Q could be nil at this point, which means there was no address record
|
161
|
-
# Q could be already part of the trail, which means there was a loop
|
162
|
-
if q == nil || trail.include?(q)
|
163
|
-
failed = true
|
164
|
-
break
|
165
|
-
end
|
166
|
-
end
|
167
|
-
|
168
|
-
if failed
|
169
|
-
q = trail.last
|
170
|
-
puts "*** Warning: CNAME record #{hostname} does not point to actual address!"
|
171
|
-
trail.each_with_index do |r, idx|
|
172
|
-
puts idx.to_s.rjust(10) + ": " + r.to_s
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
|
-
addresses[r.hostname] = q
|
177
|
-
end
|
178
|
-
|
179
|
-
return addresses, cnames
|
180
|
-
end
|
181
|
-
|
182
|
-
def check_reverse(records, dns_server)
|
183
|
-
errors = 0
|
184
|
-
okay = []
|
185
|
-
|
186
|
-
puts "[ Checking Reverse Lookups ]".center(72, "=")
|
187
|
-
|
188
|
-
records.each do |r|
|
189
|
-
next unless r.is_address?
|
190
|
-
|
191
|
-
sr = resolve_address(dns_server, r.value)
|
192
|
-
|
193
|
-
if sr == nil
|
194
|
-
puts "*** Could not resolve host"
|
195
|
-
puts "".rjust(12) + r.to_s
|
196
|
-
errors += 1
|
197
|
-
elsif r.hostname != sr.value
|
198
|
-
puts "*** Hostname does not match"
|
199
|
-
puts "Primary: ".rjust(12) + r.to_s
|
200
|
-
puts "Secondary: ".rjust(12) + sr.to_s
|
201
|
-
errors += 1
|
202
|
-
else
|
203
|
-
okay << [r, sr]
|
204
|
-
end
|
205
|
-
end
|
206
|
-
|
207
|
-
print_summary(records, errors, okay) do |r|
|
208
|
-
puts "Primary:".rjust(12) + r[0].to_s
|
209
|
-
puts "Secondary:".rjust(12) + r[1].to_s
|
210
|
-
end
|
211
|
-
end
|
212
|
-
|
213
|
-
def ping_records(records)
|
214
|
-
addresses, cnames = resolve_addresses(records)
|
215
|
-
|
216
|
-
errors = 0
|
217
|
-
okay = []
|
218
|
-
|
219
|
-
puts "[ Pinging Records ]".center(72, "=")
|
220
|
-
|
221
|
-
addresses.each do |hostname, r|
|
222
|
-
ping = "ping -c 5 -t 5 -i 1 -o #{r.value} > /dev/null"
|
223
|
-
|
224
|
-
system(ping)
|
225
|
-
|
226
|
-
if $?.exitstatus == 0
|
227
|
-
okay << r
|
228
|
-
else
|
229
|
-
puts "*** Could not ping host #{hostname.dump}: #{ping.dump}"
|
230
|
-
puts "".rjust(12) + r.to_s
|
231
|
-
errors += 1
|
232
|
-
end
|
233
|
-
end
|
234
|
-
|
235
|
-
print_summary(records, errors, okay)
|
236
|
-
end
|
237
|
-
|
238
|
-
def query_records(primary, secondary_server)
|
239
|
-
addresses, cnames = resolve_addresses(primary)
|
240
|
-
|
241
|
-
okay = []
|
242
|
-
errors = 0
|
243
|
-
|
244
|
-
primary.each do |r|
|
245
|
-
sr = resolve_hostname(secondary_server, r.hostname)
|
246
|
-
|
247
|
-
if sr == nil
|
248
|
-
puts "*** Could not resolve hostname #{r.hostname.dump}"
|
249
|
-
puts "Primary: ".rjust(12) + r.to_s
|
250
|
-
|
251
|
-
rsr = resolve_address(secondary_server, (addresses[r.value] || r).value)
|
252
|
-
puts "Address: ".rjust(12) + rsr.to_s if rsr
|
253
|
-
|
254
|
-
errors += 1
|
255
|
-
elsif sr.value != r.value
|
256
|
-
ra = addresses[r.value] if r.is_cname?
|
257
|
-
sra = addresses[sr.value] if sr.is_cname?
|
258
|
-
|
259
|
-
if (sra || sr).value != (ra || r).value
|
260
|
-
puts "*** IP Address does not match"
|
261
|
-
puts "Primary: ".rjust(12) + r.to_s
|
262
|
-
puts "Resolved: ".rjust(12) + ra.to_s if ra
|
263
|
-
puts "Secondary: ".rjust(12) + sr.to_s
|
264
|
-
puts "Resolved: ".rjust(12) + sra.to_s if sra
|
265
|
-
errors += 1
|
266
|
-
end
|
267
|
-
else
|
268
|
-
okay << r
|
269
|
-
end
|
270
|
-
end
|
271
|
-
|
272
|
-
print_summary(primary, errors, okay)
|
273
|
-
end
|
274
|
-
|
275
|
-
def check_records(primary, secondary)
|
276
|
-
s = {}
|
277
|
-
okay = []
|
278
|
-
errors = 0
|
279
|
-
|
280
|
-
secondary.each do |r|
|
281
|
-
s[r.key] = r
|
282
|
-
end
|
283
|
-
|
284
|
-
puts "[ Checking Records ]".center(72, "=")
|
285
|
-
|
286
|
-
primary.each do |r|
|
287
|
-
sr = s[r.key]
|
288
|
-
|
289
|
-
if sr == nil
|
290
|
-
puts "*** Could not find record"
|
291
|
-
puts "Primary: ".rjust(12) + r.to_s
|
292
|
-
errors += 1
|
293
|
-
elsif sr != r
|
294
|
-
puts "*** Records are different"
|
295
|
-
puts "Primary: ".rjust(12) + r.to_s
|
296
|
-
puts "Secondary: ".rjust(12) + sr.to_s
|
297
|
-
errors += 1
|
298
|
-
else
|
299
|
-
okay << r
|
300
|
-
end
|
301
|
-
end
|
302
|
-
|
303
|
-
print_summary(primary, errors, okay)
|
304
|
-
end
|
305
|
-
|
306
|
-
OPTIONS = {
|
307
|
-
:DNSServer => nil,
|
308
|
-
:DNSRoot => ".",
|
309
|
-
}
|
310
|
-
|
311
|
-
ARGV.options do |o|
|
312
|
-
script_name = File.basename($0)
|
313
|
-
|
314
|
-
o.set_summary_indent(' ')
|
315
|
-
o.banner = "Usage: #{script_name} [options]"
|
316
|
-
o.define_head "This script is designed to test and check DNS servers."
|
317
|
-
|
318
|
-
o.on("-s ns.my.domain.", "--server ns.my.domain.", String, "The DNS server to query.") { |host| OPTIONS[:DNSServer] = host }
|
319
|
-
o.on("-d my.domain.", "--domain my.domain.", String, "The DNS zone to transfer/test.") { |host| OPTIONS[:DNSRoot] = host }
|
320
|
-
|
321
|
-
o.on("-f output.yml", "--fetch output.yml", String, "Pull down a list of hosts. Filters TXT and HINFO records. DNS transfers must be enabled.") { |f|
|
322
|
-
records = retrieve_records(OPTIONS[:DNSServer], OPTIONS[:DNSRoot])
|
323
|
-
|
324
|
-
output = (f ? File.open(f, "w") : STDOUT)
|
325
|
-
|
326
|
-
output.write(YAML::dump(records))
|
327
|
-
|
328
|
-
puts "#{records.size} record(s) retrieved."
|
329
|
-
}
|
330
|
-
|
331
|
-
o.on("-c input.yml", "--check input.yml", String, "Check that the DNS server returns results as specified by the file.") { |f|
|
332
|
-
input = (f ? File.open(f) : STDIN)
|
333
|
-
|
334
|
-
master_records = YAML::load(input.read)
|
335
|
-
secondary_records = retrieve_records(OPTIONS[:DNSServer], OPTIONS[:DNSRoot])
|
336
|
-
|
337
|
-
check_records(master_records, secondary_records)
|
338
|
-
}
|
339
|
-
|
340
|
-
o.on("-q input.yml", "--query input.yml", String, "Query the remote DNS server with all hostnames in the given file, and checks the IP addresses are consistent.") { |f|
|
341
|
-
input = (f ? File.open(f) : STDIN)
|
342
|
-
|
343
|
-
master_records = YAML::load(input.read)
|
344
|
-
|
345
|
-
query_records(master_records, OPTIONS[:DNSServer])
|
346
|
-
}
|
347
|
-
|
348
|
-
o.on("-p input.yml", "--ping input.yml", String, "Ping all hosts to check if they are available or not.") { |f|
|
349
|
-
input = (f ? File.open(f) : STDIN)
|
350
|
-
|
351
|
-
master_records = YAML::load(input.read)
|
352
|
-
|
353
|
-
ping_records(master_records)
|
354
|
-
}
|
355
|
-
|
356
|
-
o.on("-r input.yml", "--reverse input.yml", String, "Check that all address records have appropriate reverse entries.") { |f|
|
357
|
-
input = (f ? File.open(f) : STDIN)
|
358
|
-
|
359
|
-
master_records = YAML::load(input.read)
|
360
|
-
|
361
|
-
check_reverse(master_records, OPTIONS[:DNSServer])
|
362
|
-
}
|
363
|
-
|
364
|
-
o.separator ""
|
365
|
-
o.separator "Help and Copyright information"
|
366
|
-
|
367
|
-
o.on_tail("--copy", "Display copyright information") {
|
368
|
-
puts "#{script_name}. Copyright (c) 2009, 2011 Samuel Williams. Released under the MIT license."
|
369
|
-
puts "See http://www.oriontransfer.co.nz/ for more information."
|
370
|
-
exit
|
371
|
-
}
|
372
|
-
|
373
|
-
o.on_tail("-h", "--help", "Show this help message.") { puts o; exit }
|
374
|
-
end.parse!
|
data/examples/Gemfile
DELETED
data/examples/README.md
DELETED
@@ -1,137 +0,0 @@
|
|
1
|
-
# RubyDNS Examples
|
2
|
-
|
3
|
-
This directory contains several examples of customized RubyDNS servers,
|
4
|
-
intended to demonstrate how RubyDNS can be easily customized to specific
|
5
|
-
needs.
|
6
|
-
|
7
|
-
## FlakeyDNS (flakey-dns.rb)
|
8
|
-
|
9
|
-
A DNS server that selectively drops queries based on the requested domain name. Queries for domains that match specified regular expressions (like 'microsoft.com' or 'sco.com') return NXDomain, while all other queries are passed to upstream resolvers.
|
10
|
-
|
11
|
-
By default this server will listen for UDP requests on port 5300 and does not need to be started as root.
|
12
|
-
|
13
|
-
To start the server, ensure that you're in the examples subdirectory and type
|
14
|
-
|
15
|
-
bundle
|
16
|
-
bundle exec ./flakey-dns.rb start
|
17
|
-
|
18
|
-
To see it in action you can then query some domains. For example,
|
19
|
-
|
20
|
-
dig @localhost -p 5300 slashdot.org -t A
|
21
|
-
dig @localhost -p 5300 www.hackernews.com -t A
|
22
|
-
|
23
|
-
give the correct results. But
|
24
|
-
|
25
|
-
dig @localhost -p 5300 microsoft.com -t A
|
26
|
-
dig @localhost -p 5300 www.microsoft.com -t A
|
27
|
-
dig @localhost -p 5300 www.microsoft.com
|
28
|
-
|
29
|
-
all give an NXDomain result.
|
30
|
-
|
31
|
-
## FortuneDNS (fortune-dns.rb)
|
32
|
-
|
33
|
-
A DNS server that allows a client to generate fortunes and fetch them with subsequent requests. The server
|
34
|
-
'remembers' the fortunes it generates, and can serve them to future requests. The reason for this is because most fortunes won't fit over UDP (maximum size 512 bytes) and the client will request the same fortune via TCP.
|
35
|
-
|
36
|
-
You will need to have the `fortune` app installed on your system. It comes installed by default on
|
37
|
-
most Linux distributions, and can be installed on a Mac with Homebrew by typing:
|
38
|
-
|
39
|
-
# Homebrew
|
40
|
-
brew install fortune
|
41
|
-
# MacPorts
|
42
|
-
sudo port install fortune
|
43
|
-
# Arch Linux
|
44
|
-
sudo pacman -S fortune-mod
|
45
|
-
|
46
|
-
By default this server will listen for UDP and TCP requests on port 53, and needs to be started as root. It
|
47
|
-
assumes the existence of a user 'daemon', as whom the process will run. If such a user doesn't exist on your
|
48
|
-
system, you will need to either create such a user or update the script to use a user that exists on your
|
49
|
-
system.
|
50
|
-
|
51
|
-
To start the server, ensure that you're in the examples subdirectory and type
|
52
|
-
|
53
|
-
bundle
|
54
|
-
sudo bundle exec ./fortune-dns.rb start
|
55
|
-
|
56
|
-
To create a new fortune type
|
57
|
-
|
58
|
-
dig @localhost fortune -t TXT
|
59
|
-
|
60
|
-
This will result in an DNS answer that looks something like this:
|
61
|
-
|
62
|
-
fortune. 0 IN TXT "Text Size: 714 Byte Size: 714"
|
63
|
-
fortune. 0 IN CNAME 32bf3bf2b0a2255f2df00ed9e95c8185.fortune.
|
64
|
-
|
65
|
-
Take the CNAME from this result and query it. For our example this would be:
|
66
|
-
|
67
|
-
dig @localhost 32bf3bf2b0a2255f2df00ed9e95c8185.fortune -t TXT
|
68
|
-
|
69
|
-
And your answer will be a fortune.
|
70
|
-
|
71
|
-
You can also generate a 'short' fortune by typing the following:
|
72
|
-
|
73
|
-
dig @localhost short.fortune -t TXT
|
74
|
-
|
75
|
-
or view the fortune stats with:
|
76
|
-
|
77
|
-
dig @localhost stats.fortune -t TXT
|
78
|
-
|
79
|
-
## GeoIPDNS (geoip-dns.rb)
|
80
|
-
|
81
|
-
A sample DNS daemon that demonstrates how to use RubyDNS to build responses
|
82
|
-
that vary based on the geolocation of the requesting peer. Clients of this
|
83
|
-
server who request A records will get an answer IP address based on the
|
84
|
-
continent of the client IP address.
|
85
|
-
|
86
|
-
Please note that use of this example requires that the peer have a public
|
87
|
-
IP address. IP addresses on private networks or the localhost IP (127.0.0.1)
|
88
|
-
cannot be resolved to a location, and so will always yield the unknown result.
|
89
|
-
|
90
|
-
This daemon requires the file downloaded from
|
91
|
-
[MaxMind](http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz)
|
92
|
-
For more information on the GeoIP library, please click [here](http://www.maxmind.com/en/geolite)
|
93
|
-
or [here](https://github.com/cjheath/geoip). This file should be unzipped and placed in the
|
94
|
-
examples root directory, i.e. `examples/GeoLiteCountry.dat`.
|
95
|
-
|
96
|
-
By default this server will listen for UDP requests on port 5300 and does not need to be started as root.
|
97
|
-
|
98
|
-
To start the server, ensure that you're in the examples subdirectory and type
|
99
|
-
|
100
|
-
bundle
|
101
|
-
sudo bundle exec ./geoip-dns.rb start
|
102
|
-
|
103
|
-
To see the behavior, run a DNS query against the server where you are running the GeoIPDNS
|
104
|
-
daemon. Depending on the continent to which the client machine's IP address is mapped,
|
105
|
-
you will receive a different IP address in the answer section:
|
106
|
-
|
107
|
-
Africa - 1.1.1.1
|
108
|
-
Antarctica - 1.1.2.1
|
109
|
-
Asia - 1.1.3.1
|
110
|
-
Europe - 1.1.4.1
|
111
|
-
North America - 1.1.5.1
|
112
|
-
Oceania - 1.1.6.1
|
113
|
-
South America - 1.1.7.1
|
114
|
-
|
115
|
-
## WikipediaDNS (wikipedia-dns.rb)
|
116
|
-
|
117
|
-
A DNS server that queries Wikipedia and returns summaries for specifically crafted queries.
|
118
|
-
|
119
|
-
By default this server will listen for UDP and TCP requests on port 53, and needs to be started as root. It
|
120
|
-
assumes the existence of a user 'daemon', as whom the process will run. If such a user doesn't exist on your
|
121
|
-
system, you will need to either create such a user or update the script to use a user that exists on your
|
122
|
-
system.
|
123
|
-
|
124
|
-
To start the server, ensure that you're in the examples subdirectory and type
|
125
|
-
|
126
|
-
bundle
|
127
|
-
sudo bundle exec ./wikipedia-dns.rb start
|
128
|
-
|
129
|
-
To query Wikipedia, pick a term - say, 'helium' - and make a DNS query like
|
130
|
-
|
131
|
-
dig @localhost helium.wikipedia -t TXT
|
132
|
-
|
133
|
-
The answer section should contain the summary for this topic from Wikipedia
|
134
|
-
|
135
|
-
helium.wikipedia. 86400 IN TXT "Helium is a chemical element with symbol He and atomic number 2. It is a colorless, odorless, tasteless, non-toxic, inert, monatomic gas that heads the noble gas group in the periodic table. Its boiling and melting points are the lowest among the elements" " and it exists only as a gas except in extreme conditions."
|
136
|
-
|
137
|
-
Long blocks of text cannot be easily replied in DNS as they must be chunked into segments at most 255 bytes. Long replies must be sent back using TCP.
|