rubydns 0.9.0 → 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1835f3164db6b9d4a9bf06f1b484be87abfee77b
4
- data.tar.gz: 53f3a898b8cf9c5b4ecda1e09e061caeb48ee4c0
3
+ metadata.gz: 4deb19b1b3f2428b941ec102d2cc15a640ad8211
4
+ data.tar.gz: 13c3d5e62e811bbb25c2eee5123195c608b30303
5
5
  SHA512:
6
- metadata.gz: 7436649377952b0e4bcbe7e8edb0108b4f6cde35341c3f5f269baa0874e2c5c6eeeb13000ebde28b8035d40c3d6b62819bf3aa591c86b043528b2249b6bdc58f
7
- data.tar.gz: db91f39c37441efb5092502e49a9ec3851f356dd0d2f89710ab6eb2464760cfa5aa73d47617b11541b69a8c0bd393377632cef534189099623a02fdd4957f441
6
+ metadata.gz: 532c64c0de7e2893704ff62e1cd523a155dacbc42e332aef20c44723d5fce08218cbfa371cb458049a94cf30a4d885b3787a8ee1ee2b525f21afa7d4dad5e0d0
7
+ data.tar.gz: 250674b3f8554f7ceb493fdd0b0f7a4b8d1cee949ce27b16276db5ef83fe5ab2868fce3a8e4037976f8a307538bf116b0775271a6b07445f29f909448f4b3c4d
data/.gitignore CHANGED
@@ -1,17 +1,26 @@
1
1
  *.gem
2
2
  *.rbc
3
- .bundle
4
- .config
5
- .yardoc
6
- Gemfile.lock
7
- InstalledFiles
8
- _yardoc
9
- coverage
10
- doc/
11
- lib/bundler/man
12
- pkg
13
- rdoc
14
- spec/reports
15
- test/tmp
16
- test/version_tmp
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /test/tmp/
9
+ /test/version_tmp/
17
10
  tmp
11
+
12
+ /.yardoc/
13
+ /_yardoc/
14
+ /doc/
15
+ /rdoc/
16
+
17
+ /.bundle/
18
+ /lib/bundler/man/
19
+
20
+ Gemfile.lock
21
+ .ruby-version
22
+ .ruby-gemset
23
+
24
+ /examples/log
25
+ /examples/run
26
+ /spec/rubydns/server/bind9/log/
data/README.md CHANGED
@@ -1,12 +1,14 @@
1
1
  # RubyDNS
