redns 0.0.0 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/VERSION +1 -1
- data/lib/redns/connection.rb +65 -0
- data/lib/redns/message.rb +30 -14
- data/lib/redns/name.rb +4 -1
- data/lib/redns/question.rb +8 -2
- data/lib/redns/resolver.rb +274 -0
- data/lib/redns/resource.rb +1 -1
- data/lib/redns/support.rb +42 -0
- data/lib/redns.rb +2 -0
- data/redns.gemspec +8 -2
- data/test/test_redns_connection.rb +39 -0
- data/test/test_redns_message.rb +137 -1
- data/test/test_redns_name.rb +10 -2
- data/test/test_redns_resolver.rb +120 -0
- data/test/test_redns_support.rb +5 -0
- metadata +9 -3
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.1.0
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'socket'
|
2
|
+
|
3
|
+
class ReDNS::Connection < EventMachine::Connection
|
4
|
+
# == Constants ============================================================
|
5
|
+
|
6
|
+
# == Extensions ===========================================================
|
7
|
+
|
8
|
+
include EventMachine::Deferrable
|
9
|
+
|
10
|
+
# == Class Methods ========================================================
|
11
|
+
|
12
|
+
def self.instance
|
13
|
+
EventMachine.open_datagram_socket(
|
14
|
+
ReDNS::Support.bind_all_addr,
|
15
|
+
0,
|
16
|
+
self
|
17
|
+
)
|
18
|
+
end
|
19
|
+
|
20
|
+
# == Instance Methods =====================================================
|
21
|
+
|
22
|
+
def post_init
|
23
|
+
# Sequence numbers do not have to be cryptographically secure, but having
|
24
|
+
# a healthy amount of randomness is a good thing.
|
25
|
+
@sequence = (rand(0x10000) ^ (object_id ^ (Time.now.to_f * 100000).to_i)) % 0x10000
|
26
|
+
|
27
|
+
# Callback tracking is done by matching response IDs in a lookup table
|
28
|
+
@callback = { }
|
29
|
+
end
|
30
|
+
|
31
|
+
def port
|
32
|
+
Socket.unpack_sockaddr_in(get_sockname)[0]
|
33
|
+
end
|
34
|
+
|
35
|
+
def receive_data(data)
|
36
|
+
message = ReDNS::Message.new(ReDNS::Buffer.new(data))
|
37
|
+
|
38
|
+
if (callback = @callback[message.id])
|
39
|
+
callback.yield(message.answers.collect { |a| a.rdata.to_s })
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def resolve(query, type = nil, &callback)
|
44
|
+
message = ReDNS::Message.question(query, type) do |m|
|
45
|
+
m.id = @sequence
|
46
|
+
end
|
47
|
+
|
48
|
+
result = send_datagram(
|
49
|
+
message.serialize.to_s,
|
50
|
+
ReDNS::Support.default_resolver_address,
|
51
|
+
ReDNS::Support.dns_port
|
52
|
+
)
|
53
|
+
|
54
|
+
if (result > 0)
|
55
|
+
@callback[@sequence] = callback
|
56
|
+
else
|
57
|
+
callback.call(nil)
|
58
|
+
end
|
59
|
+
|
60
|
+
@sequence += 1
|
61
|
+
end
|
62
|
+
|
63
|
+
def unbind
|
64
|
+
end
|
65
|
+
end
|
data/lib/redns/message.rb
CHANGED
@@ -12,7 +12,7 @@ class ReDNS::Message < ReDNS::Fragment
|
|
12
12
|
attribute :opcode, :default => :query
|
13
13
|
attribute :authorative, :boolean => true, :default => false
|
14
14
|
attribute :truncated, :boolean => true, :default => false
|
15
|
-
attribute :recursion_desired, :boolean => true, :default =>
|
15
|
+
attribute :recursion_desired, :boolean => true, :default => true
|
16
16
|
attribute :recursion_available, :boolean => true, :default => false
|
17
17
|
attribute :response_code, :default => :noerror
|
18
18
|
|
@@ -27,11 +27,28 @@ class ReDNS::Message < ReDNS::Fragment
|
|
27
27
|
attribute :additional_records, :default => lambda { [ ] }
|
28
28
|
|
29
29
|
# == Class Methods ========================================================
|
30
|
+
|
31
|
+
def self.question(name, qtype = nil)
|
32
|
+
qtype ||= ReDNS::Support.is_ip?(name) ? :ptr : :a
|
33
|
+
|
34
|
+
message = new(
|
35
|
+
:questions => [
|
36
|
+
ReDNS::Question.new(
|
37
|
+
:name => name,
|
38
|
+
:qtype => qtype
|
39
|
+
)
|
40
|
+
]
|
41
|
+
)
|
42
|
+
|
43
|
+
yield(message) if (block_given?)
|
44
|
+
|
45
|
+
message
|
46
|
+
end
|
30
47
|
|
31
48
|
# == Instance Methods =====================================================
|
32
49
|
|
33
50
|
def increment_id!
|
34
|
-
|
51
|
+
self.id += 1
|
35
52
|
end
|
36
53
|
|
37
54
|
def response?
|
@@ -83,9 +100,9 @@ class ReDNS::Message < ReDNS::Fragment
|
|
83
100
|
(ReDNS::OPCODE[self.opcode] || ReDNS::OPCODE[:unknown]) << 12 |
|
84
101
|
(self.authorative? ? 0x0400 : 0) |
|
85
102
|
(self.truncated? ? 0x0200 : 0) |
|
86
|
-
(self.
|
103
|
+
(self.recursion_desired? ? 0x0100 : 0) |
|
87
104
|
(self.recursion_available? ? 0x0080 : 0) |
|
88
|
-
(ReDNS::RCODE[self.
|
105
|
+
(ReDNS::RCODE[self.response_code] || ReDNS::RCODE[:noerror])
|
89
106
|
),
|
90
107
|
self.questions.length,
|
91
108
|
self.answers.length,
|
@@ -96,7 +113,7 @@ class ReDNS::Message < ReDNS::Fragment
|
|
96
113
|
)
|
97
114
|
|
98
115
|
[ :questions, :answers, :nameservers, :additional_records ].each do |section|
|
99
|
-
@attributes[
|
116
|
+
@attributes[section] and @attributes[section].each do |part|
|
100
117
|
part.serialize(buffer)
|
101
118
|
end
|
102
119
|
end
|
@@ -110,14 +127,13 @@ class ReDNS::Message < ReDNS::Fragment
|
|
110
127
|
self.id = data.shift
|
111
128
|
|
112
129
|
flags = data.shift
|
113
|
-
self.query = flags & 0x8000
|
114
|
-
self.opcode = (flags & 0x7800) >> 12
|
115
|
-
self.authorative = flags & 0x0400
|
116
|
-
self.truncated = flags & 0x0200
|
117
|
-
self.recursion_desired = flags & 0x0100
|
118
|
-
|
119
|
-
self.
|
120
|
-
self.response_code = flags & 0x000F
|
130
|
+
self.query = (flags & 0x8000 == 0)
|
131
|
+
self.opcode = ReDNS::OPCODE_LABEL[(flags & 0x7800) >> 12]
|
132
|
+
self.authorative = (flags & 0x0400 != 0)
|
133
|
+
self.truncated = (flags & 0x0200 != 0)
|
134
|
+
self.recursion_desired = (flags & 0x0100 != 0)
|
135
|
+
self.recursion_available = (flags & 0x0080 != 0)
|
136
|
+
self.response_code = ReDNS::RCODE_LABEL[flags & 0x000F]
|
121
137
|
|
122
138
|
SECTIONS.each do |section|
|
123
139
|
@attributes[:"#{section}_count"] = data.shift
|
@@ -128,7 +144,7 @@ class ReDNS::Message < ReDNS::Fragment
|
|
128
144
|
|
129
145
|
decode_class =
|
130
146
|
case (section)
|
131
|
-
when :
|
147
|
+
when :questions
|
132
148
|
ReDNS::Question
|
133
149
|
else
|
134
150
|
ReDNS::Resource
|
data/lib/redns/name.rb
CHANGED
@@ -13,7 +13,10 @@ class ReDNS::Name < ReDNS::Fragment
|
|
13
13
|
super(contents)
|
14
14
|
when String
|
15
15
|
super(:name => contents)
|
16
|
-
|
16
|
+
|
17
|
+
unless (ReDNS::Support.is_ip?(name) or self.name.match(/\.$/))
|
18
|
+
self.name += '.'
|
19
|
+
end
|
17
20
|
else
|
18
21
|
super(contents)
|
19
22
|
end
|
data/lib/redns/question.rb
CHANGED
@@ -20,13 +20,19 @@ class ReDNS::Question < ReDNS::Fragment
|
|
20
20
|
|
21
21
|
def serialize(buffer = ReDNS::Buffer.new)
|
22
22
|
name.serialize(buffer)
|
23
|
-
buffer.pack(
|
23
|
+
buffer.pack(
|
24
|
+
[
|
25
|
+
ReDNS::RR_TYPE[self.qtype],
|
26
|
+
ReDNS::RR_CLASS[self.qclass]
|
27
|
+
],
|
28
|
+
'nn'
|
29
|
+
)
|
24
30
|
|
25
31
|
buffer
|
26
32
|
end
|
27
33
|
|
28
34
|
def deserialize(buffer)
|
29
|
-
self.name =
|
35
|
+
self.name = ReDNS::Name.new(buffer)
|
30
36
|
|
31
37
|
data = buffer.unpack('nn')
|
32
38
|
|
@@ -0,0 +1,274 @@
|
|
1
|
+
require 'socket'
|
2
|
+
require 'fcntl'
|
3
|
+
|
4
|
+
BasicSocket.do_not_reverse_lookup = true
|
5
|
+
|
6
|
+
class ReDNS::Resolver
|
7
|
+
# == Class Properties =====================================================
|
8
|
+
|
9
|
+
@servers = nil
|
10
|
+
@timeout = 5
|
11
|
+
|
12
|
+
# == Class Methods ========================================================
|
13
|
+
|
14
|
+
def self.in_resolv_conf
|
15
|
+
list = [ ]
|
16
|
+
|
17
|
+
File.open("/etc/resolv.conf") do |fh|
|
18
|
+
list = fh.readlines.collect { |l| l.chomp }.collect { |l| l.sub(/#.*/, '') }
|
19
|
+
|
20
|
+
list.reject!{ |l| !l.sub!(/^\s*nameserver\s+/, '') }
|
21
|
+
end
|
22
|
+
|
23
|
+
list
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.servers
|
27
|
+
@servers ||= in_resolv_conf
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.servers=(list)
|
31
|
+
@servers = list
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.timeout
|
35
|
+
@timeout
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.timeout=(secs)
|
39
|
+
@timeout = secs
|
40
|
+
end
|
41
|
+
|
42
|
+
# == Instance Methods =====================================================
|
43
|
+
|
44
|
+
def initialize(options = { }, &block)
|
45
|
+
@servers = self.class.servers.dup
|
46
|
+
@responses = { }
|
47
|
+
|
48
|
+
@socket = UDPSocket.new
|
49
|
+
ReDNS::Support.io_set_nonblock(@socket)
|
50
|
+
|
51
|
+
yield(self) if (block)
|
52
|
+
end
|
53
|
+
|
54
|
+
def simple_query(type, name)
|
55
|
+
r = query do |q|
|
56
|
+
q.qtype = type
|
57
|
+
q.name = name.to_s
|
58
|
+
end
|
59
|
+
|
60
|
+
expand_answers(r)
|
61
|
+
end
|
62
|
+
|
63
|
+
def bulk_query(type, names)
|
64
|
+
results = { }
|
65
|
+
ids = [ ]
|
66
|
+
|
67
|
+
message ||= ReDNS::Message.new
|
68
|
+
q = (message.questions[0] ||= ReDNS::Question.new)
|
69
|
+
q.qtype = type
|
70
|
+
|
71
|
+
names.each do |name|
|
72
|
+
q.name = name.to_s
|
73
|
+
message.increment_id!
|
74
|
+
ids.push(message.id)
|
75
|
+
|
76
|
+
send_message(message)
|
77
|
+
end
|
78
|
+
|
79
|
+
wait_for_responses do |response, addr|
|
80
|
+
results[response.questions[0].name.to_s] = response
|
81
|
+
|
82
|
+
ids.delete(response.id)
|
83
|
+
|
84
|
+
return results if (ids.empty?)
|
85
|
+
end
|
86
|
+
|
87
|
+
results
|
88
|
+
end
|
89
|
+
|
90
|
+
def a_for(name)
|
91
|
+
simple_query(:a, name)
|
92
|
+
end
|
93
|
+
|
94
|
+
def ns_for(name)
|
95
|
+
if (name.match(/^(\d+\.\d+\.\d+)\.\d+$/))
|
96
|
+
return simple_query(:ns, ReDNS::Support.addr_to_arpa($1))
|
97
|
+
end
|
98
|
+
|
99
|
+
simple_query(:ns, name)
|
100
|
+
end
|
101
|
+
|
102
|
+
def mx_for(name)
|
103
|
+
simple_query(:mx, name)
|
104
|
+
end
|
105
|
+
|
106
|
+
def ptr_for(name)
|
107
|
+
simple_query(:ptr, DNS.to_arpa(name))
|
108
|
+
end
|
109
|
+
|
110
|
+
def ptr_for_list(name)
|
111
|
+
ips = [ ips ].flatten
|
112
|
+
|
113
|
+
bulk_query(:ptr, ips.collect { |ip| ReDNS::Support.addr_to_arpa(ip) })
|
114
|
+
end
|
115
|
+
|
116
|
+
def soa_for(name)
|
117
|
+
simple_query(:soa, name)
|
118
|
+
end
|
119
|
+
|
120
|
+
def reverse_addresses(ips)
|
121
|
+
map = ips.inject({ }) do |h, ip|
|
122
|
+
h[ReDNS::Support.addr_to_arpa(ip)] = ip
|
123
|
+
h
|
124
|
+
end
|
125
|
+
|
126
|
+
list = bulk_query(:ptr, map.keys)
|
127
|
+
|
128
|
+
list.values.inject({ }) do |h, r|
|
129
|
+
if (ip = map[r.questions[0].name.to_s])
|
130
|
+
h[ip] = (r.answers[0] and r.answers[0].rdata.to_s)
|
131
|
+
end
|
132
|
+
|
133
|
+
h
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def servers
|
138
|
+
@servers
|
139
|
+
end
|
140
|
+
|
141
|
+
def servers=(list)
|
142
|
+
@servers = list
|
143
|
+
end
|
144
|
+
|
145
|
+
def random_server
|
146
|
+
@servers[rand(@servers.length)]
|
147
|
+
end
|
148
|
+
|
149
|
+
def send_message(message, server = nil)
|
150
|
+
@socket.send(message.serialize.to_s, 0, (server or random_server), 53)
|
151
|
+
end
|
152
|
+
|
153
|
+
def query(message = nil, server = nil, async = false, &block)
|
154
|
+
# FUTURE: Fix the duplication here and in query_async
|
155
|
+
|
156
|
+
message ||= ReDNS::Message.new
|
157
|
+
message.questions[0] ||= ReDNS::Question.new
|
158
|
+
|
159
|
+
yield(message.questions[0]) if (block)
|
160
|
+
|
161
|
+
send_message(message, server)
|
162
|
+
|
163
|
+
unless (async)
|
164
|
+
wait_for_responses do |r, addr|
|
165
|
+
return r if (r.id == message.id)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def response_for(id)
|
171
|
+
@responses[id]
|
172
|
+
end
|
173
|
+
|
174
|
+
def responses
|
175
|
+
@responses
|
176
|
+
end
|
177
|
+
|
178
|
+
def timeout
|
179
|
+
@timeout or self.class.timeout
|
180
|
+
end
|
181
|
+
|
182
|
+
def timeout=(secs)
|
183
|
+
@timeout = secs
|
184
|
+
end
|
185
|
+
|
186
|
+
def wait(_timeout = nil, &block)
|
187
|
+
wait_for_response(nil, _timeout, &block)
|
188
|
+
end
|
189
|
+
|
190
|
+
def wait_for_responses(_timeout = nil, &block)
|
191
|
+
start = Time.now
|
192
|
+
|
193
|
+
_timeout ||= timeout
|
194
|
+
left = _timeout - Time.now.to_f + start.to_f
|
195
|
+
|
196
|
+
while (left > 0)
|
197
|
+
if (ready = IO.select([ @socket ], nil, nil, left))
|
198
|
+
ready[0].each do |socket|
|
199
|
+
data = socket.recvfrom(1524)
|
200
|
+
|
201
|
+
r = ReDNS::Message.new(ReDNS::Buffer.new(data[0]))
|
202
|
+
|
203
|
+
yield(r, data[1]) if (block)
|
204
|
+
|
205
|
+
@responses[r.id] = [ r, data[1] ]
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
left = _timeout - Time.now.to_f + start.to_f
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
protected
|
214
|
+
def expand_answers(r)
|
215
|
+
unless (r and r.answers)
|
216
|
+
return nil
|
217
|
+
end
|
218
|
+
|
219
|
+
result = r.answers
|
220
|
+
radd = (r.additional or [ ])
|
221
|
+
|
222
|
+
result.reject { |rr| rr.rtype == :a }.each do |rr|
|
223
|
+
# Additional resource records may be related to the query, or they
|
224
|
+
# might just be convenience records that are not directly helpful.
|
225
|
+
|
226
|
+
rr_rdata = rr.rdata.to_a[0]
|
227
|
+
|
228
|
+
# First, see if there are additional records immediately available
|
229
|
+
additional = radd.find_all { |i| i.name.to_s == rr_rdata }
|
230
|
+
|
231
|
+
if (additional.empty?)
|
232
|
+
# Otherwise go fetch them
|
233
|
+
additional = a_for(rr_rdata)
|
234
|
+
end
|
235
|
+
|
236
|
+
if (additional and !additional.empty?)
|
237
|
+
# Push any results into the record itself
|
238
|
+
rr.additional = additional
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
result
|
243
|
+
end
|
244
|
+
|
245
|
+
def expand_answers_a(r)
|
246
|
+
unless (r and r.answers)
|
247
|
+
return nil
|
248
|
+
end
|
249
|
+
|
250
|
+
rev = { }
|
251
|
+
|
252
|
+
res = r.answers.collect do |a|
|
253
|
+
row = a.to_a
|
254
|
+
rev[row[4]] = nil
|
255
|
+
row
|
256
|
+
end
|
257
|
+
|
258
|
+
r.additional and r.additional.each do |a|
|
259
|
+
row = a.to_a
|
260
|
+
rev[row[0]] = row[4]
|
261
|
+
res.push(row)
|
262
|
+
end
|
263
|
+
|
264
|
+
rev.each do |addr, ip|
|
265
|
+
unless (ip)
|
266
|
+
if (add = a_for(addr))
|
267
|
+
res += add
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
res
|
273
|
+
end
|
274
|
+
end
|
data/lib/redns/resource.rb
CHANGED
data/lib/redns/support.rb
CHANGED
@@ -14,6 +14,48 @@ module ReDNS::Support
|
|
14
14
|
c.to_i
|
15
15
|
end.pack("C*")
|
16
16
|
end
|
17
|
+
|
18
|
+
def io_nonblock?(io)
|
19
|
+
(io.fcntl(Fcntl::F_GETFL) & File::NONBLOCK) != 0
|
20
|
+
end
|
21
|
+
|
22
|
+
def io_set_nonblock(io, nb = true)
|
23
|
+
flags = io.fcntl(Fcntl::F_GETFL)
|
24
|
+
|
25
|
+
if (nb)
|
26
|
+
flags |= File::NONBLOCK
|
27
|
+
else
|
28
|
+
flags &= ~File::NONBLOCK
|
29
|
+
end
|
30
|
+
|
31
|
+
io.fcntl(Fcntl::F_SETFL, flags)
|
32
|
+
end
|
33
|
+
|
34
|
+
def io_nonblock(nb = true, &block)
|
35
|
+
flag = io_nonblock?(io)
|
36
|
+
|
37
|
+
io_set_nonblock(io, nb)
|
38
|
+
|
39
|
+
yield(block)
|
40
|
+
ensure
|
41
|
+
io_set_nonblock(io, flag)
|
42
|
+
end
|
43
|
+
|
44
|
+
def bind_all_addr
|
45
|
+
'0.0.0.0'
|
46
|
+
end
|
47
|
+
|
48
|
+
def is_ip?(address)
|
49
|
+
address and address.match(/^\d+(\.\d+)+$/)
|
50
|
+
end
|
51
|
+
|
52
|
+
def dns_port
|
53
|
+
53
|
54
|
+
end
|
55
|
+
|
56
|
+
def default_resolver_address
|
57
|
+
ReDNS::Resolver.servers.first
|
58
|
+
end
|
17
59
|
|
18
60
|
extend(self)
|
19
61
|
end
|
data/lib/redns.rb
CHANGED
@@ -64,11 +64,13 @@ module ReDNS
|
|
64
64
|
|
65
65
|
autoload(:Address, 'redns/address')
|
66
66
|
autoload(:Buffer, 'redns/buffer')
|
67
|
+
autoload(:Connection, 'redns/connection')
|
67
68
|
autoload(:Fragment, 'redns/fragment')
|
68
69
|
autoload(:Message, 'redns/message')
|
69
70
|
autoload(:Name, 'redns/name')
|
70
71
|
autoload(:Question, 'redns/question')
|
71
72
|
autoload(:Record, 'redns/record')
|
73
|
+
autoload(:Resolver, 'redns/resolver')
|
72
74
|
autoload(:Resource, 'redns/resource')
|
73
75
|
autoload(:Support, 'redns/support')
|
74
76
|
|
data/redns.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{redns}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.1.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["tadman"]
|
12
|
-
s.date = %q{2010-08-
|
12
|
+
s.date = %q{2010-08-16}
|
13
13
|
s.description = %q{ReDNS is a pure Ruby DNS library with drivers for reactor-model engines such as EventMachine}
|
14
14
|
s.email = %q{github@tadman.ca}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -24,6 +24,7 @@ Gem::Specification.new do |s|
|
|
24
24
|
"lib/redns.rb",
|
25
25
|
"lib/redns/address.rb",
|
26
26
|
"lib/redns/buffer.rb",
|
27
|
+
"lib/redns/connection.rb",
|
27
28
|
"lib/redns/fragment.rb",
|
28
29
|
"lib/redns/message.rb",
|
29
30
|
"lib/redns/name.rb",
|
@@ -32,6 +33,7 @@ Gem::Specification.new do |s|
|
|
32
33
|
"lib/redns/record/mx.rb",
|
33
34
|
"lib/redns/record/null.rb",
|
34
35
|
"lib/redns/record/soa.rb",
|
36
|
+
"lib/redns/resolver.rb",
|
35
37
|
"lib/redns/resource.rb",
|
36
38
|
"lib/redns/support.rb",
|
37
39
|
"redns.gemspec",
|
@@ -39,10 +41,12 @@ Gem::Specification.new do |s|
|
|
39
41
|
"test/test_redns.rb",
|
40
42
|
"test/test_redns_address.rb",
|
41
43
|
"test/test_redns_buffer.rb",
|
44
|
+
"test/test_redns_connection.rb",
|
42
45
|
"test/test_redns_fragment.rb",
|
43
46
|
"test/test_redns_message.rb",
|
44
47
|
"test/test_redns_name.rb",
|
45
48
|
"test/test_redns_question.rb",
|
49
|
+
"test/test_redns_resolver.rb",
|
46
50
|
"test/test_redns_resource.rb",
|
47
51
|
"test/test_redns_support.rb"
|
48
52
|
]
|
@@ -56,10 +60,12 @@ Gem::Specification.new do |s|
|
|
56
60
|
"test/test_redns.rb",
|
57
61
|
"test/test_redns_address.rb",
|
58
62
|
"test/test_redns_buffer.rb",
|
63
|
+
"test/test_redns_connection.rb",
|
59
64
|
"test/test_redns_fragment.rb",
|
60
65
|
"test/test_redns_message.rb",
|
61
66
|
"test/test_redns_name.rb",
|
62
67
|
"test/test_redns_question.rb",
|
68
|
+
"test/test_redns_resolver.rb",
|
63
69
|
"test/test_redns_resource.rb",
|
64
70
|
"test/test_redns_support.rb"
|
65
71
|
]
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
require 'eventmachine'
|
4
|
+
|
5
|
+
class TestReDNSConnection < Test::Unit::TestCase
|
6
|
+
def test_initializer
|
7
|
+
dns = nil
|
8
|
+
|
9
|
+
EventMachine.run do
|
10
|
+
dns = ReDNS::Connection.instance
|
11
|
+
|
12
|
+
EventMachine.stop_event_loop
|
13
|
+
end
|
14
|
+
|
15
|
+
assert dns
|
16
|
+
assert_equal ReDNS::Connection, dns.class
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_simple_resolve
|
20
|
+
address = nil
|
21
|
+
|
22
|
+
EventMachine.run do
|
23
|
+
dns = ReDNS::Connection.instance
|
24
|
+
|
25
|
+
dns.resolve('example.com') do |result|
|
26
|
+
address = result
|
27
|
+
|
28
|
+
EventMachine.stop_event_loop
|
29
|
+
end
|
30
|
+
|
31
|
+
EventMachine.add_timer(40) do
|
32
|
+
EventMachine.stop_event_loop
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
assert address, "Address was not defined, connection may have timed out"
|
37
|
+
assert_equal %w[ 192.0.32.10 ], address
|
38
|
+
end
|
39
|
+
end
|
data/test/test_redns_message.rb
CHANGED
@@ -17,7 +17,50 @@ class TestReDNSMessage < Test::Unit::TestCase
|
|
17
17
|
assert_equal [ ], message.nameservers
|
18
18
|
assert_equal [ ], message.additional_records
|
19
19
|
|
20
|
-
assert_equal ";; HEADER:\n;; opcode: QUERY status: NOERROR id: 1 \n;; flags: ; QUERY: 0, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0\n;; QUESTION SECTION:\n\n;; ANSWER SECTION:\n\n;; NAMESERVER SECTION:\n\n;; ADDITIONAL SECTION:\n\n", message.to_s
|
20
|
+
assert_equal ";; HEADER:\n;; opcode: QUERY status: NOERROR id: 1 \n;; flags: rd; QUERY: 0, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0\n;; QUESTION SECTION:\n\n;; ANSWER SECTION:\n\n;; NAMESERVER SECTION:\n\n;; ADDITIONAL SECTION:\n\n", message.to_s
|
21
|
+
|
22
|
+
message.increment_id!
|
23
|
+
|
24
|
+
assert_equal 2, message.id
|
25
|
+
|
26
|
+
buffer = message.serialize
|
27
|
+
message_decoded = ReDNS::Message.new(buffer)
|
28
|
+
|
29
|
+
assert_equal message.to_s, message_decoded.to_s
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_message_all_flags
|
33
|
+
message = ReDNS::Message.new(
|
34
|
+
:authorative => true,
|
35
|
+
:truncated => true,
|
36
|
+
:recursion_desired => false,
|
37
|
+
:recursion_available => true,
|
38
|
+
:response_code => :server_failure
|
39
|
+
)
|
40
|
+
|
41
|
+
assert_equal true, message.query?
|
42
|
+
|
43
|
+
assert_equal 1, message.id
|
44
|
+
assert_equal 0, message.questions_count
|
45
|
+
assert_equal 0, message.answers_count
|
46
|
+
assert_equal 0, message.nameservers_count
|
47
|
+
assert_equal 0, message.additional_records_count
|
48
|
+
|
49
|
+
assert_equal [ ], message.questions
|
50
|
+
assert_equal [ ], message.answers
|
51
|
+
assert_equal [ ], message.nameservers
|
52
|
+
assert_equal [ ], message.additional_records
|
53
|
+
|
54
|
+
assert_equal ";; HEADER:\n;; opcode: QUERY status: SERVER_FAILURE id: 1 \n;; flags: aa tc ra; QUERY: 0, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0\n;; QUESTION SECTION:\n\n;; ANSWER SECTION:\n\n;; NAMESERVER SECTION:\n\n;; ADDITIONAL SECTION:\n\n", message.to_s
|
55
|
+
|
56
|
+
message.increment_id!
|
57
|
+
|
58
|
+
assert_equal 2, message.id
|
59
|
+
|
60
|
+
buffer = message.serialize
|
61
|
+
message_decoded = ReDNS::Message.new(buffer)
|
62
|
+
|
63
|
+
assert_equal message.to_s, message_decoded.to_s
|
21
64
|
end
|
22
65
|
|
23
66
|
def test_simple_query
|
@@ -32,4 +75,97 @@ class TestReDNSMessage < Test::Unit::TestCase
|
|
32
75
|
|
33
76
|
assert_equal 1, message.questions.length
|
34
77
|
end
|
78
|
+
|
79
|
+
def test_encoded_fields
|
80
|
+
message = ReDNS::Message.new(
|
81
|
+
:authorative => true,
|
82
|
+
:truncated => true,
|
83
|
+
:questions => [
|
84
|
+
ReDNS::Question.new(
|
85
|
+
:name => 'example.com',
|
86
|
+
:qtype => :a
|
87
|
+
)
|
88
|
+
],
|
89
|
+
:answers => [
|
90
|
+
ReDNS::Resource.new(
|
91
|
+
:name => 'example.com',
|
92
|
+
:rtype => :a,
|
93
|
+
:rdata => ReDNS::Address.new('1.2.3.4'),
|
94
|
+
:ttl => 1234
|
95
|
+
)
|
96
|
+
],
|
97
|
+
:nameservers => [
|
98
|
+
ReDNS::Resource.new(
|
99
|
+
:name => 'example.com',
|
100
|
+
:rtype => :ns,
|
101
|
+
:rdata => ReDNS::Name.new('ns.example.com'),
|
102
|
+
:ttl => 4321
|
103
|
+
)
|
104
|
+
],
|
105
|
+
:additional_records => [
|
106
|
+
ReDNS::Resource.new(
|
107
|
+
:name => 'ns.example.com',
|
108
|
+
:rtype => :a,
|
109
|
+
:rdata => ReDNS::Address.new('8.6.4.2'),
|
110
|
+
:ttl => 9867
|
111
|
+
)
|
112
|
+
]
|
113
|
+
)
|
114
|
+
|
115
|
+
assert_equal ";; HEADER:\n;; opcode: QUERY status: NOERROR id: 1 \n;; flags: aa tc rd; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 1\n;; QUESTION SECTION:\nexample.com. IN A\n;; ANSWER SECTION:\nexample.com. 1234 IN A 1.2.3.4\n;; NAMESERVER SECTION:\nexample.com. 4321 IN NS ns.example.com.\n;; ADDITIONAL SECTION:\nns.example.com. 9867 IN A 8.6.4.2\n", message.to_s
|
116
|
+
|
117
|
+
buffer = message.serialize
|
118
|
+
assert !buffer.to_s.empty?
|
119
|
+
|
120
|
+
message_decoded = ReDNS::Message.new(buffer)
|
121
|
+
|
122
|
+
assert_equal message.to_s, message_decoded.to_s
|
123
|
+
end
|
124
|
+
|
125
|
+
def test_question_default_a
|
126
|
+
question = ReDNS::Message.question('example.com'.freeze)
|
127
|
+
|
128
|
+
assert_equal ReDNS::Message, question.class
|
129
|
+
|
130
|
+
assert question.query?
|
131
|
+
assert !question.response?
|
132
|
+
|
133
|
+
assert_equal 1, question.questions.length
|
134
|
+
|
135
|
+
assert_equal 'example.com.', question.questions[0].name.to_s
|
136
|
+
assert_equal :a, question.questions[0].qtype
|
137
|
+
assert_equal :in, question.questions[0].qclass
|
138
|
+
end
|
139
|
+
|
140
|
+
def test_question_default_ptr
|
141
|
+
question = ReDNS::Message.question('127.0.0.1'.freeze)
|
142
|
+
|
143
|
+
assert_equal ReDNS::Message, question.class
|
144
|
+
|
145
|
+
assert_equal 1, question.questions.length
|
146
|
+
|
147
|
+
assert_equal '127.0.0.1', question.questions[0].name.to_s
|
148
|
+
assert_equal :ptr, question.questions[0].qtype
|
149
|
+
end
|
150
|
+
|
151
|
+
def test_question_default_mx
|
152
|
+
question = ReDNS::Message.question('example.com'.freeze, :mx)
|
153
|
+
|
154
|
+
assert_equal ReDNS::Message, question.class
|
155
|
+
|
156
|
+
assert_equal 1, question.questions.length
|
157
|
+
|
158
|
+
assert_equal 'example.com.', question.questions[0].name.to_s
|
159
|
+
assert_equal :mx, question.questions[0].qtype
|
160
|
+
end
|
161
|
+
|
162
|
+
def test_question_does_yield
|
163
|
+
question = ReDNS::Message.question('example.com'.freeze) do |m|
|
164
|
+
m.id = 45532
|
165
|
+
end
|
166
|
+
|
167
|
+
assert_equal ReDNS::Message, question.class
|
168
|
+
|
169
|
+
assert_equal 45532, question.id
|
170
|
+
end
|
35
171
|
end
|
data/test/test_redns_name.rb
CHANGED
@@ -9,15 +9,23 @@ class TestReDNSName < Test::Unit::TestCase
|
|
9
9
|
|
10
10
|
assert name.empty?
|
11
11
|
end
|
12
|
-
|
12
|
+
|
13
13
|
def test_string_initializer
|
14
|
-
name = ReDNS::Name.new('example.net')
|
14
|
+
name = ReDNS::Name.new('example.net'.freeze)
|
15
15
|
|
16
16
|
assert_equal 'example.net.', name.to_s
|
17
17
|
|
18
18
|
assert !name.empty?
|
19
19
|
end
|
20
20
|
|
21
|
+
def test_string_address_initializer
|
22
|
+
name = ReDNS::Name.new('127.0.0.1'.freeze)
|
23
|
+
|
24
|
+
assert_equal '127.0.0.1', name.to_s
|
25
|
+
|
26
|
+
assert !name.empty?
|
27
|
+
end
|
28
|
+
|
21
29
|
def test_defaults
|
22
30
|
example_buffer = ReDNS::Buffer.new(
|
23
31
|
[
|
@@ -0,0 +1,120 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestReReDNSResolver < Test::Unit::TestCase
|
4
|
+
def test_create
|
5
|
+
res = ReDNS::Resolver.new
|
6
|
+
|
7
|
+
assert res
|
8
|
+
|
9
|
+
assert !res.servers.empty?
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_servers
|
13
|
+
res = ReDNS::Resolver.new
|
14
|
+
|
15
|
+
res.servers = [ "192.168.1.1" ]
|
16
|
+
|
17
|
+
assert_equal [ "192.168.1.1" ], res.servers
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_query
|
21
|
+
res = ReDNS::Resolver.new
|
22
|
+
|
23
|
+
r = res.query do |q|
|
24
|
+
q.qtype = :a
|
25
|
+
q.name = "example.com"
|
26
|
+
end
|
27
|
+
|
28
|
+
assert r, "ReDNS::Resolver#query did not produce a reply"
|
29
|
+
|
30
|
+
assert_equal 1, r.questions.size
|
31
|
+
assert_equal 1, r.answers.size
|
32
|
+
|
33
|
+
assert_equal '192.0.32.10', r.answers[0].rdata.to_s
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_ns_query
|
37
|
+
res = ReDNS::Resolver.new
|
38
|
+
|
39
|
+
assert !res.servers.empty?
|
40
|
+
|
41
|
+
r = res.query do |q|
|
42
|
+
q.qtype = :ns
|
43
|
+
q.name = "example.com"
|
44
|
+
end
|
45
|
+
|
46
|
+
assert r, "ReDNS::Resolver#query did not produce a reply"
|
47
|
+
|
48
|
+
assert_equal 1, r.questions.size
|
49
|
+
assert_equal 2, r.answers.size
|
50
|
+
|
51
|
+
assert_equal ReDNS::Name, r.answers[0].rdata.class
|
52
|
+
assert_equal ReDNS::Name, r.answers[1].rdata.class
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_bulk_query
|
56
|
+
addrs = %w[
|
57
|
+
128.100.8.1
|
58
|
+
128.100.8.2
|
59
|
+
128.100.8.3
|
60
|
+
128.100.8.4
|
61
|
+
].collect do |i|
|
62
|
+
ReDNS::Support.addr_to_arpa(i)
|
63
|
+
end
|
64
|
+
|
65
|
+
res = ReDNS::Resolver.new
|
66
|
+
|
67
|
+
rlist = res.bulk_query(:ptr, addrs)
|
68
|
+
|
69
|
+
assert rlist
|
70
|
+
|
71
|
+
assert_equal 4, rlist.length
|
72
|
+
|
73
|
+
assert_equal addrs.sort, rlist.keys.sort
|
74
|
+
|
75
|
+
assert rlist[addrs[0]]
|
76
|
+
|
77
|
+
expected = %w[
|
78
|
+
sf-ecf.gw.utoronto.ca.
|
79
|
+
fs.ecf.utoronto.ca.
|
80
|
+
ecf-if.gw.utoronto.ca.
|
81
|
+
ecf-8-hub.ecf.utoronto.ca.
|
82
|
+
]
|
83
|
+
|
84
|
+
answers = addrs.collect do |a|
|
85
|
+
rlist[a] and rlist[a].answers[0] and rlist[a].answers[0].rdata.to_s
|
86
|
+
end
|
87
|
+
|
88
|
+
assert_equal expected, answers
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_reverse_addresses
|
92
|
+
addrs = %w[
|
93
|
+
128.100.8.1
|
94
|
+
128.100.8.2
|
95
|
+
128.100.8.3
|
96
|
+
128.100.8.4
|
97
|
+
]
|
98
|
+
|
99
|
+
res = ReDNS::Resolver.new
|
100
|
+
|
101
|
+
rlist = res.reverse_addresses(addrs)
|
102
|
+
|
103
|
+
assert rlist
|
104
|
+
|
105
|
+
assert_equal addrs.length, rlist.length
|
106
|
+
|
107
|
+
expected = %w[
|
108
|
+
sf-ecf.gw.utoronto.ca.
|
109
|
+
fs.ecf.utoronto.ca.
|
110
|
+
ecf-if.gw.utoronto.ca.
|
111
|
+
ecf-8-hub.ecf.utoronto.ca.
|
112
|
+
]
|
113
|
+
|
114
|
+
answers = addrs.collect do |a|
|
115
|
+
rlist[a]
|
116
|
+
end
|
117
|
+
|
118
|
+
assert_equal expected, answers
|
119
|
+
end
|
120
|
+
end
|
data/test/test_redns_support.rb
CHANGED
@@ -13,4 +13,9 @@ class TestReDNSSupport < Test::Unit::TestCase
|
|
13
13
|
assert_equal '1.2.3.4', inet_ntoa(inet_aton('1.2.3.4'))
|
14
14
|
assert_equal '255.255.255.255', inet_ntoa(inet_aton('255.255.255.255'))
|
15
15
|
end
|
16
|
+
|
17
|
+
def test_default_resolver_address
|
18
|
+
assert ReDNS::Support.default_resolver_address
|
19
|
+
assert !ReDNS::Support.default_resolver_address.empty?
|
20
|
+
end
|
16
21
|
end
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
+
- 1
|
7
8
|
- 0
|
8
|
-
|
9
|
-
version: 0.0.0
|
9
|
+
version: 0.1.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- tadman
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-08-
|
17
|
+
date: 2010-08-16 00:00:00 -04:00
|
18
18
|
default_executable:
|
19
19
|
dependencies: []
|
20
20
|
|
@@ -35,6 +35,7 @@ files:
|
|
35
35
|
- lib/redns.rb
|
36
36
|
- lib/redns/address.rb
|
37
37
|
- lib/redns/buffer.rb
|
38
|
+
- lib/redns/connection.rb
|
38
39
|
- lib/redns/fragment.rb
|
39
40
|
- lib/redns/message.rb
|
40
41
|
- lib/redns/name.rb
|
@@ -43,6 +44,7 @@ files:
|
|
43
44
|
- lib/redns/record/mx.rb
|
44
45
|
- lib/redns/record/null.rb
|
45
46
|
- lib/redns/record/soa.rb
|
47
|
+
- lib/redns/resolver.rb
|
46
48
|
- lib/redns/resource.rb
|
47
49
|
- lib/redns/support.rb
|
48
50
|
- redns.gemspec
|
@@ -50,10 +52,12 @@ files:
|
|
50
52
|
- test/test_redns.rb
|
51
53
|
- test/test_redns_address.rb
|
52
54
|
- test/test_redns_buffer.rb
|
55
|
+
- test/test_redns_connection.rb
|
53
56
|
- test/test_redns_fragment.rb
|
54
57
|
- test/test_redns_message.rb
|
55
58
|
- test/test_redns_name.rb
|
56
59
|
- test/test_redns_question.rb
|
60
|
+
- test/test_redns_resolver.rb
|
57
61
|
- test/test_redns_resource.rb
|
58
62
|
- test/test_redns_support.rb
|
59
63
|
has_rdoc: true
|
@@ -93,9 +97,11 @@ test_files:
|
|
93
97
|
- test/test_redns.rb
|
94
98
|
- test/test_redns_address.rb
|
95
99
|
- test/test_redns_buffer.rb
|
100
|
+
- test/test_redns_connection.rb
|
96
101
|
- test/test_redns_fragment.rb
|
97
102
|
- test/test_redns_message.rb
|
98
103
|
- test/test_redns_name.rb
|
99
104
|
- test/test_redns_question.rb
|
105
|
+
- test/test_redns_resolver.rb
|
100
106
|
- test/test_redns_resource.rb
|
101
107
|
- test/test_redns_support.rb
|