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.
- checksums.yaml +4 -4
- data/.rspec +4 -0
- data/.travis.yml +9 -12
- data/Gemfile +4 -1
- data/README.md +49 -151
- data/Rakefile +2 -7
- data/examples/basic-dns.rb +24 -0
- data/examples/cname.rb +25 -0
- data/examples/flakey-dns.rb +2 -2
- data/examples/simple.rb +25 -0
- data/examples/soa-dns.rb +82 -0
- data/examples/test-dns-1.rb +83 -0
- data/examples/test-dns-2.rb +83 -0
- data/examples/wikipedia-dns.rb +4 -18
- data/lib/rubydns.rb +9 -23
- data/lib/rubydns/{server.rb → rule_based_server.rb} +2 -160
- data/lib/rubydns/version.rb +1 -1
- data/rubydns.gemspec +3 -6
- data/spec/rubydns/daemon_spec.rb +26 -22
- data/spec/rubydns/injected_supervisor_spec.rb +10 -7
- data/spec/rubydns/passthrough_spec.rb +31 -24
- data/spec/spec_helper.rb +43 -0
- metadata +21 -100
- data/lib/rubydns/chunked.rb +0 -34
- data/lib/rubydns/extensions/resolv.rb +0 -85
- data/lib/rubydns/extensions/string.rb +0 -28
- data/lib/rubydns/handler.rb +0 -188
- data/lib/rubydns/logger.rb +0 -31
- data/lib/rubydns/message.rb +0 -76
- data/lib/rubydns/resolver.rb +0 -294
- data/lib/rubydns/system.rb +0 -146
- data/lib/rubydns/transaction.rb +0 -204
- data/lib/rubydns/transport.rb +0 -75
- data/spec/rubydns/celluloid_bug_spec.rb +0 -92
- data/spec/rubydns/ipv6_spec.rb +0 -70
- data/spec/rubydns/message_spec.rb +0 -56
- data/spec/rubydns/origin_spec.rb +0 -106
- data/spec/rubydns/resolver_performance_spec.rb +0 -110
- data/spec/rubydns/resolver_spec.rb +0 -152
- data/spec/rubydns/server/bind9/generate-local.rb +0 -25
- data/spec/rubydns/server/bind9/local.zone +0 -5014
- data/spec/rubydns/server/bind9/named.conf +0 -14
- data/spec/rubydns/server/bind9/named.run +0 -0
- data/spec/rubydns/server/million.rb +0 -85
- data/spec/rubydns/server/rubydns.stackprof +0 -0
- data/spec/rubydns/server_performance_spec.rb +0 -136
- data/spec/rubydns/slow_server_spec.rb +0 -89
- data/spec/rubydns/socket_spec.rb +0 -77
- data/spec/rubydns/system_spec.rb +0 -60
- data/spec/rubydns/transaction_spec.rb +0 -138
- data/spec/rubydns/truncation_spec.rb +0 -59
data/lib/rubydns/chunked.rb
DELETED
@@ -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
|
data/lib/rubydns/handler.rb
DELETED
@@ -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
|
data/lib/rubydns/logger.rb
DELETED
@@ -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
|
data/lib/rubydns/message.rb
DELETED
@@ -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
|