async-dns 0.10.0 → 0.12.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +14 -0
- data/.travis.yml +6 -5
- data/Gemfile +0 -2
- data/async-dns.gemspec +4 -3
- data/lib/async/dns.rb +2 -2
- data/lib/async/dns/handler.rb +25 -116
- data/lib/async/dns/message.rb +1 -1
- data/lib/async/dns/resolver.rb +24 -42
- data/lib/async/dns/server.rb +14 -27
- data/lib/async/dns/transport.rb +10 -2
- data/lib/async/dns/version.rb +1 -1
- data/spec/async/dns/handler_spec.rb +18 -16
- data/spec/async/dns/ipv6_spec.rb +6 -6
- data/spec/async/dns/replace_spec.rb +1 -1
- data/spec/async/dns/resolver_performance_spec.rb +1 -1
- data/spec/async/dns/resolver_spec.rb +24 -36
- data/spec/async/dns/server_performance_spec.rb +1 -1
- data/spec/async/dns/slow_server_spec.rb +1 -1
- data/spec/async/dns/socket_spec.rb +6 -4
- data/spec/async/dns/system_spec.rb +1 -1
- data/spec/async/dns/transaction_spec.rb +1 -1
- data/spec/async/dns/truncation_spec.rb +1 -1
- data/spec/spec_helper.rb +1 -23
- metadata +24 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0302e920c59ef8d4ce72eaa34c0a442536304590
|
4
|
+
data.tar.gz: eede22f4c518bfa0dcf094933083aeda33bc82a1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 60687d211cdcee0afecee281daa5ae79322713b0adff0baf78f2c82ef700ebe99e056dc5f40d14a059f3a0d5a18c5741091b2a20cfe61bb8efd184b201c789a3
|
7
|
+
data.tar.gz: '052292c7a58dcbfa650d902a7c7b15097fe1d7e1dd2b06ebda5d5009f68c7fc3ed130cbaeb36be26ee0a8f04b0099d7be080e028bcbe35016661e75c4d76f6cb'
|
data/.gitignore
ADDED
data/.travis.yml
CHANGED
@@ -1,18 +1,19 @@
|
|
1
1
|
language: ruby
|
2
2
|
sudo: false
|
3
|
+
dist: trusty
|
4
|
+
cache: bundler
|
3
5
|
addons:
|
4
6
|
apt:
|
5
7
|
packages:
|
6
8
|
- bind9
|
7
9
|
rvm:
|
8
|
-
- 2.
|
9
|
-
- 2.
|
10
|
-
- 2.
|
11
|
-
-
|
10
|
+
- 2.1
|
11
|
+
- 2.2
|
12
|
+
- 2.3
|
13
|
+
- 2.4
|
12
14
|
- ruby-head
|
13
15
|
- jruby-head
|
14
16
|
matrix:
|
15
17
|
allow_failures:
|
16
|
-
- rvm: rbx-2
|
17
18
|
- rvm: ruby-head
|
18
19
|
- rvm: jruby-head
|
data/Gemfile
CHANGED
data/async-dns.gemspec
CHANGED
@@ -21,11 +21,12 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.require_paths = ["lib"]
|
22
22
|
spec.has_rdoc = "yard"
|
23
23
|
|
24
|
-
spec.add_dependency("async", "~> 0.
|
24
|
+
spec.add_dependency("async-io", "~> 0.1")
|
25
25
|
|
26
|
-
spec.add_development_dependency "
|
26
|
+
spec.add_development_dependency "async-rspec", "~> 1.0"
|
27
|
+
spec.add_development_dependency "process-daemon", "~> 1.0"
|
27
28
|
|
28
29
|
spec.add_development_dependency "bundler", "~> 1.3"
|
29
|
-
spec.add_development_dependency "rspec", "~> 3.
|
30
|
+
spec.add_development_dependency "rspec", "~> 3.6"
|
30
31
|
spec.add_development_dependency "rake"
|
31
32
|
end
|
data/lib/async/dns.rb
CHANGED
data/lib/async/dns/handler.rb
CHANGED
@@ -22,11 +22,16 @@ require_relative 'transport'
|
|
22
22
|
|
23
23
|
module Async::DNS
|
24
24
|
class GenericHandler
|
25
|
-
def initialize(server)
|
25
|
+
def initialize(server, address)
|
26
26
|
@server = server
|
27
|
+
@address = address
|
28
|
+
|
27
29
|
@logger = @server.logger || Async.logger
|
28
30
|
end
|
29
31
|
|
32
|
+
attr :server
|
33
|
+
attr :address
|
34
|
+
|
30
35
|
def error_response(query = nil, code = Resolv::DNS::RCode::ServFail)
|
31
36
|
# Encoding may fail, so we need to handle this particular case:
|
32
37
|
server_failure = Resolv::DNS::Message::new(query ? query.id : 0)
|
@@ -61,27 +66,23 @@ module Async::DNS
|
|
61
66
|
end
|
62
67
|
|
63
68
|
# Handling incoming UDP requests, which are single data packets, and pass them on to the given server.
|
64
|
-
class
|
65
|
-
def run(
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
69
|
+
class DatagramHandler < GenericHandler
|
70
|
+
def run(task: Async::Task.current)
|
71
|
+
@address.bind do |socket|
|
72
|
+
while true
|
73
|
+
Async.logger.debug(self.class.name) {"-> socket.recvfrom"}
|
74
|
+
input_data, remote_address = socket.recvmsg(UDP_TRUNCATION_SIZE)
|
75
|
+
Async.logger.debug(self.class.name) {"<- socket.recvfrom"}
|
76
|
+
|
77
|
+
task.async do
|
78
|
+
respond(socket, input_data, remote_address)
|
79
|
+
end
|
75
80
|
end
|
76
81
|
end
|
77
|
-
ensure
|
78
|
-
Async.logger.debug(self.class.name) {"<- Run ensure... #{$!}"}
|
79
82
|
end
|
80
83
|
|
81
|
-
def respond(socket, input_data,
|
82
|
-
|
83
|
-
|
84
|
-
response = process_query(input_data, options)
|
84
|
+
def respond(socket, input_data, remote_address)
|
85
|
+
response = process_query(input_data, remote_address: remote_address)
|
85
86
|
|
86
87
|
output_data = response.encode
|
87
88
|
|
@@ -97,7 +98,7 @@ module Async::DNS
|
|
97
98
|
output_data = truncation_error.encode
|
98
99
|
end
|
99
100
|
|
100
|
-
socket.
|
101
|
+
socket.sendmsg(output_data, 0, remote_address)
|
101
102
|
rescue IOError => error
|
102
103
|
@logger.warn "<> UDP response failed: #{error.inspect}!"
|
103
104
|
rescue EOFError => error
|
@@ -107,71 +108,19 @@ module Async::DNS
|
|
107
108
|
end
|
108
109
|
end
|
109
110
|
|
110
|
-
class
|
111
|
-
def
|
112
|
-
@
|
113
|
-
|
114
|
-
super(server)
|
115
|
-
end
|
116
|
-
|
117
|
-
attr :socket
|
118
|
-
|
119
|
-
def run(reactor: Async::Task.current.reactor)
|
120
|
-
reactor.async(self.socket) do |socket|
|
121
|
-
super(socket, reactor: reactor)
|
122
|
-
end
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
class UDPServerHandler < UDPHandler
|
127
|
-
def initialize(server, host, port)
|
128
|
-
@host = host
|
129
|
-
@port = port
|
130
|
-
|
131
|
-
super(server)
|
132
|
-
end
|
133
|
-
|
134
|
-
attr :host
|
135
|
-
attr :port
|
136
|
-
|
137
|
-
def run(reactor: Async::Task.current.reactor)
|
138
|
-
reactor.with(make_socket) do |socket|
|
139
|
-
super(socket, reactor: reactor)
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
private
|
144
|
-
|
145
|
-
def make_socket
|
146
|
-
family ||= Async::DNS::address_family(@host)
|
147
|
-
|
148
|
-
socket = ::UDPSocket.new(family)
|
149
|
-
socket.bind(@host, @port)
|
150
|
-
|
151
|
-
return socket
|
152
|
-
end
|
153
|
-
end
|
154
|
-
|
155
|
-
class TCPHandler < GenericHandler
|
156
|
-
def run(socket, reactor:)
|
157
|
-
Async.logger.debug(self.class.name) {"-> Run on #{socket}..."}
|
158
|
-
|
159
|
-
reactor.with(socket.accept) do |client|
|
111
|
+
class StreamHandler < GenericHandler
|
112
|
+
def run(task: Async::Task.current)
|
113
|
+
@address.accept do |client, address|
|
160
114
|
handle_connection(client)
|
161
|
-
end
|
162
|
-
ensure
|
163
|
-
Async.logger.debug(self.class.name) {"<- Run ensure... #{$!}"}
|
115
|
+
end
|
164
116
|
end
|
165
117
|
|
166
118
|
def handle_connection(socket)
|
167
119
|
context = Async::Task.current
|
168
120
|
|
169
|
-
_, remote_port, remote_host = socket.io.peeraddr
|
170
|
-
options = {peer: remote_host, port: remote_port, proto: :tcp}
|
171
|
-
|
172
121
|
input_data = StreamTransport.read_chunk(socket)
|
173
122
|
|
174
|
-
response = process_query(input_data,
|
123
|
+
response = process_query(input_data, remote_address: socket.remote_address)
|
175
124
|
|
176
125
|
length = StreamTransport.write_message(socket, response)
|
177
126
|
|
@@ -186,44 +135,4 @@ module Async::DNS
|
|
186
135
|
@logger.warn "<> Error: Could not decode incoming TCP data!"
|
187
136
|
end
|
188
137
|
end
|
189
|
-
|
190
|
-
class TCPSocketHandler < TCPHandler
|
191
|
-
def initialize(server, socket)
|
192
|
-
@socket = socket
|
193
|
-
|
194
|
-
super(server)
|
195
|
-
end
|
196
|
-
|
197
|
-
attr :socket
|
198
|
-
|
199
|
-
def run(reactor: Async::Task.current.reactor)
|
200
|
-
reactor.async(@socket) do |socket|
|
201
|
-
super(socket, reactor: reactor)
|
202
|
-
end
|
203
|
-
end
|
204
|
-
end
|
205
|
-
|
206
|
-
class TCPServerHandler < TCPHandler
|
207
|
-
def initialize(server, host, port)
|
208
|
-
@host = host
|
209
|
-
@port = port
|
210
|
-
|
211
|
-
super(server)
|
212
|
-
end
|
213
|
-
|
214
|
-
attr :host
|
215
|
-
attr :port
|
216
|
-
|
217
|
-
def run(reactor: Async::Task.current.reactor)
|
218
|
-
reactor.with(make_socket) do |socket|
|
219
|
-
super(socket, reactor: reactor)
|
220
|
-
end
|
221
|
-
end
|
222
|
-
|
223
|
-
private
|
224
|
-
|
225
|
-
def make_socket
|
226
|
-
::TCPServer.new(@host, @port)
|
227
|
-
end
|
228
|
-
end
|
229
138
|
end
|
data/lib/async/dns/message.rb
CHANGED
@@ -33,7 +33,7 @@ module Async::DNS
|
|
33
33
|
Message = ::Resolv::DNS::Message
|
34
34
|
DecodeError = ::Resolv::DNS::DecodeError
|
35
35
|
|
36
|
-
|
36
|
+
@dump_bad_message = nil
|
37
37
|
|
38
38
|
# 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.
|
39
39
|
def self.log_bad_messages!(log_path)
|
data/lib/async/dns/resolver.rb
CHANGED
@@ -133,20 +133,19 @@ module Async::DNS
|
|
133
133
|
end
|
134
134
|
|
135
135
|
# Send the message to available servers. If no servers respond correctly, nil is returned. This result indicates a failure of the resolver to correctly contact any server and get a valid response.
|
136
|
-
def dispatch_request(message)
|
136
|
+
def dispatch_request(message, task: Async::Task.current)
|
137
137
|
request = Request.new(message, @servers)
|
138
|
-
context = Async::Task.current
|
139
138
|
|
140
|
-
request.each do |
|
141
|
-
@logger.debug "[#{message.id}] Sending request #{message.question.inspect} to
|
139
|
+
request.each do |address|
|
140
|
+
@logger.debug "[#{message.id}] Sending request #{message.question.inspect} to address #{address.inspect}" if @logger
|
142
141
|
|
143
142
|
begin
|
144
143
|
response = nil
|
145
144
|
|
146
|
-
|
147
|
-
@logger.debug "[#{message.id}] -> Try
|
148
|
-
response = try_server(request,
|
149
|
-
@logger.debug "[#{message.id}] <- Try
|
145
|
+
task.timeout(@timeout) do
|
146
|
+
@logger.debug "[#{message.id}] -> Try address #{address}" if @logger
|
147
|
+
response = try_server(request, address)
|
148
|
+
@logger.debug "[#{message.id}] <- Try address #{address} = #{response}" if @logger
|
150
149
|
end
|
151
150
|
|
152
151
|
if valid_response(message, response)
|
@@ -158,8 +157,10 @@ module Async::DNS
|
|
158
157
|
@logger.warn "[#{message.id}] Invalid response from network: #{$!}!" if @logger
|
159
158
|
rescue DecodeError
|
160
159
|
@logger.warn "[#{message.id}] Error while decoding data from network: #{$!}!" if @logger
|
161
|
-
rescue IOError
|
160
|
+
rescue IOError, Errno::ECONNRESET
|
162
161
|
@logger.warn "[#{message.id}] Error while reading from network: #{$!}!" if @logger
|
162
|
+
rescue EOFError
|
163
|
+
@logger.warn "[#{message.id}] Could not read complete response from network: #{$!}" if @logger
|
163
164
|
end
|
164
165
|
end
|
165
166
|
|
@@ -183,14 +184,14 @@ module Async::DNS
|
|
183
184
|
end
|
184
185
|
end
|
185
186
|
|
186
|
-
def try_server(request,
|
187
|
-
case
|
188
|
-
when
|
189
|
-
|
190
|
-
when
|
191
|
-
|
187
|
+
def try_server(request, address)
|
188
|
+
case address.type
|
189
|
+
when Socket::SOCK_DGRAM
|
190
|
+
try_datagram_server(request, address)
|
191
|
+
when Socket::SOCK_STREAM
|
192
|
+
try_stream_server(request, address)
|
192
193
|
else
|
193
|
-
raise InvalidProtocolError.new(
|
194
|
+
raise InvalidProtocolError.new(address)
|
194
195
|
end
|
195
196
|
end
|
196
197
|
|
@@ -208,34 +209,20 @@ module Async::DNS
|
|
208
209
|
return false
|
209
210
|
end
|
210
211
|
|
211
|
-
def
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
def try_udp_server(request, host, port)
|
216
|
-
context = Async::Task.current
|
217
|
-
|
218
|
-
family = Async::DNS::address_family(host)
|
219
|
-
|
220
|
-
context.with(UDPSocket.new(family)) do |socket|
|
221
|
-
socket.send(request.packet, 0, host, port)
|
222
|
-
|
223
|
-
data, (_, remote_port) = socket.recvfrom(UDP_TRUNCATION_SIZE)
|
224
|
-
# Need to check host, otherwise security issue.
|
212
|
+
def try_datagram_server(request, address, task: Async::Task.current)
|
213
|
+
address.connect do |socket|
|
214
|
+
socket.sendmsg(request.packet, 0)
|
225
215
|
|
226
|
-
|
227
|
-
if port != remote_port
|
228
|
-
raise InvalidResponseError.new("Data was not received from correct remote port (#{port} != #{remote_port})")
|
229
|
-
end
|
216
|
+
data, peer = socket.recvmsg(UDP_TRUNCATION_SIZE)
|
230
217
|
|
231
218
|
return Async::DNS::decode_message(data)
|
232
219
|
end
|
233
220
|
end
|
234
221
|
|
235
|
-
def
|
222
|
+
def try_stream_server(request, address)
|
236
223
|
context = Async::Task.current
|
237
224
|
|
238
|
-
|
225
|
+
address.connect do |socket|
|
239
226
|
StreamTransport.write_chunk(socket, request.packet)
|
240
227
|
|
241
228
|
input_data = StreamTransport.read_chunk(socket)
|
@@ -263,12 +250,7 @@ module Async::DNS
|
|
263
250
|
attr :logger
|
264
251
|
|
265
252
|
def each(&block)
|
266
|
-
@servers
|
267
|
-
# TODO: This seems odd...
|
268
|
-
next if @packet.bytesize > UDP_TRUNCATION_SIZE
|
269
|
-
|
270
|
-
yield server
|
271
|
-
end
|
253
|
+
Async::IO::Address.each(@servers, &block)
|
272
254
|
end
|
273
255
|
|
274
256
|
def update_id!(id)
|
data/lib/async/dns/server.rb
CHANGED
@@ -19,6 +19,7 @@
|
|
19
19
|
# THE SOFTWARE.
|
20
20
|
|
21
21
|
require 'async'
|
22
|
+
require 'async/io/address'
|
22
23
|
|
23
24
|
require_relative 'transaction'
|
24
25
|
require_relative 'logger'
|
@@ -107,9 +108,11 @@ module Async::DNS
|
|
107
108
|
|
108
109
|
setup_handlers if @handlers.empty?
|
109
110
|
|
110
|
-
Async::Reactor.run do
|
111
|
+
Async::Reactor.run do |task|
|
111
112
|
@handlers.each do |handler|
|
112
|
-
|
113
|
+
task.async do
|
114
|
+
handler.run(*args)
|
115
|
+
end
|
113
116
|
end
|
114
117
|
|
115
118
|
fire(:start)
|
@@ -121,32 +124,16 @@ module Async::DNS
|
|
121
124
|
def setup_handlers
|
122
125
|
fire(:setup)
|
123
126
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
case protocol
|
133
|
-
when Socket::SOCK_DGRAM
|
134
|
-
@logger.info "<> Attaching to pre-existing UDP socket #{ip}:#{port}"
|
135
|
-
@handlers << UDPSocketHandler.new(self, spec)
|
136
|
-
when Socket::SOCK_STREAM
|
137
|
-
@logger.info "<> Attaching to pre-existing TCP socket #{ip}:#{port}"
|
138
|
-
@handlers << TCPSocketHandler.new(self, spec)
|
139
|
-
else
|
140
|
-
raise ArgumentError.new("Unknown socket protocol: #{protocol}")
|
141
|
-
end
|
142
|
-
elsif spec[0] == :udp
|
143
|
-
@logger.info "<> Listening on #{spec.join(':')}"
|
144
|
-
@handlers << UDPServerHandler.new(self, spec[1], spec[2])
|
145
|
-
elsif spec[0] == :tcp
|
146
|
-
@logger.info "<> Listening on #{spec.join(':')}"
|
147
|
-
@handlers << TCPServerHandler.new(self, spec[1], spec[2])
|
127
|
+
Async::IO::Address.each(@interfaces) do |address|
|
128
|
+
case address.type
|
129
|
+
when Socket::SOCK_DGRAM
|
130
|
+
@logger.info "<> Listening for datagrams on #{address.inspect}"
|
131
|
+
@handlers << DatagramHandler.new(self, address)
|
132
|
+
when Socket::SOCK_STREAM
|
133
|
+
@logger.info "<> Listening for connections on #{address.inspect}"
|
134
|
+
@handlers << StreamHandler.new(self, address)
|
148
135
|
else
|
149
|
-
raise ArgumentError.new("
|
136
|
+
raise ArgumentError.new("Don't know how to handle #{address}")
|
150
137
|
end
|
151
138
|
end
|
152
139
|
end
|
data/lib/async/dns/transport.rb
CHANGED
@@ -44,7 +44,11 @@ module Async::DNS
|
|
44
44
|
|
45
45
|
# First we need to read in the length of the packet
|
46
46
|
while buffer.size < 2
|
47
|
-
|
47
|
+
if data = socket.read(1)
|
48
|
+
buffer.write data
|
49
|
+
else
|
50
|
+
raise EOFError, "Could not read message size!"
|
51
|
+
end
|
48
52
|
end
|
49
53
|
|
50
54
|
# Read in the length, the first two bytes:
|
@@ -55,7 +59,11 @@ module Async::DNS
|
|
55
59
|
required = (2 + length) - buffer.size
|
56
60
|
|
57
61
|
# Read precisely the required amount:
|
58
|
-
|
62
|
+
if data = socket.read(required)
|
63
|
+
buffer.write data
|
64
|
+
else
|
65
|
+
raise EOFError, "Could not read message data!"
|
66
|
+
end
|
59
67
|
end
|
60
68
|
|
61
69
|
return buffer.string.byteslice(2, length)
|
data/lib/async/dns/version.rb
CHANGED
@@ -21,38 +21,40 @@
|
|
21
21
|
require 'async/dns'
|
22
22
|
require 'async/dns/system'
|
23
23
|
|
24
|
-
describe Async::DNS::
|
24
|
+
describe Async::DNS::StreamHandler do
|
25
|
+
include_context Async::RSpec::Reactor
|
26
|
+
|
25
27
|
let(:server) {Async::DNS::Server.new}
|
26
|
-
let(:
|
27
|
-
let(:port) {6665}
|
28
|
+
let(:address) {Async::IO::Address.tcp('127.0.0.1', 6666)}
|
28
29
|
|
29
|
-
subject {described_class.new(server,
|
30
|
+
subject {described_class.new(server, address)}
|
30
31
|
|
31
32
|
it "can rebind port" do
|
32
33
|
2.times do
|
33
|
-
|
34
|
-
|
34
|
+
task = reactor.async do
|
35
|
+
subject.run
|
36
|
+
end
|
35
37
|
|
36
|
-
|
37
|
-
expect(socket).to be_closed
|
38
|
+
task.stop
|
38
39
|
end
|
39
40
|
end
|
40
41
|
end
|
41
42
|
|
42
|
-
describe Async::DNS::
|
43
|
+
describe Async::DNS::DatagramHandler do
|
44
|
+
include_context Async::RSpec::Reactor
|
45
|
+
|
43
46
|
let(:server) {Async::DNS::Server.new}
|
44
|
-
let(:
|
45
|
-
let(:port) {6665}
|
47
|
+
let(:address) {Async::IO::Address.udp('127.0.0.1', 6666)}
|
46
48
|
|
47
|
-
subject {described_class.new(server,
|
49
|
+
subject {described_class.new(server, address)}
|
48
50
|
|
49
51
|
it "can rebind port" do
|
50
52
|
2.times do
|
51
|
-
|
52
|
-
|
53
|
+
task = reactor.async do
|
54
|
+
subject.run
|
55
|
+
end
|
53
56
|
|
54
|
-
|
55
|
-
expect(socket).to be_closed
|
57
|
+
task.stop
|
56
58
|
end
|
57
59
|
end
|
58
60
|
end
|
data/spec/async/dns/ipv6_spec.rb
CHANGED
@@ -34,12 +34,12 @@ module Async::DNS::IPv6Spec
|
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
|
-
describe Async::DNS::
|
37
|
+
describe Async::DNS::StreamHandler do
|
38
|
+
include_context Async::RSpec::Reactor
|
39
|
+
|
38
40
|
let(:server_interfaces) {[[:tcp, '::', 2004]]}
|
39
41
|
let(:server) {TestServer.new(listen: server_interfaces)}
|
40
42
|
|
41
|
-
include_context "reactor"
|
42
|
-
|
43
43
|
it "should connect to the server using TCP via IPv6" do
|
44
44
|
task = server.run
|
45
45
|
|
@@ -55,12 +55,12 @@ module Async::DNS::IPv6Spec
|
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
58
|
-
describe Async::DNS::
|
58
|
+
describe Async::DNS::DatagramHandler do
|
59
|
+
include_context Async::RSpec::Reactor
|
60
|
+
|
59
61
|
let(:server_interfaces) {[[:udp, '::', 2006]]}
|
60
62
|
let(:server) {TestServer.new(listen: server_interfaces)}
|
61
63
|
|
62
|
-
include_context "reactor"
|
63
|
-
|
64
64
|
it "should connect to the server using UDP via IPv6" do
|
65
65
|
task = server.run
|
66
66
|
|
@@ -25,7 +25,7 @@ require 'async/dns/replace'
|
|
25
25
|
|
26
26
|
module Async::DNS::ReplaceSpec
|
27
27
|
describe Async::DNS::Replace do
|
28
|
-
include_context
|
28
|
+
include_context Async::RSpec::Reactor
|
29
29
|
|
30
30
|
let(:default_resolver) {Async::DNS::Resolver.new([[:udp, "8.8.8.8", 53], [:tcp, "8.8.8.8", 53]])}
|
31
31
|
|
@@ -24,51 +24,39 @@ require 'async/dns'
|
|
24
24
|
|
25
25
|
module Async::DNS::ResolverSpec
|
26
26
|
describe Async::DNS::Resolver do
|
27
|
+
include_context Async::RSpec::Reactor
|
28
|
+
|
27
29
|
class JunkUDPServer
|
28
|
-
def initialize
|
29
|
-
@
|
30
|
-
@socket.bind("0.0.0.0", 6060)
|
30
|
+
def initialize(server_address = nil)
|
31
|
+
@server_address = server_address || Addrinfo.udp('0.0.0.0', 6060)
|
31
32
|
end
|
32
33
|
|
33
|
-
def
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
socket.send("Foobar", 0, host, port)
|
34
|
+
def run(task: Async::Task.current)
|
35
|
+
task.async do
|
36
|
+
Async::IO::Socket.bind(@server_address) do |socket|
|
37
|
+
while true
|
38
|
+
data, address = socket.recvfrom(1024)
|
39
|
+
socket.send("foobar", 0, address)
|
40
|
+
end
|
41
|
+
end
|
42
42
|
end
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
46
|
class JunkTCPServer
|
47
|
-
def initialize
|
48
|
-
@
|
49
|
-
end
|
50
|
-
|
51
|
-
def stop
|
52
|
-
@task.stop
|
53
|
-
@socket.close
|
47
|
+
def initialize(server_address = nil)
|
48
|
+
@server_address = server_address || Addrinfo.tcp('0.0.0.0', 6060)
|
54
49
|
end
|
55
|
-
|
56
|
-
def run(
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
end while true
|
50
|
+
|
51
|
+
def run(task: Async::Task.current)
|
52
|
+
task.async do
|
53
|
+
Async::IO::Socket.accept(@server_address, backlog: 10) do |socket|
|
54
|
+
socket.write("f\0\0bar")
|
55
|
+
end
|
62
56
|
end
|
63
57
|
end
|
64
|
-
|
65
|
-
def handle_connection(socket)
|
66
|
-
socket.write("\0\0obar")
|
67
|
-
end
|
68
58
|
end
|
69
59
|
|
70
|
-
include_context "reactor"
|
71
|
-
|
72
60
|
it "should result in non-existent domain" do
|
73
61
|
resolver = Async::DNS::Resolver.new([[:udp, "8.8.8.8", 53], [:tcp, "8.8.8.8", 53]])
|
74
62
|
|
@@ -103,7 +91,7 @@ module Async::DNS::ResolverSpec
|
|
103
91
|
let(:udp_server) {JunkUDPServer.new}
|
104
92
|
|
105
93
|
it "should fail with decode error from bad udp server" do
|
106
|
-
udp_server.run
|
94
|
+
server = udp_server.run
|
107
95
|
|
108
96
|
resolver = Async::DNS::Resolver.new([[:udp, "0.0.0.0", 6060]])
|
109
97
|
|
@@ -111,13 +99,13 @@ module Async::DNS::ResolverSpec
|
|
111
99
|
|
112
100
|
expect(response).to be == nil
|
113
101
|
|
114
|
-
|
102
|
+
server.stop
|
115
103
|
end
|
116
104
|
|
117
105
|
let(:tcp_server) {JunkTCPServer.new}
|
118
106
|
|
119
107
|
it "should fail with decode error from bad tcp server" do
|
120
|
-
tcp_server.run
|
108
|
+
server = tcp_server.run
|
121
109
|
|
122
110
|
resolver = Async::DNS::Resolver.new([[:tcp, "0.0.0.0", 6060]])
|
123
111
|
|
@@ -125,7 +113,7 @@ module Async::DNS::ResolverSpec
|
|
125
113
|
|
126
114
|
expect(response).to be == nil
|
127
115
|
|
128
|
-
|
116
|
+
server.stop
|
129
117
|
end
|
130
118
|
|
131
119
|
it "should return some IPv4 and IPv6 addresses" do
|
@@ -36,7 +36,7 @@ module Async::DNS::SlowServerSpec
|
|
36
36
|
end
|
37
37
|
|
38
38
|
describe "Async::DNS Slow Server" do
|
39
|
-
include_context
|
39
|
+
include_context Async::RSpec::Reactor
|
40
40
|
|
41
41
|
let(:server_interfaces) {[[:udp, '0.0.0.0', 5330], [:tcp, '0.0.0.0', 5330]]}
|
42
42
|
let(:server) {SlowServer.new(listen: server_interfaces)}
|
@@ -34,8 +34,8 @@ module Async::DNS::SocketSpec
|
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
|
-
describe Async::DNS::
|
38
|
-
include_context
|
37
|
+
describe Async::DNS::StreamHandler do
|
38
|
+
include_context Async::RSpec::Reactor
|
39
39
|
|
40
40
|
let(:server_interfaces) {[TCPServer.new('127.0.0.1', 2002)]}
|
41
41
|
let(:server) {TestServer.new(listen: server_interfaces)}
|
@@ -48,11 +48,12 @@ module Async::DNS::SocketSpec
|
|
48
48
|
expect(response.class).to be == Async::DNS::Message
|
49
49
|
|
50
50
|
task.stop
|
51
|
+
server_interfaces.each(&:close)
|
51
52
|
end
|
52
53
|
end
|
53
54
|
|
54
|
-
describe Async::DNS::
|
55
|
-
include_context
|
55
|
+
describe Async::DNS::DatagramHandler do
|
56
|
+
include_context Async::RSpec::Reactor
|
56
57
|
|
57
58
|
let(:server_interfaces) {[UDPSocket.new.tap{|socket| socket.bind('127.0.0.1', 2002)}]}
|
58
59
|
let(:server) {TestServer.new(listen: server_interfaces)}
|
@@ -65,6 +66,7 @@ module Async::DNS::SocketSpec
|
|
65
66
|
expect(response.class).to be == Async::DNS::Message
|
66
67
|
|
67
68
|
task.stop
|
69
|
+
server_interfaces.each(&:close)
|
68
70
|
end
|
69
71
|
end
|
70
72
|
end
|
@@ -25,7 +25,7 @@ require 'async/dns/system'
|
|
25
25
|
|
26
26
|
module Async::DNS::SystemSpec
|
27
27
|
describe Async::DNS::System do
|
28
|
-
include_context
|
28
|
+
include_context Async::RSpec::Reactor
|
29
29
|
|
30
30
|
it "should have at least one namesever" do
|
31
31
|
expect(Async::DNS::System::nameservers.length).to be > 0
|
@@ -34,7 +34,7 @@ module Async::DNS::TransactionSpec
|
|
34
34
|
let(:response) { Async::DNS::Message.new(0) }
|
35
35
|
let(:resolver) { Async::DNS::Resolver.new([[:udp, '8.8.8.8', 53], [:tcp, '8.8.8.8', 53]])}
|
36
36
|
|
37
|
-
include_context
|
37
|
+
include_context Async::RSpec::Reactor
|
38
38
|
|
39
39
|
it "should append an address" do
|
40
40
|
transaction = Async::DNS::Transaction.new(server, query, question, IN::A, response)
|
data/spec/spec_helper.rb
CHANGED
@@ -23,30 +23,8 @@ if ENV['COVERAGE'] || ENV['TRAVIS']
|
|
23
23
|
end
|
24
24
|
|
25
25
|
require "bundler/setup"
|
26
|
-
require "
|
26
|
+
require "async/rspec"
|
27
27
|
require "async/dns"
|
28
|
-
require "pp"
|
29
|
-
|
30
|
-
RSpec.shared_context "reactor" do
|
31
|
-
let(:reactor) {Async::Reactor.new}
|
32
|
-
|
33
|
-
around(:each) do |example|
|
34
|
-
result = nil
|
35
|
-
|
36
|
-
reactor.run do
|
37
|
-
result = example.run
|
38
|
-
|
39
|
-
# Force the reactor to stop running if the result was an error.
|
40
|
-
if result.is_a? Exception
|
41
|
-
reactor.stop
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
reactor.close
|
46
|
-
|
47
|
-
result
|
48
|
-
end
|
49
|
-
end
|
50
28
|
|
51
29
|
# abort "Warning, ulimit is too low!" if `ulimit -n`.to_i < 10000
|
52
30
|
|
metadata
CHANGED
@@ -1,43 +1,57 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: async-dns
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.12.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel Williams
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-05-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name: async
|
14
|
+
name: async-io
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '0.
|
19
|
+
version: '0.1'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '0.
|
26
|
+
version: '0.1'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: async-rspec
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.0'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: process-daemon
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
30
44
|
requirements:
|
31
45
|
- - "~>"
|
32
46
|
- !ruby/object:Gem::Version
|
33
|
-
version: 1.0
|
47
|
+
version: '1.0'
|
34
48
|
type: :development
|
35
49
|
prerelease: false
|
36
50
|
version_requirements: !ruby/object:Gem::Requirement
|
37
51
|
requirements:
|
38
52
|
- - "~>"
|
39
53
|
- !ruby/object:Gem::Version
|
40
|
-
version: 1.0
|
54
|
+
version: '1.0'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: bundler
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -58,14 +72,14 @@ dependencies:
|
|
58
72
|
requirements:
|
59
73
|
- - "~>"
|
60
74
|
- !ruby/object:Gem::Version
|
61
|
-
version: 3.
|
75
|
+
version: '3.6'
|
62
76
|
type: :development
|
63
77
|
prerelease: false
|
64
78
|
version_requirements: !ruby/object:Gem::Requirement
|
65
79
|
requirements:
|
66
80
|
- - "~>"
|
67
81
|
- !ruby/object:Gem::Version
|
68
|
-
version: 3.
|
82
|
+
version: '3.6'
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: rake
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -88,6 +102,7 @@ executables: []
|
|
88
102
|
extensions: []
|
89
103
|
extra_rdoc_files: []
|
90
104
|
files:
|
105
|
+
- ".gitignore"
|
91
106
|
- ".rspec"
|
92
107
|
- ".travis.yml"
|
93
108
|
- Gemfile
|