Class: ReDNS::Resolver

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

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

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

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

Yields:

  • (_self)

Yield Parameters:



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

def initialize(options = { }, &block)
  @servers = self.class.servers.dup
  @responses = { }
  
  @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
27
28
# File 'lib/redns/resolver.rb', line 14

def self.in_resolv_conf
  list = [ ]
  
  File.open("/etc/resolv.conf") do |fh|
    list = fh.readlines.collect { |l| l.chomp }.collect { |l| l.sub(/#.*/, '') }
    
    list.reject!{ |l| !l.sub!(/^\s*nameserver\s+/, '') }
  end
  
  list

rescue Errno::ENOENT
  # /etc/resolv.conf may not be present on misconfigured or offline systems
  [ ]
end

.serversObject



30
31
32
# File 'lib/redns/resolver.rb', line 30

def self.servers
  @servers ||= in_resolv_conf
end

.servers=(list) ⇒ Object



34
35
36
# File 'lib/redns/resolver.rb', line 34

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

.timeoutObject



38
39
40
# File 'lib/redns/resolver.rb', line 38

def self.timeout
  @timeout
end

.timeout=(secs) ⇒ Object



42
43
44
# File 'lib/redns/resolver.rb', line 42

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

Instance Method Details

#a_for(name) ⇒ Object



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

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

#bulk_query(type, names) ⇒ Object



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
92
# File 'lib/redns/resolver.rb', line 67

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



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

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

#ns_for(name) ⇒ Object



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

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

#ptr_for(name) ⇒ Object



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

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

#ptr_for_list(name) ⇒ Object



114
115
116
117
118
# File 'lib/redns/resolver.rb', line 114

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

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

Yields:

  • ()


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

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



149
150
151
# File 'lib/redns/resolver.rb', line 149

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

#response_for(id) ⇒ Object



174
175
176
# File 'lib/redns/resolver.rb', line 174

def response_for(id)
  @responses[id]
end

#responsesObject



178
179
180
# File 'lib/redns/resolver.rb', line 178

def responses
  @responses
end

#reverse_addresses(ips) ⇒ Object



124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/redns/resolver.rb', line 124

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.inject({ }) do |h, r|
    if (ip = map[r.questions[0].name.to_s])
      h[ip] = (r.answers[0] and r.answers[0].rdata.to_s)
    end
    
    h
  end
end

#send_message(message, server = nil) ⇒ Object



153
154
155
# File 'lib/redns/resolver.rb', line 153

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

#serversObject



141
142
143
# File 'lib/redns/resolver.rb', line 141

def servers
  @servers
end

#servers=(list) ⇒ Object



145
146
147
# File 'lib/redns/resolver.rb', line 145

def servers=(list)
  @servers = list
end

#simple_query(type, name) ⇒ Object



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

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



120
121
122
# File 'lib/redns/resolver.rb', line 120

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

#timeoutObject



182
183
184
# File 'lib/redns/resolver.rb', line 182

def timeout
  @timeout or self.class.timeout
end

#timeout=(secs) ⇒ Object



186
187
188
# File 'lib/redns/resolver.rb', line 186

def timeout=(secs)
  @timeout = secs
end

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



190
191
192
# File 'lib/redns/resolver.rb', line 190

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

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



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

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, left))
      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