toolmantim-zeroconf 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +44 -0
- data/Rakefile +71 -0
- data/lib/dnssd.rb +137 -0
- data/lib/net/dns.rb +49 -0
- data/lib/net/dns/mdns-sd.rb +240 -0
- data/lib/net/dns/mdns.rb +1189 -0
- data/lib/net/dns/resolv-mdns.rb +230 -0
- data/lib/net/dns/resolv-replace.rb +66 -0
- data/lib/net/dns/resolv.rb +2012 -0
- data/lib/net/dns/resolvx.rb +219 -0
- data/lib/zeroconf.rb +15 -0
- data/lib/zeroconf/common.rb +0 -0
- data/lib/zeroconf/ext.rb +7 -0
- data/lib/zeroconf/pure.rb +13 -0
- data/lib/zeroconf/version.rb +3 -0
- data/originals/dnssd-0.6.0/COPYING +56 -0
- data/originals/dnssd-0.6.0/README +50 -0
- data/originals/net-mdns-0.4/COPYING +58 -0
- data/originals/net-mdns-0.4/README +21 -0
- data/originals/net-mdns-0.4/TODO +278 -0
- data/samples/exhttp.rb +50 -0
- data/samples/exhttpv1.rb +29 -0
- data/samples/exwebrick.rb +56 -0
- data/samples/mdns-watch.rb +132 -0
- data/samples/mdns.rb +238 -0
- data/samples/test_dns.rb +128 -0
- data/samples/v1demo.rb +167 -0
- data/samples/v1mdns.rb +111 -0
- data/test/stress/stress_register.rb +48 -0
- data/test/test_browse.rb +24 -0
- data/test/test_highlevel_api.rb +35 -0
- data/test/test_register.rb +32 -0
- data/test/test_resolve.rb +23 -0
- data/test/test_resolve_ichat.rb +56 -0
- data/test/test_textrecord.rb +58 -0
- metadata +93 -0
@@ -0,0 +1,278 @@
|
|
1
|
+
TODO
|
2
|
+
|
3
|
+
Release: 0.0 "seeing if its possible" - done
|
4
|
+
|
5
|
+
Release: 0.1 "making it work"
|
6
|
+
|
7
|
+
A complete rewrite, too many changes to even begin to mention.
|
8
|
+
|
9
|
+
Release: 0.2 "doing the right thing"
|
10
|
+
|
11
|
+
- must always respond to requests for the A record for this host's .local
|
12
|
+
address
|
13
|
+
|
14
|
+
- cache the answers in the additional section
|
15
|
+
|
16
|
+
- in MDNSSD, put the handle into the reply as the "service" attribute
|
17
|
+
|
18
|
+
- need to send TTL=0 message on service shutdown
|
19
|
+
|
20
|
+
- implement flags, particularly add/remove flags
|
21
|
+
|
22
|
+
- remove all use of absolute in name comparisons, I have had too many bugs
|
23
|
+
involving this
|
24
|
+
|
25
|
+
- deal with timeouts in Resolv::MDNS, how long, can they be set, etc.
|
26
|
+
|
27
|
+
- reverse lookup of names by addresses using mDNS, see notes in
|
28
|
+
#generate_candidates. I think I should allow reverse lookup of addresss in
|
29
|
+
the private address spaces [RFC1918] (address prefixes of 10/8, 172.16/12,
|
30
|
+
and 192.168/16).
|
31
|
+
|
32
|
+
- correctly encode a nil in a text_record, and allow "key" w/no value for "mdns.rb -R"
|
33
|
+
|
34
|
+
- probe for name conflicts before registering a service
|
35
|
+
|
36
|
+
- when we see a question, flush answers over a few seconds old from cache
|
37
|
+
.. and do we notify queries that the answers are being deleted, too?
|
38
|
+
|
39
|
+
- escape/parse DNS-SD names ...
|
40
|
+
|
41
|
+
- try the meta-queries (_services._dns-sd._udp.local.)
|
42
|
+
|
43
|
+
- add known answers to queries
|
44
|
+
|
45
|
+
- answer unicast questions
|
46
|
+
|
47
|
+
- implement a MDNSSD api for DNSServiceQueryRecord, and 'mdns.rb -Q"
|
48
|
+
|
49
|
+
Release: 0.3 "keep it working"
|
50
|
+
|
51
|
+
- Change the technique for looking up IPv4 address of the default interface,
|
52
|
+
the old technique stopped working on OS X boxes that had IPv6 enabled (which
|
53
|
+
was the default).
|
54
|
+
|
55
|
+
- Fixed a bug causing infinite loops (in the wrong place) in background query.
|
56
|
+
|
57
|
+
|
58
|
+
Todo:
|
59
|
+
|
60
|
+
- define constants in module MDNSSD::Types like Http = '_http._tcp', ...?
|
61
|
+
|
62
|
+
- mdns.rb -K, watch for records and immediately register replacements pointing
|
63
|
+
to somewhere else
|
64
|
+
|
65
|
+
- general code cleanups
|
66
|
+
|
67
|
+
- Add #to_s to the RR types.
|
68
|
+
|
69
|
+
- Add #to_s the *classes* of the RR types ("IN::TXT", ...)
|
70
|
+
|
71
|
+
- HINFO RR service
|
72
|
+
|
73
|
+
- A RR service
|
74
|
+
|
75
|
+
- wildcard answering services
|
76
|
+
|
77
|
+
- Query#start, #restart
|
78
|
+
|
79
|
+
- let Query.new take a block, and yield itself, or yield with every answer?
|
80
|
+
|
81
|
+
- move hierarchal DNS Name comparison operators to an optional file.
|
82
|
+
|
83
|
+
- DNS packet dumper
|
84
|
+
|
85
|
+
- to make both TXT objects and TXT classes have a value,
|
86
|
+
add methods type_value and type_class.
|
87
|
+
|
88
|
+
|
89
|
+
|
90
|
+
dns-sd test mode results:
|
91
|
+
-A ok, but don't support -Q so don't see HINFO add/update/remove
|
92
|
+
-U ok
|
93
|
+
-N ok, but don't support -Q so don't see NULL add
|
94
|
+
-T ok
|
95
|
+
-M no, we don't support multiple TXT records for a service
|
96
|
+
-I ok
|
97
|
+
|
98
|
+
|
99
|
+
|
100
|
+
Open resolv.rb issues:
|
101
|
+
|
102
|
+
- Reverse DNS lookups are done by sock.recv, seems like its a problem for a
|
103
|
+
DNS library...
|
104
|
+
|
105
|
+
Shouldn't BasicSocket.do_not_reverse_lookup be set? Or be set on our sockets?
|
106
|
+
It's weird that in @sock.recv we get a tuple with the address... when we ARE
|
107
|
+
a resolver library.... and if you call resolv-replace, won't we call
|
108
|
+
ourselves in order to resolve the IP when you call recv to get the peer info?
|
109
|
+
And isn't resolv-replace ignoring BasicSocket.do_not_reverse_lookup? So, it
|
110
|
+
is very weird that resolv.rb does ad socket.recv that causes (blocking) DNS
|
111
|
+
queries to occure for its peer IP address...
|
112
|
+
|
113
|
+
- Resolv::Hosts returns IPv6 addresses before IPv4, so Resolv.getaddress('localhost')
|
114
|
+
is ::1 on my system - this is not good.
|
115
|
+
|
116
|
+
- See [DNSOPV6:3.1], does resolv.rb do this?
|
117
|
+
|
118
|
+
|
119
|
+
[DNSOPV6]
|
120
|
+
[DNSOPBADRES] draft-ietf-dnsop-bad-dns-res-03.tx
|
121
|
+
|
122
|
+
Open design issues:
|
123
|
+
|
124
|
+
- how to get the local ifx ipv4 address?
|
125
|
+
|
126
|
+
- Net classes that do socksetopts, so you don't have to pack the structs
|
127
|
+
yourself! or maybe implement the 8 functions of Stevens?
|
128
|
+
|
129
|
+
|
130
|
+
System differences in multicast:
|
131
|
+
|
132
|
+
[EACCES] The destination address is a broadcast address, and SO_BROADCAST has not been set on the socket.
|
133
|
+
|
134
|
+
|
135
|
+
Comments for DNS-SD:
|
136
|
+
|
137
|
+
* domain and type end in a '.', is that necessary?
|
138
|
+
|
139
|
+
* Names of Stuff
|
140
|
+
|
141
|
+
I'm getting lost in trying to remember what goes into a method, and what is available
|
142
|
+
in it's Reply object. I think the following convention would help:
|
143
|
+
|
144
|
+
Every function argument maps to a Reply attribute of the same name.
|
145
|
+
|
146
|
+
The Reply attributes and function arguments should be the same.
|
147
|
+
|
148
|
+
This makes things easy to remember, as data goes into #browse, comes out
|
149
|
+
BrowseReply, goes into #resolve, comes out ResolveReply it doesn't change its
|
150
|
+
name!
|
151
|
+
|
152
|
+
|
153
|
+
|
154
|
+
Currently:
|
155
|
+
|
156
|
+
DNSSD::BrowseReply.instance_methods:
|
157
|
+
["flags", "service", "domain", "fullname", "interface", "name", "type"]
|
158
|
+
|
159
|
+
Note that #type overrides Object#type.
|
160
|
+
service_type had its name changed to type
|
161
|
+
|
162
|
+
DNSSD::ResolveReply.instance_methods:
|
163
|
+
[ "flags", "service", "fullname", "interface", "port", "target", "text_record"]
|
164
|
+
|
165
|
+
Missing #domain!
|
166
|
+
Missing #name!
|
167
|
+
Missing #type!
|
168
|
+
|
169
|
+
#resolve takes argument #service_name, it comes from BrowseReply#name
|
170
|
+
#resolve takes argument #service_type, it comes from BrowseReply#type
|
171
|
+
#resolve takes argument #service_domain, it comes from BrowseReply#domain
|
172
|
+
|
173
|
+
Note that interface is still interface.
|
174
|
+
|
175
|
+
#browse has argument domain, #register has argument #service_domain
|
176
|
+
|
177
|
+
|
178
|
+
DNSSD::RegisterReply.instance_methods:
|
179
|
+
|
180
|
+
[ "flags", "service", "domain", "name", "type" ]
|
181
|
+
|
182
|
+
Missing #interface, #port, #target, #text_record.
|
183
|
+
|
184
|
+
|
185
|
+
As it is, I find the naming really confusing. Changing the names in the replies
|
186
|
+
causes interface breakage, so how about changing the names in the arguments so
|
187
|
+
they are the same as the attributes in the reply, and so that all 3 functions
|
188
|
+
use the same name for the same thing?
|
189
|
+
|
190
|
+
|
191
|
+
This code supplies some missing methods:
|
192
|
+
|
193
|
+
module DNSSD
|
194
|
+
def self.namesplit(n)
|
195
|
+
n.scan(/(?:\\.|[^\.])+/)
|
196
|
+
end
|
197
|
+
class ResolveReply
|
198
|
+
def domain
|
199
|
+
DNSSD.namesplit(fullname)[-1]
|
200
|
+
end
|
201
|
+
def type
|
202
|
+
DNSSD.namesplit(fullname)[1,2].join('.')
|
203
|
+
end
|
204
|
+
def name
|
205
|
+
DNSSD.namesplit(fullname)[0]
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
|
211
|
+
|
212
|
+
|
213
|
+
Comments for Apple:
|
214
|
+
|
215
|
+
* [MDNS:5] Reverse Address Mapping - should allow reverse mapping
|
216
|
+
in the [RFC1918] address space as well. Does Apple's resolver
|
217
|
+
do this?
|
218
|
+
|
219
|
+
* TXT record is required by mDNSResponder
|
220
|
+
|
221
|
+
DNS-SD does not require a responder advertising a service to have
|
222
|
+
a TXT record.
|
223
|
+
|
224
|
+
|
225
|
+
Problem:
|
226
|
+
|
227
|
+
I assume it is done because if you ask for SRV and TXT (or ANY), and
|
228
|
+
get only SRV, you don't know if it is because there is no TXT, or because
|
229
|
+
it didn't make it across unreliable UDP.
|
230
|
+
|
231
|
+
Solutions:
|
232
|
+
|
233
|
+
Require a TXT record (curent mDNSResponder behaviour).
|
234
|
+
|
235
|
+
Require that all the questions in a single DNS message be responded
|
236
|
+
to in a single DNS message. This allows:
|
237
|
+
|
238
|
+
1 - asking for ANY?, and if you get a SRV but no TXT, it means there
|
239
|
+
is no TXT
|
240
|
+
2 - asking for TXT? and SRV?, and if you get a SRV but no TXT, it means
|
241
|
+
there is no TXT
|
242
|
+
|
243
|
+
Recommend:
|
244
|
+
|
245
|
+
I prefer the latter. It scales to more than two records associated with a
|
246
|
+
service, so in the future if a service needs a SRV, TXT, and NUL record, a
|
247
|
+
single query can be sent, and a single query can be expected as a response.
|
248
|
+
|
249
|
+
For legacy interop reasons, we are probably stuck with having to advertise a
|
250
|
+
TXT record. I still think all questions from a single message should be answered
|
251
|
+
in a single message. Possible exception is when to large, in which case the
|
252
|
+
TC bit should be set so the resolver knows to expect another message.
|
253
|
+
|
254
|
+
|
255
|
+
* TXT records from mDNSResponder may have zero character-strings
|
256
|
+
|
257
|
+
Violates DNS spec.
|
258
|
+
|
259
|
+
DNS-SD claims to conform to DNS.
|
260
|
+
|
261
|
+
DNS-SD says TXT has zero or more character-strings.
|
262
|
+
|
263
|
+
Two statements not in agreement.
|
264
|
+
|
265
|
+
Recommend that:
|
266
|
+
- DNS-SD be altered to state TXT records MUST conform to DNS specs.
|
267
|
+
- DNS-SD include a warning that deployed responders generate TXT
|
268
|
+
with zero char-strings, and implementations SHOULD be capable of handling
|
269
|
+
this as being equivalent to a TXT with one zero-length character string.
|
270
|
+
|
271
|
+
|
272
|
+
* OS X puts additional answers in the answers section, not the additional section
|
273
|
+
|
274
|
+
* OS X resolver generates queries for ensemble.local.local
|
275
|
+
|
276
|
+
This violates DNS-SD.
|
277
|
+
|
278
|
+
|
data/samples/exhttp.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
#!/usr/local/bin/ruby18 -w
|
2
|
+
# Author: Sam Roberts <sroberts@uniserve.com>
|
3
|
+
# Licence: this file is placed in the public domain
|
4
|
+
|
5
|
+
require 'net/http'
|
6
|
+
require 'thread'
|
7
|
+
require 'pp'
|
8
|
+
|
9
|
+
# For MDNSSD
|
10
|
+
require 'net/dns/mdns-sd'
|
11
|
+
|
12
|
+
# To make Resolv aware of mDNS
|
13
|
+
require 'net/dns/resolv-mdns'
|
14
|
+
|
15
|
+
# To make TCPSocket use Resolv, not the C library resolver.
|
16
|
+
require 'net/dns/resolv-replace'
|
17
|
+
|
18
|
+
# Use a short name.
|
19
|
+
DNSSD = Net::DNS::MDNSSD
|
20
|
+
|
21
|
+
# Sync stdout, and don't write to console from multiple threads.
|
22
|
+
$stdout.sync
|
23
|
+
$lock = Mutex.new
|
24
|
+
|
25
|
+
# Be quiet.
|
26
|
+
debug = false
|
27
|
+
|
28
|
+
DNSSD.browse('_http._tcp') do |b|
|
29
|
+
$lock.synchronize { pp b } if debug
|
30
|
+
DNSSD.resolve(b.name, b.type) do |r|
|
31
|
+
$lock.synchronize { pp r } if debug
|
32
|
+
begin
|
33
|
+
http = Net::HTTP.new(r.target, r.port)
|
34
|
+
|
35
|
+
path = r.text_record['path'] || '/'
|
36
|
+
|
37
|
+
headers = http.head(path)
|
38
|
+
|
39
|
+
$lock.synchronize do
|
40
|
+
puts "#{r.name.inspect} on #{r.target}:#{r.port}#{path} using server #{headers['server']}"
|
41
|
+
end
|
42
|
+
rescue
|
43
|
+
$lock.synchronize { puts $!; puts $!.backtrace }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Hit enter when you think that's all.
|
49
|
+
STDIN.gets
|
50
|
+
|
data/samples/exhttpv1.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/local/bin/ruby18 -w
|
2
|
+
# Author: Sam Roberts <sroberts@uniserve.com>
|
3
|
+
# Licence: this file is placed in the public domain
|
4
|
+
|
5
|
+
require 'net/http'
|
6
|
+
require 'net/dns/resolv-mdns'
|
7
|
+
|
8
|
+
mdns = Resolv::MDNS.default
|
9
|
+
|
10
|
+
mdns.each_resource('_http._tcp.local', Resolv::DNS::Resource::IN::PTR) do |rrhttp|
|
11
|
+
service = rrhttp.name
|
12
|
+
host = nil
|
13
|
+
port = nil
|
14
|
+
path = '/'
|
15
|
+
|
16
|
+
rrsrv = mdns.getresource(rrhttp.name, Resolv::DNS::Resource::IN::SRV)
|
17
|
+
host, port = rrsrv.target.to_s, rrsrv.port
|
18
|
+
rrtxt = mdns.getresource(rrhttp.name, Resolv::DNS::Resource::IN::TXT)
|
19
|
+
if rrtxt.data =~ /path=(.*)/
|
20
|
+
path = $1
|
21
|
+
end
|
22
|
+
|
23
|
+
http = Net::HTTP.new(host, port)
|
24
|
+
|
25
|
+
headers = http.head(path)
|
26
|
+
|
27
|
+
puts "#{service[0]} on #{host}:#{port}#{path} was last-modified #{headers['last-modified']}"
|
28
|
+
end
|
29
|
+
|
@@ -0,0 +1,56 @@
|
|
1
|
+
#!/usr/local/bin/ruby18 -w
|
2
|
+
# Author: Sam Roberts <sroberts@uniserve.com>
|
3
|
+
# Licence: this file is placed in the public domain
|
4
|
+
#
|
5
|
+
# Advertise a webrick server over mDNS.
|
6
|
+
|
7
|
+
require 'webrick'
|
8
|
+
require 'net/dns/mdns-sd'
|
9
|
+
|
10
|
+
DNSSD = Net::DNS::MDNSSD
|
11
|
+
|
12
|
+
class HelloServlet < WEBrick::HTTPServlet::AbstractServlet
|
13
|
+
def do_GET(req, resp)
|
14
|
+
resp.body = "hello, world\n"
|
15
|
+
resp['content-type'] = 'text/plain'
|
16
|
+
raise WEBrick::HTTPStatus::OK
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# This may seem convoluted... but if there are multiple address families
|
21
|
+
# available, like AF_INET6 and AF_INET, this should create multiple TCPServer
|
22
|
+
# sockets for them.
|
23
|
+
families = Socket.getaddrinfo(nil, 1, Socket::AF_UNSPEC, Socket::SOCK_STREAM, 0, Socket::AI_PASSIVE)
|
24
|
+
|
25
|
+
listeners = []
|
26
|
+
port = 0
|
27
|
+
|
28
|
+
families.each do |af, one, dns, addr|
|
29
|
+
p port, addr
|
30
|
+
listeners << TCPServer.new(addr, port)
|
31
|
+
port = listeners.first.addr[1] unless port != 0
|
32
|
+
end
|
33
|
+
|
34
|
+
listeners.each do |s|
|
35
|
+
puts "listen on #{s.addr.inspect}"
|
36
|
+
end
|
37
|
+
|
38
|
+
# This will dynamically allocate multiple TCPServers, each on a different port.
|
39
|
+
server = WEBrick::HTTPServer.new( :Port => 0 )
|
40
|
+
|
41
|
+
# So we replace them with our TCPServer sockets which are all on the same
|
42
|
+
# (dynamically assigned) port.
|
43
|
+
server.listeners.each do |s| s.close end
|
44
|
+
server.listeners.replace listeners
|
45
|
+
server.config[:Port] = port
|
46
|
+
|
47
|
+
server.mount( '/hello/', HelloServlet )
|
48
|
+
|
49
|
+
handle = DNSSD.register("hello", '_http._tcp', 'local', port, 'path' => '/hello/')
|
50
|
+
|
51
|
+
['INT', 'TERM'].each { |signal|
|
52
|
+
trap(signal) { server.shutdown; handle.stop; }
|
53
|
+
}
|
54
|
+
|
55
|
+
server.start
|
56
|
+
|
@@ -0,0 +1,132 @@
|
|
1
|
+
#!/usr/local/bin/ruby18
|
2
|
+
|
3
|
+
require 'socket'
|
4
|
+
require 'ipaddr'
|
5
|
+
require 'net/dns'
|
6
|
+
|
7
|
+
$stderr.sync = true
|
8
|
+
$stdout.sync = true
|
9
|
+
|
10
|
+
Addr = "224.0.0.251"
|
11
|
+
Port = 5353
|
12
|
+
|
13
|
+
include Net::DNS
|
14
|
+
|
15
|
+
@hostname = Name.create(Socket.gethostname)
|
16
|
+
@hostname.absolute = true
|
17
|
+
@hostaddr = Socket.getaddrinfo(@hostname.to_s, 0, Socket::AF_INET, Socket::SOCK_STREAM)[0][3]
|
18
|
+
@hostrr = [ @hostname, 240, IN::A.new(@hostaddr) ]
|
19
|
+
@hostaddr = IPAddr.new(@hostaddr).hton
|
20
|
+
|
21
|
+
@sock = UDPSocket.new
|
22
|
+
|
23
|
+
# TODO - do we need this?
|
24
|
+
@sock.fcntl(Fcntl::F_SETFD, 1)
|
25
|
+
|
26
|
+
# Allow 5353 to be shared.
|
27
|
+
so_reuseport = 0x0200 # The definition on OS X, where it is required.
|
28
|
+
if Socket.constants.include? 'SO_REUSEPORT'
|
29
|
+
so_reuseport = Socket::SO_REUSEPORT
|
30
|
+
end
|
31
|
+
begin
|
32
|
+
@sock.setsockopt(Socket::SOL_SOCKET, so_reuseport, 1)
|
33
|
+
rescue
|
34
|
+
warn( "set SO_REUSEPORT raised #{$!}, try SO_REUSEADDR" )
|
35
|
+
so_reuseport = Socket::SO_REUSEADDR
|
36
|
+
@sock.setsockopt(Socket::SOL_SOCKET, so_reuseport, 1)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Request dest addr and ifx ids... no.
|
40
|
+
|
41
|
+
# Join the multicast group.
|
42
|
+
# option is a struct ip_mreq { struct in_addr, struct in_addr }
|
43
|
+
ip_mreq = IPAddr.new(Addr).hton + @hostaddr
|
44
|
+
@sock.setsockopt(Socket::IPPROTO_IP, Socket::IP_ADD_MEMBERSHIP, ip_mreq)
|
45
|
+
@sock.setsockopt(Socket::IPPROTO_IP, Socket::IP_MULTICAST_IF, @hostaddr)
|
46
|
+
|
47
|
+
# Set IP TTL for outgoing packets.
|
48
|
+
@sock.setsockopt(Socket::IPPROTO_IP, Socket::IP_TTL, 255)
|
49
|
+
@sock.setsockopt(Socket::IPPROTO_IP, Socket::IP_MULTICAST_TTL, 255)
|
50
|
+
|
51
|
+
# Apple source makes it appear that optval may need to be a "char" on
|
52
|
+
# some systems:
|
53
|
+
# @sock.setsockopt(Socket::IPPROTO_IP, Socket::IP_MULTICAST_TTL, 255 as int)
|
54
|
+
# - or -
|
55
|
+
# @sock.setsockopt(Socket::IPPROTO_IP, Socket::IP_MULTICAST_TTL, 255 as byte)
|
56
|
+
|
57
|
+
# Bind to our port.
|
58
|
+
@sock.bind(Socket::INADDR_ANY, Port)
|
59
|
+
|
60
|
+
class Resolv
|
61
|
+
class DNS
|
62
|
+
class Resource
|
63
|
+
module IN
|
64
|
+
class SRV
|
65
|
+
def inspect
|
66
|
+
"#{target}:#{port} weight=#{weight} priority=#{priority}"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
class TXT
|
70
|
+
def inspect
|
71
|
+
strings.inspect
|
72
|
+
end
|
73
|
+
end
|
74
|
+
class PTR
|
75
|
+
def inspect
|
76
|
+
name.to_s
|
77
|
+
end
|
78
|
+
end
|
79
|
+
class A
|
80
|
+
def inspect
|
81
|
+
address.to_s
|
82
|
+
end
|
83
|
+
end
|
84
|
+
class HINFO
|
85
|
+
def inspect
|
86
|
+
"os=#{os.inspect}\ncpu=#{cpu.inspect}"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
loop do
|
95
|
+
|
96
|
+
reply, from = @sock.recvfrom(9000)
|
97
|
+
|
98
|
+
puts "++ from #{from.inspect}"
|
99
|
+
|
100
|
+
if false
|
101
|
+
puts reply.inspect
|
102
|
+
puts "--"
|
103
|
+
end
|
104
|
+
|
105
|
+
msg = Resolv::DNS::Message.decode(reply)
|
106
|
+
|
107
|
+
qr = msg.qr==0 ? 'Q' : 'R'
|
108
|
+
qrstr = msg.qr==0 ? 'Query' : 'Resp'
|
109
|
+
|
110
|
+
opcode = { 0=>'QUERY', 1=>'IQUERY', 2=>'STATUS'}[msg.opcode]
|
111
|
+
|
112
|
+
puts "#{qrstr}: id #{msg.id} qr #{qr} opcode #{opcode} aa #{msg.aa} tc #{msg.tc} rd #{msg.rd} ra #{msg.ra} rcode #{msg.rcode}"
|
113
|
+
|
114
|
+
msg.question.each do |name, type, unicast|
|
115
|
+
puts "qu #{Net::DNS.rrname type} #{name.to_s.inspect} unicast=#{unicast}"
|
116
|
+
end
|
117
|
+
msg.answer.each do |name, ttl, data, cacheflush|
|
118
|
+
puts "an #{Net::DNS.rrname data} #{name.to_s.inspect} ttl=#{ttl} cacheflush=#{cacheflush}"
|
119
|
+
puts " #{data.inspect}"
|
120
|
+
end
|
121
|
+
msg.authority.each do |name, ttl, data, cacheflush|
|
122
|
+
puts "au #{Net::DNS.rrname data} #{name.to_s.inspect} ttl=#{ttl} cacheflush=#{cacheflush.inspect}"
|
123
|
+
puts " #{data.inspect}"
|
124
|
+
end
|
125
|
+
msg.additional.each do |name, ttl, data, cacheflush|
|
126
|
+
puts "ad #{Net::DNS.rrname data} #{name.to_s.inspect} ttl=#{ttl} cacheflush=#{cacheflush.inspect}"
|
127
|
+
puts " #{data.inspect}"
|
128
|
+
end
|
129
|
+
|
130
|
+
puts
|
131
|
+
end
|
132
|
+
|