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 CHANGED
@@ -1 +1 @@
1
- 0.0.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 => false
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
- @attributes[:id] += 1
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.ecursion_desired? ? 0x0100 : 0) |
103
+ (self.recursion_desired? ? 0x0100 : 0) |
87
104
  (self.recursion_available? ? 0x0080 : 0) |
88
- (ReDNS::RCODE[self.reponse_code] || ReDNS::RCODE[:noerror])
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[:group].each do |part|
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.recursion_available = flags & 0x0080
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 :question
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
- self.name << '.' unless (self.name.match(/\.$/))
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
@@ -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([ self.qtype_rfc, self.qclass_rfc ], "nn")
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 = DNS::Name.new(buffer)
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
@@ -55,7 +55,7 @@ class ReDNS::Resource < ReDNS::Fragment
55
55
 
56
56
  def deserialize(buffer)
57
57
  self.name = ReDNS::Name.new(buffer)
58
-
58
+
59
59
  raw = buffer.unpack("nnNn")
60
60
 
61
61
  self.rtype = ReDNS::RR_TYPE_LABEL[raw.shift]
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.0.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-13}
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
@@ -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
@@ -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
@@ -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
- - 0
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-13 00:00:00 -04:00
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