toolmantim-zeroconf 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|