Class: ReDNS::Connection

Inherits:
EventMachine::Connection
  • Object
show all
Includes:
EventMachine::Deferrable
Defined in:
lib/redns/connection.rb

Constant Summary collapse

DEFAULT_TIMEOUT =

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

5
DEFAULT_ATTEMPTS =
2
SEQUENCE_LIMIT =
0x10000

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#attemptsObject

Properties ===========================================================



12
13
14
# File 'lib/redns/connection.rb', line 12

def attempts
  @attempts
end

#timeoutObject

Properties ===========================================================



12
13
14
# File 'lib/redns/connection.rb', line 12

def timeout
  @timeout
end

Class Method Details

.instance {|connection| ... } ⇒ Object

Returns a new instance of a reactor-bound resolver. If a block is given, the instance is supplied for customization purposes.

Yields:

  • (connection)


22
23
24
25
26
27
28
29
30
31
32
# File 'lib/redns/connection.rb', line 22

def self.instance
  connection = EventMachine.open_datagram_socket(
    ReDNS::Support.bind_all_addr,
    0,
    self
  )
  
  yield(connection) if (block_given?)
  
  connection
end

Instance Method Details

#nameserversObject

Returns the configured list of nameservers as an Array. If not configured specifically, will look in the resolver configuration file, typically /etc/resolv.conf for which servers to use.



53
54
55
# File 'lib/redns/connection.rb', line 53

def nameservers
  @nameservers ||= ReDNS::Support.default_nameservers
end

#nameservers=(*list) ⇒ Object

Configure the nameservers to use. Supplied value can be either a string containing one IP address, an Array containing multiple IP addresses, or nil which reverts to defaults.



60
61
62
63
# File 'lib/redns/connection.rb', line 60

def nameservers=(*list)
  @nameservers = list.flatten.compact
  @nameservers = nil if (list.empty?)
end

#portObject

Returns the current port in use.



71
72
73
# File 'lib/redns/connection.rb', line 71

def port
  Socket.unpack_sockaddr_in(get_sockname)[0]
end

#post_initObject

EventMachine: Called after the connection is initialized.



113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/redns/connection.rb', line 113

def post_init
  # Sequence numbers do not have to be cryptographically secure, but having
  # a healthy amount of randomness is a good thing.
  @sequence = (rand(SEQUENCE_LIMIT) ^ (object_id ^ (Time.now.to_f * SEQUENCE_LIMIT).to_i)) % SEQUENCE_LIMIT
  
  # Callback tracking is done by matching response IDs in a lookup table
  @callback = { }
  
  @timeout ||= DEFAULT_TIMEOUT
  @attempts ||= DEFAULT_ATTEMPTS
  
  EventMachine.add_periodic_timer(1) do
    check_for_timeouts!
  end
end

#random_nameserverObject

Picks a random nameserver from the configured list=



66
67
68
# File 'lib/redns/connection.rb', line 66

def random_nameserver
  nameservers[rand(nameservers.length)]
end

#receive_data(data) ⇒ Object

EventMachine: Called when data is received on the active socket.



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

def receive_data(data)
  message = ReDNS::Message.new(ReDNS::Buffer.new(data))
  
  if (callback = @callback.delete(message.id))
    answers = message.answers

    if (type = callback[:filter_by_type])
      answers = answers.select { |a| a.rtype == type }
    end

    callback[:callback].call(answers)
  end
end

#resolve(query, type = nil, filter = true, &callback) ⇒ Object

Resolves a given query and optional type asynchronously, yielding to the callback function with either the answers or nil if a timeout or error occurred. The filter option will restrict responses ot those matching the requested type if true, or return all responses if false. The default is to filter responses.



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/redns/connection.rb', line 80

def resolve(query, type = nil, filter = true, &callback)
  message = ReDNS::Message.question(query, type) do |m|
    m.id = @sequence
  end
  
  serialized_message = message.serialize.to_s
  target_nameserver = random_nameserver

  result = send_datagram(
    serialized_message,
    target_nameserver,
    ReDNS::Support.dns_port
  )

  if (result > 0)
    @callback[@sequence] = {
      :serialized_message => serialized_message,
      :type => type,
      :filter_by_type => (type == :any || !filter) ? false : type,
      :nameserver => target_nameserver,
      :attempts => self.attempts - 1,
      :callback => callback,
      :at => Time.now
    }
  else
    callback.call(nil)
  end

  @sequence += 1
  @sequence %= SEQUENCE_LIMIT
end

#unbindObject

EventMachine: Called when the connection is closed.



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

def unbind
end