rubydns 1.0.3 → 2.0.0.pre.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +4 -0
  3. data/.travis.yml +9 -12
  4. data/Gemfile +4 -1
  5. data/README.md +49 -151
  6. data/Rakefile +2 -7
  7. data/examples/basic-dns.rb +24 -0
  8. data/examples/cname.rb +25 -0
  9. data/examples/flakey-dns.rb +2 -2
  10. data/examples/simple.rb +25 -0
  11. data/examples/soa-dns.rb +82 -0
  12. data/examples/test-dns-1.rb +83 -0
  13. data/examples/test-dns-2.rb +83 -0
  14. data/examples/wikipedia-dns.rb +4 -18
  15. data/lib/rubydns.rb +9 -23
  16. data/lib/rubydns/{server.rb → rule_based_server.rb} +2 -160
  17. data/lib/rubydns/version.rb +1 -1
  18. data/rubydns.gemspec +3 -6
  19. data/spec/rubydns/daemon_spec.rb +26 -22
  20. data/spec/rubydns/injected_supervisor_spec.rb +10 -7
  21. data/spec/rubydns/passthrough_spec.rb +31 -24
  22. data/spec/spec_helper.rb +43 -0
  23. metadata +21 -100
  24. data/lib/rubydns/chunked.rb +0 -34
  25. data/lib/rubydns/extensions/resolv.rb +0 -85
  26. data/lib/rubydns/extensions/string.rb +0 -28
  27. data/lib/rubydns/handler.rb +0 -188
  28. data/lib/rubydns/logger.rb +0 -31
  29. data/lib/rubydns/message.rb +0 -76
  30. data/lib/rubydns/resolver.rb +0 -294
  31. data/lib/rubydns/system.rb +0 -146
  32. data/lib/rubydns/transaction.rb +0 -204
  33. data/lib/rubydns/transport.rb +0 -75
  34. data/spec/rubydns/celluloid_bug_spec.rb +0 -92
  35. data/spec/rubydns/ipv6_spec.rb +0 -70
  36. data/spec/rubydns/message_spec.rb +0 -56
  37. data/spec/rubydns/origin_spec.rb +0 -106
  38. data/spec/rubydns/resolver_performance_spec.rb +0 -110
  39. data/spec/rubydns/resolver_spec.rb +0 -152
  40. data/spec/rubydns/server/bind9/generate-local.rb +0 -25
  41. data/spec/rubydns/server/bind9/local.zone +0 -5014
  42. data/spec/rubydns/server/bind9/named.conf +0 -14
  43. data/spec/rubydns/server/bind9/named.run +0 -0
  44. data/spec/rubydns/server/million.rb +0 -85
  45. data/spec/rubydns/server/rubydns.stackprof +0 -0
  46. data/spec/rubydns/server_performance_spec.rb +0 -136
  47. data/spec/rubydns/slow_server_spec.rb +0 -89
  48. data/spec/rubydns/socket_spec.rb +0 -77
  49. data/spec/rubydns/system_spec.rb +0 -60
  50. data/spec/rubydns/transaction_spec.rb +0 -138
  51. data/spec/rubydns/truncation_spec.rb +0 -59
