Class: ReDNS::Resolver

Inherits:
Object
  • Object
show all
Defined in:
lib/redns/resolver.rb

Constant Summary collapse

TIMEOUT_DEFAULT =

Constants ============================================================

5
RESOLV_CONF =
'/etc/resolv.conf'.freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = { }) {|_self| ... } ⇒ Resolver

Instance Methods =====================================================

Yields:

  • (_self)

Yield Parameters:



46
47
48
49
50
51
52
53
54
55
# File 'lib/redns/resolver.rb', line 46

def initialize(options = { }, &block)
  @servers = self.class.servers.dup
  @responses = { }
  @timeout = nil
  
  @socket = UDPSocket.new
  ReDNS::Support.io_set_nonblock(@socket)
  
  yield(self) if (block)
end

Class Method Details

.in_resolv_confObject

Class Methods ========================================================



14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/redns/resolver.rb', line 14

def self.in_resolv_conf
  File.open(RESOLV_CONF) do |fh|
    fh.readlines.map do |l|
      l.chomp.sub(/#.*/, '')
    end.reject do |l|
      !l.sub!(/\A\s*nameserver\s+/, '')
    end
  end
  
rescue Errno::ENOENT
  # /etc/resolv.conf may not be present on misconfigured or offline systems
  [ ]
end

.serversObject



28
29
30
# File 'lib/redns/resolver.rb', line 28

def self.servers
  @servers ||= self.in_resolv_conf
end

.servers=(list) ⇒ Object



32
33
34
# File 'lib/redns/resolver.rb', line 32

def self.servers=(list)
  @servers = list
end

.timeoutObject



36
37
38
# File 'lib/redns/resolver.rb', line 36

def self.timeout
  @timeout ||= TIMEOUT_DEFAULT
end

.timeout=(secs) ⇒ Object



40
41
42
# File 'lib/redns/resolver.rb', line 40

def self.timeout=(secs)
  @timeout = secs
end

Instance Method Details

#a_for(name) ⇒ Object



93
94
95
# File 'lib/redns/resolver.rb', line 93

def a_for(name)
  simple_query(:a, name)
end

#bulk_query(type, names) ⇒ Object



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/redns/resolver.rb', line 66

def bulk_query(type, names)
  results = { }
  ids = [ ]
  
  message ||= ReDNS::Message.new
  q = (message.questions[0] ||= ReDNS::Question.new)
  q.qtype = type
  
  names.each do |name|
    q.name = name.to_s
    message.increment_id!
    ids.push(message.id)
    
    send_message(message)
  end
  
  wait_for_responses do |response, addr|
    results[response.questions[0].name.to_s] = response

    ids.delete(response.id)
      
    return results if (ids.empty?)
  end
  
  results
end

#mx_for(name) ⇒ Object



105
106
107
# File 'lib/redns/resolver.rb', line 105

def mx_for(name)
  simple_query(:mx, name)
end

#ns_for(name) ⇒ Object



97
98
99
100
101
102
103
# File 'lib/redns/resolver.rb', line 97

def ns_for(name)
  if (name.match(/\A(\d+\.\d+\.\d+)\.\d+$/))
    return simple_query(:ns, ReDNS::Support.addr_to_arpa($1))
  end
  
  simple_query(:ns, name)
end

#ptr_for(name) ⇒ Object



109
110
111
# File 'lib/redns/resolver.rb', line 109

def ptr_for(name)
  simple_query(:ptr, ReDNS::Support.addr_to_arpa(name))
end

#ptr_for_list(name) ⇒ Object



113
114
115
116
117
118
119
120
121
122
# File 'lib/redns/resolver.rb', line 113

def ptr_for_list(name)
  ips = [ ips ].flatten
  
  bulk_query(
    :ptr,
    ips.map do |ip|
      ReDNS::Support.addr_to_arpa(ip)
    end
  )
end

#query(message = nil, server = nil, async = false) {|| ... } ⇒ Object

Yields:

  • ()


159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# File 'lib/redns/resolver.rb', line 159

def query(message = nil, server = nil, async = false, &block)
  # FUTURE: Fix the duplication here and in query_async

  message ||= ReDNS::Message.new
  message.questions[0] ||= ReDNS::Question.new
  
  yield(message.questions[0]) if (block)
  
  send_message(message, server)
  
  unless (async)
    wait_for_responses do |r, addr|
      return r if (r.id == message.id)
    end
  end
end

#random_serverObject



151
152
153
# File 'lib/redns/resolver.rb', line 151

def random_server
  @servers[rand(@servers.length)]
end

#response_for(id) ⇒ Object



176
177
178
# File 'lib/redns/resolver.rb', line 176

def response_for(id)
  @responses[id]
end

#responsesObject



180
181
182
# File 'lib/redns/resolver.rb', line 180

def responses
  @responses
end

#reverse_addresses(ips) ⇒ Object



128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/redns/resolver.rb', line 128

def reverse_addresses(ips)
  map = ips.inject({ }) do |h, ip|
    h[ReDNS::Support.addr_to_arpa(ip)] = ip
    h
  end
  
  list = bulk_query(:ptr, map.keys)
  
  list.values.each_with_object({ }) do |r, h|
    if (ip = map[r.questions[0].name.to_s])
      h[ip] = (r.answers[0] and r.answers[0].rdata.to_s)
    end
  end
end

#send_message(message, server = nil) ⇒ Object



155
156
157
# File 'lib/redns/resolver.rb', line 155

def send_message(message, server = nil)
  @socket.send(message.serialize.to_s, 0, (server or random_server), 53)
end

#serversObject



143
144
145
# File 'lib/redns/resolver.rb', line 143

def servers
  @servers
end

#servers=(list) ⇒ Object



147
148
149
# File 'lib/redns/resolver.rb', line 147

def servers=(list)
  @servers = list
end

#simple_query(type, name) ⇒ Object



57
58
59
60
61
62
63
64
# File 'lib/redns/resolver.rb', line 57

def simple_query(type, name)
  r = query do |q|
    q.qtype = type
    q.name = name.to_s
  end
  
  expand_answers(r)
end

#soa_for(name) ⇒ Object



124
125
126
# File 'lib/redns/resolver.rb', line 124

def soa_for(name)
  simple_query(:soa, name)
end

#timeoutObject



184
185
186
# File 'lib/redns/resolver.rb', line 184

def timeout
  @timeout or self.class.timeout
end

#timeout=(secs) ⇒ Object



188
189
190
# File 'lib/redns/resolver.rb', line 188

def timeout=(secs)
  @timeout = secs
end

#wait(_timeout = nil, &block) ⇒ Object



192
193
194
# File 'lib/redns/resolver.rb', line 192

def wait(_timeout = nil, &block)
  wait_for_response(nil, _timeout, &block)
end

#wait_for_responses(_timeout = nil, &block) ⇒ Object



196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
# File 'lib/redns/resolver.rb', line 196

def wait_for_responses(_timeout = nil, &block)
  start = Time.now

  _timeout ||= timeout
  left = _timeout - Time.now.to_f + start.to_f

  while (left > 0)
    if (ready = IO.select([ @socket ], nil, nil, [ 1.0, left ].min))
      ready[0].each do |socket|
        data = socket.recvfrom(1524)
    
        r = ReDNS::Message.new(ReDNS::Buffer.new(data[0]))
        
        yield(r, data[1]) if (block)

        @responses[r.id] = [ r, data[1] ]
      end
    end

    left = _timeout - Time.now.to_f + start.to_f
  end
end