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
data/samples/mdns.rb
ADDED
@@ -0,0 +1,238 @@
|
|
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
|
+
$:.unshift(File.dirname($0))
|
6
|
+
|
7
|
+
require 'getoptlong'
|
8
|
+
|
9
|
+
$stdout.sync = true
|
10
|
+
$stderr.sync = true
|
11
|
+
|
12
|
+
=begin
|
13
|
+
Apple's dns-sd options:
|
14
|
+
|
15
|
+
mdns -E (Enumerate recommended registration domains)
|
16
|
+
mdns -F (Enumerate recommended browsing domains)
|
17
|
+
mdns -B <Type> <Domain> (Browse for service instances)
|
18
|
+
mdns -L <Name> <Type> <Domain> (Look up a service instance)
|
19
|
+
mdns -R <Name> <Type> <Domain> <Port> [<TXT>...] (Register a service)
|
20
|
+
mdns -P <Name> <Type> <Domain> <Port> <Host> <IP> [<TXT>...] (Proxy)
|
21
|
+
mdns -Q <FQDN> <rrtype> <rrclass> (Generic query for any record type)
|
22
|
+
=end
|
23
|
+
|
24
|
+
@debug = false
|
25
|
+
@log = nil
|
26
|
+
|
27
|
+
@recursive = false
|
28
|
+
@domain = 'local'
|
29
|
+
@type = nil
|
30
|
+
@name = nil
|
31
|
+
@port = nil
|
32
|
+
@txt = {}
|
33
|
+
|
34
|
+
@cmd = nil
|
35
|
+
|
36
|
+
|
37
|
+
# TODO - can I use introspection on class names to determine all supported
|
38
|
+
# RR types in DNS::Resource::IN?
|
39
|
+
|
40
|
+
HELP =<<EOF
|
41
|
+
Usage:
|
42
|
+
mdns [options] -B <type> [domain] (Browse for service instances)
|
43
|
+
mdns [options] -L <name> <type> [domain] (Look up a service instance)
|
44
|
+
mdns [options] -R <name> <type> [domain] <port> [<TXT>...] (Register a service)
|
45
|
+
mdns [options] -Q <fqdn> [rrtype] [rrclass] (Generic query for any record type)
|
46
|
+
|
47
|
+
Note: -Q is not yet implemented.
|
48
|
+
|
49
|
+
For -B, -L, and -R, [domain] is optional and defaults to "local".
|
50
|
+
|
51
|
+
For -Q, [rrtype] defaults to A, other values are TXT, PTR, SRV, CNAME, ...
|
52
|
+
|
53
|
+
For -Q, [rrclass] defaults to 1 (IN).
|
54
|
+
|
55
|
+
|
56
|
+
[<TXT>...] is optional for -R, it can be a series of key=value pairs.
|
57
|
+
|
58
|
+
You can use long names --browse, --lookup, and --register instead of -B, -L,
|
59
|
+
and -R.
|
60
|
+
|
61
|
+
Options:
|
62
|
+
-m,--mdnssd Attempt to use 'net/dns/mdns-sd', a pure-ruby DNS-SD resolver
|
63
|
+
library (this is the default).
|
64
|
+
-n,--dnssd Attempt to use 'dnssd', the interface to the native ("-n")
|
65
|
+
DNS-SD resolver library APIs, "dns_sd.h" from Apple.
|
66
|
+
-d,--debug Print debug messages to stderr.
|
67
|
+
|
68
|
+
Examples:
|
69
|
+
mdns -B _http._tcp
|
70
|
+
mdns -L "My Music" _daap._tcp
|
71
|
+
mdns -R me _example._tcp local 4321 key=value key2=value2
|
72
|
+
|
73
|
+
These work with the test modes of Apple's dns-sd utility:
|
74
|
+
mdns -L Test _testupdate._tcp (for dns-sd -A, -U, -N)
|
75
|
+
mdns -L Test _testlargetxt._tcp (for dns-sd -T)
|
76
|
+
mdns -L Test _testdualtxt._tcp (for dns-sd -M)
|
77
|
+
mdns -L Test _testtxt._tcp (for dns-sd -I)
|
78
|
+
|
79
|
+
EOF
|
80
|
+
|
81
|
+
opts = GetoptLong.new(
|
82
|
+
[ "--debug", "-d", GetoptLong::NO_ARGUMENT ],
|
83
|
+
[ "--help", "-h", GetoptLong::NO_ARGUMENT ],
|
84
|
+
[ "--dnssd", "-n", GetoptLong::NO_ARGUMENT ],
|
85
|
+
[ "--mdnssd", "-m", GetoptLong::NO_ARGUMENT ],
|
86
|
+
|
87
|
+
[ "--browse", "-B", GetoptLong::NO_ARGUMENT ],
|
88
|
+
[ "--lookup", "-L", GetoptLong::NO_ARGUMENT ],
|
89
|
+
[ "--register", "-R", GetoptLong::NO_ARGUMENT ]
|
90
|
+
)
|
91
|
+
|
92
|
+
opts.each do |opt, arg|
|
93
|
+
case opt
|
94
|
+
when "--debug"
|
95
|
+
require 'pp'
|
96
|
+
require 'logger'
|
97
|
+
|
98
|
+
@debug = true
|
99
|
+
@log = Logger.new(STDERR)
|
100
|
+
@log.level = Logger::DEBUG
|
101
|
+
|
102
|
+
when "--help"
|
103
|
+
print HELP
|
104
|
+
exit 0
|
105
|
+
|
106
|
+
when '--dnssd'
|
107
|
+
require 'dnssd'
|
108
|
+
require 'socket'
|
109
|
+
|
110
|
+
when "--browse"
|
111
|
+
@cmd = :browse
|
112
|
+
@type = ARGV.shift
|
113
|
+
@domain = ARGV.shift || @domain
|
114
|
+
|
115
|
+
when "--lookup"
|
116
|
+
@cmd = :lookup
|
117
|
+
@name = ARGV.shift
|
118
|
+
@type = ARGV.shift
|
119
|
+
@domain = ARGV.shift || @domain
|
120
|
+
|
121
|
+
unless @name && @type
|
122
|
+
puts 'name and type required for -L'
|
123
|
+
exit 1
|
124
|
+
end
|
125
|
+
|
126
|
+
when "--register"
|
127
|
+
@cmd = :register
|
128
|
+
@name = ARGV.shift
|
129
|
+
@type = ARGV.shift
|
130
|
+
@port = ARGV.shift
|
131
|
+
if @port.to_i == 0
|
132
|
+
@domain = @port
|
133
|
+
@port = ARGV.shift.to_i
|
134
|
+
else
|
135
|
+
@port = @port.to_i
|
136
|
+
end
|
137
|
+
ARGV.each do |kv|
|
138
|
+
kv.match(/([^=]+)=([^=]+)/)
|
139
|
+
@txt[$1] = $2
|
140
|
+
end
|
141
|
+
ARGV.replace([])
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
begin
|
146
|
+
DNSSD.class
|
147
|
+
puts "Using native DNSSD..."
|
148
|
+
|
149
|
+
Thread.abort_on_exception = true # So we notice exceptions in DNSSD threads.
|
150
|
+
|
151
|
+
module DNSSD
|
152
|
+
def self.namesplit(n)
|
153
|
+
n.scan(/(?:\\.|[^\.])+/)
|
154
|
+
end
|
155
|
+
# DNSSD > 0.6.0 uses class Reply which has these methods already
|
156
|
+
class ResolveReply
|
157
|
+
def domain
|
158
|
+
DNSSD.namesplit(fullname)[-1]
|
159
|
+
end
|
160
|
+
def type
|
161
|
+
DNSSD.namesplit(fullname)[1,2].join('.')
|
162
|
+
end
|
163
|
+
def name
|
164
|
+
DNSSD.namesplit(fullname)[0]
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
rescue NameError
|
169
|
+
require 'net/dns/mdns-sd'
|
170
|
+
DNSSD = Net::DNS::MDNSSD
|
171
|
+
Net::DNS::MDNS::Responder.instance.log = @log if @log
|
172
|
+
puts "Using Net::DNS::MDNSSD..."
|
173
|
+
end
|
174
|
+
|
175
|
+
unless @cmd
|
176
|
+
print HELP
|
177
|
+
exit 1
|
178
|
+
end
|
179
|
+
|
180
|
+
case @cmd
|
181
|
+
when :browse
|
182
|
+
STDERR.puts( "DNSSD.#{@cmd}(#{@type}, #{@domain}) =>" ) if @debug
|
183
|
+
|
184
|
+
fmt = "%-3.3s %-8.8s %-15.15s %-20.20s\n"
|
185
|
+
printf fmt, "Ttl", "Domain", "Service Type", "Instance Name"
|
186
|
+
|
187
|
+
handle = DNSSD.browse(@type, @domain) do |reply|
|
188
|
+
begin
|
189
|
+
printf fmt, reply.flags.to_i, reply.domain, reply.type, reply.name
|
190
|
+
rescue
|
191
|
+
p $!
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
$stdin.gets
|
196
|
+
handle.stop
|
197
|
+
|
198
|
+
|
199
|
+
when :lookup
|
200
|
+
STDERR.puts( "DNSSD.#{@cmd}(#{@name}, #{@type}, #{@domain}) =>" ) if @debug
|
201
|
+
|
202
|
+
fmt = "%-3.3s %-8.8s %-19.19s %-20.20s %-20.20s %s\n"
|
203
|
+
printf fmt, "Ttl", "Domain", "Service Type", "Instance Name", "Location", "Text"
|
204
|
+
|
205
|
+
handle = DNSSD.resolve(@name, @type, @domain) do |reply|
|
206
|
+
begin
|
207
|
+
location = "#{reply.target}:#{reply.port}"
|
208
|
+
text = reply.text_record.to_a.map { |kv| "#{kv[0]}=#{kv[1].inspect}" }.join(', ')
|
209
|
+
printf fmt, reply.flags.to_i, reply.domain, reply.type, reply.name, location, text
|
210
|
+
rescue
|
211
|
+
p $!
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
$stdin.gets
|
216
|
+
handle.stop
|
217
|
+
|
218
|
+
when :register
|
219
|
+
STDERR.puts( "DNSSD.#{@cmd}(#{@name}, #{@type}, #{@domain}, #{@port}, #{@txt.inspect}) =>" ) if @debug
|
220
|
+
|
221
|
+
fmt = "%-3.3s %-8.8s %-19.19s %-20.20s %-20.20s %s\n"
|
222
|
+
printf fmt, "Ttl", "Domain", "Service Type", "Instance Name", "Location", "Text"
|
223
|
+
|
224
|
+
handle = DNSSD.register(@name, @type, @domain, @port, @txt) do |notice|
|
225
|
+
begin
|
226
|
+
location = "#{Socket.gethostname}:#{@port}"
|
227
|
+
text = @txt.to_a.map { |kv| "#{kv[0]}=#{kv[1].inspect}" }.join(', ')
|
228
|
+
printf fmt, 'N/A', notice.domain, notice.type, notice.name, location, text
|
229
|
+
rescue
|
230
|
+
p $!
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
$stdin.gets
|
235
|
+
handle.stop
|
236
|
+
|
237
|
+
end
|
238
|
+
|
data/samples/test_dns.rb
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
|
3
|
+
$:.unshift File.dirname($0)
|
4
|
+
|
5
|
+
require 'net/dns/resolvx.rb'
|
6
|
+
require 'test/unit'
|
7
|
+
|
8
|
+
require 'pp'
|
9
|
+
|
10
|
+
Name = Resolv::DNS::Name
|
11
|
+
|
12
|
+
class TestDns < Test::Unit::TestCase
|
13
|
+
|
14
|
+
def test_name_what_I_think_are_odd_behaviours
|
15
|
+
# Why can't test against strings?
|
16
|
+
assert_equal(false, Name.create("example.CoM") == "example.com")
|
17
|
+
assert_equal(false, Name.create("example.CoM").eql?("example.com"))
|
18
|
+
|
19
|
+
# Why does making it absolute mean they aren't equal?
|
20
|
+
assert_equal(false, Name.create("example.CoM").eql?(Name.create("example.com.")))
|
21
|
+
assert_equal(false, Name.create("example.CoM") == Name.create("example.com."))
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_name_CoMparisons
|
25
|
+
|
26
|
+
assert_equal(true, Name.create("example.CoM").eql?(Name.create("example.com")))
|
27
|
+
assert_equal(true, Name.create("example.CoM") == Name.create("example.com"))
|
28
|
+
|
29
|
+
assert_equal(true, Name.create("example.CoM").equal?("example.com."))
|
30
|
+
assert_equal(true, Name.create("example.CoM").equal?("example.com"))
|
31
|
+
|
32
|
+
assert_equal(true, Name.create("www.example.CoM") < "example.com")
|
33
|
+
assert_equal(true, Name.create("www.example.CoM") <= "example.com")
|
34
|
+
assert_equal(-1, Name.create("www.example.CoM") <=> "example.com")
|
35
|
+
assert_equal(false, Name.create("www.example.CoM") >= "example.com")
|
36
|
+
assert_equal(false, Name.create("www.example.CoM") > "example.com")
|
37
|
+
|
38
|
+
assert_equal(false, Name.create("example.CoM") < "example.com")
|
39
|
+
assert_equal(true, Name.create("example.CoM") <= "example.com")
|
40
|
+
assert_equal(0, Name.create("example.CoM") <=> "example.com")
|
41
|
+
assert_equal(true, Name.create("example.CoM") >= "example.com")
|
42
|
+
assert_equal(false, Name.create("example.CoM") > "example.com")
|
43
|
+
|
44
|
+
assert_equal(false, Name.create("CoM") < "example.com")
|
45
|
+
assert_equal(false, Name.create("CoM") <= "example.com")
|
46
|
+
assert_equal(+1, Name.create("CoM") <=> "example.com")
|
47
|
+
assert_equal(true, Name.create("CoM") >= "example.com")
|
48
|
+
assert_equal(true, Name.create("CoM") > "example.com")
|
49
|
+
|
50
|
+
assert_equal(nil, Name.create("bar.CoM") < "example.com")
|
51
|
+
assert_equal(nil, Name.create("bar.CoM") <= "example.com")
|
52
|
+
assert_equal(nil, Name.create("bar.CoM") <=> "example.com")
|
53
|
+
assert_equal(nil, Name.create("bar.CoM") >= "example.com")
|
54
|
+
assert_equal(nil, Name.create("bar.CoM") > "example.com")
|
55
|
+
|
56
|
+
assert_equal(nil, Name.create("net.") < "com")
|
57
|
+
assert_equal(nil, Name.create("net.") <= "com")
|
58
|
+
assert_equal(nil, Name.create("net.") <=> "com")
|
59
|
+
assert_equal(nil, Name.create("net.") >= "com")
|
60
|
+
assert_equal(nil, Name.create("net.") > "com")
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_txt_with_0_strs
|
65
|
+
# Packet collected from the wild, it is non-conformant with DNS
|
66
|
+
# specification, TXT record has zero strings, but should have 1 or more.
|
67
|
+
d = "\000\000\204\000\000\000\000\005\000\000\000\000\002me\005local\000\000\001\200\001\000\000\000\360\000\004\300\250\003\003\005proxy\010_example\004_tcp\300\017\000!\200\001\000\000\000\360\000\010\000\000\000\000'\017\300\f\300$\000\020\200\001\000\000\000\360\000\000\t_services\a_dns-sd\004_udp\300\017\000\f\000\001\000\000\034 \000\002\300*\300*\000\f\000\001\000\000\034 \000\002\300$"
|
68
|
+
|
69
|
+
m = Resolv::DNS::Message.decode( d )
|
70
|
+
|
71
|
+
assert_equal('', m.answer[2][2].data)
|
72
|
+
assert_equal([''], m.answer[2][2].strings)
|
73
|
+
end
|
74
|
+
|
75
|
+
def txt_codec(*args)
|
76
|
+
m = Resolv::DNS::Message.new
|
77
|
+
m.add_answer('example.local', 0, Resolv::DNS::Resource::IN::TXT.new(*args))
|
78
|
+
# pp m
|
79
|
+
m = Resolv::DNS::Message.decode(m.encode)
|
80
|
+
txt = m.answer[0][2]
|
81
|
+
# pp txt
|
82
|
+
txt
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_txt_with_large_str
|
86
|
+
# short or no strings
|
87
|
+
txt = txt_codec()
|
88
|
+
assert_equal('', txt.data)
|
89
|
+
assert_equal([''], txt.strings)
|
90
|
+
|
91
|
+
txt = txt_codec('')
|
92
|
+
assert_equal('', txt.data)
|
93
|
+
assert_equal([''], txt.strings)
|
94
|
+
|
95
|
+
txt = txt_codec('s')
|
96
|
+
assert_equal('s', txt.data)
|
97
|
+
assert_equal(['s'], txt.strings)
|
98
|
+
|
99
|
+
txt = txt_codec('s', 'a', 'm')
|
100
|
+
assert_equal('sam', txt.data)
|
101
|
+
assert_equal(['s', 'a', 'm'], txt.strings)
|
102
|
+
|
103
|
+
s = '0' * 255
|
104
|
+
|
105
|
+
# long strings
|
106
|
+
txt = txt_codec(s)
|
107
|
+
assert_equal(s, txt.data)
|
108
|
+
assert_equal([s], txt.strings)
|
109
|
+
|
110
|
+
# long strings
|
111
|
+
f = s + 'a'
|
112
|
+
txt = txt_codec(f)
|
113
|
+
assert_equal(f, txt.data)
|
114
|
+
assert_equal([s, 'a'], txt.strings)
|
115
|
+
|
116
|
+
f = s + s
|
117
|
+
txt = txt_codec(f)
|
118
|
+
assert_equal(f, txt.data)
|
119
|
+
assert_equal([s, s], txt.strings)
|
120
|
+
|
121
|
+
assert_raise(ArgumentError) { txt_codec(f, 'a') }
|
122
|
+
assert_raise(ArgumentError) { txt_codec('a', f) }
|
123
|
+
|
124
|
+
end
|
125
|
+
|
126
|
+
|
127
|
+
end
|
128
|
+
|
data/samples/v1demo.rb
ADDED
@@ -0,0 +1,167 @@
|
|
1
|
+
#!/usr/local/bin/ruby18 -w
|
2
|
+
#
|
3
|
+
# Example code to use the multicast library
|
4
|
+
# (c) 2005 Ben Giddings
|
5
|
+
# License: Ruby's License
|
6
|
+
|
7
|
+
# Include local dir
|
8
|
+
$: << File.dirname($0)
|
9
|
+
|
10
|
+
require 'net/dns/resolv-mdns'
|
11
|
+
require 'pp'
|
12
|
+
|
13
|
+
# default to browsing
|
14
|
+
operation = ARGV[0] || 'browse'
|
15
|
+
|
16
|
+
resolver = Resolv::MDNS.new
|
17
|
+
resolver.lazy_initialize
|
18
|
+
|
19
|
+
def usage
|
20
|
+
$stderr.puts <<-EOF
|
21
|
+
Usage: #{$0} [browse|discover|resolve|lookup] [service_str]
|
22
|
+
|
23
|
+
Use "browse" to find names offering the service requested.
|
24
|
+
|
25
|
+
Examples:
|
26
|
+
zsh% #{$0} browse
|
27
|
+
Searching for _http._tcp.local services
|
28
|
+
Matching entries in _http._tcp.local
|
29
|
+
Cool Webserver
|
30
|
+
|
31
|
+
zsh% #{$0} browse http
|
32
|
+
Searching for _http._tcp.local services
|
33
|
+
Matching entries in _http._tcp.local
|
34
|
+
Cool Webserver
|
35
|
+
|
36
|
+
zsh% #{$0} browse _http._tcp.local
|
37
|
+
Searching for _http._tcp.local services
|
38
|
+
Matching entries in _http._tcp.local
|
39
|
+
Cool Webserver
|
40
|
+
|
41
|
+
zsh% #{$0} browse _telnet._tcp.local
|
42
|
+
Searching for _telnet._tcp.local services
|
43
|
+
Matching entries in _telnet._tcp.local
|
44
|
+
Embedded Device (MAC addr: 00:01:02:03:04:05)
|
45
|
+
|
46
|
+
By default 'browse' looks for _http._tcp.local services/
|
47
|
+
If the only parameter supplied is a protocol, it looks for
|
48
|
+
local tcp services of that protocol
|
49
|
+
|
50
|
+
Use "resolve" to look up the dns name, port and ip address of a device
|
51
|
+
|
52
|
+
zsh% #{$0} resolve 'Cool Webserver'
|
53
|
+
Searching for Cool Webserver._http._tcp.local instance
|
54
|
+
Cool Webserver._http._tcp.local is
|
55
|
+
coolweb.local:80 at IP 192.168.0.12
|
56
|
+
|
57
|
+
zsh% #{$0} resolve 'Cool Webserver._http._tcp.local'
|
58
|
+
Searching for Cool Webserver._http._tcp.local instance
|
59
|
+
Cool Webserver._http._tcp.local is
|
60
|
+
coolweb.local:80 at IP 192.168.0.12
|
61
|
+
|
62
|
+
zsh% #{$0} resolve 'Embedded Device (MAC addr: 00:01:02:03:04:05)._telnet._tcp.local'
|
63
|
+
Searching for Embedded Device (MAC addr: 00:01:02:03:04:05)._telnet._tcp.local instance
|
64
|
+
Embedded Device (MAC addr: 00:01:02:03:04:05)._telnet._tcp.local is
|
65
|
+
emb000102030405.local:23 at IP 192.168.0.93
|
66
|
+
|
67
|
+
By default 'resolve' will append _http._tcp.local if it is missing
|
68
|
+
|
69
|
+
EOF
|
70
|
+
end
|
71
|
+
|
72
|
+
case (operation.downcase)
|
73
|
+
when 'browse', 'discover'
|
74
|
+
#
|
75
|
+
# To browse / discover services, use a ptr lookup on the service protocol
|
76
|
+
# A typical call might be
|
77
|
+
# resolver.getresources('_http._tcp.local', Resolv::DNS::Resource::IN::PTR)
|
78
|
+
#
|
79
|
+
|
80
|
+
# default to browsing for http hosts
|
81
|
+
service_str = ARGV[1] || 'http'
|
82
|
+
|
83
|
+
# prepend an underscore if necessary
|
84
|
+
# p service_str
|
85
|
+
|
86
|
+
if ?_ != service_str[0]
|
87
|
+
puts "prepending underscore to #{service_str}"
|
88
|
+
service_str = '_' + service_str
|
89
|
+
end
|
90
|
+
|
91
|
+
# append a ._tcp.local if necessary (assume tcp and local)
|
92
|
+
if service_str.index('.').nil?
|
93
|
+
puts "No dot found in service name, appending ._tcp.local"
|
94
|
+
service_str += '._tcp.local'
|
95
|
+
end
|
96
|
+
|
97
|
+
puts "Searching for #{service_str} services"
|
98
|
+
|
99
|
+
entries = resolver.getresources(service_str, Resolv::DNS::Resource::IN::PTR)
|
100
|
+
|
101
|
+
# p entries
|
102
|
+
|
103
|
+
puts "Matching entries in #{service_str}"
|
104
|
+
entries.each {
|
105
|
+
|entry|
|
106
|
+
# p entry
|
107
|
+
# I think this will always match but just in case...
|
108
|
+
friendly_name_regexp = /(.*?)\.#{service_str}/
|
109
|
+
|
110
|
+
match = friendly_name_regexp.match(entry.name.to_s)
|
111
|
+
if match
|
112
|
+
puts match[1]
|
113
|
+
else
|
114
|
+
puts entry.name
|
115
|
+
end
|
116
|
+
}
|
117
|
+
when 'resolve', 'lookup'
|
118
|
+
#
|
119
|
+
# To resolve / lookup services, first use a SRV lookup to lookup the service
|
120
|
+
# details, then extract the hostname from the result. Using this hostname,
|
121
|
+
# lookup the A record to find the IP address.
|
122
|
+
#
|
123
|
+
|
124
|
+
service_str = ARGV[1]
|
125
|
+
if service_str.nil?
|
126
|
+
$stderr.puts("Service string required for resolve / lookup")
|
127
|
+
usage()
|
128
|
+
exit(1)
|
129
|
+
end
|
130
|
+
|
131
|
+
# append a ._http._tcp.local if necessary (assume http, tcp and local)
|
132
|
+
if service_str.index('.').nil?
|
133
|
+
puts "No dot found in service name, appending ._http._tcp.local"
|
134
|
+
service_str += '._http._tcp.local'
|
135
|
+
|
136
|
+
end
|
137
|
+
|
138
|
+
puts "Searching for #{service_str} instance"
|
139
|
+
entries = resolver.getresources(service_str, Resolv::DNS::Resource::IN::SRV)
|
140
|
+
|
141
|
+
if 0 == entries.size
|
142
|
+
puts "Unable to find #{service_str}"
|
143
|
+
exit(0)
|
144
|
+
end
|
145
|
+
|
146
|
+
entry = entries[0]
|
147
|
+
# puts "Found match at #{entry.target}, port #{entry.port}"
|
148
|
+
|
149
|
+
hostname = entry.target
|
150
|
+
port = entry.port
|
151
|
+
entries = resolver.getresources(hostname, Resolv::DNS::Resource::IN::A)
|
152
|
+
|
153
|
+
if 0 == entries.size
|
154
|
+
puts "Unable to resolve #{hostname}"
|
155
|
+
exit(1)
|
156
|
+
end
|
157
|
+
|
158
|
+
entry = entries[0]
|
159
|
+
# p entry
|
160
|
+
# p entry.address
|
161
|
+
puts "#{service_str} is\n#{hostname}:#{port} at IP #{entry.address.to_s}"
|
162
|
+
|
163
|
+
else
|
164
|
+
$stderr.puts("unknown operation #{operation.inspect}")
|
165
|
+
usage()
|
166
|
+
exit(1)
|
167
|
+
end
|