2
+ [![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)
2
3
 
3
4
  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
 
5
- In addition, RubyDNS includes a high-performance asynchronous DNS resolver built on top of EventMachine. This module can be used by itself in client applications without using the full RubyDNS server stack.
6
+ 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.
6
7
 
7
- For examples and documentation please see the main [project page][1].
8
+ For examples and documentation please see the main [project page][2].
8
9
 
9
- [1]: http://www.codeotaku.com/projects/rubydns/
10
+ [1]: https://celluloid.io
11
+ [2]: http://www.codeotaku.com/projects/rubydns/
10
12
 
11
13
  [![Build Status](https://travis-ci.org/ioquatix/rubydns.svg?branch=master)](https://travis-ci.org/ioquatix/rubydns)
12
14
  [![Code Climate](https://codeclimate.com/github/ioquatix/rubydns.png)](https://codeclimate.com/github/ioquatix/rubydns)
@@ -44,7 +46,7 @@ This is copied from `test/examples/test-dns-2.rb`. It has been simplified slight
44
46
 
45
47
  # Start the RubyDNS server
46
48
  RubyDNS::run_server(:listen => INTERFACES) do
47
- match(/test.mydomain.org/, IN::A) do |transaction|
49
+ match(/test\.mydomain\.org/, IN::A) do |transaction|
48
50
  transaction.respond!("10.0.0.80")
49
51
  end
50
52
 
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'rubydns', path: '../'
4
+ gem "process-daemon"
5
+ gem 'nokogiri'
6
+ gem 'http'
7
+ gem 'geoip'
@@ -0,0 +1,137 @@
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
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
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
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
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.
@@ -1,17 +1,17 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  # Copyright, 2009, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
4
- #
4
+ #
5
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  # of this software and associated documentation files (the "Software"), to deal
7
7
  # in the Software without restriction, including without limitation the rights
8
8
  # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
9
  # copies of the Software, and to permit persons to whom the Software is
10
10
  # furnished to do so, subject to the following conditions:
11
- #
11
+ #
12
12
  # The above copyright notice and this permission notice shall be included in
13
13
  # all copies or substantial portions of the Software.
14
- #
14
+ #
15
15
  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
16
  # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
17
  # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -26,40 +26,47 @@ require 'rubydns'
26
26
  require 'rubydns/system'
27
27
 
28
28
  INTERFACES = [
29
- [:udp, "0.0.0.0", 5300]
29
+ [:udp, '0.0.0.0', 5300]
30
30
  ]
31
31
 
32
- class DroppingDaemon < Process::Daemon
32
+ # A DNS server that selectively drops queries based on the requested domain
33
+ # name. Queries for domains that match specified regular expresssions
34
+ # (like 'microsoft.com' or 'sco.com') return NXDomain, while all other
35
+ # queries are passed to upstream resolvers.
36
+ class FlakeyDNS < Process::Daemon
33
37
  Name = Resolv::DNS::Name
34
38
  IN = Resolv::DNS::Resource::IN
35
- R = RubyDNS::Resolver.new(RubyDNS::System::nameservers)
36
-
39
+
37
40
  def startup
38
- RubyDNS::run_server(:listen => INTERFACES) do
41
+ RubyDNS.run_server(listen: INTERFACES) do
39
42
  # Fail the resolution of certain domains ;)
40
43
  match(/(m?i?c?r?o?s?o?f?t)/) do |transaction, match_data|
41
44
  if match_data[1].size > 7
42
- logger.info "Dropping domain MICROSOFT..."
45
+ logger.info 'Dropping domain MICROSOFT...'
43
46
  transaction.fail!(:NXDomain)
44
47
  else
45
48
  # Pass the request to the otherwise handler
46
49
  false
47
50
  end
48
51
  end
49
-
52
+
50
53
  # Hmm....
51
54
  match(/^(.+\.)?sco\./) do |transaction|
52
- logger.info "Dropping domain SCO..."
55
+ logger.info 'Dropping domain SCO...'
53
56
  transaction.fail!(:NXDomain)
54
57
  end
55
58
 
56
59
  # Default DNS handler
57
60
  otherwise do |transaction|
58
- logger.info "Passing DNS request upstream..."
59
- transaction.passthrough!(R)
61
+ logger.info 'Passing DNS request upstream...'
62
+ transaction.passthrough!(FlakeyDNS.fallback_resolver)
60
63
  end
61
64
  end
62
- end
65
+ end
66
+
67
+ def self.fallback_resolver
68
+ @resolver ||= RubyDNS::Resolver.new(RubyDNS::System.nameservers)
69
+ end
63
70
  end
64
71
 
65
- DroppingDaemon.daemonize
72
+ FlakeyDNS.daemonize
@@ -0,0 +1,106 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ # Copyright, 2009, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
5
+ #
6
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ # of this software and associated documentation files (the "Software"), to deal
8
+ # in the Software without restriction, including without limitation the rights
9
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ # copies of the Software, and to permit persons to whom the Software is
11
+ # furnished to do so, subject to the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be included in
14
+ # all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
+ # THE SOFTWARE.
23
+
24
+ require 'process/daemon'
25
+ require 'process/daemon/privileges'
26
+
27
+ require 'rubydns'
28
+ require 'rubydns/extensions/string'
29
+
30
+ require 'digest/md5'
31
+
32
+ # You might need to change the user name "daemon". This can be a user name
33
+ # or a user id.
34
+ RUN_AS = 'daemon'
35
+
36
+ if Process::Daemon::Privileges.current_user != 'root'
37
+ $stderr.puts 'Sorry, this command needs to be run as root!'
38
+ exit 1
39
+ end
40
+
41
+ # A DNS server that allows a client to generate fortunes and fetch them with
42
+ # subsequent requests. The server 'remembers' the fortunes it generates,
43
+ # and can serve them to future requests.
44
+ class FortuneDNS < Process::Daemon
45
+ Name = Resolv::DNS::Name
46
+ IN = Resolv::DNS::Resource::IN
47
+
48
+ def startup
49
+ cache = {}
50
+ stats = { requested: 0 }
51
+
52
+ # Start the RubyDNS server
53
+ RubyDNS.run_server do
54
+ on(:start) do
55
+ Process::Daemon::Privileges.change_user(RUN_AS)
56
+
57
+ if ARGV.include?('--debug')
58
+ @logger.level = Logger::DEBUG
59
+ $stderr.sync = true
60
+ else
61
+ @logger.level = Logger::WARN
62
+ end
63
+ end
64
+
65
+ match(/short\.fortune/, IN::TXT) do |transaction|
66
+ fortune = `fortune -s`.gsub(/\s+/, ' ').strip
67
+
68
+ transaction.respond!(*fortune.chunked, ttl: 0)
69
+ end
70
+
71
+ match(/stats\.fortune/, IN::TXT) do |transaction|
72
+ $stderr.puts "Sending stats: #{stats.inspect}"
73
+ transaction.respond!(stats.inspect)
74
+ end
75
+
76
+ match(/([a-f0-9]*)\.fortune/, IN::TXT) do |transaction, match|
77
+ fortune = cache[match[1]]
78
+ stats[:requested] += 1
79
+
80
+ if fortune
81
+ transaction.respond!(*fortune.chunked)
82
+ else
83
+ transaction.fail!(:NXDomain)
84
+ end
85
+ end
86
+
87
+ match(/fortune/, [IN::CNAME, IN::TXT]) do |transaction|
88
+ fortune = `fortune`.gsub(/\s+/, ' ').strip
89
+ checksum = Digest::MD5.hexdigest(fortune)
90
+ cache[checksum] = fortune
91
+
92
+ answer_txt = "Text Size: #{fortune.size} Byte Size: #{fortune.bytesize}"
93
+ transaction.respond!(answer_txt, resource_class: IN::TXT, ttl: 0)
94
+ answer_cname = Name.create(checksum + '.fortune')
95
+ transaction.respond!(answer_cname, resource_class: IN::CNAME, ttl: 0)
96
+ end
97
+
98
+ # Default DNS handler
99
+ otherwise do |transaction|
100
+ transaction.fail!(:NXDomain)
101
+ end
102
+ end
103
+ end
104
+ end
105
+
106
+ FortuneDNS.daemonize
@@ -0,0 +1,117 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Copyright, 2009, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
23
+ require 'geoip'
24
+
25
+ require 'process/daemon'
26
+
27
+ require 'rubydns'
28
+ require 'rubydns/system'
29
+
30
+ INTERFACES = [
31
+ [:udp, '0.0.0.0', 5300]
32
+ ]
33
+
34
+ # Path to the GeoIP file downloaded from
35
+ # http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz
36
+ # If you have renamed the ungzipped file, or have placed it somewhere other than
37
+ # the repository root directory you will need to update this path.
38
+ PATH_TO_GEOIP_DAT_FILE =
39
+ File.expand_path('../GeoIP.dat', File.dirname(__FILE__))
40
+
41
+ # A sample DNS daemon that demonstrates how to use RubyDNS to build responses
42
+ # that vary based on the geolocation of the requesting peer. Clients of
43
+ # this server who request A records will get an answer IP address based
44
+ # on the continent of the client IP address.
45
+ #
46
+ # Please note that use of this example requires that the peer have a public
47
+ # IP address. IP addresses on private networks or the localhost IP (127.0.0.1)
48
+ # cannot be resolved to a location, and so will always yield the unknown result.
49
+ # This daemon requires the file downloaded from
50
+ # http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz
51
+ # For more information, please see http://www.maxmind.com/en/geolite and
52
+ # http://geoip.rubyforge.org
53
+ class GeoIPDNS < Process::Daemon
54
+ GEO = GeoIP.new(PATH_TO_GEOIP_DAT_FILE)
55
+
56
+ Name = Resolv::DNS::Name
57
+ IN = Resolv::DNS::Resource::IN
58
+
59
+ def startup
60
+ RubyDNS.run_server(listen: INTERFACES) do
61
+ match(//, IN::A) do |transaction|
62
+ logger.debug 'In block'
63
+
64
+ # The IP Address of the peer is stored in the transaction options
65
+ # with the key :peer
66
+ ip_address = transaction.options[:peer]
67
+ logger.debug "Looking up geographic information for peer #{ip_address}"
68
+ location = GeoIPDNS.ip_to_location(ip_address)
69
+
70
+ if location
71
+ logger.debug "Found location #{location} for #{ip_address}"
72
+ else
73
+ logger.debug "Could not resolve location for #{ip_address}"
74
+ end
75
+
76
+ code = location ? location.continent_code : nil
77
+ answer = GeoIPDNS.answer_for_continent_code(code)
78
+ logger.debug "Answer is #{answer}"
79
+ transaction.respond!(answer)
80
+ end
81
+
82
+ # Default DNS handler
83
+ otherwise do |transaction|
84
+ logger.debug 'In otherwise'
85
+ transaction.passthrough!(GeoIPDNS.fallback_resolver)
86
+ end
87
+ end
88
+ end
89
+
90
+ def self.fallback_resolver
91
+ @resolver ||= RubyDNS::Resolver.new(RubyDNS::System.nameservers)
92
+ end
93
+
94
+ # Maps each continent code to a fixed IP address for the response.
95
+ # A simple mapper to demonstrate the behavior.
96
+ def self.answer_for_continent_code(code)
97
+ case code
98
+ when 'AF' then '1.1.1.1'
99
+ when 'AN' then '1.1.2.1'
100
+ when 'AS' then '1.1.3.1'
101
+ when 'EU' then '1.1.4.1'
102
+ when 'NA' then '1.1.5.1'
103
+ when 'OC' then '1.1.6.1'
104
+ when 'SA' then '1.1.7.1'
105
+ else '1.1.8.1'
106
+ end
107
+ end
108
+
109
+ # Finds the continent code for the specified IP address.
110
+ # Returns nil if the IP address cannot be mapped to a location.
111
+ def self.ip_to_location(ip_address)
112
+ return nil unless ip_address
113
+ GEO.country(ip_address)
114
+ end
115
+ end
116
+
117
+ GeoIPDNS.daemonize
@@ -0,0 +1,120 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ # Copyright, 2009, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
5
+ #
6
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ # of this software and associated documentation files (the "Software"), to deal
8
+ # in the Software without restriction, including without limitation the rights
9
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ # copies of the Software, and to permit persons to whom the Software is
11
+ # furnished to do so, subject to the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be included in
14
+ # all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
+ # THE SOFTWARE.
23
+
24
+ require 'rubydns'
25
+ require 'rubydns/extensions/string'
26
+
27
+ require 'process/daemon'
28
+ require 'process/daemon/privileges'
29
+
30
+ require 'cgi'
31
+ require 'nokogiri'
32
+ require 'json'
33
+
34
+ require 'digest/md5'
35
+
36
+ # You might need to change the user name "daemon". This can be a user name
37
+ # or a user id.
38
+ RUN_AS = 'daemon'
39
+
40
+ if Process::Daemon::Privileges.current_user != 'root'
41
+ $stderr.puts 'Sorry, this command needs to be run as root!'
42
+ exit 1
43
+ end
44
+
45
+ require 'http'
46
+
47
+ # Celluloid::IO fetcher to retrieve URLs.
48
+ class HttpFetcher
49
+ include Celluloid::IO
50
+
51
+ def get(url)
52
+ # Note: For SSL support specify:
53
+ # ssl_socket_class: Celluloid::IO::SSLSocket
54
+ HTTP.get(url, socket_class: Celluloid::IO::TCPSocket)
55
+ end
56
+ end
57
+
58
+ # Encapsulates the logic for fetching information from Wikipedia.
59
+ module Wikipedia
60
+ def self.summary_url(title)
61
+ "http://en.wikipedia.org/w/api.php?action=parse&page=#{CGI.escape title}&prop=text&section=0&format=json"
62
+ end
63
+
64
+ def self.extract_summary(json_text)
65
+ document = JSON.parse(json_text)
66
+ return Nokogiri::HTML(document['parse']['text']['*']).css('p')[0].text
67
+ rescue
68
+ return 'Invalid Article.'
69
+ end
70
+ end
71
+
72
+ # A DNS server that queries Wikipedia and returns summaries for
73
+ # specifically crafted queries.
74
+ class WikipediaDNS < Process::Daemon
75
+ Name = Resolv::DNS::Name
76
+ IN = Resolv::DNS::Resource::IN
77
+
78
+ def startup
79
+ # Don't buffer output (for debug purposes)
80
+ $stderr.sync = true
81
+
82
+ stats = { requested: 0 }
83
+
84
+ fetcher = HttpFetcher.new
85
+
86
+ # Start the RubyDNS server
87
+ RubyDNS.run_server do
88
+ on(:start) do
89
+ Process::Daemon::Privileges.change_user(RUN_AS)
90
+ if ARGV.include?('--debug')
91
+ @logger.level = Logger::DEBUG
92
+ else
93
+ @logger.level = Logger::WARN
94
+ end
95
+ end
96
+
97
+ match(/stats\.wikipedia/, IN::TXT) do |transaction|
98
+ transaction.respond!(*stats.inspect.chunked)
99
+ end
100
+
101
+ match(/(.+)\.wikipedia/, IN::TXT) do |transaction, match_data|
102
+ title = match_data[1]
103
+ stats[:requested] += 1
104
+
105
+ response = fetcher.get(Wikipedia.summary_url(title))
106
+
107
+ summary =
108
+ Wikipedia.extract_summary(response).force_encoding('ASCII-8BIT')
109
+ transaction.respond!(*summary.chunked)
110
+ end
111
+
112
+ # Default DNS handler
113
+ otherwise do |transaction|
114
+ transaction.fail!(:NXDomain)
115
+ end
116
+ end
117
+ end
118
+ end
119
+
120
+ WikipediaDNS.daemonize
@@ -29,21 +29,21 @@ require_relative 'rubydns/logger'
29
29
  module RubyDNS
30
30
  # Run a server with the given rules.
31
31
  def self.run_server (options = {}, &block)
32
- supervisor = RubyDNS::RuleBasedServer.supervise(options, &block)
32
+ supervisor_class = options[:supervisor_class] || RuleBasedServer
33
33
 
34
- supervisor.actors.first.run
34
+ supervisor = supervisor_class.supervise(options, &block)
35
35
 
36
+ supervisor.actors.first.run
36
37
  if options[:asynchronous]
37
38
  return supervisor
38
39
  else
39
40
  read, write = IO.pipe
40
-
41
+
41
42
  trap(:INT) {
42
43
  write.puts
43
44
  }
44
-
45
- IO.select([read])
46
45
 
46
+ IO.select([read])
47
47
  supervisor.terminate
48
48
  end
49
49
  end
@@ -95,6 +95,9 @@ module RubyDNS
95
95
  begin
96
96
  response = nil
97
97
 
98
+ # This may be causing a problem, perhaps try:
99
+ # after(timeout) { socket.close }
100
+ # https://github.com/celluloid/celluloid-io/issues/121
98
101
  timeout(request_timeout) do
99
102
  response = try_server(request, server)
100
103
  end
@@ -165,6 +168,8 @@ module RubyDNS
165
168
  begin
166
169
  socket = TCPSocket.new(host, port)
167
170
  rescue Errno::EALREADY
171
+ # This is a hack to work around faulty behaviour in celluloid-io:
172
+ # https://github.com/celluloid/celluloid/issues/436
168
173
  raise IOError.new("Could not connect to remote host!")
169
174
  end
170
175
 
@@ -19,5 +19,5 @@
19
19
  # THE SOFTWARE.
20
20
 
21
21
  module RubyDNS
22
- VERSION = "0.9.0"
22
+ VERSION = "0.9.1"
23
23
  end
@@ -15,7 +15,7 @@ Gem::Specification.new do |spec|
15
15
  a remote DNS server or fetched from a local cache, depending on requirements.
16
16
 
17
17
  In addition, RubyDNS includes a high-performance asynchronous DNS resolver
18
- built on top of EventMachine. This module can be used by itself in client
18
+ built on top of Celluloid. This module can be used by itself in client
19
19
  applications without using the full RubyDNS server stack.
20
20
  EOF
21
21
  spec.summary = "An easy to use DNS server and resolver for Ruby."
@@ -36,6 +36,6 @@ Gem::Specification.new do |spec|
36
36
 
37
37
  spec.add_development_dependency "bundler", "~> 1.3"
38
38
  spec.add_development_dependency "process-daemon", "~> 0.5.5"
39
- spec.add_development_dependency "rspec", "~> 3.0.0"
39
+ spec.add_development_dependency "rspec", "~> 3.1.0"
40
40
  spec.add_development_dependency "rake"
41
41
  end
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Copyright, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
23
+ require 'rubydns'
24
+
25
+ module RubyDNS::CelluloidBugSpec
26
+ describe RubyDNS::Resolver do
27
+ context 'benchmark' do
28
+ domains = %W(
29
+ Facebook.com
30
+ Twitter.com
31
+ Google.com
32
+ Youtube.com
33
+ Wordpress.org
34
+ Adobe.com
35
+ Blogspot.com
36
+ Wikipedia.org
37
+ Linkedin.com
38
+ Wordpress.com
39
+ Yahoo.com
40
+ Amazon.com
41
+ Flickr.com
42
+ Pinterest.com
43
+ Tumblr.com
44
+ W3.org
45
+ Apple.com
46
+ Myspace.com
47
+ Vimeo.com
48
+ Microsoft.com
49
+ Youtu.be
50
+ Qq.com
51
+ Digg.com
52
+ Baidu.com
53
+ Stumbleupon.com
54
+ Addthis.com
55
+ Statcounter.com
56
+ Feedburner.com
57
+ TradeMe.co.nz
58
+ Delicious.com
59
+ Nytimes.com
60
+ Reddit.com
61
+ Weebly.com
62
+ Bbc.co.uk
63
+ Blogger.com
64
+ Msn.com
65
+ Macromedia.com
66
+ Goo.gl
67
+ Instagram.com
68
+ Gov.uk
69
+ Icio.us
70
+ Yandex.ru
71
+ Cnn.com
72
+ Webs.com
73
+ Google.de
74
+ T.co
75
+ Livejournal.com
76
+ Imdb.com
77
+ Mail.ru
78
+ Jimdo.com
79
+ )
80
+
81
+ it 'should be faster than native resolver' do
82
+ Celluloid.logger.level = Logger::ERROR
83
+
84
+ resolver = RubyDNS::Resolver.new([[:udp, "8.8.8.8", 53], [:tcp, "8.8.8.8", 53]], timeout: 0.1)
85
+
86
+ futures = domains.map { |domain| resolver.future.addresses_for(domain) }
87
+
88
+ futures.map { |future| future.value }
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Copyright, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
23
+ require 'rubydns'
24
+ require 'rubydns/extensions/string'
25
+
26
+ module RubyDNS::InjectedSupervisorSpec
27
+ class TestServer < RubyDNS::RuleBasedServer
28
+ def test_message
29
+ 'Testing...'
30
+ end
31
+ end
32
+
33
+ SERVER_PORTS = [[:udp, '127.0.0.1', 5520]]
34
+ IN = Resolv::DNS::Resource::IN
35
+
36
+ describe "RubyDNS Injected Supervisor" do
37
+ before(:all) do
38
+ Celluloid.shutdown
39
+ Celluloid.boot
40
+
41
+ # Start the RubyDNS server
42
+ RubyDNS::run_server(listen: SERVER_PORTS, supervisor_class: TestServer, asynchronous: true) do
43
+ match("test_message", IN::TXT) do |transaction|
44
+ transaction.respond!(*test_message.chunked)
45
+ end
46
+
47
+ # Default DNS handler
48
+ otherwise do |transaction|
49
+ transaction.fail!(:NXDomain)
50
+ end
51
+ end
52
+ end
53
+
54
+ it "should use the injected class" do
55
+ resolver = RubyDNS::Resolver.new(SERVER_PORTS)
56
+ response = resolver.query("test_message", IN::TXT)
57
+ text = response.answer.first
58
+ expect(text[2].strings.join).to be == 'Testing...'
59
+ end
60
+ end
61
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubydns
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.9.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-10-23 00:00:00.000000000 Z
11
+ date: 2014-11-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: celluloid
@@ -86,14 +86,14 @@ dependencies:
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: 3.0.0
89
+ version: 3.1.0
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: 3.0.0
96
+ version: 3.1.0
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: rake
99
99
  requirement: !ruby/object:Gem::Requirement
@@ -113,7 +113,7 @@ description: "\t\tRubyDNS is a high-performance DNS server which can be easily i
113
113
  pattern matching. Results can be hard-coded, computed, fetched from\n\t\ta remote
114
114
  DNS server or fetched from a local cache, depending on requirements.\n\n\t\tIn addition,
115
115
  RubyDNS includes a high-performance asynchronous DNS resolver\n\t\tbuilt on top
116
- of EventMachine. This module can be used by itself in client\n\t\tapplications without
116
+ of Celluloid. This module can be used by itself in client\n\t\tapplications without
117
117
  using the full RubyDNS server stack.\n"
118
118
  email:
119
119
  - samuel.williams@oriontransfer.co.nz
@@ -129,7 +129,12 @@ files:
129
129
  - README.md
130
130
  - Rakefile
131
131
  - bin/rubydns-check
132
- - examples/dropping-dns.rb
132
+ - examples/Gemfile
133
+ - examples/README.md
134
+ - examples/flakey-dns.rb
135
+ - examples/fortune-dns.rb
136
+ - examples/geoip-dns.rb
137
+ - examples/wikipedia-dns.rb
133
138
  - lib/rubydns.rb
134
139
  - lib/rubydns/chunked.rb
135
140
  - lib/rubydns/extensions/resolv.rb
@@ -144,8 +149,10 @@ files:
144
149
  - lib/rubydns/transport.rb
145
150
  - lib/rubydns/version.rb
146
151
  - rubydns.gemspec
152
+ - spec/rubydns/celluloid_bug_spec.rb
147
153
  - spec/rubydns/daemon_spec.rb
148
154
  - spec/rubydns/hosts.txt
155
+ - spec/rubydns/injected_supervisor_spec.rb
149
156
  - spec/rubydns/message_spec.rb
150
157
  - spec/rubydns/passthrough_spec.rb
151
158
  - spec/rubydns/resolver_performance_spec.rb
@@ -189,8 +196,10 @@ signing_key:
189
196
  specification_version: 4
190
197
  summary: An easy to use DNS server and resolver for Ruby.
191
198
  test_files:
199
+ - spec/rubydns/celluloid_bug_spec.rb
192
200
  - spec/rubydns/daemon_spec.rb
193
201
  - spec/rubydns/hosts.txt
202
+ - spec/rubydns/injected_supervisor_spec.rb
194
203
  - spec/rubydns/message_spec.rb
195
204
  - spec/rubydns/passthrough_spec.rb
196
205
  - spec/rubydns/resolver_performance_spec.rb