redns 0.0.0 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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