@@ -1,34 +0,0 @@
1
- # Copyright, 2009, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
- #
3
- # Permission is hereby granted, free of charge, to any person obtaining a copy
4
- # of this software and associated documentation files (the "Software"), to deal
5
- # in the Software without restriction, including without limitation the rights
6
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
- # copies of the Software, and to permit persons to whom the Software is
8
- # furnished to do so, subject to the following conditions:
9
- #
10
- # The above copyright notice and this permission notice shall be included in
11
- # all copies or substantial portions of the Software.
12
- #
13
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
- # THE SOFTWARE.
20
-
21
- module RubyDNS
22
- # Produces an array of arrays of binary data with each sub-array a maximum of chunk_size bytes.
23
- def self.chunked(string, chunk_size = 255)
24
- chunks = []
25
-
26
- offset = 0
27
- while offset < string.bytesize
28
- chunks << string.byteslice(offset, chunk_size)
29
- offset += chunk_size
30
- end
31
-
32
- return chunks
33
- end
34
- end
@@ -1,85 +0,0 @@
1
- # Copyright, 2009, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
- #
3
- # Permission is hereby granted, free of charge, to any person obtaining a copy
4
- # of this software and associated documentation files (the "Software"), to deal
5
- # in the Software without restriction, including without limitation the rights
6
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
- # copies of the Software, and to permit persons to whom the Software is
8
- # furnished to do so, subject to the following conditions:
9
- #
10
- # The above copyright notice and this permission notice shall be included in
11
- # all copies or substantial portions of the Software.
12
- #
13
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
- # THE SOFTWARE.
20
-
21
- require 'resolv'
22
-
23
- class Resolv
24
- class DNS
25
- class Message
26
- # Merge the given message with this message. A number of heuristics are applied in order to ensure that the result makes sense. For example, If the current message is not recursive but is being merged with a message that was recursive, this bit is maintained. If either message is authoritive, then the result is also authoritive.
27
- #
28
- # Modifies the current message in place.
29
- def merge! (other)
30
- # Authoritive Answer
31
- @aa = @aa && other.aa
32
-
33
- @question += other.question
34
- @answer += other.answer
35
- @authority += other.authority
36
- @additional += other.additional
37
-
38
- # Recursion Available
39
- @ra = @ra || other.ra
40
-
41
- # Result Code (Error Code)
42
- @rcode = other.rcode unless other.rcode == 0
43
-
44
- # Recursion Desired
45
- @rd = @rd || other.rd
46
- end
47
- end
48
-
49
- class OriginError < ArgumentError
50
- end
51
-
52
- class Name
53
- def to_s
54
- "#{@labels.join('.')}#{@absolute ? '.' : ''}"
55
- end
56
-
57
- def inspect
58
- "#<#{self.class}: #{self.to_s}>"
59
- end
60
-
61
- # Return the name, typically absolute, with the specified origin as a suffix. If the origin is nil, don't change the name, but change it to absolute (as specified).
62
- def with_origin(origin, absolute = true)
63
- return self.class.new(@labels, absolute) if origin == nil
64
-
65
- origin = Label.split(origin) if String === origin
66
-
67
- return self.class.new(@labels + origin, absolute)
68
- end
69
-
70
-
71
- # Return the name, typically relative, without the specified origin suffix. If the origin is nil, don't change the name, but change it to absolute (as specified).
72
- def without_origin(origin, absolute = false)
73
- return self.class.new(@labels, absolute) if origin == nil
74
-
75
- origin = Label.split(origin) if String === origin
76
-
77
- if @labels.last(origin.length) == origin
78
- return self.class.new(@labels.first(@labels.length - origin.length), absolute)
79
- else
80
- raise OriginError.new("#{self} does not end with #{origin.join('.')}")
81
- end
82
- end
83
- end
84
- end
85
- end
@@ -1,28 +0,0 @@
1
- # Copyright, 2009, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
- #
3
- # Permission is hereby granted, free of charge, to any person obtaining a copy
4
- # of this software and associated documentation files (the "Software"), to deal
5
- # in the Software without restriction, including without limitation the rights
6
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
- # copies of the Software, and to permit persons to whom the Software is
8
- # furnished to do so, subject to the following conditions:
9
- #
10
- # The above copyright notice and this permission notice shall be included in
11
- # all copies or substantial portions of the Software.
12
- #
13
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
- # THE SOFTWARE.
20
-
21
- require_relative '../chunked'
22
-
23
- class String
24
- # Chunk a string which is required for the TEXT `resource_class`.
25
- def chunked(chunk_size = 255)
26
- RubyDNS::chunked(self)
27
- end
28
- end
@@ -1,188 +0,0 @@
1
- # Copyright, 2009, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
- #
3
- # Permission is hereby granted, free of charge, to any person obtaining a copy
4
- # of this software and associated documentation files (the "Software"), to deal
5
- # in the Software without restriction, including without limitation the rights
6
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
- # copies of the Software, and to permit persons to whom the Software is
8
- # furnished to do so, subject to the following conditions:
9
- #
10
- # The above copyright notice and this permission notice shall be included in
11
- # all copies or substantial portions of the Software.
12
- #
13
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
- # THE SOFTWARE.
20
-
21
- require_relative 'transport'
22
-
23
- module RubyDNS
24
- class GenericHandler
25
- include Celluloid::IO
26
-
27
- def initialize(server)
28
- @server = server
29
- @logger = @server.logger || Celluloid.logger
30
- end
31
-
32
- def error_response(query = nil, code = Resolv::DNS::RCode::ServFail)
33
- # Encoding may fail, so we need to handle this particular case:
34
- server_failure = Resolv::DNS::Message::new(query ? query.id : 0)
35
-
36
- server_failure.qr = 1
37
- server_failure.opcode = query ? query.opcode : 0
38
- server_failure.aa = 1
39
- server_failure.rd = 0
40
- server_failure.ra = 0
41
-
42
- server_failure.rcode = code
43
-
44
- # We can't do anything at this point...
45
- return server_failure
46
- end
47
-
48
- def process_query(data, options)
49
- @logger.debug "<> Receiving incoming query (#{data.bytesize} bytes) to #{self.class.name}..."
50
- query = nil
51
-
52
- begin
53
- query = RubyDNS::decode_message(data)
54
-
55
- return @server.process_query(query, options)
56
- rescue Celluloid::ResumableError
57
- # Celluloid terminates tasks, we may be stuck in a task when the server is terminated. We don't want to reply to the client in this case, because the server is being terminated. It might be an option to return a server failure
58
- raise
59
- rescue StandardError => error
60
- @logger.error "<> Error processing request: #{error.inspect}!"
61
- RubyDNS::log_exception(@logger, error)
62
-
63
- return error_response(query)
64
- end
65
- end
66
- end
67
-
68
- # Handling incoming UDP requests, which are single data packets, and pass them on to the given server.
69
- class UDPSocketHandler < GenericHandler
70
- include Celluloid::IO
71
-
72
- def initialize(server, socket)
73
- super(server)
74
-
75
- @socket = socket
76
-
77
- async.run
78
- end
79
-
80
- def run
81
- loop { handle_connection }
82
- end
83
-
84
- def respond(input_data, remote_host, remote_port)
85
- options = {peer: remote_host, port: remote_port, proto: :udp}
86
-
87
- response = process_query(input_data, options)
88
-
89
- output_data = response.encode
90
-
91
- @logger.debug "<#{response.id}> Writing #{output_data.bytesize} bytes response to client via UDP..."
92
-
93
- if output_data.bytesize > UDP_TRUNCATION_SIZE
94
- @logger.warn "<#{response.id}>Response via UDP was larger than #{UDP_TRUNCATION_SIZE}!"
95
-
96
- # Reencode data with truncation flag marked as true:
97
- truncation_error = Resolv::DNS::Message.new(response.id)
98
- truncation_error.tc = 1
99
-
100
- output_data = truncation_error.encode
101
- end
102
-
103
- @socket.send(output_data, 0, remote_host, remote_port)
104
- rescue IOError => error
105
- @logger.warn "<> UDP response failed: #{error.inspect}!"
106
- rescue EOFError => error
107
- @logger.warn "<> UDP session ended prematurely: #{error.inspect}!"
108
- rescue DecodeError
109
- @logger.warn "<> Could not decode incoming UDP data!"
110
- end
111
-
112
- def handle_connection
113
- # @logger.debug "Waiting for incoming UDP packet #{@socket.inspect}..."
114
-
115
- input_data, (_, remote_port, remote_host) = @socket.recvfrom(UDP_TRUNCATION_SIZE, 0)
116
-
117
- async.respond(input_data, remote_host, remote_port)
118
- rescue IOError => error
119
- @logger.warn "<> UDP connection failed: #{error.inspect}!"
120
- rescue EOFError => error
121
- @logger.warn "<> UDP session ended prematurely!"
122
- end
123
- end
124
-
125
- class UDPHandler < UDPSocketHandler
126
- def initialize(server, host, port)
127
- family = RubyDNS::address_family(host)
128
- socket = UDPSocket.new(family)
129
-
130
- socket.bind(host, port)
131
-
132
- super(server, socket)
133
- end
134
-
135
- finalizer :finalize
136
-
137
- def finalize
138
- @socket.close if @socket
139
- end
140
- end
141
-
142
- class TCPSocketHandler < GenericHandler
143
- def initialize(server, socket)
144
- super(server)
145
-
146
- @socket = socket
147
-
148
- async.run
149
- end
150
-
151
- def run
152
- loop { async.handle_connection @socket.accept }
153
- end
154
-
155
- def handle_connection(socket)
156
- _, remote_port, remote_host = socket.peeraddr
157
- options = {peer: remote_host, port: remote_port, proto: :tcp}
158
-
159
- input_data = StreamTransport.read_chunk(socket)
160
-
161
- response = process_query(input_data, options)
162
-
163
- length = StreamTransport.write_message(socket, response)
164
-
165
- @logger.debug "<#{response.id}> Wrote #{length} bytes via TCP..."
166
- rescue EOFError => error
167
- @logger.warn "<> TCP session ended prematurely!"
168
- rescue DecodeError
169
- @logger.warn "<> Could not decode incoming TCP data!"
170
- ensure
171
- socket.close
172
- end
173
- end
174
-
175
- class TCPHandler < TCPSocketHandler
176
- def initialize(server, host, port)
177
- socket = TCPServer.new(host, port)
178
-
179
- super(server, socket)
180
- end
181
-
182
- finalizer :finalize
183
-
184
- def finalize
185
- @socket.close if @socket
186
- end
187
- end
188
- end
@@ -1,31 +0,0 @@
1
- # Copyright, 2009, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
- #
3
- # Permission is hereby granted, free of charge, to any person obtaining a copy
4
- # of this software and associated documentation files (the "Software"), to deal
5
- # in the Software without restriction, including without limitation the rights
6
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
- # copies of the Software, and to permit persons to whom the Software is
8
- # furnished to do so, subject to the following conditions:
9
- #
10
- # The above copyright notice and this permission notice shall be included in
11
- # all copies or substantial portions of the Software.
12
- #
13
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
- # THE SOFTWARE.
20
-
21
- require 'logger'
22
-
23
- module RubyDNS
24
- # Logs an exception nicely to a standard `Logger`.
25
- def self.log_exception(logger, exception)
26
- logger.error "#{exception.class}: #{exception.message}"
27
- if exception.backtrace
28
- Array(exception.backtrace).each { |at| logger.error at }
29
- end
30
- end
31
- end
@@ -1,76 +0,0 @@
1
- # Copyright, 2009, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
- #
3
- # Permission is hereby granted, free of charge, to any person obtaining a copy
4
- # of this software and associated documentation files (the "Software"), to deal
5
- # in the Software without restriction, including without limitation the rights
6
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
- # copies of the Software, and to permit persons to whom the Software is
8
- # furnished to do so, subject to the following conditions:
9
- #
10
- # The above copyright notice and this permission notice shall be included in
11
- # all copies or substantial portions of the Software.
12
- #
13
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
- # THE SOFTWARE.
20
-
21
- require 'stringio'
22
- require 'resolv'
23
-
24
- require 'base64'
25
-
26
- require_relative 'logger'
27
- require_relative 'extensions/resolv'
28
-
29
- module RubyDNS
30
- UDP_TRUNCATION_SIZE = 512
31
-
32
- # The DNS message container.
33
- Message = Resolv::DNS::Message
34
-
35
- DecodeError = Resolv::DNS::DecodeError
36
-
37
- @@dump_bad_message = nil
38
-
39
- # Call this function with a path where bad messages will be saved. Any message that causes an exception to be thrown while decoding the binary will be saved in base64 for later inspection. The log file could grow quickly so be careful - not designed for long term use.
40
- def self.log_bad_messages!(log_path)
41
- bad_messages_log = Logger.new(log_path, 10, 1024*100)
42
- bad_messages_log.level = Logger::DEBUG
43
-
44
- @dump_bad_message = lambda do |error, data|
45
- bad_messages_log.debug("Bad message: #{Base64.encode64(data)}")
46
- RubyDNS.log_exception(bad_messages_log, error)
47
- end
48
- end
49
-
50
- # Decodes binary data into a {Message}.
51
- def self.decode_message(data)
52
- # Otherwise the decode process might fail with non-binary data.
53
- if data.respond_to? :force_encoding
54
- data.force_encoding("BINARY")
55
- end
56
-
57
- begin
58
- return Message.decode(data)
59
- rescue DecodeError
60
- raise
61
- rescue StandardError => error
62
- new_error = DecodeError.new(error.message)
63
- new_error.set_backtrace(error.backtrace)
64
-
65
- raise new_error
66
- end
67
-
68
- rescue => error
69
- # Log the bad messsage if required:
70
- if @dump_bad_message
71
- @dump_bad_message.call(error, data)
72
- end
73
-
74
- raise
75
- end
76
- end