ruby_on_ruby 0.0.1
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/.gitignore +18 -0
- data/.rvmrc +1 -0
- data/Gemfile +6 -0
- data/LICENSE +22 -0
- data/README.md +66 -0
- data/Rakefile +1 -0
- data/lib/ruby_on_ruby.rb +5 -0
- data/lib/ruby_on_ruby/console.rb +7 -0
- data/lib/ruby_on_ruby/context.rb +33 -0
- data/lib/ruby_on_ruby/file_loader.rb +31 -0
- data/lib/ruby_on_ruby/ruby_stream.rb +27 -0
- data/lib/ruby_on_ruby/version.rb +3 -0
- data/lib/rubyonruby.rb +1 -0
- data/ruby_in_ruby.gemspec +19 -0
- data/vendor/javascripts/emscripted-ruby/lib/.document +106 -0
- data/vendor/javascripts/emscripted-ruby/lib/English.rb +155 -0
- data/vendor/javascripts/emscripted-ruby/lib/Env.rb +18 -0
- data/vendor/javascripts/emscripted-ruby/lib/README +96 -0
- data/vendor/javascripts/emscripted-ruby/lib/abbrev.rb +103 -0
- data/vendor/javascripts/emscripted-ruby/lib/base64.rb +133 -0
- data/vendor/javascripts/emscripted-ruby/lib/benchmark.rb +572 -0
- data/vendor/javascripts/emscripted-ruby/lib/cgi-lib.rb +272 -0
- data/vendor/javascripts/emscripted-ruby/lib/cgi.rb +2308 -0
- data/vendor/javascripts/emscripted-ruby/lib/cgi/.document +2 -0
- data/vendor/javascripts/emscripted-ruby/lib/cgi/session.rb +498 -0
- data/vendor/javascripts/emscripted-ruby/lib/cgi/session/pstore.rb +111 -0
- data/vendor/javascripts/emscripted-ruby/lib/complex.rb +663 -0
- data/vendor/javascripts/emscripted-ruby/lib/csv.rb +992 -0
- data/vendor/javascripts/emscripted-ruby/lib/date.rb +1767 -0
- data/vendor/javascripts/emscripted-ruby/lib/date/format.rb +1190 -0
- data/vendor/javascripts/emscripted-ruby/lib/date2.rb +5 -0
- data/vendor/javascripts/emscripted-ruby/lib/debug.rb +947 -0
- data/vendor/javascripts/emscripted-ruby/lib/delegate.rb +337 -0
- data/vendor/javascripts/emscripted-ruby/lib/drb.rb +2 -0
- data/vendor/javascripts/emscripted-ruby/lib/drb/acl.rb +146 -0
- data/vendor/javascripts/emscripted-ruby/lib/drb/drb.rb +1782 -0
- data/vendor/javascripts/emscripted-ruby/lib/drb/eq.rb +16 -0
- data/vendor/javascripts/emscripted-ruby/lib/drb/extserv.rb +64 -0
- data/vendor/javascripts/emscripted-ruby/lib/drb/extservm.rb +89 -0
- data/vendor/javascripts/emscripted-ruby/lib/drb/gw.rb +122 -0
- data/vendor/javascripts/emscripted-ruby/lib/drb/invokemethod.rb +36 -0
- data/vendor/javascripts/emscripted-ruby/lib/drb/observer.rb +22 -0
- data/vendor/javascripts/emscripted-ruby/lib/drb/ssl.rb +190 -0
- data/vendor/javascripts/emscripted-ruby/lib/drb/timeridconv.rb +91 -0
- data/vendor/javascripts/emscripted-ruby/lib/drb/unix.rb +108 -0
- data/vendor/javascripts/emscripted-ruby/lib/e2mmap.rb +195 -0
- data/vendor/javascripts/emscripted-ruby/lib/erb.rb +880 -0
- data/vendor/javascripts/emscripted-ruby/lib/eregex.rb +37 -0
- data/vendor/javascripts/emscripted-ruby/lib/fileutils.rb +1591 -0
- data/vendor/javascripts/emscripted-ruby/lib/finalize.rb +193 -0
- data/vendor/javascripts/emscripted-ruby/lib/find.rb +79 -0
- data/vendor/javascripts/emscripted-ruby/lib/forwardable.rb +218 -0
- data/vendor/javascripts/emscripted-ruby/lib/ftools.rb +261 -0
- data/vendor/javascripts/emscripted-ruby/lib/generator.rb +418 -0
- data/vendor/javascripts/emscripted-ruby/lib/getoptlong.rb +621 -0
- data/vendor/javascripts/emscripted-ruby/lib/getopts.rb +127 -0
- data/vendor/javascripts/emscripted-ruby/lib/gserver.rb +253 -0
- data/vendor/javascripts/emscripted-ruby/lib/importenv.rb +33 -0
- data/vendor/javascripts/emscripted-ruby/lib/ipaddr.rb +814 -0
- data/vendor/javascripts/emscripted-ruby/lib/irb.rb +346 -0
- data/vendor/javascripts/emscripted-ruby/lib/irb/cmd/chws.rb +33 -0
- data/vendor/javascripts/emscripted-ruby/lib/irb/cmd/fork.rb +39 -0
- data/vendor/javascripts/emscripted-ruby/lib/irb/cmd/help.rb +34 -0
- data/vendor/javascripts/emscripted-ruby/lib/irb/cmd/load.rb +67 -0
- data/vendor/javascripts/emscripted-ruby/lib/irb/cmd/nop.rb +39 -0
- data/vendor/javascripts/emscripted-ruby/lib/irb/cmd/pushws.rb +39 -0
- data/vendor/javascripts/emscripted-ruby/lib/irb/cmd/subirb.rb +43 -0
- data/vendor/javascripts/emscripted-ruby/lib/irb/completion.rb +205 -0
- data/vendor/javascripts/emscripted-ruby/lib/irb/context.rb +255 -0
- data/vendor/javascripts/emscripted-ruby/lib/irb/ext/change-ws.rb +62 -0
- data/vendor/javascripts/emscripted-ruby/lib/irb/ext/history.rb +110 -0
- data/vendor/javascripts/emscripted-ruby/lib/irb/ext/loader.rb +120 -0
- data/vendor/javascripts/emscripted-ruby/lib/irb/ext/math-mode.rb +37 -0
- data/vendor/javascripts/emscripted-ruby/lib/irb/ext/multi-irb.rb +241 -0
- data/vendor/javascripts/emscripted-ruby/lib/irb/ext/save-history.rb +85 -0
- data/vendor/javascripts/emscripted-ruby/lib/irb/ext/tracer.rb +61 -0
- data/vendor/javascripts/emscripted-ruby/lib/irb/ext/use-loader.rb +65 -0
- data/vendor/javascripts/emscripted-ruby/lib/irb/ext/workspaces.rb +56 -0
- data/vendor/javascripts/emscripted-ruby/lib/irb/extend-command.rb +264 -0
- data/vendor/javascripts/emscripted-ruby/lib/irb/frame.rb +67 -0
- data/vendor/javascripts/emscripted-ruby/lib/irb/help.rb +33 -0
- data/vendor/javascripts/emscripted-ruby/lib/irb/init.rb +259 -0
- data/vendor/javascripts/emscripted-ruby/lib/irb/input-method.rb +120 -0
- data/vendor/javascripts/emscripted-ruby/lib/irb/lc/error.rb +30 -0
- data/vendor/javascripts/emscripted-ruby/lib/irb/lc/help-message +35 -0
- data/vendor/javascripts/emscripted-ruby/lib/irb/lc/ja/error.rb +27 -0
- data/vendor/javascripts/emscripted-ruby/lib/irb/lc/ja/help-message +36 -0
- data/vendor/javascripts/emscripted-ruby/lib/irb/locale.rb +184 -0
- data/vendor/javascripts/emscripted-ruby/lib/irb/notifier.rb +145 -0
- data/vendor/javascripts/emscripted-ruby/lib/irb/output-method.rb +85 -0
- data/vendor/javascripts/emscripted-ruby/lib/irb/ruby-lex.rb +1149 -0
- data/vendor/javascripts/emscripted-ruby/lib/irb/ruby-token.rb +273 -0
- data/vendor/javascripts/emscripted-ruby/lib/irb/slex.rb +285 -0
- data/vendor/javascripts/emscripted-ruby/lib/irb/version.rb +16 -0
- data/vendor/javascripts/emscripted-ruby/lib/irb/workspace.rb +107 -0
- data/vendor/javascripts/emscripted-ruby/lib/irb/ws-for-case-2.rb +15 -0
- data/vendor/javascripts/emscripted-ruby/lib/irb/xmp.rb +86 -0
- data/vendor/javascripts/emscripted-ruby/lib/jcode.rb +220 -0
- data/vendor/javascripts/emscripted-ruby/lib/logger.rb +703 -0
- data/vendor/javascripts/emscripted-ruby/lib/mailread.rb +62 -0
- data/vendor/javascripts/emscripted-ruby/lib/mathn.rb +308 -0
- data/vendor/javascripts/emscripted-ruby/lib/matrix.rb +1278 -0
- data/vendor/javascripts/emscripted-ruby/lib/mkmf.rb +1811 -0
- data/vendor/javascripts/emscripted-ruby/lib/monitor.rb +352 -0
- data/vendor/javascripts/emscripted-ruby/lib/mutex_m.rb +122 -0
- data/vendor/javascripts/emscripted-ruby/lib/net/ftp.rb +927 -0
- data/vendor/javascripts/emscripted-ruby/lib/net/http.rb +2277 -0
- data/vendor/javascripts/emscripted-ruby/lib/net/https.rb +173 -0
- data/vendor/javascripts/emscripted-ruby/lib/net/imap.rb +3371 -0
- data/vendor/javascripts/emscripted-ruby/lib/net/pop.rb +999 -0
- data/vendor/javascripts/emscripted-ruby/lib/net/protocol.rb +392 -0
- data/vendor/javascripts/emscripted-ruby/lib/net/smtp.rb +1014 -0
- data/vendor/javascripts/emscripted-ruby/lib/net/telnet.rb +756 -0
- data/vendor/javascripts/emscripted-ruby/lib/observer.rb +192 -0
- data/vendor/javascripts/emscripted-ruby/lib/open-uri.rb +678 -0
- data/vendor/javascripts/emscripted-ruby/lib/open3.rb +101 -0
- data/vendor/javascripts/emscripted-ruby/lib/optparse.rb +1790 -0
- data/vendor/javascripts/emscripted-ruby/lib/optparse/date.rb +17 -0
- data/vendor/javascripts/emscripted-ruby/lib/optparse/shellwords.rb +6 -0
- data/vendor/javascripts/emscripted-ruby/lib/optparse/time.rb +10 -0
- data/vendor/javascripts/emscripted-ruby/lib/optparse/uri.rb +6 -0
- data/vendor/javascripts/emscripted-ruby/lib/optparse/version.rb +70 -0
- data/vendor/javascripts/emscripted-ruby/lib/ostruct.rb +146 -0
- data/vendor/javascripts/emscripted-ruby/lib/parsearg.rb +87 -0
- data/vendor/javascripts/emscripted-ruby/lib/parsedate.rb +53 -0
- data/vendor/javascripts/emscripted-ruby/lib/pathname.rb +1062 -0
- data/vendor/javascripts/emscripted-ruby/lib/ping.rb +64 -0
- data/vendor/javascripts/emscripted-ruby/lib/pp.rb +654 -0
- data/vendor/javascripts/emscripted-ruby/lib/prettyprint.rb +896 -0
- data/vendor/javascripts/emscripted-ruby/lib/profile.rb +6 -0
- data/vendor/javascripts/emscripted-ruby/lib/profiler.rb +59 -0
- data/vendor/javascripts/emscripted-ruby/lib/pstore.rb +395 -0
- data/vendor/javascripts/emscripted-ruby/lib/racc/parser.rb +442 -0
- data/vendor/javascripts/emscripted-ruby/lib/rational.rb +564 -0
- data/vendor/javascripts/emscripted-ruby/lib/readbytes.rb +41 -0
- data/vendor/javascripts/emscripted-ruby/lib/resolv-replace.rb +62 -0
- data/vendor/javascripts/emscripted-ruby/lib/resolv.rb +2210 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/attlistdecl.rb +62 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/attribute.rb +185 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/cdata.rb +67 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/child.rb +96 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/comment.rb +80 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/doctype.rb +271 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/document.rb +208 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/dtd/attlistdecl.rb +10 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/dtd/dtd.rb +51 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/dtd/elementdecl.rb +17 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/dtd/entitydecl.rb +56 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/dtd/notationdecl.rb +39 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/element.rb +1227 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/encoding.rb +71 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/encodings/CP-1252.rb +103 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/encodings/EUC-JP.rb +35 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/encodings/ICONV.rb +22 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/encodings/ISO-8859-1.rb +7 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/encodings/ISO-8859-15.rb +72 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/encodings/SHIFT-JIS.rb +37 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/encodings/SHIFT_JIS.rb +1 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/encodings/UNILE.rb +34 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/encodings/US-ASCII.rb +30 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/encodings/UTF-16.rb +35 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/encodings/UTF-8.rb +18 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/entity.rb +165 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/formatters/default.rb +109 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/formatters/pretty.rb +137 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/formatters/transitive.rb +56 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/functions.rb +382 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/instruction.rb +70 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/light/node.rb +196 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/namespace.rb +47 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/node.rb +75 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/output.rb +24 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/parent.rb +166 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/parseexception.rb +51 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/parsers/baseparser.rb +503 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/parsers/lightparser.rb +60 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/parsers/pullparser.rb +196 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/parsers/sax2parser.rb +238 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/parsers/streamparser.rb +46 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/parsers/treeparser.rb +97 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/parsers/ultralightparser.rb +56 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/parsers/xpathparser.rb +698 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/quickpath.rb +266 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/rexml.rb +32 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/sax2listener.rb +97 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/source.rb +251 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/streamlistener.rb +92 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/syncenumerator.rb +33 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/text.rb +344 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/undefinednamespaceexception.rb +8 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/validation/relaxng.rb +559 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/validation/validation.rb +155 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/validation/validationexception.rb +9 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/xmldecl.rb +119 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/xmltokens.rb +18 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/xpath.rb +66 -0
- data/vendor/javascripts/emscripted-ruby/lib/rexml/xpath_parser.rb +792 -0
- data/vendor/javascripts/emscripted-ruby/lib/rinda/rinda.rb +283 -0
- data/vendor/javascripts/emscripted-ruby/lib/rinda/ring.rb +271 -0
- data/vendor/javascripts/emscripted-ruby/lib/rinda/tuplespace.rb +642 -0
- data/vendor/javascripts/emscripted-ruby/lib/rss.rb +19 -0
- data/vendor/javascripts/emscripted-ruby/lib/rss/0.9.rb +428 -0
- data/vendor/javascripts/emscripted-ruby/lib/rss/1.0.rb +452 -0
- data/vendor/javascripts/emscripted-ruby/lib/rss/2.0.rb +111 -0
- data/vendor/javascripts/emscripted-ruby/lib/rss/atom.rb +749 -0
- data/vendor/javascripts/emscripted-ruby/lib/rss/content.rb +31 -0
- data/vendor/javascripts/emscripted-ruby/lib/rss/content/1.0.rb +10 -0
- data/vendor/javascripts/emscripted-ruby/lib/rss/content/2.0.rb +12 -0
- data/vendor/javascripts/emscripted-ruby/lib/rss/converter.rb +162 -0
- data/vendor/javascripts/emscripted-ruby/lib/rss/dublincore.rb +161 -0
- data/vendor/javascripts/emscripted-ruby/lib/rss/dublincore/1.0.rb +13 -0
- data/vendor/javascripts/emscripted-ruby/lib/rss/dublincore/2.0.rb +13 -0
- data/vendor/javascripts/emscripted-ruby/lib/rss/dublincore/atom.rb +17 -0
- data/vendor/javascripts/emscripted-ruby/lib/rss/image.rb +193 -0
- data/vendor/javascripts/emscripted-ruby/lib/rss/itunes.rb +410 -0
- data/vendor/javascripts/emscripted-ruby/lib/rss/maker.rb +44 -0
- data/vendor/javascripts/emscripted-ruby/lib/rss/maker/0.9.rb +467 -0
- data/vendor/javascripts/emscripted-ruby/lib/rss/maker/1.0.rb +434 -0
- data/vendor/javascripts/emscripted-ruby/lib/rss/maker/2.0.rb +223 -0
- data/vendor/javascripts/emscripted-ruby/lib/rss/maker/atom.rb +172 -0
- data/vendor/javascripts/emscripted-ruby/lib/rss/maker/base.rb +868 -0
- data/vendor/javascripts/emscripted-ruby/lib/rss/maker/content.rb +21 -0
- data/vendor/javascripts/emscripted-ruby/lib/rss/maker/dublincore.rb +124 -0
- data/vendor/javascripts/emscripted-ruby/lib/rss/maker/entry.rb +163 -0
- data/vendor/javascripts/emscripted-ruby/lib/rss/maker/feed.rb +429 -0
- data/vendor/javascripts/emscripted-ruby/lib/rss/maker/image.rb +111 -0
- data/vendor/javascripts/emscripted-ruby/lib/rss/maker/itunes.rb +242 -0
- data/vendor/javascripts/emscripted-ruby/lib/rss/maker/slash.rb +33 -0
- data/vendor/javascripts/emscripted-ruby/lib/rss/maker/syndication.rb +18 -0
- data/vendor/javascripts/emscripted-ruby/lib/rss/maker/taxonomy.rb +118 -0
- data/vendor/javascripts/emscripted-ruby/lib/rss/maker/trackback.rb +61 -0
- data/vendor/javascripts/emscripted-ruby/lib/rss/parser.rb +541 -0
- data/vendor/javascripts/emscripted-ruby/lib/rss/rexmlparser.rb +54 -0
- data/vendor/javascripts/emscripted-ruby/lib/rss/rss.rb +1312 -0
- data/vendor/javascripts/emscripted-ruby/lib/rss/slash.rb +49 -0
- data/vendor/javascripts/emscripted-ruby/lib/rss/syndication.rb +67 -0
- data/vendor/javascripts/emscripted-ruby/lib/rss/taxonomy.rb +145 -0
- data/vendor/javascripts/emscripted-ruby/lib/rss/trackback.rb +288 -0
- data/vendor/javascripts/emscripted-ruby/lib/rss/utils.rb +111 -0
- data/vendor/javascripts/emscripted-ruby/lib/rss/xml-stylesheet.rb +105 -0
- data/vendor/javascripts/emscripted-ruby/lib/rss/xml.rb +71 -0
- data/vendor/javascripts/emscripted-ruby/lib/rss/xmlparser.rb +93 -0
- data/vendor/javascripts/emscripted-ruby/lib/rss/xmlscanner.rb +121 -0
- data/vendor/javascripts/emscripted-ruby/lib/rubyunit.rb +6 -0
- data/vendor/javascripts/emscripted-ruby/lib/runit/assert.rb +73 -0
- data/vendor/javascripts/emscripted-ruby/lib/runit/cui/testrunner.rb +51 -0
- data/vendor/javascripts/emscripted-ruby/lib/runit/error.rb +9 -0
- data/vendor/javascripts/emscripted-ruby/lib/runit/testcase.rb +45 -0
- data/vendor/javascripts/emscripted-ruby/lib/runit/testresult.rb +44 -0
- data/vendor/javascripts/emscripted-ruby/lib/runit/testsuite.rb +26 -0
- data/vendor/javascripts/emscripted-ruby/lib/runit/topublic.rb +8 -0
- data/vendor/javascripts/emscripted-ruby/lib/scanf.rb +702 -0
- data/vendor/javascripts/emscripted-ruby/lib/securerandom.rb +137 -0
- data/vendor/javascripts/emscripted-ruby/lib/set.rb +1233 -0
- data/vendor/javascripts/emscripted-ruby/lib/shell.rb +269 -0
- data/vendor/javascripts/emscripted-ruby/lib/shell/builtin-command.rb +154 -0
- data/vendor/javascripts/emscripted-ruby/lib/shell/command-processor.rb +592 -0
- data/vendor/javascripts/emscripted-ruby/lib/shell/error.rb +26 -0
- data/vendor/javascripts/emscripted-ruby/lib/shell/filter.rb +110 -0
- data/vendor/javascripts/emscripted-ruby/lib/shell/process-controller.rb +260 -0
- data/vendor/javascripts/emscripted-ruby/lib/shell/system-command.rb +168 -0
- data/vendor/javascripts/emscripted-ruby/lib/shell/version.rb +16 -0
- data/vendor/javascripts/emscripted-ruby/lib/shellwords.rb +172 -0
- data/vendor/javascripts/emscripted-ruby/lib/singleton.rb +360 -0
- data/vendor/javascripts/emscripted-ruby/lib/soap/attachment.rb +107 -0
- data/vendor/javascripts/emscripted-ruby/lib/soap/baseData.rb +942 -0
- data/vendor/javascripts/emscripted-ruby/lib/soap/element.rb +258 -0
- data/vendor/javascripts/emscripted-ruby/lib/soap/encodingstyle/aspDotNetHandler.rb +213 -0
- data/vendor/javascripts/emscripted-ruby/lib/soap/encodingstyle/handler.rb +100 -0
- data/vendor/javascripts/emscripted-ruby/lib/soap/encodingstyle/literalHandler.rb +226 -0
- data/vendor/javascripts/emscripted-ruby/lib/soap/encodingstyle/soapHandler.rb +582 -0
- data/vendor/javascripts/emscripted-ruby/lib/soap/generator.rb +268 -0
- data/vendor/javascripts/emscripted-ruby/lib/soap/header/handler.rb +57 -0
- data/vendor/javascripts/emscripted-ruby/lib/soap/header/handlerset.rb +70 -0
- data/vendor/javascripts/emscripted-ruby/lib/soap/header/simplehandler.rb +44 -0
- data/vendor/javascripts/emscripted-ruby/lib/soap/httpconfigloader.rb +119 -0
- data/vendor/javascripts/emscripted-ruby/lib/soap/mapping.rb +10 -0
- data/vendor/javascripts/emscripted-ruby/lib/soap/mapping/factory.rb +355 -0
- data/vendor/javascripts/emscripted-ruby/lib/soap/mapping/mapping.rb +381 -0
- data/vendor/javascripts/emscripted-ruby/lib/soap/mapping/registry.rb +541 -0
- data/vendor/javascripts/emscripted-ruby/lib/soap/mapping/rubytypeFactory.rb +475 -0
- data/vendor/javascripts/emscripted-ruby/lib/soap/mapping/typeMap.rb +50 -0
- data/vendor/javascripts/emscripted-ruby/lib/soap/mapping/wsdlencodedregistry.rb +280 -0
- data/vendor/javascripts/emscripted-ruby/lib/soap/mapping/wsdlliteralregistry.rb +418 -0
- data/vendor/javascripts/emscripted-ruby/lib/soap/marshal.rb +59 -0
- data/vendor/javascripts/emscripted-ruby/lib/soap/mimemessage.rb +240 -0
- data/vendor/javascripts/emscripted-ruby/lib/soap/netHttpClient.rb +190 -0
- data/vendor/javascripts/emscripted-ruby/lib/soap/parser.rb +251 -0
- data/vendor/javascripts/emscripted-ruby/lib/soap/processor.rb +66 -0
- data/vendor/javascripts/emscripted-ruby/lib/soap/property.rb +333 -0
- data/vendor/javascripts/emscripted-ruby/lib/soap/rpc/cgistub.rb +206 -0
- data/vendor/javascripts/emscripted-ruby/lib/soap/rpc/driver.rb +254 -0
- data/vendor/javascripts/emscripted-ruby/lib/soap/rpc/element.rb +325 -0
- data/vendor/javascripts/emscripted-ruby/lib/soap/rpc/httpserver.rb +129 -0
- data/vendor/javascripts/emscripted-ruby/lib/soap/rpc/proxy.rb +497 -0
- data/vendor/javascripts/emscripted-ruby/lib/soap/rpc/router.rb +594 -0
- data/vendor/javascripts/emscripted-ruby/lib/soap/rpc/rpc.rb +25 -0
- data/vendor/javascripts/emscripted-ruby/lib/soap/rpc/soaplet.rb +162 -0
- data/vendor/javascripts/emscripted-ruby/lib/soap/rpc/standaloneServer.rb +43 -0
- data/vendor/javascripts/emscripted-ruby/lib/soap/soap.rb +140 -0
- data/vendor/javascripts/emscripted-ruby/lib/soap/streamHandler.rb +229 -0
- data/vendor/javascripts/emscripted-ruby/lib/soap/wsdlDriver.rb +575 -0
- data/vendor/javascripts/emscripted-ruby/lib/sync.rb +311 -0
- data/vendor/javascripts/emscripted-ruby/lib/tempfile.rb +209 -0
- data/vendor/javascripts/emscripted-ruby/lib/test/unit.rb +280 -0
- data/vendor/javascripts/emscripted-ruby/lib/test/unit/assertionfailederror.rb +14 -0
- data/vendor/javascripts/emscripted-ruby/lib/test/unit/assertions.rb +622 -0
- data/vendor/javascripts/emscripted-ruby/lib/test/unit/autorunner.rb +220 -0
- data/vendor/javascripts/emscripted-ruby/lib/test/unit/collector.rb +43 -0
- data/vendor/javascripts/emscripted-ruby/lib/test/unit/collector/dir.rb +107 -0
- data/vendor/javascripts/emscripted-ruby/lib/test/unit/collector/objectspace.rb +34 -0
- data/vendor/javascripts/emscripted-ruby/lib/test/unit/error.rb +56 -0
- data/vendor/javascripts/emscripted-ruby/lib/test/unit/failure.rb +51 -0
- data/vendor/javascripts/emscripted-ruby/lib/test/unit/testcase.rb +160 -0
- data/vendor/javascripts/emscripted-ruby/lib/test/unit/testresult.rb +80 -0
- data/vendor/javascripts/emscripted-ruby/lib/test/unit/testsuite.rb +76 -0
- data/vendor/javascripts/emscripted-ruby/lib/test/unit/ui/console/testrunner.rb +127 -0
- data/vendor/javascripts/emscripted-ruby/lib/test/unit/ui/fox/testrunner.rb +268 -0
- data/vendor/javascripts/emscripted-ruby/lib/test/unit/ui/gtk/testrunner.rb +416 -0
- data/vendor/javascripts/emscripted-ruby/lib/test/unit/ui/gtk2/testrunner.rb +465 -0
- data/vendor/javascripts/emscripted-ruby/lib/test/unit/ui/testrunnermediator.rb +68 -0
- data/vendor/javascripts/emscripted-ruby/lib/test/unit/ui/testrunnerutilities.rb +46 -0
- data/vendor/javascripts/emscripted-ruby/lib/test/unit/ui/tk/testrunner.rb +260 -0
- data/vendor/javascripts/emscripted-ruby/lib/test/unit/util/backtracefilter.rb +40 -0
- data/vendor/javascripts/emscripted-ruby/lib/test/unit/util/observable.rb +90 -0
- data/vendor/javascripts/emscripted-ruby/lib/test/unit/util/procwrapper.rb +48 -0
- data/vendor/javascripts/emscripted-ruby/lib/thread.rb +479 -0
- data/vendor/javascripts/emscripted-ruby/lib/thwait.rb +169 -0
- data/vendor/javascripts/emscripted-ruby/lib/time.rb +797 -0
- data/vendor/javascripts/emscripted-ruby/lib/timeout.rb +122 -0
- data/vendor/javascripts/emscripted-ruby/lib/tmpdir.rb +130 -0
- data/vendor/javascripts/emscripted-ruby/lib/tracer.rb +167 -0
- data/vendor/javascripts/emscripted-ruby/lib/tsort.rb +290 -0
- data/vendor/javascripts/emscripted-ruby/lib/un.rb +235 -0
- data/vendor/javascripts/emscripted-ruby/lib/uri.rb +29 -0
- data/vendor/javascripts/emscripted-ruby/lib/uri/common.rb +611 -0
- data/vendor/javascripts/emscripted-ruby/lib/uri/ftp.rb +198 -0
- data/vendor/javascripts/emscripted-ruby/lib/uri/generic.rb +1122 -0
- data/vendor/javascripts/emscripted-ruby/lib/uri/http.rb +100 -0
- data/vendor/javascripts/emscripted-ruby/lib/uri/https.rb +20 -0
- data/vendor/javascripts/emscripted-ruby/lib/uri/ldap.rb +190 -0
- data/vendor/javascripts/emscripted-ruby/lib/uri/ldaps.rb +12 -0
- data/vendor/javascripts/emscripted-ruby/lib/uri/mailto.rb +266 -0
- data/vendor/javascripts/emscripted-ruby/lib/weakref.rb +100 -0
- data/vendor/javascripts/emscripted-ruby/lib/webrick.rb +29 -0
- data/vendor/javascripts/emscripted-ruby/lib/webrick/accesslog.rb +67 -0
- data/vendor/javascripts/emscripted-ruby/lib/webrick/cgi.rb +257 -0
- data/vendor/javascripts/emscripted-ruby/lib/webrick/compat.rb +15 -0
- data/vendor/javascripts/emscripted-ruby/lib/webrick/config.rb +97 -0
- data/vendor/javascripts/emscripted-ruby/lib/webrick/cookie.rb +110 -0
- data/vendor/javascripts/emscripted-ruby/lib/webrick/htmlutils.rb +25 -0
- data/vendor/javascripts/emscripted-ruby/lib/webrick/httpauth.rb +45 -0
- data/vendor/javascripts/emscripted-ruby/lib/webrick/httpauth/authenticator.rb +79 -0
- data/vendor/javascripts/emscripted-ruby/lib/webrick/httpauth/basicauth.rb +65 -0
- data/vendor/javascripts/emscripted-ruby/lib/webrick/httpauth/digestauth.rb +343 -0
- data/vendor/javascripts/emscripted-ruby/lib/webrick/httpauth/htdigest.rb +91 -0
- data/vendor/javascripts/emscripted-ruby/lib/webrick/httpauth/htgroup.rb +61 -0
- data/vendor/javascripts/emscripted-ruby/lib/webrick/httpauth/htpasswd.rb +83 -0
- data/vendor/javascripts/emscripted-ruby/lib/webrick/httpauth/userdb.rb +29 -0
- data/vendor/javascripts/emscripted-ruby/lib/webrick/httpproxy.rb +254 -0
- data/vendor/javascripts/emscripted-ruby/lib/webrick/httprequest.rb +365 -0
- data/vendor/javascripts/emscripted-ruby/lib/webrick/httpresponse.rb +327 -0
- data/vendor/javascripts/emscripted-ruby/lib/webrick/https.rb +63 -0
- data/vendor/javascripts/emscripted-ruby/lib/webrick/httpserver.rb +210 -0
- data/vendor/javascripts/emscripted-ruby/lib/webrick/httpservlet.rb +22 -0
- data/vendor/javascripts/emscripted-ruby/lib/webrick/httpservlet/abstract.rb +71 -0
- data/vendor/javascripts/emscripted-ruby/lib/webrick/httpservlet/cgi_runner.rb +47 -0
- data/vendor/javascripts/emscripted-ruby/lib/webrick/httpservlet/cgihandler.rb +108 -0
- data/vendor/javascripts/emscripted-ruby/lib/webrick/httpservlet/erbhandler.rb +54 -0
- data/vendor/javascripts/emscripted-ruby/lib/webrick/httpservlet/filehandler.rb +435 -0
- data/vendor/javascripts/emscripted-ruby/lib/webrick/httpservlet/prochandler.rb +33 -0
- data/vendor/javascripts/emscripted-ruby/lib/webrick/httpstatus.rb +126 -0
- data/vendor/javascripts/emscripted-ruby/lib/webrick/httputils.rb +399 -0
- data/vendor/javascripts/emscripted-ruby/lib/webrick/httpversion.rb +49 -0
- data/vendor/javascripts/emscripted-ruby/lib/webrick/log.rb +88 -0
- data/vendor/javascripts/emscripted-ruby/lib/webrick/server.rb +200 -0
- data/vendor/javascripts/emscripted-ruby/lib/webrick/ssl.rb +126 -0
- data/vendor/javascripts/emscripted-ruby/lib/webrick/utils.rb +100 -0
- data/vendor/javascripts/emscripted-ruby/lib/webrick/version.rb +13 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/binding.rb +65 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/data.rb +64 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/definitions.rb +250 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/documentation.rb +32 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/import.rb +80 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/importer.rb +38 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/info.rb +39 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/message.rb +54 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/operation.rb +130 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/operationBinding.rb +108 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/param.rb +85 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/parser.rb +163 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/part.rb +52 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/port.rb +84 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/portType.rb +73 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/service.rb +61 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/soap/address.rb +40 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/soap/binding.rb +49 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/soap/body.rb +56 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/soap/cgiStubCreator.rb +76 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/soap/classDefCreator.rb +314 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/soap/classDefCreatorSupport.rb +126 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/soap/clientSkeltonCreator.rb +78 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/soap/complexType.rb +161 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/soap/data.rb +42 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/soap/definitions.rb +149 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/soap/driverCreator.rb +95 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/soap/element.rb +28 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/soap/fault.rb +56 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/soap/header.rb +86 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/soap/headerfault.rb +56 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/soap/mappingRegistryCreator.rb +92 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/soap/methodDefCreator.rb +228 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/soap/operation.rb +122 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/soap/servantSkeltonCreator.rb +67 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/soap/standaloneServerStubCreator.rb +85 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/soap/wsdl2ruby.rb +176 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/types.rb +43 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/wsdl.rb +23 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/all.rb +69 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/annotation.rb +34 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/any.rb +56 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/attribute.rb +127 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/choice.rb +69 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/complexContent.rb +92 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/complexType.rb +139 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/content.rb +96 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/data.rb +80 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/element.rb +154 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/enumeration.rb +36 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/import.rb +65 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/importer.rb +87 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/include.rb +54 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/length.rb +35 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/parser.rb +166 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/pattern.rb +36 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/schema.rb +143 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/sequence.rb +69 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/simpleContent.rb +65 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/simpleExtension.rb +54 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/simpleRestriction.rb +73 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/simpleType.rb +73 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/unique.rb +34 -0
- data/vendor/javascripts/emscripted-ruby/lib/wsdl/xmlSchema/xsd2ruby.rb +107 -0
- data/vendor/javascripts/emscripted-ruby/lib/xmlrpc/.document +1 -0
- data/vendor/javascripts/emscripted-ruby/lib/xmlrpc/README.txt +31 -0
- data/vendor/javascripts/emscripted-ruby/lib/xmlrpc/base64.rb +81 -0
- data/vendor/javascripts/emscripted-ruby/lib/xmlrpc/client.rb +624 -0
- data/vendor/javascripts/emscripted-ruby/lib/xmlrpc/config.rb +40 -0
- data/vendor/javascripts/emscripted-ruby/lib/xmlrpc/create.rb +290 -0
- data/vendor/javascripts/emscripted-ruby/lib/xmlrpc/datetime.rb +142 -0
- data/vendor/javascripts/emscripted-ruby/lib/xmlrpc/httpserver.rb +178 -0
- data/vendor/javascripts/emscripted-ruby/lib/xmlrpc/marshal.rb +76 -0
- data/vendor/javascripts/emscripted-ruby/lib/xmlrpc/parser.rb +813 -0
- data/vendor/javascripts/emscripted-ruby/lib/xmlrpc/server.rb +780 -0
- data/vendor/javascripts/emscripted-ruby/lib/xmlrpc/utils.rb +165 -0
- data/vendor/javascripts/emscripted-ruby/lib/xsd/charset.rb +187 -0
- data/vendor/javascripts/emscripted-ruby/lib/xsd/codegen.rb +12 -0
- data/vendor/javascripts/emscripted-ruby/lib/xsd/codegen/classdef.rb +203 -0
- data/vendor/javascripts/emscripted-ruby/lib/xsd/codegen/commentdef.rb +34 -0
- data/vendor/javascripts/emscripted-ruby/lib/xsd/codegen/gensupport.rb +166 -0
- data/vendor/javascripts/emscripted-ruby/lib/xsd/codegen/methoddef.rb +63 -0
- data/vendor/javascripts/emscripted-ruby/lib/xsd/codegen/moduledef.rb +191 -0
- data/vendor/javascripts/emscripted-ruby/lib/xsd/datatypes.rb +1269 -0
- data/vendor/javascripts/emscripted-ruby/lib/xsd/datatypes1999.rb +20 -0
- data/vendor/javascripts/emscripted-ruby/lib/xsd/iconvcharset.rb +33 -0
- data/vendor/javascripts/emscripted-ruby/lib/xsd/mapping.rb +42 -0
- data/vendor/javascripts/emscripted-ruby/lib/xsd/namedelements.rb +95 -0
- data/vendor/javascripts/emscripted-ruby/lib/xsd/ns.rb +140 -0
- data/vendor/javascripts/emscripted-ruby/lib/xsd/qname.rb +78 -0
- data/vendor/javascripts/emscripted-ruby/lib/xsd/xmlparser.rb +61 -0
- data/vendor/javascripts/emscripted-ruby/lib/xsd/xmlparser/parser.rb +96 -0
- data/vendor/javascripts/emscripted-ruby/lib/xsd/xmlparser/rexmlparser.rb +54 -0
- data/vendor/javascripts/emscripted-ruby/lib/xsd/xmlparser/xmlparser.rb +50 -0
- data/vendor/javascripts/emscripted-ruby/lib/xsd/xmlparser/xmlscanner.rb +147 -0
- data/vendor/javascripts/emscripted-ruby/lib/yaml.rb +440 -0
- data/vendor/javascripts/emscripted-ruby/lib/yaml/baseemitter.rb +247 -0
- data/vendor/javascripts/emscripted-ruby/lib/yaml/basenode.rb +216 -0
- data/vendor/javascripts/emscripted-ruby/lib/yaml/constants.rb +45 -0
- data/vendor/javascripts/emscripted-ruby/lib/yaml/dbm.rb +111 -0
- data/vendor/javascripts/emscripted-ruby/lib/yaml/encoding.rb +33 -0
- data/vendor/javascripts/emscripted-ruby/lib/yaml/error.rb +34 -0
- data/vendor/javascripts/emscripted-ruby/lib/yaml/loader.rb +14 -0
- data/vendor/javascripts/emscripted-ruby/lib/yaml/rubytypes.rb +408 -0
- data/vendor/javascripts/emscripted-ruby/lib/yaml/store.rb +43 -0
- data/vendor/javascripts/emscripted-ruby/lib/yaml/stream.rb +40 -0
- data/vendor/javascripts/emscripted-ruby/lib/yaml/stringio.rb +83 -0
- data/vendor/javascripts/emscripted-ruby/lib/yaml/syck.rb +19 -0
- data/vendor/javascripts/emscripted-ruby/lib/yaml/tag.rb +91 -0
- data/vendor/javascripts/emscripted-ruby/lib/yaml/types.rb +192 -0
- data/vendor/javascripts/emscripted-ruby/lib/yaml/yamlnode.rb +54 -0
- data/vendor/javascripts/emscripted-ruby/lib/yaml/ypath.rb +52 -0
- data/vendor/javascripts/emscripted-ruby/ruby.closure.js +7201 -0
- metadata +554 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# TruncatedDataError is raised when IO#readbytes fails to read enough data.
|
|
2
|
+
|
|
3
|
+
class TruncatedDataError<IOError
|
|
4
|
+
def initialize(mesg, data) # :nodoc:
|
|
5
|
+
@data = data
|
|
6
|
+
super(mesg)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# The read portion of an IO#readbytes attempt.
|
|
10
|
+
attr_reader :data
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
class IO
|
|
14
|
+
# Reads exactly +n+ bytes.
|
|
15
|
+
#
|
|
16
|
+
# If the data read is nil an EOFError is raised.
|
|
17
|
+
#
|
|
18
|
+
# If the data read is too short a TruncatedDataError is raised and the read
|
|
19
|
+
# data is obtainable via its #data method.
|
|
20
|
+
def readbytes(n)
|
|
21
|
+
str = read(n)
|
|
22
|
+
if str == nil
|
|
23
|
+
raise EOFError, "End of file reached"
|
|
24
|
+
end
|
|
25
|
+
if str.size < n
|
|
26
|
+
raise TruncatedDataError.new("data truncated", str)
|
|
27
|
+
end
|
|
28
|
+
str
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
if __FILE__ == $0
|
|
33
|
+
begin
|
|
34
|
+
loop do
|
|
35
|
+
print STDIN.readbytes(6)
|
|
36
|
+
end
|
|
37
|
+
rescue TruncatedDataError
|
|
38
|
+
p $!.data
|
|
39
|
+
raise
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
require 'socket'
|
|
2
|
+
require 'resolv'
|
|
3
|
+
|
|
4
|
+
class << IPSocket
|
|
5
|
+
alias original_resolv_getaddress getaddress
|
|
6
|
+
def getaddress(host)
|
|
7
|
+
begin
|
|
8
|
+
return Resolv.getaddress(host).to_s
|
|
9
|
+
rescue Resolv::ResolvError
|
|
10
|
+
raise SocketError, "Hostname not known: #{host}"
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
class TCPSocket
|
|
16
|
+
alias original_resolv_initialize initialize
|
|
17
|
+
def initialize(host, serv, *rest)
|
|
18
|
+
rest[0] = IPSocket.getaddress(rest[0]) unless rest.empty?
|
|
19
|
+
original_resolv_initialize(IPSocket.getaddress(host), serv, *rest)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
class UDPSocket
|
|
24
|
+
alias original_resolv_bind bind
|
|
25
|
+
def bind(host, port)
|
|
26
|
+
original_resolv_bind(IPSocket.getaddress(host), port)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
alias original_resolv_connect connect
|
|
30
|
+
def connect(host, port)
|
|
31
|
+
original_resolv_connect(IPSocket.getaddress(host), port)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
alias original_resolv_send send
|
|
35
|
+
def send(mesg, flags, *rest)
|
|
36
|
+
if rest.length == 2
|
|
37
|
+
host, port = rest
|
|
38
|
+
begin
|
|
39
|
+
addrs = Resolv.getaddresses(host)
|
|
40
|
+
rescue Resolv::ResolvError
|
|
41
|
+
raise SocketError, "Hostname not known: #{host}"
|
|
42
|
+
end
|
|
43
|
+
err = nil
|
|
44
|
+
addrs[0...-1].each {|addr|
|
|
45
|
+
begin
|
|
46
|
+
return original_resolv_send(mesg, flags, addr, port)
|
|
47
|
+
rescue SystemCallError
|
|
48
|
+
end
|
|
49
|
+
}
|
|
50
|
+
original_resolv_send(mesg, flags, addrs[-1], port)
|
|
51
|
+
else
|
|
52
|
+
original_resolv_send(mesg, flags, *rest)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
class SOCKSSocket
|
|
58
|
+
alias original_resolv_initialize initialize
|
|
59
|
+
def initialize(host, serv)
|
|
60
|
+
original_resolv_initialize(IPSocket.getaddress(host), port)
|
|
61
|
+
end
|
|
62
|
+
end if defined? SOCKSSocket
|
|
@@ -0,0 +1,2210 @@
|
|
|
1
|
+
require 'socket'
|
|
2
|
+
require 'fcntl'
|
|
3
|
+
require 'timeout'
|
|
4
|
+
require 'thread'
|
|
5
|
+
|
|
6
|
+
# Resolv is a thread-aware DNS resolver library written in Ruby. Resolv can
|
|
7
|
+
# handle multiple DNS requests concurrently without blocking. The ruby
|
|
8
|
+
# interpreter.
|
|
9
|
+
#
|
|
10
|
+
# See also resolv-replace.rb to replace the libc resolver with # Resolv.
|
|
11
|
+
#
|
|
12
|
+
# Resolv can look up various DNS resources using the DNS module directly.
|
|
13
|
+
#
|
|
14
|
+
# Examples:
|
|
15
|
+
#
|
|
16
|
+
# p Resolv.getaddress "www.ruby-lang.org"
|
|
17
|
+
# p Resolv.getname "210.251.121.214"
|
|
18
|
+
#
|
|
19
|
+
# Resolv::DNS.open do |dns|
|
|
20
|
+
# ress = dns.getresources "www.ruby-lang.org", Resolv::DNS::Resource::IN::A
|
|
21
|
+
# p ress.map { |r| r.address }
|
|
22
|
+
# ress = dns.getresources "ruby-lang.org", Resolv::DNS::Resource::IN::MX
|
|
23
|
+
# p ress.map { |r| [r.exchange.to_s, r.preference] }
|
|
24
|
+
# end
|
|
25
|
+
#
|
|
26
|
+
#
|
|
27
|
+
# == Bugs
|
|
28
|
+
#
|
|
29
|
+
# * NIS is not supported.
|
|
30
|
+
# * /etc/nsswitch.conf is not supported.
|
|
31
|
+
|
|
32
|
+
class Resolv
|
|
33
|
+
|
|
34
|
+
##
|
|
35
|
+
# Looks up the first IP address for +name+.
|
|
36
|
+
|
|
37
|
+
def self.getaddress(name)
|
|
38
|
+
DefaultResolver.getaddress(name)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
##
|
|
42
|
+
# Looks up all IP address for +name+.
|
|
43
|
+
|
|
44
|
+
def self.getaddresses(name)
|
|
45
|
+
DefaultResolver.getaddresses(name)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
##
|
|
49
|
+
# Iterates over all IP addresses for +name+.
|
|
50
|
+
|
|
51
|
+
def self.each_address(name, &block)
|
|
52
|
+
DefaultResolver.each_address(name, &block)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
##
|
|
56
|
+
# Looks up the hostname of +address+.
|
|
57
|
+
|
|
58
|
+
def self.getname(address)
|
|
59
|
+
DefaultResolver.getname(address)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
##
|
|
63
|
+
# Looks up all hostnames for +address+.
|
|
64
|
+
|
|
65
|
+
def self.getnames(address)
|
|
66
|
+
DefaultResolver.getnames(address)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
##
|
|
70
|
+
# Iterates over all hostnames for +address+.
|
|
71
|
+
|
|
72
|
+
def self.each_name(address, &proc)
|
|
73
|
+
DefaultResolver.each_name(address, &proc)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
##
|
|
77
|
+
# Creates a new Resolv using +resolvers+.
|
|
78
|
+
|
|
79
|
+
def initialize(resolvers=[Hosts.new, DNS.new])
|
|
80
|
+
@resolvers = resolvers
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
##
|
|
84
|
+
# Looks up the first IP address for +name+.
|
|
85
|
+
|
|
86
|
+
def getaddress(name)
|
|
87
|
+
each_address(name) {|address| return address}
|
|
88
|
+
raise ResolvError.new("no address for #{name}")
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
##
|
|
92
|
+
# Looks up all IP address for +name+.
|
|
93
|
+
|
|
94
|
+
def getaddresses(name)
|
|
95
|
+
ret = []
|
|
96
|
+
each_address(name) {|address| ret << address}
|
|
97
|
+
return ret
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
##
|
|
101
|
+
# Iterates over all IP addresses for +name+.
|
|
102
|
+
|
|
103
|
+
def each_address(name)
|
|
104
|
+
if AddressRegex =~ name
|
|
105
|
+
yield name
|
|
106
|
+
return
|
|
107
|
+
end
|
|
108
|
+
yielded = false
|
|
109
|
+
@resolvers.each {|r|
|
|
110
|
+
r.each_address(name) {|address|
|
|
111
|
+
yield address.to_s
|
|
112
|
+
yielded = true
|
|
113
|
+
}
|
|
114
|
+
return if yielded
|
|
115
|
+
}
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
##
|
|
119
|
+
# Looks up the hostname of +address+.
|
|
120
|
+
|
|
121
|
+
def getname(address)
|
|
122
|
+
each_name(address) {|name| return name}
|
|
123
|
+
raise ResolvError.new("no name for #{address}")
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
##
|
|
127
|
+
# Looks up all hostnames for +address+.
|
|
128
|
+
|
|
129
|
+
def getnames(address)
|
|
130
|
+
ret = []
|
|
131
|
+
each_name(address) {|name| ret << name}
|
|
132
|
+
return ret
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
##
|
|
136
|
+
# Iterates over all hostnames for +address+.
|
|
137
|
+
|
|
138
|
+
def each_name(address)
|
|
139
|
+
yielded = false
|
|
140
|
+
@resolvers.each {|r|
|
|
141
|
+
r.each_name(address) {|name|
|
|
142
|
+
yield name.to_s
|
|
143
|
+
yielded = true
|
|
144
|
+
}
|
|
145
|
+
return if yielded
|
|
146
|
+
}
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
##
|
|
150
|
+
# Indicates a failure to resolve a name or address.
|
|
151
|
+
|
|
152
|
+
class ResolvError < StandardError; end
|
|
153
|
+
|
|
154
|
+
##
|
|
155
|
+
# Indicates a timeout resolving a name or address.
|
|
156
|
+
|
|
157
|
+
class ResolvTimeout < TimeoutError; end
|
|
158
|
+
|
|
159
|
+
##
|
|
160
|
+
# DNS::Hosts is a hostname resolver that uses the system hosts file.
|
|
161
|
+
|
|
162
|
+
class Hosts
|
|
163
|
+
if /mswin32|mingw|bccwin/ =~ RUBY_PLATFORM
|
|
164
|
+
require 'win32/resolv'
|
|
165
|
+
DefaultFileName = Win32::Resolv.get_hosts_path
|
|
166
|
+
else
|
|
167
|
+
DefaultFileName = '/etc/hosts'
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
##
|
|
171
|
+
# Creates a new DNS::Hosts, using +filename+ for its data source.
|
|
172
|
+
|
|
173
|
+
def initialize(filename = DefaultFileName)
|
|
174
|
+
@filename = filename
|
|
175
|
+
@mutex = Mutex.new
|
|
176
|
+
@initialized = nil
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def lazy_initialize # :nodoc:
|
|
180
|
+
@mutex.synchronize {
|
|
181
|
+
unless @initialized
|
|
182
|
+
@name2addr = {}
|
|
183
|
+
@addr2name = {}
|
|
184
|
+
open(@filename) {|f|
|
|
185
|
+
f.each {|line|
|
|
186
|
+
line.sub!(/#.*/, '')
|
|
187
|
+
addr, hostname, *aliases = line.split(/\s+/)
|
|
188
|
+
next unless addr
|
|
189
|
+
addr.untaint
|
|
190
|
+
hostname.untaint
|
|
191
|
+
@addr2name[addr] = [] unless @addr2name.include? addr
|
|
192
|
+
@addr2name[addr] << hostname
|
|
193
|
+
@addr2name[addr] += aliases
|
|
194
|
+
@name2addr[hostname] = [] unless @name2addr.include? hostname
|
|
195
|
+
@name2addr[hostname] << addr
|
|
196
|
+
aliases.each {|n|
|
|
197
|
+
n.untaint
|
|
198
|
+
@name2addr[n] = [] unless @name2addr.include? n
|
|
199
|
+
@name2addr[n] << addr
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
@name2addr.each {|name, arr| arr.reverse!}
|
|
204
|
+
@initialized = true
|
|
205
|
+
end
|
|
206
|
+
}
|
|
207
|
+
self
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
##
|
|
211
|
+
# Gets the IP address of +name+ from the hosts file.
|
|
212
|
+
|
|
213
|
+
def getaddress(name)
|
|
214
|
+
each_address(name) {|address| return address}
|
|
215
|
+
raise ResolvError.new("#{@filename} has no name: #{name}")
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
##
|
|
219
|
+
# Gets all IP addresses for +name+ from the hosts file.
|
|
220
|
+
|
|
221
|
+
def getaddresses(name)
|
|
222
|
+
ret = []
|
|
223
|
+
each_address(name) {|address| ret << address}
|
|
224
|
+
return ret
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
##
|
|
228
|
+
# Iterates over all IP addresses for +name+ retrieved from the hosts file.
|
|
229
|
+
|
|
230
|
+
def each_address(name, &proc)
|
|
231
|
+
lazy_initialize
|
|
232
|
+
if @name2addr.include?(name)
|
|
233
|
+
@name2addr[name].each(&proc)
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
##
|
|
238
|
+
# Gets the hostname of +address+ from the hosts file.
|
|
239
|
+
|
|
240
|
+
def getname(address)
|
|
241
|
+
each_name(address) {|name| return name}
|
|
242
|
+
raise ResolvError.new("#{@filename} has no address: #{address}")
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
##
|
|
246
|
+
# Gets all hostnames for +address+ from the hosts file.
|
|
247
|
+
|
|
248
|
+
def getnames(address)
|
|
249
|
+
ret = []
|
|
250
|
+
each_name(address) {|name| ret << name}
|
|
251
|
+
return ret
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
##
|
|
255
|
+
# Iterates over all hostnames for +address+ retrived from the hosts file.
|
|
256
|
+
|
|
257
|
+
def each_name(address, &proc)
|
|
258
|
+
lazy_initialize
|
|
259
|
+
if @addr2name.include?(address)
|
|
260
|
+
@addr2name[address].each(&proc)
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
##
|
|
266
|
+
# Resolv::DNS is a DNS stub resolver.
|
|
267
|
+
#
|
|
268
|
+
# Information taken from the following places:
|
|
269
|
+
#
|
|
270
|
+
# * STD0013
|
|
271
|
+
# * RFC 1035
|
|
272
|
+
# * ftp://ftp.isi.edu/in-notes/iana/assignments/dns-parameters
|
|
273
|
+
# * etc.
|
|
274
|
+
|
|
275
|
+
class DNS
|
|
276
|
+
|
|
277
|
+
##
|
|
278
|
+
# Default DNS Port
|
|
279
|
+
|
|
280
|
+
Port = 53
|
|
281
|
+
|
|
282
|
+
##
|
|
283
|
+
# Default DNS UDP packet size
|
|
284
|
+
|
|
285
|
+
UDPSize = 512
|
|
286
|
+
|
|
287
|
+
##
|
|
288
|
+
# Group of DNS resolver threads
|
|
289
|
+
|
|
290
|
+
DNSThreadGroup = ThreadGroup.new
|
|
291
|
+
|
|
292
|
+
##
|
|
293
|
+
# Creates a new DNS resolver. See Resolv::DNS.new for argument details.
|
|
294
|
+
#
|
|
295
|
+
# Yields the created DNS resolver to the block, if given, otherwise
|
|
296
|
+
# returns it.
|
|
297
|
+
|
|
298
|
+
def self.open(*args)
|
|
299
|
+
dns = new(*args)
|
|
300
|
+
return dns unless block_given?
|
|
301
|
+
begin
|
|
302
|
+
yield dns
|
|
303
|
+
ensure
|
|
304
|
+
dns.close
|
|
305
|
+
end
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
##
|
|
309
|
+
# Creates a new DNS resolver.
|
|
310
|
+
#
|
|
311
|
+
# +config_info+ can be:
|
|
312
|
+
#
|
|
313
|
+
# nil:: Uses /etc/resolv.conf.
|
|
314
|
+
# String:: Path to a file using /etc/resolv.conf's format.
|
|
315
|
+
# Hash:: Must contain :nameserver, :search and :ndots keys.
|
|
316
|
+
#
|
|
317
|
+
# Example:
|
|
318
|
+
#
|
|
319
|
+
# Resolv::DNS.new(:nameserver => ['210.251.121.21'],
|
|
320
|
+
# :search => ['ruby-lang.org'],
|
|
321
|
+
# :ndots => 1)
|
|
322
|
+
|
|
323
|
+
def initialize(config_info=nil)
|
|
324
|
+
@mutex = Mutex.new
|
|
325
|
+
@config = Config.new(config_info)
|
|
326
|
+
@initialized = nil
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
def lazy_initialize # :nodoc:
|
|
330
|
+
@mutex.synchronize {
|
|
331
|
+
unless @initialized
|
|
332
|
+
@config.lazy_initialize
|
|
333
|
+
|
|
334
|
+
if nameserver = @config.single?
|
|
335
|
+
@requester = Requester::ConnectedUDP.new(nameserver)
|
|
336
|
+
else
|
|
337
|
+
@requester = Requester::UnconnectedUDP.new
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
@initialized = true
|
|
341
|
+
end
|
|
342
|
+
}
|
|
343
|
+
self
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
##
|
|
347
|
+
# Closes the DNS resolver.
|
|
348
|
+
|
|
349
|
+
def close
|
|
350
|
+
@mutex.synchronize {
|
|
351
|
+
if @initialized
|
|
352
|
+
@requester.close if @requester
|
|
353
|
+
@requester = nil
|
|
354
|
+
@initialized = false
|
|
355
|
+
end
|
|
356
|
+
}
|
|
357
|
+
end
|
|
358
|
+
|
|
359
|
+
##
|
|
360
|
+
# Gets the IP address of +name+ from the DNS resolver.
|
|
361
|
+
#
|
|
362
|
+
# +name+ can be a Resolv::DNS::Name or a String. Retrieved address will
|
|
363
|
+
# be a Resolv::IPv4 or Resolv::IPv6
|
|
364
|
+
|
|
365
|
+
def getaddress(name)
|
|
366
|
+
each_address(name) {|address| return address}
|
|
367
|
+
raise ResolvError.new("DNS result has no information for #{name}")
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
##
|
|
371
|
+
# Gets all IP addresses for +name+ from the DNS resolver.
|
|
372
|
+
#
|
|
373
|
+
# +name+ can be a Resolv::DNS::Name or a String. Retrieved addresses will
|
|
374
|
+
# be a Resolv::IPv4 or Resolv::IPv6
|
|
375
|
+
|
|
376
|
+
def getaddresses(name)
|
|
377
|
+
ret = []
|
|
378
|
+
each_address(name) {|address| ret << address}
|
|
379
|
+
return ret
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
##
|
|
383
|
+
# Iterates over all IP addresses for +name+ retrieved from the DNS
|
|
384
|
+
# resolver.
|
|
385
|
+
#
|
|
386
|
+
# +name+ can be a Resolv::DNS::Name or a String. Retrieved addresses will
|
|
387
|
+
# be a Resolv::IPv4 or Resolv::IPv6
|
|
388
|
+
|
|
389
|
+
def each_address(name)
|
|
390
|
+
each_resource(name, Resource::IN::A) {|resource| yield resource.address}
|
|
391
|
+
each_resource(name, Resource::IN::AAAA) {|resource| yield resource.address}
|
|
392
|
+
end
|
|
393
|
+
|
|
394
|
+
##
|
|
395
|
+
# Gets the hostname for +address+ from the DNS resolver.
|
|
396
|
+
#
|
|
397
|
+
# +address+ must be a Resolv::IPv4, Resolv::IPv6 or a String. Retrieved
|
|
398
|
+
# name will be a Resolv::DNS::Name.
|
|
399
|
+
|
|
400
|
+
def getname(address)
|
|
401
|
+
each_name(address) {|name| return name}
|
|
402
|
+
raise ResolvError.new("DNS result has no information for #{address}")
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
##
|
|
406
|
+
# Gets all hostnames for +address+ from the DNS resolver.
|
|
407
|
+
#
|
|
408
|
+
# +address+ must be a Resolv::IPv4, Resolv::IPv6 or a String. Retrieved
|
|
409
|
+
# names will be Resolv::DNS::Name instances.
|
|
410
|
+
|
|
411
|
+
def getnames(address)
|
|
412
|
+
ret = []
|
|
413
|
+
each_name(address) {|name| ret << name}
|
|
414
|
+
return ret
|
|
415
|
+
end
|
|
416
|
+
|
|
417
|
+
##
|
|
418
|
+
# Iterates over all hostnames for +address+ retrieved from the DNS
|
|
419
|
+
# resolver.
|
|
420
|
+
#
|
|
421
|
+
# +address+ must be a Resolv::IPv4, Resolv::IPv6 or a String. Retrieved
|
|
422
|
+
# names will be Resolv::DNS::Name instances.
|
|
423
|
+
|
|
424
|
+
def each_name(address)
|
|
425
|
+
case address
|
|
426
|
+
when Name
|
|
427
|
+
ptr = address
|
|
428
|
+
when IPv4::Regex
|
|
429
|
+
ptr = IPv4.create(address).to_name
|
|
430
|
+
when IPv6::Regex
|
|
431
|
+
ptr = IPv6.create(address).to_name
|
|
432
|
+
else
|
|
433
|
+
raise ResolvError.new("cannot interpret as address: #{address}")
|
|
434
|
+
end
|
|
435
|
+
each_resource(ptr, Resource::IN::PTR) {|resource| yield resource.name}
|
|
436
|
+
end
|
|
437
|
+
|
|
438
|
+
##
|
|
439
|
+
# Look up the +typeclass+ DNS resource of +name+.
|
|
440
|
+
#
|
|
441
|
+
# +name+ must be a Resolv::DNS::Name or a String.
|
|
442
|
+
#
|
|
443
|
+
# +typeclass+ should be one of the following:
|
|
444
|
+
#
|
|
445
|
+
# * Resolv::DNS::Resource::IN::A
|
|
446
|
+
# * Resolv::DNS::Resource::IN::AAAA
|
|
447
|
+
# * Resolv::DNS::Resource::IN::ANY
|
|
448
|
+
# * Resolv::DNS::Resource::IN::CNAME
|
|
449
|
+
# * Resolv::DNS::Resource::IN::HINFO
|
|
450
|
+
# * Resolv::DNS::Resource::IN::MINFO
|
|
451
|
+
# * Resolv::DNS::Resource::IN::MX
|
|
452
|
+
# * Resolv::DNS::Resource::IN::NS
|
|
453
|
+
# * Resolv::DNS::Resource::IN::PTR
|
|
454
|
+
# * Resolv::DNS::Resource::IN::SOA
|
|
455
|
+
# * Resolv::DNS::Resource::IN::TXT
|
|
456
|
+
# * Resolv::DNS::Resource::IN::WKS
|
|
457
|
+
#
|
|
458
|
+
# Returned resource is represented as a Resolv::DNS::Resource instance,
|
|
459
|
+
# i.e. Resolv::DNS::Resource::IN::A.
|
|
460
|
+
|
|
461
|
+
def getresource(name, typeclass)
|
|
462
|
+
each_resource(name, typeclass) {|resource| return resource}
|
|
463
|
+
raise ResolvError.new("DNS result has no information for #{name}")
|
|
464
|
+
end
|
|
465
|
+
|
|
466
|
+
##
|
|
467
|
+
# Looks up all +typeclass+ DNS resources for +name+. See #getresource for
|
|
468
|
+
# argument details.
|
|
469
|
+
|
|
470
|
+
def getresources(name, typeclass)
|
|
471
|
+
ret = []
|
|
472
|
+
each_resource(name, typeclass) {|resource| ret << resource}
|
|
473
|
+
return ret
|
|
474
|
+
end
|
|
475
|
+
|
|
476
|
+
##
|
|
477
|
+
# Iterates over all +typeclass+ DNS resources for +name+. See
|
|
478
|
+
# #getresource for argument details.
|
|
479
|
+
|
|
480
|
+
def each_resource(name, typeclass, &proc)
|
|
481
|
+
lazy_initialize
|
|
482
|
+
q = Queue.new
|
|
483
|
+
senders = {}
|
|
484
|
+
begin
|
|
485
|
+
@config.resolv(name) {|candidate, tout, nameserver|
|
|
486
|
+
msg = Message.new
|
|
487
|
+
msg.rd = 1
|
|
488
|
+
msg.add_question(candidate, typeclass)
|
|
489
|
+
unless sender = senders[[candidate, nameserver]]
|
|
490
|
+
sender = senders[[candidate, nameserver]] =
|
|
491
|
+
@requester.sender(msg, candidate, q, nameserver)
|
|
492
|
+
end
|
|
493
|
+
sender.send
|
|
494
|
+
reply = reply_name = nil
|
|
495
|
+
timeout(tout, ResolvTimeout) { reply, reply_name = q.pop }
|
|
496
|
+
case reply.rcode
|
|
497
|
+
when RCode::NoError
|
|
498
|
+
extract_resources(reply, reply_name, typeclass, &proc)
|
|
499
|
+
return
|
|
500
|
+
when RCode::NXDomain
|
|
501
|
+
raise Config::NXDomain.new(reply_name.to_s)
|
|
502
|
+
else
|
|
503
|
+
raise Config::OtherResolvError.new(reply_name.to_s)
|
|
504
|
+
end
|
|
505
|
+
}
|
|
506
|
+
ensure
|
|
507
|
+
@requester.delete(q)
|
|
508
|
+
end
|
|
509
|
+
end
|
|
510
|
+
|
|
511
|
+
def extract_resources(msg, name, typeclass) # :nodoc:
|
|
512
|
+
if typeclass < Resource::ANY
|
|
513
|
+
n0 = Name.create(name)
|
|
514
|
+
msg.each_answer {|n, ttl, data|
|
|
515
|
+
yield data if n0 == n
|
|
516
|
+
}
|
|
517
|
+
end
|
|
518
|
+
yielded = false
|
|
519
|
+
n0 = Name.create(name)
|
|
520
|
+
msg.each_answer {|n, ttl, data|
|
|
521
|
+
if n0 == n
|
|
522
|
+
case data
|
|
523
|
+
when typeclass
|
|
524
|
+
yield data
|
|
525
|
+
yielded = true
|
|
526
|
+
when Resource::CNAME
|
|
527
|
+
n0 = data.name
|
|
528
|
+
end
|
|
529
|
+
end
|
|
530
|
+
}
|
|
531
|
+
return if yielded
|
|
532
|
+
msg.each_answer {|n, ttl, data|
|
|
533
|
+
if n0 == n
|
|
534
|
+
case data
|
|
535
|
+
when typeclass
|
|
536
|
+
yield data
|
|
537
|
+
end
|
|
538
|
+
end
|
|
539
|
+
}
|
|
540
|
+
end
|
|
541
|
+
|
|
542
|
+
class Requester # :nodoc:
|
|
543
|
+
def initialize
|
|
544
|
+
@senders = {}
|
|
545
|
+
end
|
|
546
|
+
|
|
547
|
+
def close
|
|
548
|
+
thread, sock, @thread, @sock = @thread, @sock
|
|
549
|
+
begin
|
|
550
|
+
if thread
|
|
551
|
+
thread.kill
|
|
552
|
+
thread.join
|
|
553
|
+
end
|
|
554
|
+
ensure
|
|
555
|
+
sock.close if sock
|
|
556
|
+
end
|
|
557
|
+
end
|
|
558
|
+
|
|
559
|
+
def delete(arg)
|
|
560
|
+
case arg
|
|
561
|
+
when Sender
|
|
562
|
+
@senders.delete_if {|k, s| s == arg }
|
|
563
|
+
when Queue
|
|
564
|
+
@senders.delete_if {|k, s| s.queue == arg }
|
|
565
|
+
else
|
|
566
|
+
raise ArgumentError.new("neither Sender or Queue: #{arg}")
|
|
567
|
+
end
|
|
568
|
+
end
|
|
569
|
+
|
|
570
|
+
class Sender # :nodoc:
|
|
571
|
+
def initialize(msg, data, sock, queue)
|
|
572
|
+
@msg = msg
|
|
573
|
+
@data = data
|
|
574
|
+
@sock = sock
|
|
575
|
+
@queue = queue
|
|
576
|
+
end
|
|
577
|
+
attr_reader :queue
|
|
578
|
+
|
|
579
|
+
def recv(msg)
|
|
580
|
+
@queue.push([msg, @data])
|
|
581
|
+
end
|
|
582
|
+
end
|
|
583
|
+
|
|
584
|
+
class UnconnectedUDP < Requester # :nodoc:
|
|
585
|
+
def initialize
|
|
586
|
+
super()
|
|
587
|
+
@sock = UDPSocket.new
|
|
588
|
+
@sock.fcntl(Fcntl::F_SETFD, 1) if defined? Fcntl::F_SETFD
|
|
589
|
+
@id = {}
|
|
590
|
+
@id.default = -1
|
|
591
|
+
@thread = Thread.new {
|
|
592
|
+
DNSThreadGroup.add Thread.current
|
|
593
|
+
loop {
|
|
594
|
+
reply, from = @sock.recvfrom(UDPSize)
|
|
595
|
+
msg = begin
|
|
596
|
+
Message.decode(reply)
|
|
597
|
+
rescue DecodeError
|
|
598
|
+
STDERR.print("DNS message decoding error: #{reply.inspect}\n")
|
|
599
|
+
next
|
|
600
|
+
end
|
|
601
|
+
if s = @senders[[[from[3],from[1]],msg.id]]
|
|
602
|
+
s.recv msg
|
|
603
|
+
else
|
|
604
|
+
#STDERR.print("non-handled DNS message: #{msg.inspect} from #{from.inspect}\n")
|
|
605
|
+
end
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
end
|
|
609
|
+
|
|
610
|
+
def sender(msg, data, queue, host, port=Port)
|
|
611
|
+
service = [host, port]
|
|
612
|
+
id = Thread.exclusive {
|
|
613
|
+
@id[service] = (@id[service] + 1) & 0xffff
|
|
614
|
+
}
|
|
615
|
+
request = msg.encode
|
|
616
|
+
request[0,2] = [id].pack('n')
|
|
617
|
+
return @senders[[service, id]] =
|
|
618
|
+
Sender.new(request, data, @sock, host, port, queue)
|
|
619
|
+
end
|
|
620
|
+
|
|
621
|
+
class Sender < Requester::Sender # :nodoc:
|
|
622
|
+
def initialize(msg, data, sock, host, port, queue)
|
|
623
|
+
super(msg, data, sock, queue)
|
|
624
|
+
@host = host
|
|
625
|
+
@port = port
|
|
626
|
+
end
|
|
627
|
+
|
|
628
|
+
def send
|
|
629
|
+
@sock.send(@msg, 0, @host, @port)
|
|
630
|
+
end
|
|
631
|
+
end
|
|
632
|
+
end
|
|
633
|
+
|
|
634
|
+
class ConnectedUDP < Requester # :nodoc:
|
|
635
|
+
def initialize(host, port=Port)
|
|
636
|
+
super()
|
|
637
|
+
@host = host
|
|
638
|
+
@port = port
|
|
639
|
+
@sock = UDPSocket.new(host.index(':') ? Socket::AF_INET6 : Socket::AF_INET)
|
|
640
|
+
@sock.connect(host, port)
|
|
641
|
+
@sock.fcntl(Fcntl::F_SETFD, 1) if defined? Fcntl::F_SETFD
|
|
642
|
+
@id = -1
|
|
643
|
+
@thread = Thread.new {
|
|
644
|
+
DNSThreadGroup.add Thread.current
|
|
645
|
+
loop {
|
|
646
|
+
reply = @sock.recv(UDPSize)
|
|
647
|
+
msg = begin
|
|
648
|
+
Message.decode(reply)
|
|
649
|
+
rescue DecodeError
|
|
650
|
+
STDERR.print("DNS message decoding error: #{reply.inspect}")
|
|
651
|
+
next
|
|
652
|
+
end
|
|
653
|
+
if s = @senders[msg.id]
|
|
654
|
+
s.recv msg
|
|
655
|
+
else
|
|
656
|
+
#STDERR.print("non-handled DNS message: #{msg.inspect}")
|
|
657
|
+
end
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
end
|
|
661
|
+
|
|
662
|
+
def sender(msg, data, queue, host=@host, port=@port)
|
|
663
|
+
unless host == @host && port == @port
|
|
664
|
+
raise RequestError.new("host/port don't match: #{host}:#{port}")
|
|
665
|
+
end
|
|
666
|
+
id = Thread.exclusive { @id = (@id + 1) & 0xffff }
|
|
667
|
+
request = msg.encode
|
|
668
|
+
request[0,2] = [id].pack('n')
|
|
669
|
+
return @senders[id] = Sender.new(request, data, @sock, queue)
|
|
670
|
+
end
|
|
671
|
+
|
|
672
|
+
class Sender < Requester::Sender # :nodoc:
|
|
673
|
+
def send
|
|
674
|
+
@sock.send(@msg, 0)
|
|
675
|
+
end
|
|
676
|
+
end
|
|
677
|
+
end
|
|
678
|
+
|
|
679
|
+
class TCP < Requester # :nodoc:
|
|
680
|
+
def initialize(host, port=Port)
|
|
681
|
+
super()
|
|
682
|
+
@host = host
|
|
683
|
+
@port = port
|
|
684
|
+
@sock = TCPSocket.new
|
|
685
|
+
@sock.connect(host, port)
|
|
686
|
+
@sock.fcntl(Fcntl::F_SETFD, 1) if defined? Fcntl::F_SETFD
|
|
687
|
+
@id = -1
|
|
688
|
+
@senders = {}
|
|
689
|
+
@thread = Thread.new {
|
|
690
|
+
DNSThreadGroup.add Thread.current
|
|
691
|
+
loop {
|
|
692
|
+
len = @sock.read(2).unpack('n')
|
|
693
|
+
reply = @sock.read(len)
|
|
694
|
+
msg = begin
|
|
695
|
+
Message.decode(reply)
|
|
696
|
+
rescue DecodeError
|
|
697
|
+
STDERR.print("DNS message decoding error: #{reply.inspect}")
|
|
698
|
+
next
|
|
699
|
+
end
|
|
700
|
+
if s = @senders[msg.id]
|
|
701
|
+
s.push msg
|
|
702
|
+
else
|
|
703
|
+
#STDERR.print("non-handled DNS message: #{msg.inspect}")
|
|
704
|
+
end
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
end
|
|
708
|
+
|
|
709
|
+
def sender(msg, data, queue, host=@host, port=@port)
|
|
710
|
+
unless host == @host && port == @port
|
|
711
|
+
raise RequestError.new("host/port don't match: #{host}:#{port}")
|
|
712
|
+
end
|
|
713
|
+
id = Thread.exclusive { @id = (@id + 1) & 0xffff }
|
|
714
|
+
request = msg.encode
|
|
715
|
+
request[0,2] = [request.length, id].pack('nn')
|
|
716
|
+
return @senders[id] = Sender.new(request, data, @sock, queue)
|
|
717
|
+
end
|
|
718
|
+
|
|
719
|
+
class Sender < Requester::Sender # :nodoc:
|
|
720
|
+
def send
|
|
721
|
+
@sock.print(@msg)
|
|
722
|
+
@sock.flush
|
|
723
|
+
end
|
|
724
|
+
end
|
|
725
|
+
end
|
|
726
|
+
|
|
727
|
+
##
|
|
728
|
+
# Indicates a problem with the DNS request.
|
|
729
|
+
|
|
730
|
+
class RequestError < StandardError
|
|
731
|
+
end
|
|
732
|
+
end
|
|
733
|
+
|
|
734
|
+
class Config # :nodoc:
|
|
735
|
+
def initialize(config_info=nil)
|
|
736
|
+
@mutex = Mutex.new
|
|
737
|
+
@config_info = config_info
|
|
738
|
+
@initialized = nil
|
|
739
|
+
end
|
|
740
|
+
|
|
741
|
+
def Config.parse_resolv_conf(filename)
|
|
742
|
+
nameserver = []
|
|
743
|
+
search = nil
|
|
744
|
+
ndots = 1
|
|
745
|
+
open(filename) {|f|
|
|
746
|
+
f.each {|line|
|
|
747
|
+
line.sub!(/[#;].*/, '')
|
|
748
|
+
keyword, *args = line.split(/\s+/)
|
|
749
|
+
args.each { |arg|
|
|
750
|
+
arg.untaint
|
|
751
|
+
}
|
|
752
|
+
next unless keyword
|
|
753
|
+
case keyword
|
|
754
|
+
when 'nameserver'
|
|
755
|
+
nameserver += args
|
|
756
|
+
when 'domain'
|
|
757
|
+
next if args.empty?
|
|
758
|
+
search = [args[0]]
|
|
759
|
+
when 'search'
|
|
760
|
+
next if args.empty?
|
|
761
|
+
search = args
|
|
762
|
+
when 'options'
|
|
763
|
+
args.each {|arg|
|
|
764
|
+
case arg
|
|
765
|
+
when /\Andots:(\d+)\z/
|
|
766
|
+
ndots = $1.to_i
|
|
767
|
+
end
|
|
768
|
+
}
|
|
769
|
+
end
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
return { :nameserver => nameserver, :search => search, :ndots => ndots }
|
|
773
|
+
end
|
|
774
|
+
|
|
775
|
+
def Config.default_config_hash(filename="/etc/resolv.conf")
|
|
776
|
+
if File.exist? filename
|
|
777
|
+
config_hash = Config.parse_resolv_conf(filename)
|
|
778
|
+
else
|
|
779
|
+
if /mswin32|cygwin|mingw|bccwin/ =~ RUBY_PLATFORM
|
|
780
|
+
require 'win32/resolv'
|
|
781
|
+
search, nameserver = Win32::Resolv.get_resolv_info
|
|
782
|
+
config_hash = {}
|
|
783
|
+
config_hash[:nameserver] = nameserver if nameserver
|
|
784
|
+
config_hash[:search] = [search].flatten if search
|
|
785
|
+
end
|
|
786
|
+
end
|
|
787
|
+
config_hash
|
|
788
|
+
end
|
|
789
|
+
|
|
790
|
+
def lazy_initialize
|
|
791
|
+
@mutex.synchronize {
|
|
792
|
+
unless @initialized
|
|
793
|
+
@nameserver = []
|
|
794
|
+
@search = nil
|
|
795
|
+
@ndots = 1
|
|
796
|
+
case @config_info
|
|
797
|
+
when nil
|
|
798
|
+
config_hash = Config.default_config_hash
|
|
799
|
+
when String
|
|
800
|
+
config_hash = Config.parse_resolv_conf(@config_info)
|
|
801
|
+
when Hash
|
|
802
|
+
config_hash = @config_info.dup
|
|
803
|
+
if String === config_hash[:nameserver]
|
|
804
|
+
config_hash[:nameserver] = [config_hash[:nameserver]]
|
|
805
|
+
end
|
|
806
|
+
if String === config_hash[:search]
|
|
807
|
+
config_hash[:search] = [config_hash[:search]]
|
|
808
|
+
end
|
|
809
|
+
else
|
|
810
|
+
raise ArgumentError.new("invalid resolv configuration: #{@config_info.inspect}")
|
|
811
|
+
end
|
|
812
|
+
@nameserver = config_hash[:nameserver] if config_hash.include? :nameserver
|
|
813
|
+
@search = config_hash[:search] if config_hash.include? :search
|
|
814
|
+
@ndots = config_hash[:ndots] if config_hash.include? :ndots
|
|
815
|
+
|
|
816
|
+
@nameserver = ['0.0.0.0'] if @nameserver.empty?
|
|
817
|
+
if @search
|
|
818
|
+
@search = @search.map {|arg| Label.split(arg) }
|
|
819
|
+
else
|
|
820
|
+
hostname = Socket.gethostname
|
|
821
|
+
if /\./ =~ hostname
|
|
822
|
+
@search = [Label.split($')]
|
|
823
|
+
else
|
|
824
|
+
@search = [[]]
|
|
825
|
+
end
|
|
826
|
+
end
|
|
827
|
+
|
|
828
|
+
if !@nameserver.kind_of?(Array) ||
|
|
829
|
+
!@nameserver.all? {|ns| String === ns }
|
|
830
|
+
raise ArgumentError.new("invalid nameserver config: #{@nameserver.inspect}")
|
|
831
|
+
end
|
|
832
|
+
|
|
833
|
+
if !@search.kind_of?(Array) ||
|
|
834
|
+
!@search.all? {|ls| ls.all? {|l| Label::Str === l } }
|
|
835
|
+
raise ArgumentError.new("invalid search config: #{@search.inspect}")
|
|
836
|
+
end
|
|
837
|
+
|
|
838
|
+
if !@ndots.kind_of?(Integer)
|
|
839
|
+
raise ArgumentError.new("invalid ndots config: #{@ndots.inspect}")
|
|
840
|
+
end
|
|
841
|
+
|
|
842
|
+
@initialized = true
|
|
843
|
+
end
|
|
844
|
+
}
|
|
845
|
+
self
|
|
846
|
+
end
|
|
847
|
+
|
|
848
|
+
def single?
|
|
849
|
+
lazy_initialize
|
|
850
|
+
if @nameserver.length == 1
|
|
851
|
+
return @nameserver[0]
|
|
852
|
+
else
|
|
853
|
+
return nil
|
|
854
|
+
end
|
|
855
|
+
end
|
|
856
|
+
|
|
857
|
+
def generate_candidates(name)
|
|
858
|
+
candidates = nil
|
|
859
|
+
name = Name.create(name)
|
|
860
|
+
if name.absolute?
|
|
861
|
+
candidates = [name]
|
|
862
|
+
else
|
|
863
|
+
if @ndots <= name.length - 1
|
|
864
|
+
candidates = [Name.new(name.to_a)]
|
|
865
|
+
else
|
|
866
|
+
candidates = []
|
|
867
|
+
end
|
|
868
|
+
candidates.concat(@search.map {|domain| Name.new(name.to_a + domain)})
|
|
869
|
+
end
|
|
870
|
+
return candidates
|
|
871
|
+
end
|
|
872
|
+
|
|
873
|
+
InitialTimeout = 5
|
|
874
|
+
|
|
875
|
+
def generate_timeouts
|
|
876
|
+
ts = [InitialTimeout]
|
|
877
|
+
ts << ts[-1] * 2 / @nameserver.length
|
|
878
|
+
ts << ts[-1] * 2
|
|
879
|
+
ts << ts[-1] * 2
|
|
880
|
+
return ts
|
|
881
|
+
end
|
|
882
|
+
|
|
883
|
+
def resolv(name)
|
|
884
|
+
candidates = generate_candidates(name)
|
|
885
|
+
timeouts = generate_timeouts
|
|
886
|
+
begin
|
|
887
|
+
candidates.each {|candidate|
|
|
888
|
+
begin
|
|
889
|
+
timeouts.each {|tout|
|
|
890
|
+
@nameserver.each {|nameserver|
|
|
891
|
+
begin
|
|
892
|
+
yield candidate, tout, nameserver
|
|
893
|
+
rescue ResolvTimeout
|
|
894
|
+
end
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
raise ResolvError.new("DNS resolv timeout: #{name}")
|
|
898
|
+
rescue NXDomain
|
|
899
|
+
end
|
|
900
|
+
}
|
|
901
|
+
rescue ResolvError
|
|
902
|
+
end
|
|
903
|
+
end
|
|
904
|
+
|
|
905
|
+
##
|
|
906
|
+
# Indicates no such domain was found.
|
|
907
|
+
|
|
908
|
+
class NXDomain < ResolvError
|
|
909
|
+
end
|
|
910
|
+
|
|
911
|
+
##
|
|
912
|
+
# Indicates some other unhandled resolver error was encountered.
|
|
913
|
+
|
|
914
|
+
class OtherResolvError < ResolvError
|
|
915
|
+
end
|
|
916
|
+
end
|
|
917
|
+
|
|
918
|
+
module OpCode # :nodoc:
|
|
919
|
+
Query = 0
|
|
920
|
+
IQuery = 1
|
|
921
|
+
Status = 2
|
|
922
|
+
Notify = 4
|
|
923
|
+
Update = 5
|
|
924
|
+
end
|
|
925
|
+
|
|
926
|
+
module RCode # :nodoc:
|
|
927
|
+
NoError = 0
|
|
928
|
+
FormErr = 1
|
|
929
|
+
ServFail = 2
|
|
930
|
+
NXDomain = 3
|
|
931
|
+
NotImp = 4
|
|
932
|
+
Refused = 5
|
|
933
|
+
YXDomain = 6
|
|
934
|
+
YXRRSet = 7
|
|
935
|
+
NXRRSet = 8
|
|
936
|
+
NotAuth = 9
|
|
937
|
+
NotZone = 10
|
|
938
|
+
BADVERS = 16
|
|
939
|
+
BADSIG = 16
|
|
940
|
+
BADKEY = 17
|
|
941
|
+
BADTIME = 18
|
|
942
|
+
BADMODE = 19
|
|
943
|
+
BADNAME = 20
|
|
944
|
+
BADALG = 21
|
|
945
|
+
end
|
|
946
|
+
|
|
947
|
+
##
|
|
948
|
+
# Indicates that the DNS response was unable to be decoded.
|
|
949
|
+
|
|
950
|
+
class DecodeError < StandardError
|
|
951
|
+
end
|
|
952
|
+
|
|
953
|
+
##
|
|
954
|
+
# Indicates that the DNS request was unable to be encoded.
|
|
955
|
+
|
|
956
|
+
class EncodeError < StandardError
|
|
957
|
+
end
|
|
958
|
+
|
|
959
|
+
module Label # :nodoc:
|
|
960
|
+
def self.split(arg)
|
|
961
|
+
labels = []
|
|
962
|
+
arg.scan(/[^\.]+/) {labels << Str.new($&)}
|
|
963
|
+
return labels
|
|
964
|
+
end
|
|
965
|
+
|
|
966
|
+
class Str # :nodoc:
|
|
967
|
+
def initialize(string)
|
|
968
|
+
@string = string
|
|
969
|
+
@downcase = string.downcase
|
|
970
|
+
end
|
|
971
|
+
attr_reader :string, :downcase
|
|
972
|
+
|
|
973
|
+
def to_s
|
|
974
|
+
return @string
|
|
975
|
+
end
|
|
976
|
+
|
|
977
|
+
def inspect
|
|
978
|
+
return "#<#{self.class} #{self.to_s}>"
|
|
979
|
+
end
|
|
980
|
+
|
|
981
|
+
def ==(other)
|
|
982
|
+
return @downcase == other.downcase
|
|
983
|
+
end
|
|
984
|
+
|
|
985
|
+
def eql?(other)
|
|
986
|
+
return self == other
|
|
987
|
+
end
|
|
988
|
+
|
|
989
|
+
def hash
|
|
990
|
+
return @downcase.hash
|
|
991
|
+
end
|
|
992
|
+
end
|
|
993
|
+
end
|
|
994
|
+
|
|
995
|
+
##
|
|
996
|
+
# A representation of a DNS name.
|
|
997
|
+
|
|
998
|
+
class Name
|
|
999
|
+
|
|
1000
|
+
##
|
|
1001
|
+
# Creates a new DNS name from +arg+. +arg+ can be:
|
|
1002
|
+
#
|
|
1003
|
+
# Name:: returns +arg+.
|
|
1004
|
+
# String:: Creates a new Name.
|
|
1005
|
+
|
|
1006
|
+
def self.create(arg)
|
|
1007
|
+
case arg
|
|
1008
|
+
when Name
|
|
1009
|
+
return arg
|
|
1010
|
+
when String
|
|
1011
|
+
return Name.new(Label.split(arg), /\.\z/ =~ arg ? true : false)
|
|
1012
|
+
else
|
|
1013
|
+
raise ArgumentError.new("cannot interpret as DNS name: #{arg.inspect}")
|
|
1014
|
+
end
|
|
1015
|
+
end
|
|
1016
|
+
|
|
1017
|
+
def initialize(labels, absolute=true) # :nodoc:
|
|
1018
|
+
@labels = labels
|
|
1019
|
+
@absolute = absolute
|
|
1020
|
+
end
|
|
1021
|
+
|
|
1022
|
+
def inspect # :nodoc:
|
|
1023
|
+
"#<#{self.class}: #{self.to_s}#{@absolute ? '.' : ''}>"
|
|
1024
|
+
end
|
|
1025
|
+
|
|
1026
|
+
##
|
|
1027
|
+
# True if this name is absolute.
|
|
1028
|
+
|
|
1029
|
+
def absolute?
|
|
1030
|
+
return @absolute
|
|
1031
|
+
end
|
|
1032
|
+
|
|
1033
|
+
def ==(other) # :nodoc:
|
|
1034
|
+
return false unless Name === other
|
|
1035
|
+
return @labels.join == other.to_a.join && @absolute == other.absolute?
|
|
1036
|
+
end
|
|
1037
|
+
|
|
1038
|
+
alias eql? == # :nodoc:
|
|
1039
|
+
|
|
1040
|
+
##
|
|
1041
|
+
# Returns true if +other+ is a subdomain.
|
|
1042
|
+
#
|
|
1043
|
+
# Example:
|
|
1044
|
+
#
|
|
1045
|
+
# domain = Resolv::DNS::Name.create("y.z")
|
|
1046
|
+
# p Resolv::DNS::Name.create("w.x.y.z").subdomain_of?(domain) #=> true
|
|
1047
|
+
# p Resolv::DNS::Name.create("x.y.z").subdomain_of?(domain) #=> true
|
|
1048
|
+
# p Resolv::DNS::Name.create("y.z").subdomain_of?(domain) #=> false
|
|
1049
|
+
# p Resolv::DNS::Name.create("z").subdomain_of?(domain) #=> false
|
|
1050
|
+
# p Resolv::DNS::Name.create("x.y.z.").subdomain_of?(domain) #=> false
|
|
1051
|
+
# p Resolv::DNS::Name.create("w.z").subdomain_of?(domain) #=> false
|
|
1052
|
+
#
|
|
1053
|
+
|
|
1054
|
+
def subdomain_of?(other)
|
|
1055
|
+
raise ArgumentError, "not a domain name: #{other.inspect}" unless Name === other
|
|
1056
|
+
return false if @absolute != other.absolute?
|
|
1057
|
+
other_len = other.length
|
|
1058
|
+
return false if @labels.length <= other_len
|
|
1059
|
+
return @labels[-other_len, other_len] == other.to_a
|
|
1060
|
+
end
|
|
1061
|
+
|
|
1062
|
+
def hash # :nodoc:
|
|
1063
|
+
return @labels.hash ^ @absolute.hash
|
|
1064
|
+
end
|
|
1065
|
+
|
|
1066
|
+
def to_a # :nodoc:
|
|
1067
|
+
return @labels
|
|
1068
|
+
end
|
|
1069
|
+
|
|
1070
|
+
def length # :nodoc:
|
|
1071
|
+
return @labels.length
|
|
1072
|
+
end
|
|
1073
|
+
|
|
1074
|
+
def [](i) # :nodoc:
|
|
1075
|
+
return @labels[i]
|
|
1076
|
+
end
|
|
1077
|
+
|
|
1078
|
+
##
|
|
1079
|
+
# returns the domain name as a string.
|
|
1080
|
+
#
|
|
1081
|
+
# The domain name doesn't have a trailing dot even if the name object is
|
|
1082
|
+
# absolute.
|
|
1083
|
+
#
|
|
1084
|
+
# Example:
|
|
1085
|
+
#
|
|
1086
|
+
# p Resolv::DNS::Name.create("x.y.z.").to_s #=> "x.y.z"
|
|
1087
|
+
# p Resolv::DNS::Name.create("x.y.z").to_s #=> "x.y.z"
|
|
1088
|
+
|
|
1089
|
+
def to_s
|
|
1090
|
+
return @labels.join('.')
|
|
1091
|
+
end
|
|
1092
|
+
end
|
|
1093
|
+
|
|
1094
|
+
class Message # :nodoc:
|
|
1095
|
+
@@identifier = -1
|
|
1096
|
+
|
|
1097
|
+
def initialize(id = (@@identifier += 1) & 0xffff)
|
|
1098
|
+
@id = id
|
|
1099
|
+
@qr = 0
|
|
1100
|
+
@opcode = 0
|
|
1101
|
+
@aa = 0
|
|
1102
|
+
@tc = 0
|
|
1103
|
+
@rd = 0 # recursion desired
|
|
1104
|
+
@ra = 0 # recursion available
|
|
1105
|
+
@rcode = 0
|
|
1106
|
+
@question = []
|
|
1107
|
+
@answer = []
|
|
1108
|
+
@authority = []
|
|
1109
|
+
@additional = []
|
|
1110
|
+
end
|
|
1111
|
+
|
|
1112
|
+
attr_accessor :id, :qr, :opcode, :aa, :tc, :rd, :ra, :rcode
|
|
1113
|
+
attr_reader :question, :answer, :authority, :additional
|
|
1114
|
+
|
|
1115
|
+
def ==(other)
|
|
1116
|
+
return @id == other.id &&
|
|
1117
|
+
@qr == other.qr &&
|
|
1118
|
+
@opcode == other.opcode &&
|
|
1119
|
+
@aa == other.aa &&
|
|
1120
|
+
@tc == other.tc &&
|
|
1121
|
+
@rd == other.rd &&
|
|
1122
|
+
@ra == other.ra &&
|
|
1123
|
+
@rcode == other.rcode &&
|
|
1124
|
+
@question == other.question &&
|
|
1125
|
+
@answer == other.answer &&
|
|
1126
|
+
@authority == other.authority &&
|
|
1127
|
+
@additional == other.additional
|
|
1128
|
+
end
|
|
1129
|
+
|
|
1130
|
+
def add_question(name, typeclass)
|
|
1131
|
+
@question << [Name.create(name), typeclass]
|
|
1132
|
+
end
|
|
1133
|
+
|
|
1134
|
+
def each_question
|
|
1135
|
+
@question.each {|name, typeclass|
|
|
1136
|
+
yield name, typeclass
|
|
1137
|
+
}
|
|
1138
|
+
end
|
|
1139
|
+
|
|
1140
|
+
def add_answer(name, ttl, data)
|
|
1141
|
+
@answer << [Name.create(name), ttl, data]
|
|
1142
|
+
end
|
|
1143
|
+
|
|
1144
|
+
def each_answer
|
|
1145
|
+
@answer.each {|name, ttl, data|
|
|
1146
|
+
yield name, ttl, data
|
|
1147
|
+
}
|
|
1148
|
+
end
|
|
1149
|
+
|
|
1150
|
+
def add_authority(name, ttl, data)
|
|
1151
|
+
@authority << [Name.create(name), ttl, data]
|
|
1152
|
+
end
|
|
1153
|
+
|
|
1154
|
+
def each_authority
|
|
1155
|
+
@authority.each {|name, ttl, data|
|
|
1156
|
+
yield name, ttl, data
|
|
1157
|
+
}
|
|
1158
|
+
end
|
|
1159
|
+
|
|
1160
|
+
def add_additional(name, ttl, data)
|
|
1161
|
+
@additional << [Name.create(name), ttl, data]
|
|
1162
|
+
end
|
|
1163
|
+
|
|
1164
|
+
def each_additional
|
|
1165
|
+
@additional.each {|name, ttl, data|
|
|
1166
|
+
yield name, ttl, data
|
|
1167
|
+
}
|
|
1168
|
+
end
|
|
1169
|
+
|
|
1170
|
+
def each_resource
|
|
1171
|
+
each_answer {|name, ttl, data| yield name, ttl, data}
|
|
1172
|
+
each_authority {|name, ttl, data| yield name, ttl, data}
|
|
1173
|
+
each_additional {|name, ttl, data| yield name, ttl, data}
|
|
1174
|
+
end
|
|
1175
|
+
|
|
1176
|
+
def encode
|
|
1177
|
+
return MessageEncoder.new {|msg|
|
|
1178
|
+
msg.put_pack('nnnnnn',
|
|
1179
|
+
@id,
|
|
1180
|
+
(@qr & 1) << 15 |
|
|
1181
|
+
(@opcode & 15) << 11 |
|
|
1182
|
+
(@aa & 1) << 10 |
|
|
1183
|
+
(@tc & 1) << 9 |
|
|
1184
|
+
(@rd & 1) << 8 |
|
|
1185
|
+
(@ra & 1) << 7 |
|
|
1186
|
+
(@rcode & 15),
|
|
1187
|
+
@question.length,
|
|
1188
|
+
@answer.length,
|
|
1189
|
+
@authority.length,
|
|
1190
|
+
@additional.length)
|
|
1191
|
+
@question.each {|q|
|
|
1192
|
+
name, typeclass = q
|
|
1193
|
+
msg.put_name(name)
|
|
1194
|
+
msg.put_pack('nn', typeclass::TypeValue, typeclass::ClassValue)
|
|
1195
|
+
}
|
|
1196
|
+
[@answer, @authority, @additional].each {|rr|
|
|
1197
|
+
rr.each {|r|
|
|
1198
|
+
name, ttl, data = r
|
|
1199
|
+
msg.put_name(name)
|
|
1200
|
+
msg.put_pack('nnN', data.class::TypeValue, data.class::ClassValue, ttl)
|
|
1201
|
+
msg.put_length16 {data.encode_rdata(msg)}
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
}.to_s
|
|
1205
|
+
end
|
|
1206
|
+
|
|
1207
|
+
class MessageEncoder # :nodoc:
|
|
1208
|
+
def initialize
|
|
1209
|
+
@data = ''
|
|
1210
|
+
@names = {}
|
|
1211
|
+
yield self
|
|
1212
|
+
end
|
|
1213
|
+
|
|
1214
|
+
def to_s
|
|
1215
|
+
return @data
|
|
1216
|
+
end
|
|
1217
|
+
|
|
1218
|
+
def put_bytes(d)
|
|
1219
|
+
@data << d
|
|
1220
|
+
end
|
|
1221
|
+
|
|
1222
|
+
def put_pack(template, *d)
|
|
1223
|
+
@data << d.pack(template)
|
|
1224
|
+
end
|
|
1225
|
+
|
|
1226
|
+
def put_length16
|
|
1227
|
+
length_index = @data.length
|
|
1228
|
+
@data << "\0\0"
|
|
1229
|
+
data_start = @data.length
|
|
1230
|
+
yield
|
|
1231
|
+
data_end = @data.length
|
|
1232
|
+
@data[length_index, 2] = [data_end - data_start].pack("n")
|
|
1233
|
+
end
|
|
1234
|
+
|
|
1235
|
+
def put_string(d)
|
|
1236
|
+
self.put_pack("C", d.length)
|
|
1237
|
+
@data << d
|
|
1238
|
+
end
|
|
1239
|
+
|
|
1240
|
+
def put_string_list(ds)
|
|
1241
|
+
ds.each {|d|
|
|
1242
|
+
self.put_string(d)
|
|
1243
|
+
}
|
|
1244
|
+
end
|
|
1245
|
+
|
|
1246
|
+
def put_name(d)
|
|
1247
|
+
put_labels(d.to_a)
|
|
1248
|
+
end
|
|
1249
|
+
|
|
1250
|
+
def put_labels(d)
|
|
1251
|
+
d.each_index {|i|
|
|
1252
|
+
domain = d[i..-1]
|
|
1253
|
+
if idx = @names[domain]
|
|
1254
|
+
self.put_pack("n", 0xc000 | idx)
|
|
1255
|
+
return
|
|
1256
|
+
else
|
|
1257
|
+
@names[domain] = @data.length
|
|
1258
|
+
self.put_label(d[i])
|
|
1259
|
+
end
|
|
1260
|
+
}
|
|
1261
|
+
@data << "\0"
|
|
1262
|
+
end
|
|
1263
|
+
|
|
1264
|
+
def put_label(d)
|
|
1265
|
+
self.put_string(d.to_s)
|
|
1266
|
+
end
|
|
1267
|
+
end
|
|
1268
|
+
|
|
1269
|
+
def Message.decode(m)
|
|
1270
|
+
o = Message.new(0)
|
|
1271
|
+
MessageDecoder.new(m) {|msg|
|
|
1272
|
+
id, flag, qdcount, ancount, nscount, arcount =
|
|
1273
|
+
msg.get_unpack('nnnnnn')
|
|
1274
|
+
o.id = id
|
|
1275
|
+
o.qr = (flag >> 15) & 1
|
|
1276
|
+
o.opcode = (flag >> 11) & 15
|
|
1277
|
+
o.aa = (flag >> 10) & 1
|
|
1278
|
+
o.tc = (flag >> 9) & 1
|
|
1279
|
+
o.rd = (flag >> 8) & 1
|
|
1280
|
+
o.ra = (flag >> 7) & 1
|
|
1281
|
+
o.rcode = flag & 15
|
|
1282
|
+
(1..qdcount).each {
|
|
1283
|
+
name, typeclass = msg.get_question
|
|
1284
|
+
o.add_question(name, typeclass)
|
|
1285
|
+
}
|
|
1286
|
+
(1..ancount).each {
|
|
1287
|
+
name, ttl, data = msg.get_rr
|
|
1288
|
+
o.add_answer(name, ttl, data)
|
|
1289
|
+
}
|
|
1290
|
+
(1..nscount).each {
|
|
1291
|
+
name, ttl, data = msg.get_rr
|
|
1292
|
+
o.add_authority(name, ttl, data)
|
|
1293
|
+
}
|
|
1294
|
+
(1..arcount).each {
|
|
1295
|
+
name, ttl, data = msg.get_rr
|
|
1296
|
+
o.add_additional(name, ttl, data)
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
return o
|
|
1300
|
+
end
|
|
1301
|
+
|
|
1302
|
+
class MessageDecoder # :nodoc:
|
|
1303
|
+
def initialize(data)
|
|
1304
|
+
@data = data
|
|
1305
|
+
@index = 0
|
|
1306
|
+
@limit = data.length
|
|
1307
|
+
yield self
|
|
1308
|
+
end
|
|
1309
|
+
|
|
1310
|
+
def get_length16
|
|
1311
|
+
len, = self.get_unpack('n')
|
|
1312
|
+
save_limit = @limit
|
|
1313
|
+
@limit = @index + len
|
|
1314
|
+
d = yield(len)
|
|
1315
|
+
if @index < @limit
|
|
1316
|
+
raise DecodeError.new("junk exists")
|
|
1317
|
+
elsif @limit < @index
|
|
1318
|
+
raise DecodeError.new("limit exceeded")
|
|
1319
|
+
end
|
|
1320
|
+
@limit = save_limit
|
|
1321
|
+
return d
|
|
1322
|
+
end
|
|
1323
|
+
|
|
1324
|
+
def get_bytes(len = @limit - @index)
|
|
1325
|
+
d = @data[@index, len]
|
|
1326
|
+
@index += len
|
|
1327
|
+
return d
|
|
1328
|
+
end
|
|
1329
|
+
|
|
1330
|
+
def get_unpack(template)
|
|
1331
|
+
len = 0
|
|
1332
|
+
template.each_byte {|byte|
|
|
1333
|
+
case byte
|
|
1334
|
+
when ?c, ?C
|
|
1335
|
+
len += 1
|
|
1336
|
+
when ?n
|
|
1337
|
+
len += 2
|
|
1338
|
+
when ?N
|
|
1339
|
+
len += 4
|
|
1340
|
+
else
|
|
1341
|
+
raise StandardError.new("unsupported template: '#{byte.chr}' in '#{template}'")
|
|
1342
|
+
end
|
|
1343
|
+
}
|
|
1344
|
+
raise DecodeError.new("limit exceeded") if @limit < @index + len
|
|
1345
|
+
arr = @data.unpack("@#{@index}#{template}")
|
|
1346
|
+
@index += len
|
|
1347
|
+
return arr
|
|
1348
|
+
end
|
|
1349
|
+
|
|
1350
|
+
def get_string
|
|
1351
|
+
len = @data[@index]
|
|
1352
|
+
raise DecodeError.new("limit exceeded") if @limit < @index + 1 + len
|
|
1353
|
+
d = @data[@index + 1, len]
|
|
1354
|
+
@index += 1 + len
|
|
1355
|
+
return d
|
|
1356
|
+
end
|
|
1357
|
+
|
|
1358
|
+
def get_string_list
|
|
1359
|
+
strings = []
|
|
1360
|
+
while @index < @limit
|
|
1361
|
+
strings << self.get_string
|
|
1362
|
+
end
|
|
1363
|
+
strings
|
|
1364
|
+
end
|
|
1365
|
+
|
|
1366
|
+
def get_name
|
|
1367
|
+
return Name.new(self.get_labels)
|
|
1368
|
+
end
|
|
1369
|
+
|
|
1370
|
+
def get_labels(limit=nil)
|
|
1371
|
+
limit = @index if !limit || @index < limit
|
|
1372
|
+
d = []
|
|
1373
|
+
while true
|
|
1374
|
+
case @data[@index]
|
|
1375
|
+
when 0
|
|
1376
|
+
@index += 1
|
|
1377
|
+
return d
|
|
1378
|
+
when 192..255
|
|
1379
|
+
idx = self.get_unpack('n')[0] & 0x3fff
|
|
1380
|
+
if limit <= idx
|
|
1381
|
+
raise DecodeError.new("non-backward name pointer")
|
|
1382
|
+
end
|
|
1383
|
+
save_index = @index
|
|
1384
|
+
@index = idx
|
|
1385
|
+
d += self.get_labels(limit)
|
|
1386
|
+
@index = save_index
|
|
1387
|
+
return d
|
|
1388
|
+
else
|
|
1389
|
+
d << self.get_label
|
|
1390
|
+
end
|
|
1391
|
+
end
|
|
1392
|
+
return d
|
|
1393
|
+
end
|
|
1394
|
+
|
|
1395
|
+
def get_label
|
|
1396
|
+
return Label::Str.new(self.get_string)
|
|
1397
|
+
end
|
|
1398
|
+
|
|
1399
|
+
def get_question
|
|
1400
|
+
name = self.get_name
|
|
1401
|
+
type, klass = self.get_unpack("nn")
|
|
1402
|
+
return name, Resource.get_class(type, klass)
|
|
1403
|
+
end
|
|
1404
|
+
|
|
1405
|
+
def get_rr
|
|
1406
|
+
name = self.get_name
|
|
1407
|
+
type, klass, ttl = self.get_unpack('nnN')
|
|
1408
|
+
typeclass = Resource.get_class(type, klass)
|
|
1409
|
+
return name, ttl, self.get_length16 {typeclass.decode_rdata(self)}
|
|
1410
|
+
end
|
|
1411
|
+
end
|
|
1412
|
+
end
|
|
1413
|
+
|
|
1414
|
+
##
|
|
1415
|
+
# A DNS query abstract class.
|
|
1416
|
+
|
|
1417
|
+
class Query
|
|
1418
|
+
def encode_rdata(msg) # :nodoc:
|
|
1419
|
+
raise EncodeError.new("#{self.class} is query.")
|
|
1420
|
+
end
|
|
1421
|
+
|
|
1422
|
+
def self.decode_rdata(msg) # :nodoc:
|
|
1423
|
+
raise DecodeError.new("#{self.class} is query.")
|
|
1424
|
+
end
|
|
1425
|
+
end
|
|
1426
|
+
|
|
1427
|
+
##
|
|
1428
|
+
# A DNS resource abstract class.
|
|
1429
|
+
|
|
1430
|
+
class Resource < Query
|
|
1431
|
+
|
|
1432
|
+
##
|
|
1433
|
+
# Remaining Time To Live for this Resource.
|
|
1434
|
+
|
|
1435
|
+
attr_reader :ttl
|
|
1436
|
+
|
|
1437
|
+
ClassHash = {} # :nodoc:
|
|
1438
|
+
|
|
1439
|
+
def encode_rdata(msg) # :nodoc:
|
|
1440
|
+
raise NotImplementedError.new
|
|
1441
|
+
end
|
|
1442
|
+
|
|
1443
|
+
def self.decode_rdata(msg) # :nodoc:
|
|
1444
|
+
raise NotImplementedError.new
|
|
1445
|
+
end
|
|
1446
|
+
|
|
1447
|
+
def ==(other) # :nodoc:
|
|
1448
|
+
return self.class == other.class &&
|
|
1449
|
+
self.instance_variables == other.instance_variables &&
|
|
1450
|
+
self.instance_variables.collect {|name| self.instance_eval name} ==
|
|
1451
|
+
other.instance_variables.collect {|name| other.instance_eval name}
|
|
1452
|
+
end
|
|
1453
|
+
|
|
1454
|
+
def eql?(other) # :nodoc:
|
|
1455
|
+
return self == other
|
|
1456
|
+
end
|
|
1457
|
+
|
|
1458
|
+
def hash # :nodoc:
|
|
1459
|
+
h = 0
|
|
1460
|
+
self.instance_variables.each {|name|
|
|
1461
|
+
h ^= self.instance_eval("#{name}.hash")
|
|
1462
|
+
}
|
|
1463
|
+
return h
|
|
1464
|
+
end
|
|
1465
|
+
|
|
1466
|
+
def self.get_class(type_value, class_value) # :nodoc:
|
|
1467
|
+
return ClassHash[[type_value, class_value]] ||
|
|
1468
|
+
Generic.create(type_value, class_value)
|
|
1469
|
+
end
|
|
1470
|
+
|
|
1471
|
+
##
|
|
1472
|
+
# A generic resource abstract class.
|
|
1473
|
+
|
|
1474
|
+
class Generic < Resource
|
|
1475
|
+
|
|
1476
|
+
##
|
|
1477
|
+
# Creates a new generic resource.
|
|
1478
|
+
|
|
1479
|
+
def initialize(data)
|
|
1480
|
+
@data = data
|
|
1481
|
+
end
|
|
1482
|
+
|
|
1483
|
+
##
|
|
1484
|
+
# Data for this generic resource.
|
|
1485
|
+
|
|
1486
|
+
attr_reader :data
|
|
1487
|
+
|
|
1488
|
+
def encode_rdata(msg) # :nodoc:
|
|
1489
|
+
msg.put_bytes(data)
|
|
1490
|
+
end
|
|
1491
|
+
|
|
1492
|
+
def self.decode_rdata(msg) # :nodoc:
|
|
1493
|
+
return self.new(msg.get_bytes)
|
|
1494
|
+
end
|
|
1495
|
+
|
|
1496
|
+
def self.create(type_value, class_value) # :nodoc:
|
|
1497
|
+
c = Class.new(Generic)
|
|
1498
|
+
c.const_set(:TypeValue, type_value)
|
|
1499
|
+
c.const_set(:ClassValue, class_value)
|
|
1500
|
+
Generic.const_set("Type#{type_value}_Class#{class_value}", c)
|
|
1501
|
+
ClassHash[[type_value, class_value]] = c
|
|
1502
|
+
return c
|
|
1503
|
+
end
|
|
1504
|
+
end
|
|
1505
|
+
|
|
1506
|
+
##
|
|
1507
|
+
# Domain Name resource abstract class.
|
|
1508
|
+
|
|
1509
|
+
class DomainName < Resource
|
|
1510
|
+
|
|
1511
|
+
##
|
|
1512
|
+
# Creates a new DomainName from +name+.
|
|
1513
|
+
|
|
1514
|
+
def initialize(name)
|
|
1515
|
+
@name = name
|
|
1516
|
+
end
|
|
1517
|
+
|
|
1518
|
+
##
|
|
1519
|
+
# The name of this DomainName.
|
|
1520
|
+
|
|
1521
|
+
attr_reader :name
|
|
1522
|
+
|
|
1523
|
+
def encode_rdata(msg) # :nodoc:
|
|
1524
|
+
msg.put_name(@name)
|
|
1525
|
+
end
|
|
1526
|
+
|
|
1527
|
+
def self.decode_rdata(msg) # :nodoc:
|
|
1528
|
+
return self.new(msg.get_name)
|
|
1529
|
+
end
|
|
1530
|
+
end
|
|
1531
|
+
|
|
1532
|
+
# Standard (class generic) RRs
|
|
1533
|
+
|
|
1534
|
+
ClassValue = nil # :nodoc:
|
|
1535
|
+
|
|
1536
|
+
##
|
|
1537
|
+
# An authoritative name server.
|
|
1538
|
+
|
|
1539
|
+
class NS < DomainName
|
|
1540
|
+
TypeValue = 2 # :nodoc:
|
|
1541
|
+
end
|
|
1542
|
+
|
|
1543
|
+
##
|
|
1544
|
+
# The canonical name for an alias.
|
|
1545
|
+
|
|
1546
|
+
class CNAME < DomainName
|
|
1547
|
+
TypeValue = 5 # :nodoc:
|
|
1548
|
+
end
|
|
1549
|
+
|
|
1550
|
+
##
|
|
1551
|
+
# Start Of Authority resource.
|
|
1552
|
+
|
|
1553
|
+
class SOA < Resource
|
|
1554
|
+
|
|
1555
|
+
TypeValue = 6 # :nodoc:
|
|
1556
|
+
|
|
1557
|
+
##
|
|
1558
|
+
# Creates a new SOA record. See the attr documentation for the
|
|
1559
|
+
# details of each argument.
|
|
1560
|
+
|
|
1561
|
+
def initialize(mname, rname, serial, refresh, retry_, expire, minimum)
|
|
1562
|
+
@mname = mname
|
|
1563
|
+
@rname = rname
|
|
1564
|
+
@serial = serial
|
|
1565
|
+
@refresh = refresh
|
|
1566
|
+
@retry = retry_
|
|
1567
|
+
@expire = expire
|
|
1568
|
+
@minimum = minimum
|
|
1569
|
+
end
|
|
1570
|
+
|
|
1571
|
+
##
|
|
1572
|
+
# Name of the host where the master zone file for this zone resides.
|
|
1573
|
+
|
|
1574
|
+
attr_reader :mname
|
|
1575
|
+
|
|
1576
|
+
##
|
|
1577
|
+
# The person responsible for this domain name.
|
|
1578
|
+
|
|
1579
|
+
attr_reader :rname
|
|
1580
|
+
|
|
1581
|
+
##
|
|
1582
|
+
# The version number of the zone file.
|
|
1583
|
+
|
|
1584
|
+
attr_reader :serial
|
|
1585
|
+
|
|
1586
|
+
##
|
|
1587
|
+
# How often, in seconds, a secondary name server is to check for
|
|
1588
|
+
# updates from the primary name server.
|
|
1589
|
+
|
|
1590
|
+
attr_reader :refresh
|
|
1591
|
+
|
|
1592
|
+
##
|
|
1593
|
+
# How often, in seconds, a secondary name server is to retry after a
|
|
1594
|
+
# failure to check for a refresh.
|
|
1595
|
+
|
|
1596
|
+
attr_reader :retry
|
|
1597
|
+
|
|
1598
|
+
##
|
|
1599
|
+
# Time in seconds that a secondary name server is to use the data
|
|
1600
|
+
# before refreshing from the primary name server.
|
|
1601
|
+
|
|
1602
|
+
attr_reader :expire
|
|
1603
|
+
|
|
1604
|
+
##
|
|
1605
|
+
# The minimum number of seconds to be used for TTL values in RRs.
|
|
1606
|
+
|
|
1607
|
+
attr_reader :minimum
|
|
1608
|
+
|
|
1609
|
+
def encode_rdata(msg) # :nodoc:
|
|
1610
|
+
msg.put_name(@mname)
|
|
1611
|
+
msg.put_name(@rname)
|
|
1612
|
+
msg.put_pack('NNNNN', @serial, @refresh, @retry, @expire, @minimum)
|
|
1613
|
+
end
|
|
1614
|
+
|
|
1615
|
+
def self.decode_rdata(msg) # :nodoc:
|
|
1616
|
+
mname = msg.get_name
|
|
1617
|
+
rname = msg.get_name
|
|
1618
|
+
serial, refresh, retry_, expire, minimum = msg.get_unpack('NNNNN')
|
|
1619
|
+
return self.new(
|
|
1620
|
+
mname, rname, serial, refresh, retry_, expire, minimum)
|
|
1621
|
+
end
|
|
1622
|
+
end
|
|
1623
|
+
|
|
1624
|
+
##
|
|
1625
|
+
# A Pointer to another DNS name.
|
|
1626
|
+
|
|
1627
|
+
class PTR < DomainName
|
|
1628
|
+
TypeValue = 12 # :nodoc:
|
|
1629
|
+
end
|
|
1630
|
+
|
|
1631
|
+
##
|
|
1632
|
+
# Host Information resource.
|
|
1633
|
+
|
|
1634
|
+
class HINFO < Resource
|
|
1635
|
+
|
|
1636
|
+
TypeValue = 13 # :nodoc:
|
|
1637
|
+
|
|
1638
|
+
##
|
|
1639
|
+
# Creates a new HINFO running +os+ on +cpu+.
|
|
1640
|
+
|
|
1641
|
+
def initialize(cpu, os)
|
|
1642
|
+
@cpu = cpu
|
|
1643
|
+
@os = os
|
|
1644
|
+
end
|
|
1645
|
+
|
|
1646
|
+
##
|
|
1647
|
+
# CPU architecture for this resource.
|
|
1648
|
+
|
|
1649
|
+
attr_reader :cpu
|
|
1650
|
+
|
|
1651
|
+
##
|
|
1652
|
+
# Operating system for this resource.
|
|
1653
|
+
|
|
1654
|
+
attr_reader :os
|
|
1655
|
+
|
|
1656
|
+
def encode_rdata(msg) # :nodoc:
|
|
1657
|
+
msg.put_string(@cpu)
|
|
1658
|
+
msg.put_string(@os)
|
|
1659
|
+
end
|
|
1660
|
+
|
|
1661
|
+
def self.decode_rdata(msg) # :nodoc:
|
|
1662
|
+
cpu = msg.get_string
|
|
1663
|
+
os = msg.get_string
|
|
1664
|
+
return self.new(cpu, os)
|
|
1665
|
+
end
|
|
1666
|
+
end
|
|
1667
|
+
|
|
1668
|
+
##
|
|
1669
|
+
# Mailing list or mailbox information.
|
|
1670
|
+
|
|
1671
|
+
class MINFO < Resource
|
|
1672
|
+
|
|
1673
|
+
TypeValue = 14 # :nodoc:
|
|
1674
|
+
|
|
1675
|
+
def initialize(rmailbx, emailbx)
|
|
1676
|
+
@rmailbx = rmailbx
|
|
1677
|
+
@emailbx = emailbx
|
|
1678
|
+
end
|
|
1679
|
+
|
|
1680
|
+
##
|
|
1681
|
+
# Domain name responsible for this mail list or mailbox.
|
|
1682
|
+
|
|
1683
|
+
attr_reader :rmailbx
|
|
1684
|
+
|
|
1685
|
+
##
|
|
1686
|
+
# Mailbox to use for error messages related to the mail list or mailbox.
|
|
1687
|
+
|
|
1688
|
+
attr_reader :emailbx
|
|
1689
|
+
|
|
1690
|
+
def encode_rdata(msg) # :nodoc:
|
|
1691
|
+
msg.put_name(@rmailbx)
|
|
1692
|
+
msg.put_name(@emailbx)
|
|
1693
|
+
end
|
|
1694
|
+
|
|
1695
|
+
def self.decode_rdata(msg) # :nodoc:
|
|
1696
|
+
rmailbx = msg.get_string
|
|
1697
|
+
emailbx = msg.get_string
|
|
1698
|
+
return self.new(rmailbx, emailbx)
|
|
1699
|
+
end
|
|
1700
|
+
end
|
|
1701
|
+
|
|
1702
|
+
##
|
|
1703
|
+
# Mail Exchanger resource.
|
|
1704
|
+
|
|
1705
|
+
class MX < Resource
|
|
1706
|
+
|
|
1707
|
+
TypeValue= 15 # :nodoc:
|
|
1708
|
+
|
|
1709
|
+
##
|
|
1710
|
+
# Creates a new MX record with +preference+, accepting mail at
|
|
1711
|
+
# +exchange+.
|
|
1712
|
+
|
|
1713
|
+
def initialize(preference, exchange)
|
|
1714
|
+
@preference = preference
|
|
1715
|
+
@exchange = exchange
|
|
1716
|
+
end
|
|
1717
|
+
|
|
1718
|
+
##
|
|
1719
|
+
# The preference for this MX.
|
|
1720
|
+
|
|
1721
|
+
attr_reader :preference
|
|
1722
|
+
|
|
1723
|
+
##
|
|
1724
|
+
# The host of this MX.
|
|
1725
|
+
|
|
1726
|
+
attr_reader :exchange
|
|
1727
|
+
|
|
1728
|
+
def encode_rdata(msg) # :nodoc:
|
|
1729
|
+
msg.put_pack('n', @preference)
|
|
1730
|
+
msg.put_name(@exchange)
|
|
1731
|
+
end
|
|
1732
|
+
|
|
1733
|
+
def self.decode_rdata(msg) # :nodoc:
|
|
1734
|
+
preference, = msg.get_unpack('n')
|
|
1735
|
+
exchange = msg.get_name
|
|
1736
|
+
return self.new(preference, exchange)
|
|
1737
|
+
end
|
|
1738
|
+
end
|
|
1739
|
+
|
|
1740
|
+
##
|
|
1741
|
+
# Unstructured text resource.
|
|
1742
|
+
|
|
1743
|
+
class TXT < Resource
|
|
1744
|
+
|
|
1745
|
+
TypeValue = 16 # :nodoc:
|
|
1746
|
+
|
|
1747
|
+
def initialize(first_string, *rest_strings)
|
|
1748
|
+
@strings = [first_string, *rest_strings]
|
|
1749
|
+
end
|
|
1750
|
+
|
|
1751
|
+
##
|
|
1752
|
+
# Returns an Array of Strings for this TXT record.
|
|
1753
|
+
|
|
1754
|
+
attr_reader :strings
|
|
1755
|
+
|
|
1756
|
+
##
|
|
1757
|
+
# Returns the first string from +strings+.
|
|
1758
|
+
|
|
1759
|
+
def data
|
|
1760
|
+
@strings[0]
|
|
1761
|
+
end
|
|
1762
|
+
|
|
1763
|
+
def encode_rdata(msg) # :nodoc:
|
|
1764
|
+
msg.put_string_list(@strings)
|
|
1765
|
+
end
|
|
1766
|
+
|
|
1767
|
+
def self.decode_rdata(msg) # :nodoc:
|
|
1768
|
+
strings = msg.get_string_list
|
|
1769
|
+
return self.new(*strings)
|
|
1770
|
+
end
|
|
1771
|
+
end
|
|
1772
|
+
|
|
1773
|
+
##
|
|
1774
|
+
# A Query type requesting any RR.
|
|
1775
|
+
|
|
1776
|
+
class ANY < Query
|
|
1777
|
+
TypeValue = 255 # :nodoc:
|
|
1778
|
+
end
|
|
1779
|
+
|
|
1780
|
+
ClassInsensitiveTypes = [ # :nodoc:
|
|
1781
|
+
NS, CNAME, SOA, PTR, HINFO, MINFO, MX, TXT, ANY
|
|
1782
|
+
]
|
|
1783
|
+
|
|
1784
|
+
##
|
|
1785
|
+
# module IN contains ARPA Internet specific RRs.
|
|
1786
|
+
|
|
1787
|
+
module IN
|
|
1788
|
+
|
|
1789
|
+
ClassValue = 1 # :nodoc:
|
|
1790
|
+
|
|
1791
|
+
ClassInsensitiveTypes.each {|s|
|
|
1792
|
+
c = Class.new(s)
|
|
1793
|
+
c.const_set(:TypeValue, s::TypeValue)
|
|
1794
|
+
c.const_set(:ClassValue, ClassValue)
|
|
1795
|
+
ClassHash[[s::TypeValue, ClassValue]] = c
|
|
1796
|
+
self.const_set(s.name.sub(/.*::/, ''), c)
|
|
1797
|
+
}
|
|
1798
|
+
|
|
1799
|
+
##
|
|
1800
|
+
# IPv4 Address resource
|
|
1801
|
+
|
|
1802
|
+
class A < Resource
|
|
1803
|
+
TypeValue = 1
|
|
1804
|
+
ClassValue = IN::ClassValue
|
|
1805
|
+
ClassHash[[TypeValue, ClassValue]] = self # :nodoc:
|
|
1806
|
+
|
|
1807
|
+
##
|
|
1808
|
+
# Creates a new A for +address+.
|
|
1809
|
+
|
|
1810
|
+
def initialize(address)
|
|
1811
|
+
@address = IPv4.create(address)
|
|
1812
|
+
end
|
|
1813
|
+
|
|
1814
|
+
##
|
|
1815
|
+
# The Resolv::IPv4 address for this A.
|
|
1816
|
+
|
|
1817
|
+
attr_reader :address
|
|
1818
|
+
|
|
1819
|
+
def encode_rdata(msg) # :nodoc:
|
|
1820
|
+
msg.put_bytes(@address.address)
|
|
1821
|
+
end
|
|
1822
|
+
|
|
1823
|
+
def self.decode_rdata(msg) # :nodoc:
|
|
1824
|
+
return self.new(IPv4.new(msg.get_bytes(4)))
|
|
1825
|
+
end
|
|
1826
|
+
end
|
|
1827
|
+
|
|
1828
|
+
##
|
|
1829
|
+
# Well Known Service resource.
|
|
1830
|
+
|
|
1831
|
+
class WKS < Resource
|
|
1832
|
+
TypeValue = 11
|
|
1833
|
+
ClassValue = IN::ClassValue
|
|
1834
|
+
ClassHash[[TypeValue, ClassValue]] = self # :nodoc:
|
|
1835
|
+
|
|
1836
|
+
def initialize(address, protocol, bitmap)
|
|
1837
|
+
@address = IPv4.create(address)
|
|
1838
|
+
@protocol = protocol
|
|
1839
|
+
@bitmap = bitmap
|
|
1840
|
+
end
|
|
1841
|
+
|
|
1842
|
+
##
|
|
1843
|
+
# The host these services run on.
|
|
1844
|
+
|
|
1845
|
+
attr_reader :address
|
|
1846
|
+
|
|
1847
|
+
##
|
|
1848
|
+
# IP protocol number for these services.
|
|
1849
|
+
|
|
1850
|
+
attr_reader :protocol
|
|
1851
|
+
|
|
1852
|
+
##
|
|
1853
|
+
# A bit map of enabled services on this host.
|
|
1854
|
+
#
|
|
1855
|
+
# If protocol is 6 (TCP) then the 26th bit corresponds to the SMTP
|
|
1856
|
+
# service (port 25). If this bit is set, then an SMTP server should
|
|
1857
|
+
# be listening on TCP port 25; if zero, SMTP service is not
|
|
1858
|
+
# supported.
|
|
1859
|
+
|
|
1860
|
+
attr_reader :bitmap
|
|
1861
|
+
|
|
1862
|
+
def encode_rdata(msg) # :nodoc:
|
|
1863
|
+
msg.put_bytes(@address.address)
|
|
1864
|
+
msg.put_pack("n", @protocol)
|
|
1865
|
+
msg.put_bytes(@bitmap)
|
|
1866
|
+
end
|
|
1867
|
+
|
|
1868
|
+
def self.decode_rdata(msg) # :nodoc:
|
|
1869
|
+
address = IPv4.new(msg.get_bytes(4))
|
|
1870
|
+
protocol, = msg.get_unpack("n")
|
|
1871
|
+
bitmap = msg.get_bytes
|
|
1872
|
+
return self.new(address, protocol, bitmap)
|
|
1873
|
+
end
|
|
1874
|
+
end
|
|
1875
|
+
|
|
1876
|
+
##
|
|
1877
|
+
# An IPv6 address record.
|
|
1878
|
+
|
|
1879
|
+
class AAAA < Resource
|
|
1880
|
+
TypeValue = 28
|
|
1881
|
+
ClassValue = IN::ClassValue
|
|
1882
|
+
ClassHash[[TypeValue, ClassValue]] = self # :nodoc:
|
|
1883
|
+
|
|
1884
|
+
##
|
|
1885
|
+
# Creates a new AAAA for +address+.
|
|
1886
|
+
|
|
1887
|
+
def initialize(address)
|
|
1888
|
+
@address = IPv6.create(address)
|
|
1889
|
+
end
|
|
1890
|
+
|
|
1891
|
+
##
|
|
1892
|
+
# The Resolv::IPv6 address for this AAAA.
|
|
1893
|
+
|
|
1894
|
+
attr_reader :address
|
|
1895
|
+
|
|
1896
|
+
def encode_rdata(msg) # :nodoc:
|
|
1897
|
+
msg.put_bytes(@address.address)
|
|
1898
|
+
end
|
|
1899
|
+
|
|
1900
|
+
def self.decode_rdata(msg) # :nodoc:
|
|
1901
|
+
return self.new(IPv6.new(msg.get_bytes(16)))
|
|
1902
|
+
end
|
|
1903
|
+
end
|
|
1904
|
+
|
|
1905
|
+
##
|
|
1906
|
+
# SRV resource record defined in RFC 2782
|
|
1907
|
+
#
|
|
1908
|
+
# These records identify the hostname and port that a service is
|
|
1909
|
+
# available at.
|
|
1910
|
+
|
|
1911
|
+
class SRV < Resource
|
|
1912
|
+
TypeValue = 33
|
|
1913
|
+
ClassValue = IN::ClassValue
|
|
1914
|
+
ClassHash[[TypeValue, ClassValue]] = self # :nodoc:
|
|
1915
|
+
|
|
1916
|
+
# Create a SRV resource record.
|
|
1917
|
+
#
|
|
1918
|
+
# See the documentation for #priority, #weight, #port and #target
|
|
1919
|
+
# for +priority+, +weight+, +port and +target+ respectively.
|
|
1920
|
+
|
|
1921
|
+
def initialize(priority, weight, port, target)
|
|
1922
|
+
@priority = priority.to_int
|
|
1923
|
+
@weight = weight.to_int
|
|
1924
|
+
@port = port.to_int
|
|
1925
|
+
@target = Name.create(target)
|
|
1926
|
+
end
|
|
1927
|
+
|
|
1928
|
+
# The priority of this target host.
|
|
1929
|
+
#
|
|
1930
|
+
# A client MUST attempt to contact the target host with the
|
|
1931
|
+
# lowest-numbered priority it can reach; target hosts with the same
|
|
1932
|
+
# priority SHOULD be tried in an order defined by the weight field.
|
|
1933
|
+
# The range is 0-65535. Note that it is not widely implemented and
|
|
1934
|
+
# should be set to zero.
|
|
1935
|
+
|
|
1936
|
+
attr_reader :priority
|
|
1937
|
+
|
|
1938
|
+
# A server selection mechanism.
|
|
1939
|
+
#
|
|
1940
|
+
# The weight field specifies a relative weight for entries with the
|
|
1941
|
+
# same priority. Larger weights SHOULD be given a proportionately
|
|
1942
|
+
# higher probability of being selected. The range of this number is
|
|
1943
|
+
# 0-65535. Domain administrators SHOULD use Weight 0 when there
|
|
1944
|
+
# isn't any server selection to do, to make the RR easier to read
|
|
1945
|
+
# for humans (less noisy). Note that it is not widely implemented
|
|
1946
|
+
# and should be set to zero.
|
|
1947
|
+
|
|
1948
|
+
attr_reader :weight
|
|
1949
|
+
|
|
1950
|
+
# The port on this target host of this service.
|
|
1951
|
+
#
|
|
1952
|
+
# The range is 0-65535.
|
|
1953
|
+
|
|
1954
|
+
attr_reader :port
|
|
1955
|
+
|
|
1956
|
+
# The domain name of the target host.
|
|
1957
|
+
#
|
|
1958
|
+
# A target of "." means that the service is decidedly not available
|
|
1959
|
+
# at this domain.
|
|
1960
|
+
|
|
1961
|
+
attr_reader :target
|
|
1962
|
+
|
|
1963
|
+
def encode_rdata(msg) # :nodoc:
|
|
1964
|
+
msg.put_pack("n", @priority)
|
|
1965
|
+
msg.put_pack("n", @weight)
|
|
1966
|
+
msg.put_pack("n", @port)
|
|
1967
|
+
msg.put_name(@target)
|
|
1968
|
+
end
|
|
1969
|
+
|
|
1970
|
+
def self.decode_rdata(msg) # :nodoc:
|
|
1971
|
+
priority, = msg.get_unpack("n")
|
|
1972
|
+
weight, = msg.get_unpack("n")
|
|
1973
|
+
port, = msg.get_unpack("n")
|
|
1974
|
+
target = msg.get_name
|
|
1975
|
+
return self.new(priority, weight, port, target)
|
|
1976
|
+
end
|
|
1977
|
+
end
|
|
1978
|
+
end
|
|
1979
|
+
end
|
|
1980
|
+
end
|
|
1981
|
+
|
|
1982
|
+
##
|
|
1983
|
+
# A Resolv::DNS IPv4 address.
|
|
1984
|
+
|
|
1985
|
+
class IPv4
|
|
1986
|
+
|
|
1987
|
+
##
|
|
1988
|
+
# Regular expression IPv4 addresses must match.
|
|
1989
|
+
|
|
1990
|
+
Regex = /\A(\d+)\.(\d+)\.(\d+)\.(\d+)\z/
|
|
1991
|
+
|
|
1992
|
+
def self.create(arg)
|
|
1993
|
+
case arg
|
|
1994
|
+
when IPv4
|
|
1995
|
+
return arg
|
|
1996
|
+
when Regex
|
|
1997
|
+
if (0..255) === (a = $1.to_i) &&
|
|
1998
|
+
(0..255) === (b = $2.to_i) &&
|
|
1999
|
+
(0..255) === (c = $3.to_i) &&
|
|
2000
|
+
(0..255) === (d = $4.to_i)
|
|
2001
|
+
return self.new([a, b, c, d].pack("CCCC"))
|
|
2002
|
+
else
|
|
2003
|
+
raise ArgumentError.new("IPv4 address with invalid value: " + arg)
|
|
2004
|
+
end
|
|
2005
|
+
else
|
|
2006
|
+
raise ArgumentError.new("cannot interpret as IPv4 address: #{arg.inspect}")
|
|
2007
|
+
end
|
|
2008
|
+
end
|
|
2009
|
+
|
|
2010
|
+
def initialize(address) # :nodoc:
|
|
2011
|
+
unless address.kind_of?(String) && address.length == 4
|
|
2012
|
+
raise ArgumentError.new('IPv4 address must be 4 bytes')
|
|
2013
|
+
end
|
|
2014
|
+
@address = address
|
|
2015
|
+
end
|
|
2016
|
+
|
|
2017
|
+
##
|
|
2018
|
+
# A String reperesentation of this IPv4 address.
|
|
2019
|
+
|
|
2020
|
+
##
|
|
2021
|
+
# The raw IPv4 address as a String.
|
|
2022
|
+
|
|
2023
|
+
attr_reader :address
|
|
2024
|
+
|
|
2025
|
+
def to_s # :nodoc:
|
|
2026
|
+
return sprintf("%d.%d.%d.%d", *@address.unpack("CCCC"))
|
|
2027
|
+
end
|
|
2028
|
+
|
|
2029
|
+
def inspect # :nodoc:
|
|
2030
|
+
return "#<#{self.class} #{self.to_s}>"
|
|
2031
|
+
end
|
|
2032
|
+
|
|
2033
|
+
##
|
|
2034
|
+
# Turns this IPv4 address into a Resolv::DNS::Name.
|
|
2035
|
+
|
|
2036
|
+
def to_name
|
|
2037
|
+
return DNS::Name.create(
|
|
2038
|
+
'%d.%d.%d.%d.in-addr.arpa.' % @address.unpack('CCCC').reverse)
|
|
2039
|
+
end
|
|
2040
|
+
|
|
2041
|
+
def ==(other) # :nodoc:
|
|
2042
|
+
return @address == other.address
|
|
2043
|
+
end
|
|
2044
|
+
|
|
2045
|
+
def eql?(other) # :nodoc:
|
|
2046
|
+
return self == other
|
|
2047
|
+
end
|
|
2048
|
+
|
|
2049
|
+
def hash # :nodoc:
|
|
2050
|
+
return @address.hash
|
|
2051
|
+
end
|
|
2052
|
+
end
|
|
2053
|
+
|
|
2054
|
+
##
|
|
2055
|
+
# A Resolv::DNS IPv6 address.
|
|
2056
|
+
|
|
2057
|
+
class IPv6
|
|
2058
|
+
|
|
2059
|
+
##
|
|
2060
|
+
# IPv6 address format a:b:c:d:e:f:g:h
|
|
2061
|
+
Regex_8Hex = /\A
|
|
2062
|
+
(?:[0-9A-Fa-f]{1,4}:){7}
|
|
2063
|
+
[0-9A-Fa-f]{1,4}
|
|
2064
|
+
\z/x
|
|
2065
|
+
|
|
2066
|
+
##
|
|
2067
|
+
# Compressed IPv6 address format a::b
|
|
2068
|
+
|
|
2069
|
+
Regex_CompressedHex = /\A
|
|
2070
|
+
((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?) ::
|
|
2071
|
+
((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)
|
|
2072
|
+
\z/x
|
|
2073
|
+
|
|
2074
|
+
##
|
|
2075
|
+
# IPv4 mapped IPv6 address format a:b:c:d:e:f:w.x.y.z
|
|
2076
|
+
|
|
2077
|
+
Regex_6Hex4Dec = /\A
|
|
2078
|
+
((?:[0-9A-Fa-f]{1,4}:){6,6})
|
|
2079
|
+
(\d+)\.(\d+)\.(\d+)\.(\d+)
|
|
2080
|
+
\z/x
|
|
2081
|
+
|
|
2082
|
+
##
|
|
2083
|
+
# Compressed IPv4 mapped IPv6 address format a::b:w.x.y.z
|
|
2084
|
+
|
|
2085
|
+
Regex_CompressedHex4Dec = /\A
|
|
2086
|
+
((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?) ::
|
|
2087
|
+
((?:[0-9A-Fa-f]{1,4}:)*)
|
|
2088
|
+
(\d+)\.(\d+)\.(\d+)\.(\d+)
|
|
2089
|
+
\z/x
|
|
2090
|
+
|
|
2091
|
+
##
|
|
2092
|
+
# A composite IPv6 address Regexp.
|
|
2093
|
+
|
|
2094
|
+
Regex = /
|
|
2095
|
+
(?:#{Regex_8Hex}) |
|
|
2096
|
+
(?:#{Regex_CompressedHex}) |
|
|
2097
|
+
(?:#{Regex_6Hex4Dec}) |
|
|
2098
|
+
(?:#{Regex_CompressedHex4Dec})/x
|
|
2099
|
+
|
|
2100
|
+
##
|
|
2101
|
+
# Creates a new IPv6 address from +arg+ which may be:
|
|
2102
|
+
#
|
|
2103
|
+
# IPv6:: returns +arg+.
|
|
2104
|
+
# String:: +arg+ must match one of the IPv6::Regex* constants
|
|
2105
|
+
|
|
2106
|
+
def self.create(arg)
|
|
2107
|
+
case arg
|
|
2108
|
+
when IPv6
|
|
2109
|
+
return arg
|
|
2110
|
+
when String
|
|
2111
|
+
address = ''
|
|
2112
|
+
if Regex_8Hex =~ arg
|
|
2113
|
+
arg.scan(/[0-9A-Fa-f]+/) {|hex| address << [hex.hex].pack('n')}
|
|
2114
|
+
elsif Regex_CompressedHex =~ arg
|
|
2115
|
+
prefix = $1
|
|
2116
|
+
suffix = $2
|
|
2117
|
+
a1 = ''
|
|
2118
|
+
a2 = ''
|
|
2119
|
+
prefix.scan(/[0-9A-Fa-f]+/) {|hex| a1 << [hex.hex].pack('n')}
|
|
2120
|
+
suffix.scan(/[0-9A-Fa-f]+/) {|hex| a2 << [hex.hex].pack('n')}
|
|
2121
|
+
omitlen = 16 - a1.length - a2.length
|
|
2122
|
+
address << a1 << "\0" * omitlen << a2
|
|
2123
|
+
elsif Regex_6Hex4Dec =~ arg
|
|
2124
|
+
prefix, a, b, c, d = $1, $2.to_i, $3.to_i, $4.to_i, $5.to_i
|
|
2125
|
+
if (0..255) === a && (0..255) === b && (0..255) === c && (0..255) === d
|
|
2126
|
+
prefix.scan(/[0-9A-Fa-f]+/) {|hex| address << [hex.hex].pack('n')}
|
|
2127
|
+
address << [a, b, c, d].pack('CCCC')
|
|
2128
|
+
else
|
|
2129
|
+
raise ArgumentError.new("not numeric IPv6 address: " + arg)
|
|
2130
|
+
end
|
|
2131
|
+
elsif Regex_CompressedHex4Dec =~ arg
|
|
2132
|
+
prefix, suffix, a, b, c, d = $1, $2, $3.to_i, $4.to_i, $5.to_i, $6.to_i
|
|
2133
|
+
if (0..255) === a && (0..255) === b && (0..255) === c && (0..255) === d
|
|
2134
|
+
a1 = ''
|
|
2135
|
+
a2 = ''
|
|
2136
|
+
prefix.scan(/[0-9A-Fa-f]+/) {|hex| a1 << [hex.hex].pack('n')}
|
|
2137
|
+
suffix.scan(/[0-9A-Fa-f]+/) {|hex| a2 << [hex.hex].pack('n')}
|
|
2138
|
+
omitlen = 12 - a1.length - a2.length
|
|
2139
|
+
address << a1 << "\0" * omitlen << a2 << [a, b, c, d].pack('CCCC')
|
|
2140
|
+
else
|
|
2141
|
+
raise ArgumentError.new("not numeric IPv6 address: " + arg)
|
|
2142
|
+
end
|
|
2143
|
+
else
|
|
2144
|
+
raise ArgumentError.new("not numeric IPv6 address: " + arg)
|
|
2145
|
+
end
|
|
2146
|
+
return IPv6.new(address)
|
|
2147
|
+
else
|
|
2148
|
+
raise ArgumentError.new("cannot interpret as IPv6 address: #{arg.inspect}")
|
|
2149
|
+
end
|
|
2150
|
+
end
|
|
2151
|
+
|
|
2152
|
+
def initialize(address) # :nodoc:
|
|
2153
|
+
unless address.kind_of?(String) && address.length == 16
|
|
2154
|
+
raise ArgumentError.new('IPv6 address must be 16 bytes')
|
|
2155
|
+
end
|
|
2156
|
+
@address = address
|
|
2157
|
+
end
|
|
2158
|
+
|
|
2159
|
+
##
|
|
2160
|
+
# The raw IPv6 address as a String.
|
|
2161
|
+
|
|
2162
|
+
attr_reader :address
|
|
2163
|
+
|
|
2164
|
+
def to_s # :nodoc:
|
|
2165
|
+
address = sprintf("%X:%X:%X:%X:%X:%X:%X:%X", *@address.unpack("nnnnnnnn"))
|
|
2166
|
+
unless address.sub!(/(^|:)0(:0)+(:|$)/, '::')
|
|
2167
|
+
address.sub!(/(^|:)0(:|$)/, '::')
|
|
2168
|
+
end
|
|
2169
|
+
return address
|
|
2170
|
+
end
|
|
2171
|
+
|
|
2172
|
+
def inspect # :nodoc:
|
|
2173
|
+
return "#<#{self.class} #{self.to_s}>"
|
|
2174
|
+
end
|
|
2175
|
+
|
|
2176
|
+
##
|
|
2177
|
+
# Turns this IPv6 address into a Resolv::DNS::Name.
|
|
2178
|
+
#--
|
|
2179
|
+
# ip6.arpa should be searched too. [RFC3152]
|
|
2180
|
+
|
|
2181
|
+
def to_name
|
|
2182
|
+
return DNS::Name.new(
|
|
2183
|
+
@address.unpack("H32")[0].split(//).reverse + ['ip6', 'arpa'])
|
|
2184
|
+
end
|
|
2185
|
+
|
|
2186
|
+
def ==(other) # :nodoc:
|
|
2187
|
+
return @address == other.address
|
|
2188
|
+
end
|
|
2189
|
+
|
|
2190
|
+
def eql?(other) # :nodoc:
|
|
2191
|
+
return self == other
|
|
2192
|
+
end
|
|
2193
|
+
|
|
2194
|
+
def hash # :nodoc:
|
|
2195
|
+
return @address.hash
|
|
2196
|
+
end
|
|
2197
|
+
end
|
|
2198
|
+
|
|
2199
|
+
##
|
|
2200
|
+
# Default resolver to use for Resolv class methods.
|
|
2201
|
+
|
|
2202
|
+
DefaultResolver = self.new
|
|
2203
|
+
|
|
2204
|
+
##
|
|
2205
|
+
# Address Regexp to use for matching IP addresses.
|
|
2206
|
+
|
|
2207
|
+
AddressRegex = /(?:#{IPv4::Regex})|(?:#{IPv6::Regex})/
|
|
2208
|
+
|
|
2209
|
+
end
|
|
2210
|
+
|