Class: MDNS

Inherits:
Object
  • Object
show all
Defined in:
lib/mdns.rb,
lib/mdns/version.rb

Constant Summary collapse

MULTICAST_IP =
'224.0.0.251'
MDNS_PORT =
5353
VERSION =
"0.1.1"

Class Method Summary collapse

Class Method Details

.add_record(record) ⇒ Object



61
62
63
64
65
66
67
# File 'lib/mdns.rb', line 61

def add_record(record)
  if record.is_a?(String)
    record = Net::DNS::RR.new(record)
  end
  records[record.name.downcase] = record
  respond_with(record) if @socket && !@socket.closed?
end

.hostsObject



73
74
75
# File 'lib/mdns.rb', line 73

def hosts
  records.keys
end

.recordsObject



69
70
71
# File 'lib/mdns.rb', line 69

def records
  @records ||= {}
end

.resetObject



77
78
79
80
# File 'lib/mdns.rb', line 77

def reset
  @records = nil
  stop
end

.respond_to(query) ⇒ Object



44
45
46
47
48
# File 'lib/mdns.rb', line 44

def respond_to(query)
  puts "#{Time.now} Responding to query"
  record = records[query.question.first.qName.downcase]
  respond_with(record)
end

.respond_with(record) ⇒ Object



50
51
52
53
54
55
56
57
58
59
# File 'lib/mdns.rb', line 50

def respond_with(record)
  # I have no idea what I'm doing
  response = Net::DNS::Packet.new(record.name)
  response.header.qr = true
  response.header.aa = true
  response.header.anCount = 1
  response.header.arCount = 1
  response.answer = record
  @socket.send(response.data, 0, MULTICAST_IP, MDNS_PORT)
end

.startObject



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/mdns.rb', line 9

def start
  @socket = UDPSocket.new
  @socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true)
  @socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEPORT, true)
  ip_mreq = IPAddr.new(MULTICAST_IP).hton + IPAddr.new('0.0.0.0').hton
  @socket.setsockopt(Socket::IPPROTO_IP, Socket::IP_ADD_MEMBERSHIP, ip_mreq)
  @socket.setsockopt(Socket::IPPROTO_IP, Socket::IP_TTL, 255)
  @socket.setsockopt(Socket::IPPROTO_IP, Socket::IP_MULTICAST_TTL, 255)
  @socket.bind(Socket::INADDR_ANY, MDNS_PORT)
  Thread.abort_on_exception = true
  @thr = Thread.new do
    loop do
      data = @socket.recvfrom(1024)
      next unless data[0...8] == "\x00\x00\x00\x00\x00\x01\x00\x00"
      packet = begin
        Net::DNS::Packet::parse(data)
      rescue => e
        # Net::DNS::Packet doesn't handle a bunch of mDNS packets
      end
      next if packet.nil?
      if packet.header.query? && packet.question.any? { |q| hosts.include?(q.qName.downcase) && q.qType.to_s == 'A' }
        respond_to(packet)
      end
    end
  end

  records.values.each do |record|
    respond_with(record)
  end

  at_exit do
    stop
  end
end

.stopObject



82
83
84
85
86
87
88
89
90
# File 'lib/mdns.rb', line 82

def stop
  if @thr
    @thr.kill
    @thr = nil
  end
  if @socket && !@socket.closed?
    @socket.close
  end
end