redns 0.1.17 → 0.2.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.
- checksums.yaml +7 -0
- data/.travis.yml +8 -0
- data/Gemfile +8 -0
- data/LICENSE.txt +20 -0
- data/README.md +31 -0
- data/Rakefile +2 -13
- data/VERSION +1 -1
- data/bin/redig +20 -13
- data/lib/redns.rb +32 -32
- data/lib/redns/address.rb +19 -19
- data/lib/redns/connection.rb +16 -16
- data/lib/redns/fragment.rb +5 -5
- data/lib/redns/message.rb +127 -127
- data/lib/redns/name.rb +35 -33
- data/lib/redns/question.rb +27 -27
- data/lib/redns/record/mx.rb +19 -19
- data/lib/redns/record/null.rb +27 -27
- data/lib/redns/record/soa.rb +49 -49
- data/lib/redns/resolver.rb +264 -262
- data/lib/redns/resource.rb +61 -61
- data/lib/redns/support.rb +41 -41
- data/redns.gemspec +26 -15
- data/test/test_redns_connection.rb +18 -6
- data/test/test_redns_fragment.rb +7 -7
- data/test/test_redns_message.rb +40 -40
- data/test/test_redns_name.rb +1 -1
- data/test/test_redns_question.rb +2 -2
- data/test/test_redns_resolver.rb +125 -119
- data/test/test_redns_resource.rb +32 -32
- metadata +43 -13
- data/README.rdoc +0 -17
data/lib/redns/name.rb
CHANGED
@@ -5,7 +5,7 @@ class ReDNS::Name < ReDNS::Fragment
|
|
5
5
|
|
6
6
|
# == Attributes ===========================================================
|
7
7
|
|
8
|
-
attribute :name, :
|
8
|
+
attribute :name, default: '.'
|
9
9
|
|
10
10
|
# == Instance Methods =====================================================
|
11
11
|
|
@@ -16,7 +16,7 @@ class ReDNS::Name < ReDNS::Fragment
|
|
16
16
|
# method, not intercepted and treated as an actual String
|
17
17
|
super(contents)
|
18
18
|
when String
|
19
|
-
super(:
|
19
|
+
super(name: contents)
|
20
20
|
|
21
21
|
unless (ReDNS::Support.is_ip?(name) or self.name.match(/\.$/))
|
22
22
|
self.name += '.'
|
@@ -26,37 +26,37 @@ class ReDNS::Name < ReDNS::Fragment
|
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
29
|
+
def to_s
|
30
|
+
self.name
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_a
|
34
|
+
[ self.name ]
|
35
|
+
end
|
36
|
+
|
37
|
+
def length
|
38
|
+
to_s.length
|
39
|
+
end
|
40
|
+
|
41
|
+
def empty?
|
42
|
+
name == '.'
|
43
|
+
end
|
44
|
+
|
45
|
+
def serialize(buffer = ReDNS::Buffer.new)
|
46
|
+
buffer.append(
|
47
|
+
self.name.split(/\./).collect { |l| [ l.length, l ].pack("ca*") }.join('')
|
48
|
+
)
|
49
49
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
50
|
+
buffer.append("\0")
|
51
|
+
|
52
|
+
buffer
|
53
|
+
end
|
54
|
+
|
55
|
+
def deserialize(buffer)
|
56
|
+
self.name = ''
|
57
|
+
|
58
|
+
return_to_offset = nil
|
59
|
+
pointer_count = 0
|
60
60
|
|
61
61
|
while (c = buffer.unpack('C')[0])
|
62
62
|
if (c & 0xC0 == 0xC0)
|
@@ -99,7 +99,9 @@ class ReDNS::Name < ReDNS::Fragment
|
|
99
99
|
buffer.rewind
|
100
100
|
buffer.advance(return_to_offset)
|
101
101
|
end
|
102
|
+
|
103
|
+
self.name.encode!('UTF-8')
|
102
104
|
|
103
105
|
self
|
104
|
-
|
106
|
+
end
|
105
107
|
end
|
data/lib/redns/question.rb
CHANGED
@@ -3,38 +3,38 @@ class ReDNS::Question < ReDNS::Fragment
|
|
3
3
|
|
4
4
|
# == Attributes ===========================================================
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
attribute :name, class: ReDNS::Name, default: lambda { ReDNS::Name.new }
|
7
|
+
|
8
|
+
attribute :qclass, default: :in
|
9
|
+
attribute :qtype, default: :any
|
10
10
|
|
11
11
|
# == Class Methods ========================================================
|
12
12
|
|
13
13
|
# == Instance Methods =====================================================
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
15
|
+
def to_s
|
16
|
+
"#{name} #{qclass.to_s.upcase} #{qtype.to_s.upcase}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def serialize(buffer = ReDNS::Buffer.new)
|
20
|
+
name.serialize(buffer)
|
21
|
+
buffer.pack(
|
22
|
+
'nn',
|
23
|
+
ReDNS::RR_TYPE[self.qtype],
|
24
|
+
ReDNS::RR_CLASS[self.qclass]
|
25
|
+
)
|
26
26
|
|
27
27
|
buffer
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
28
|
+
end
|
29
|
+
|
30
|
+
def deserialize(buffer)
|
31
|
+
self.name = ReDNS::Name.new(buffer)
|
32
|
+
|
33
|
+
data = buffer.unpack('nn')
|
34
|
+
|
35
|
+
self.qtype = ReDNS::RR_TYPE_LABEL[data.shift]
|
36
|
+
self.qclass = ReDNS::RR_CLASS_LABEL[data.shift]
|
37
|
+
|
38
|
+
self
|
39
|
+
end
|
40
40
|
end
|
data/lib/redns/record/mx.rb
CHANGED
@@ -1,28 +1,28 @@
|
|
1
1
|
class ReDNS::Record::MX < ReDNS::Fragment
|
2
2
|
# == Attributes ===========================================================
|
3
3
|
|
4
|
-
attribute :name, :
|
5
|
-
attribute :preference, :
|
4
|
+
attribute :name, default: lambda { ReDNS::Name.new }, class: ReDNS::Name
|
5
|
+
attribute :preference, default: 0, convert: :to_i
|
6
6
|
|
7
7
|
# == Class Methods ========================================================
|
8
8
|
|
9
9
|
# == Instance Methods =====================================================
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
10
|
+
|
11
|
+
def to_s
|
12
|
+
"#{preference} #{name}"
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_a
|
16
|
+
[ name.to_s, preference ]
|
17
|
+
end
|
18
|
+
|
19
|
+
def serialize(buffer = ReDNS::Buffer.new)
|
20
|
+
buffer.pack('n', self.preference)
|
21
|
+
self.name.serialize(buffer)
|
22
|
+
end
|
23
23
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
24
|
+
def deserialize(buffer)
|
25
|
+
self.preference = buffer.unpack('n')[0]
|
26
|
+
self.name = ReDNS::Name.new(buffer)
|
27
|
+
end
|
28
28
|
end
|
data/lib/redns/record/null.rb
CHANGED
@@ -1,39 +1,39 @@
|
|
1
1
|
class ReDNS::Record::Null < ReDNS::Fragment
|
2
2
|
# == Attributes ===========================================================
|
3
3
|
|
4
|
-
attribute :contents, :
|
4
|
+
attribute :contents, default: '', primary: true
|
5
5
|
|
6
6
|
# == Class Methods ========================================================
|
7
7
|
|
8
8
|
# == Instance Methods =====================================================
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
9
|
+
|
10
|
+
def to_s
|
11
|
+
"#{self.contents}"
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_a
|
15
|
+
[ self.contents ]
|
16
|
+
end
|
17
|
+
|
18
|
+
def serialize(buffer = ReDNS::Buffer.new)
|
19
|
+
buffer.pack('C', self.contents.length)
|
20
20
|
|
21
|
-
|
21
|
+
buffer.append(self.contents)
|
22
22
|
|
23
|
-
|
24
|
-
|
23
|
+
buffer
|
24
|
+
end
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
26
|
+
def deserialize(buffer)
|
27
|
+
self.contents = ''
|
28
|
+
|
29
|
+
while (!buffer.empty?)
|
30
|
+
if (content_length = buffer.unpack('C')[0])
|
31
|
+
if (string = buffer.unpack("a#{content_length}")[0])
|
32
|
+
self.contents << string
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
36
|
|
37
|
-
|
38
|
-
|
37
|
+
self
|
38
|
+
end
|
39
39
|
end
|
data/lib/redns/record/soa.rb
CHANGED
@@ -1,63 +1,63 @@
|
|
1
1
|
class ReDNS::Record::SOA < ReDNS::Fragment
|
2
2
|
# == Attributes ===========================================================
|
3
3
|
|
4
|
-
attribute :mname, :
|
5
|
-
attribute :rname, :
|
4
|
+
attribute :mname, default: lambda { ReDNS::Name.new }, class: ReDNS::Name
|
5
|
+
attribute :rname, default: lambda { ReDNS::Name.new }, class: ReDNS::Name
|
6
6
|
|
7
|
-
attribute :serial, :
|
8
|
-
attribute :refresh, :
|
9
|
-
attribute :retry, :
|
10
|
-
attribute :expire, :
|
11
|
-
attribute :minimum, :
|
7
|
+
attribute :serial, default: 0, convert: :to_i
|
8
|
+
attribute :refresh, default: 0, convert: :to_i
|
9
|
+
attribute :retry, default: 0, convert: :to_i
|
10
|
+
attribute :expire, default: 0, convert: :to_i
|
11
|
+
attribute :minimum, default: 0, convert: :to_i
|
12
12
|
|
13
13
|
# == Class Methods ========================================================
|
14
14
|
|
15
15
|
# == Instance Methods =====================================================
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
16
|
+
|
17
|
+
def to_s
|
18
|
+
to_a.join(' ')
|
19
|
+
end
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
21
|
+
def to_a
|
22
|
+
[
|
23
|
+
self.mname,
|
24
|
+
self.rname,
|
25
|
+
self.serial,
|
26
|
+
self.refresh,
|
27
|
+
self.retry,
|
28
|
+
self.expire,
|
29
|
+
self.minimum
|
30
|
+
]
|
31
|
+
end
|
32
|
+
|
33
|
+
def serialize(buffer = ReDNS::Buffer.new)
|
34
|
+
self.mname.serialize(buffer)
|
35
|
+
self.rname.serialize(buffer)
|
36
36
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
37
|
+
buffer.pack(
|
38
|
+
'NNNNN',
|
39
|
+
self.serial,
|
40
|
+
self.refresh,
|
41
|
+
self.retry,
|
42
|
+
self.expire,
|
43
|
+
self.minimum
|
44
|
+
)
|
45
|
+
|
46
|
+
buffer
|
47
|
+
end
|
48
48
|
|
49
|
-
|
50
|
-
|
51
|
-
|
49
|
+
def deserialize(buffer)
|
50
|
+
self.mname = ReDNS::Name.new(buffer)
|
51
|
+
self.rname = ReDNS::Name.new(buffer)
|
52
52
|
|
53
|
-
|
53
|
+
data = buffer.unpack('NNNNN')
|
54
54
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
55
|
+
self.serial = data.shift
|
56
|
+
self.refresh = data.shift
|
57
|
+
self.retry = data.shift
|
58
|
+
self.expire = data.shift
|
59
|
+
self.minimum = data.shift
|
60
|
+
|
61
|
+
self
|
62
|
+
end
|
63
63
|
end
|
data/lib/redns/resolver.rb
CHANGED
@@ -4,285 +4,287 @@ require 'fcntl'
|
|
4
4
|
BasicSocket.do_not_reverse_lookup = true
|
5
5
|
|
6
6
|
class ReDNS::Resolver
|
7
|
-
|
8
|
-
|
9
|
-
@servers = nil
|
10
|
-
@timeout = 5
|
11
|
-
|
12
|
-
# == Class Methods ========================================================
|
7
|
+
# == Constants ============================================================
|
13
8
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
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
|
9
|
+
TIMEOUT_DEFAULT = 5
|
10
|
+
RESOLV_CONF = '/etc/resolv.conf'.freeze
|
11
|
+
|
12
|
+
# == Class Methods ========================================================
|
24
13
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
14
|
+
def self.in_resolv_conf
|
15
|
+
File.open(RESOLV_CONF) do |fh|
|
16
|
+
fh.readlines.map do |l|
|
17
|
+
l.chomp.sub(/#.*/, '')
|
18
|
+
end.reject do |l|
|
19
|
+
!l.sub!(/\A\s*nameserver\s+/, '')
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
rescue Errno::ENOENT
|
24
|
+
# /etc/resolv.conf may not be present on misconfigured or offline systems
|
25
|
+
[ ]
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.servers
|
29
|
+
@servers ||= self.in_resolv_conf
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.servers=(list)
|
33
|
+
@servers = list
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.timeout
|
37
|
+
@timeout ||= TIMEOUT_DEFAULT
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.timeout=(secs)
|
41
|
+
@timeout = secs
|
42
|
+
end
|
43
|
+
|
44
|
+
# == Instance Methods =====================================================
|
47
45
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
46
|
+
def initialize(options = { }, &block)
|
47
|
+
@servers = self.class.servers.dup
|
48
|
+
@responses = { }
|
49
|
+
@timeout = nil
|
50
|
+
|
51
|
+
@socket = UDPSocket.new
|
52
|
+
ReDNS::Support.io_set_nonblock(@socket)
|
53
|
+
|
54
|
+
yield(self) if (block)
|
55
|
+
end
|
56
|
+
|
57
|
+
def simple_query(type, name)
|
58
|
+
r = query do |q|
|
59
|
+
q.qtype = type
|
60
|
+
q.name = name.to_s
|
61
|
+
end
|
62
|
+
|
63
|
+
expand_answers(r)
|
64
|
+
end
|
65
|
+
|
66
|
+
def bulk_query(type, names)
|
67
|
+
results = { }
|
68
|
+
ids = [ ]
|
69
|
+
|
70
|
+
message ||= ReDNS::Message.new
|
71
|
+
q = (message.questions[0] ||= ReDNS::Question.new)
|
72
|
+
q.qtype = type
|
73
|
+
|
74
|
+
names.each do |name|
|
75
|
+
q.name = name.to_s
|
76
|
+
message.increment_id!
|
77
|
+
ids.push(message.id)
|
78
|
+
|
79
|
+
send_message(message)
|
80
|
+
end
|
81
|
+
|
82
|
+
wait_for_responses do |response, addr|
|
83
|
+
results[response.questions[0].name.to_s] = response
|
85
84
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
85
|
+
ids.delete(response.id)
|
86
|
+
|
87
|
+
return results if (ids.empty?)
|
88
|
+
end
|
89
|
+
|
90
|
+
results
|
91
|
+
end
|
93
92
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
93
|
+
def a_for(name)
|
94
|
+
simple_query(:a, name)
|
95
|
+
end
|
96
|
+
|
97
|
+
def ns_for(name)
|
98
|
+
if (name.match(/\A(\d+\.\d+\.\d+)\.\d+$/))
|
99
|
+
return simple_query(:ns, ReDNS::Support.addr_to_arpa($1))
|
100
|
+
end
|
101
|
+
|
102
|
+
simple_query(:ns, name)
|
103
|
+
end
|
105
104
|
|
106
|
-
|
107
|
-
|
108
|
-
|
105
|
+
def mx_for(name)
|
106
|
+
simple_query(:mx, name)
|
107
|
+
end
|
109
108
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
109
|
+
def ptr_for(name)
|
110
|
+
simple_query(:ptr, ReDNS::Support.addr_to_arpa(name))
|
111
|
+
end
|
112
|
+
|
113
|
+
def ptr_for_list(name)
|
114
|
+
ips = [ ips ].flatten
|
115
|
+
|
116
|
+
bulk_query(
|
117
|
+
:ptr,
|
118
|
+
ips.map do |ip|
|
119
|
+
ReDNS::Support.addr_to_arpa(ip)
|
120
|
+
end
|
121
|
+
)
|
122
|
+
end
|
119
123
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
def query(message = nil, server = nil, async = false, &block)
|
158
|
-
# FUTURE: Fix the duplication here and in query_async
|
124
|
+
def soa_for(name)
|
125
|
+
simple_query(:soa, name)
|
126
|
+
end
|
127
|
+
|
128
|
+
def reverse_addresses(ips)
|
129
|
+
map = ips.inject({ }) do |h, ip|
|
130
|
+
h[ReDNS::Support.addr_to_arpa(ip)] = ip
|
131
|
+
h
|
132
|
+
end
|
133
|
+
|
134
|
+
list = bulk_query(:ptr, map.keys)
|
135
|
+
|
136
|
+
list.values.each_with_object({ }) do |r, h|
|
137
|
+
if (ip = map[r.questions[0].name.to_s])
|
138
|
+
h[ip] = (r.answers[0] and r.answers[0].rdata.to_s)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def servers
|
144
|
+
@servers
|
145
|
+
end
|
146
|
+
|
147
|
+
def servers=(list)
|
148
|
+
@servers = list
|
149
|
+
end
|
150
|
+
|
151
|
+
def random_server
|
152
|
+
@servers[rand(@servers.length)]
|
153
|
+
end
|
154
|
+
|
155
|
+
def send_message(message, server = nil)
|
156
|
+
@socket.send(message.serialize.to_s, 0, (server or random_server), 53)
|
157
|
+
end
|
158
|
+
|
159
|
+
def query(message = nil, server = nil, async = false, &block)
|
160
|
+
# FUTURE: Fix the duplication here and in query_async
|
159
161
|
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
162
|
+
message ||= ReDNS::Message.new
|
163
|
+
message.questions[0] ||= ReDNS::Question.new
|
164
|
+
|
165
|
+
yield(message.questions[0]) if (block)
|
166
|
+
|
167
|
+
send_message(message, server)
|
168
|
+
|
169
|
+
unless (async)
|
170
|
+
wait_for_responses do |r, addr|
|
171
|
+
return r if (r.id == message.id)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def response_for(id)
|
177
|
+
@responses[id]
|
178
|
+
end
|
179
|
+
|
180
|
+
def responses
|
181
|
+
@responses
|
182
|
+
end
|
183
|
+
|
184
|
+
def timeout
|
185
|
+
@timeout or self.class.timeout
|
186
|
+
end
|
187
|
+
|
188
|
+
def timeout=(secs)
|
189
|
+
@timeout = secs
|
190
|
+
end
|
189
191
|
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
192
|
+
def wait(_timeout = nil, &block)
|
193
|
+
wait_for_response(nil, _timeout, &block)
|
194
|
+
end
|
195
|
+
|
196
|
+
def wait_for_responses(_timeout = nil, &block)
|
197
|
+
start = Time.now
|
196
198
|
|
197
|
-
|
198
|
-
|
199
|
+
_timeout ||= timeout
|
200
|
+
left = _timeout - Time.now.to_f + start.to_f
|
199
201
|
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
202
|
+
while (left > 0)
|
203
|
+
if (ready = IO.select([ @socket ], nil, nil, [ 1.0, left ].min))
|
204
|
+
ready[0].each do |socket|
|
205
|
+
data = socket.recvfrom(1524)
|
206
|
+
|
207
|
+
r = ReDNS::Message.new(ReDNS::Buffer.new(data[0]))
|
208
|
+
|
209
|
+
yield(r, data[1]) if (block)
|
210
|
+
|
211
|
+
@responses[r.id] = [ r, data[1] ]
|
212
|
+
end
|
213
|
+
end
|
212
214
|
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
215
|
+
left = _timeout - Time.now.to_f + start.to_f
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
217
219
|
protected
|
218
|
-
|
220
|
+
def expand_answers(r)
|
219
221
|
|
220
|
-
|
221
|
-
|
222
|
-
|
222
|
+
unless (r and r.answers)
|
223
|
+
return nil
|
224
|
+
end
|
223
225
|
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
226
|
+
result = r.answers
|
227
|
+
radd = (r.additional_records or [ ])
|
228
|
+
|
229
|
+
result.select do |rr|
|
230
|
+
case (rr.rtype)
|
231
|
+
when :ns
|
232
|
+
# These record types require further investigation if they are to
|
233
|
+
# be included in the result-set.
|
234
|
+
true
|
233
235
|
else
|
234
236
|
false
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
237
|
+
end
|
238
|
+
end.each do |rr|
|
239
|
+
# Additional resource records may be related to the query, or they
|
240
|
+
# might just be convenience records that are not directly helpful.
|
241
|
+
|
242
|
+
rr_rdata = rr.rdata.to_a[0]
|
243
|
+
|
244
|
+
# First, see if there are additional records immediately available
|
245
|
+
additional = radd.find_all { |i| i.name.to_s == rr_rdata }
|
246
|
+
|
247
|
+
if (additional.empty?)
|
248
|
+
# Otherwise go fetch them
|
249
|
+
additional = a_for(rr_rdata)
|
250
|
+
end
|
251
|
+
|
252
|
+
if (additional and !additional.empty?)
|
253
|
+
# Push any results into the record itself
|
254
|
+
r.additional_records = additional
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
result
|
259
|
+
end
|
258
260
|
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
261
|
+
def expand_answers_a(r)
|
262
|
+
unless (r and r.answers)
|
263
|
+
return nil
|
264
|
+
end
|
265
|
+
|
266
|
+
rev = { }
|
267
|
+
|
268
|
+
res = r.answers.collect do |a|
|
269
|
+
row = a.to_a
|
270
|
+
rev[row[4]] = nil
|
271
|
+
row
|
272
|
+
end
|
273
|
+
|
274
|
+
r.additional_records and r.additional_records.each do |a|
|
275
|
+
row = a.to_a
|
276
|
+
rev[row[0]] = row[4]
|
277
|
+
res.push(row)
|
278
|
+
end
|
279
|
+
|
280
|
+
rev.each do |addr, ip|
|
281
|
+
unless (ip)
|
282
|
+
if (add = a_for(addr))
|
283
|
+
res += add
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
res
|
289
|
+
end
|
288
290
|
end
|