rubygems-update 4.0.21 → 4.1.0.beta1

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.
Files changed (496) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +590 -53
  3. data/CONTRIBUTING.md +66 -5
  4. data/MIT.txt +4 -3
  5. data/Manifest.txt +332 -375
  6. data/README.md +26 -6
  7. data/bundler.gemspec +63 -0
  8. data/doc/POLICIES.md +147 -0
  9. data/doc/UPGRADING.md +4 -4
  10. data/{bundler/lib → lib}/bundler/build_metadata.rb +2 -2
  11. data/{bundler/lib → lib}/bundler/checksum.rb +40 -25
  12. data/{bundler/lib → lib}/bundler/ci_detector.rb +1 -1
  13. data/{bundler/lib → lib}/bundler/cli/add.rb +3 -4
  14. data/{bundler/lib → lib}/bundler/cli/cache.rb +4 -0
  15. data/{bundler/lib → lib}/bundler/cli/clean.rb +5 -0
  16. data/{bundler/lib → lib}/bundler/cli/common.rb +37 -1
  17. data/{bundler/lib → lib}/bundler/cli/config.rb +4 -2
  18. data/{bundler/lib → lib}/bundler/cli/gem.rb +0 -17
  19. data/{bundler/lib → lib}/bundler/cli/install.rb +4 -5
  20. data/{bundler/lib → lib}/bundler/cli/lock.rb +1 -2
  21. data/{bundler/lib → lib}/bundler/cli/outdated.rb +8 -3
  22. data/{bundler/lib → lib}/bundler/cli/pristine.rb +2 -1
  23. data/{bundler/lib → lib}/bundler/cli/update.rb +21 -12
  24. data/{bundler/lib → lib}/bundler/cli.rb +14 -11
  25. data/{bundler/lib → lib}/bundler/definition.rb +61 -24
  26. data/{bundler/lib → lib}/bundler/dependency.rb +4 -0
  27. data/{bundler/lib → lib}/bundler/dsl.rb +77 -11
  28. data/{bundler/lib → lib}/bundler/endpoint_specification.rb +51 -14
  29. data/{bundler/lib → lib}/bundler/env.rb +7 -24
  30. data/{bundler/lib → lib}/bundler/errors.rb +34 -5
  31. data/{bundler/lib → lib}/bundler/fetcher/compact_index.rb +14 -5
  32. data/lib/bundler/fetcher/connection_pools.rb +150 -0
  33. data/{bundler/lib → lib}/bundler/fetcher/downloader.rb +31 -16
  34. data/{bundler/lib → lib}/bundler/fetcher.rb +8 -47
  35. data/{bundler/lib → lib}/bundler/injector.rb +3 -3
  36. data/{bundler/lib → lib}/bundler/inline.rb +44 -4
  37. data/{bundler/lib → lib}/bundler/installer/parallel_installer.rb +25 -30
  38. data/{bundler/lib → lib}/bundler/installer.rb +20 -6
  39. data/{bundler/lib → lib}/bundler/lazy_specification.rb +44 -17
  40. data/{bundler/lib → lib}/bundler/lockfile_generator.rb +24 -2
  41. data/{bundler/lib → lib}/bundler/lockfile_parser.rb +43 -5
  42. data/{bundler/lib → lib}/bundler/man/bundle-add.1 +7 -4
  43. data/{bundler/lib → lib}/bundler/man/bundle-add.1.ronn +8 -4
  44. data/{bundler/lib → lib}/bundler/man/bundle-binstubs.1 +1 -1
  45. data/{bundler/lib → lib}/bundler/man/bundle-cache.1 +2 -2
  46. data/{bundler/lib → lib}/bundler/man/bundle-cache.1.ronn +2 -2
  47. data/{bundler/lib → lib}/bundler/man/bundle-check.1 +1 -1
  48. data/{bundler/lib → lib}/bundler/man/bundle-clean.1 +1 -1
  49. data/{bundler/lib → lib}/bundler/man/bundle-config.1 +38 -6
  50. data/{bundler/lib → lib}/bundler/man/bundle-config.1.ronn +143 -10
  51. data/{bundler/lib → lib}/bundler/man/bundle-console.1 +1 -1
  52. data/{bundler/lib → lib}/bundler/man/bundle-doctor.1 +1 -1
  53. data/{bundler/lib → lib}/bundler/man/bundle-env.1 +1 -1
  54. data/{bundler/lib → lib}/bundler/man/bundle-exec.1 +1 -1
  55. data/{bundler/lib → lib}/bundler/man/bundle-fund.1 +1 -1
  56. data/{bundler/lib → lib}/bundler/man/bundle-gem.1 +1 -1
  57. data/{bundler/lib → lib}/bundler/man/bundle-help.1 +1 -1
  58. data/{bundler/lib → lib}/bundler/man/bundle-info.1 +1 -1
  59. data/{bundler/lib → lib}/bundler/man/bundle-init.1 +1 -1
  60. data/{bundler/lib → lib}/bundler/man/bundle-install.1 +2 -2
  61. data/{bundler/lib → lib}/bundler/man/bundle-install.1.ronn +4 -4
  62. data/{bundler/lib → lib}/bundler/man/bundle-issue.1 +1 -1
  63. data/{bundler/lib → lib}/bundler/man/bundle-licenses.1 +1 -1
  64. data/{bundler/lib → lib}/bundler/man/bundle-list.1 +1 -1
  65. data/{bundler/lib → lib}/bundler/man/bundle-lock.1 +3 -3
  66. data/{bundler/lib → lib}/bundler/man/bundle-lock.1.ronn +5 -5
  67. data/{bundler/lib → lib}/bundler/man/bundle-open.1 +1 -1
  68. data/{bundler/lib → lib}/bundler/man/bundle-outdated.1 +1 -1
  69. data/{bundler/lib → lib}/bundler/man/bundle-platform.1 +1 -1
  70. data/{bundler/lib → lib}/bundler/man/bundle-plugin.1 +1 -1
  71. data/{bundler/lib → lib}/bundler/man/bundle-pristine.1 +1 -1
  72. data/{bundler/lib → lib}/bundler/man/bundle-remove.1 +1 -1
  73. data/{bundler/lib → lib}/bundler/man/bundle-show.1 +1 -1
  74. data/{bundler/lib → lib}/bundler/man/bundle-update.1 +3 -3
  75. data/{bundler/lib → lib}/bundler/man/bundle-update.1.ronn +3 -5
  76. data/{bundler/lib → lib}/bundler/man/bundle-version.1 +1 -1
  77. data/{bundler/lib → lib}/bundler/man/bundle.1 +1 -1
  78. data/{bundler/lib → lib}/bundler/man/gemfile.5 +45 -1
  79. data/{bundler/lib → lib}/bundler/man/gemfile.5.ronn +53 -0
  80. data/lib/bundler/match_metadata.rb +50 -0
  81. data/{bundler/lib → lib}/bundler/match_platform.rb +25 -2
  82. data/lib/bundler/match_remote_metadata.rb +44 -0
  83. data/{bundler/lib → lib}/bundler/materialization.rb +2 -1
  84. data/lib/bundler/override.rb +69 -0
  85. data/{bundler/lib → lib}/bundler/plugin/dsl.rb +3 -5
  86. data/{bundler/lib → lib}/bundler/plugin/events.rb +55 -13
  87. data/{bundler/lib → lib}/bundler/plugin/index.rb +87 -11
  88. data/{bundler/lib → lib}/bundler/plugin/installer/path.rb +1 -1
  89. data/{bundler/lib → lib}/bundler/plugin/installer.rb +13 -5
  90. data/{bundler/lib → lib}/bundler/plugin.rb +58 -30
  91. data/{bundler/lib → lib}/bundler/remote_specification.rb +6 -3
  92. data/{bundler/lib → lib}/bundler/resolver/base.rb +2 -1
  93. data/{bundler/lib → lib}/bundler/resolver/incompatibility.rb +1 -1
  94. data/{bundler/lib → lib}/bundler/resolver.rb +73 -23
  95. data/{bundler/lib → lib}/bundler/ruby_version.rb +0 -2
  96. data/{bundler/lib → lib}/bundler/rubygems_ext.rb +71 -1
  97. data/{bundler/lib → lib}/bundler/rubygems_gem_installer.rb +41 -2
  98. data/{bundler/lib → lib}/bundler/rubygems_integration.rb +7 -2
  99. data/{bundler/lib → lib}/bundler/runtime.rb +69 -2
  100. data/{bundler/lib → lib}/bundler/self_manager.rb +9 -15
  101. data/{bundler/lib → lib}/bundler/settings.rb +373 -30
  102. data/{bundler/lib → lib}/bundler/shared_helpers.rb +2 -1
  103. data/{bundler/lib → lib}/bundler/source/git/git_proxy.rb +2 -10
  104. data/{bundler/lib → lib}/bundler/source/git.rb +15 -6
  105. data/{bundler/lib → lib}/bundler/source/path/installer.rb +1 -1
  106. data/{bundler/lib → lib}/bundler/source/rubygems/remote.rb +10 -5
  107. data/{bundler/lib → lib}/bundler/source/rubygems.rb +48 -12
  108. data/{bundler/lib → lib}/bundler/spec_set.rb +16 -4
  109. data/{bundler/lib → lib}/bundler/stub_specification.rb +2 -1
  110. data/{bundler/lib → lib}/bundler/templates/newgem/Gemfile.tt +4 -4
  111. data/{bundler/lib → lib}/bundler/templates/newgem/newgem.gemspec.tt +3 -3
  112. data/{bundler/lib → lib}/bundler/templates/newgem/spec/newgem_spec.rb.tt +1 -1
  113. data/{bundler/lib → lib}/bundler/templates/newgem/test/minitest/test_newgem.rb.tt +1 -1
  114. data/{bundler/lib → lib}/bundler/ui/shell.rb +0 -4
  115. data/{bundler/lib → lib}/bundler/ui/silent.rb +0 -4
  116. data/{bundler/lib → lib}/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb +35 -2
  117. data/{bundler/lib → lib}/bundler/vendor/thor/lib/thor/base.rb +2 -1
  118. data/{bundler/lib → lib}/bundler/vendor/thor/lib/thor/shell/basic.rb +14 -6
  119. data/{bundler/lib → lib}/bundler/vendor/thor/lib/thor/shell/color.rb +2 -0
  120. data/{bundler/lib → lib}/bundler/vendor/thor/lib/thor/version.rb +1 -1
  121. data/{bundler/lib → lib}/bundler/vendor/thor/lib/thor.rb +34 -1
  122. data/lib/bundler/vendored_pub_grub.rb +7 -0
  123. data/lib/bundler/vendored_securerandom.rb +15 -0
  124. data/lib/bundler/vendored_uri.rb +21 -0
  125. data/{bundler/lib → lib}/bundler/version.rb +1 -1
  126. data/{bundler/lib → lib}/bundler/worker.rb +3 -2
  127. data/{bundler/lib → lib}/bundler.rb +1 -1
  128. data/lib/rubygems/basic_specification.rb +15 -14
  129. data/lib/rubygems/bundler_settings.rb +137 -0
  130. data/lib/rubygems/bundler_version_finder.rb +13 -55
  131. data/lib/rubygems/ci_detector.rb +1 -1
  132. data/lib/rubygems/commands/build_command.rb +8 -1
  133. data/lib/rubygems/commands/cert_command.rb +9 -7
  134. data/lib/rubygems/commands/contents_command.rb +1 -1
  135. data/lib/rubygems/commands/dependency_command.rb +15 -3
  136. data/lib/rubygems/commands/environment_command.rb +1 -0
  137. data/lib/rubygems/commands/exec_command.rb +3 -0
  138. data/lib/rubygems/commands/fetch_command.rb +1 -1
  139. data/lib/rubygems/commands/help_command.rb +3 -1
  140. data/lib/rubygems/commands/install_command.rb +13 -3
  141. data/lib/rubygems/commands/lock_command.rb +2 -2
  142. data/lib/rubygems/commands/outdated_command.rb +77 -2
  143. data/lib/rubygems/commands/owner_command.rb +1 -1
  144. data/lib/rubygems/commands/push_command.rb +159 -21
  145. data/lib/rubygems/commands/setup_command.rb +20 -23
  146. data/lib/rubygems/commands/signin_command.rb +3 -1
  147. data/lib/rubygems/commands/signout_command.rb +26 -6
  148. data/lib/rubygems/commands/specification_command.rb +1 -1
  149. data/lib/rubygems/commands/uninstall_command.rb +1 -1
  150. data/lib/rubygems/commands/update_command.rb +84 -2
  151. data/lib/rubygems/commands/yank_command.rb +10 -7
  152. data/lib/rubygems/compact_index_client/cache.rb +122 -0
  153. data/lib/rubygems/compact_index_client/cache_file.rb +147 -0
  154. data/lib/rubygems/compact_index_client/http_fetcher.rb +88 -0
  155. data/lib/rubygems/compact_index_client/parser.rb +90 -0
  156. data/lib/rubygems/compact_index_client/updater.rb +113 -0
  157. data/lib/rubygems/compact_index_client.rb +111 -0
  158. data/lib/rubygems/config_file.rb +304 -22
  159. data/lib/rubygems/content_address.rb +194 -0
  160. data/lib/rubygems/cooldown.rb +173 -0
  161. data/lib/rubygems/cooldown_option.rb +27 -0
  162. data/lib/rubygems/cooldown_settings.rb +57 -0
  163. data/lib/rubygems/credential_store/native/linux.rb +97 -0
  164. data/lib/rubygems/credential_store/native/macos.rb +88 -0
  165. data/lib/rubygems/credential_store/native/windows.rb +130 -0
  166. data/lib/rubygems/credential_store.rb +332 -0
  167. data/lib/rubygems/defaults.rb +9 -0
  168. data/lib/rubygems/dependency_installer.rb +15 -0
  169. data/lib/rubygems/doctor.rb +23 -6
  170. data/lib/rubygems/exceptions.rb +11 -43
  171. data/lib/rubygems/ext/builder.rb +70 -5
  172. data/lib/rubygems/ext/cargo_builder.rb +0 -9
  173. data/lib/rubygems/ext/ext_conf_builder.rb +8 -15
  174. data/lib/rubygems/gemcutter_utilities.rb +44 -2
  175. data/lib/rubygems/install_update_options.rb +16 -0
  176. data/lib/rubygems/installer.rb +90 -11
  177. data/lib/rubygems/installer_uninstaller_utils.rb +24 -3
  178. data/lib/rubygems/name_tuple.rb +55 -18
  179. data/lib/rubygems/package/old.rb +1 -1
  180. data/lib/rubygems/package.rb +200 -47
  181. data/lib/rubygems/package_task.rb +2 -2
  182. data/lib/rubygems/platform.rb +2 -2
  183. data/lib/rubygems/query_utils.rb +84 -24
  184. data/lib/rubygems/remote_fetcher.rb +65 -17
  185. data/lib/rubygems/request/connection_pools.rb +3 -0
  186. data/lib/rubygems/request_set/gem_dependency_api.rb +1 -1
  187. data/lib/rubygems/request_set/lockfile.rb +0 -2
  188. data/lib/rubygems/request_set.rb +105 -17
  189. data/lib/rubygems/resolver/api_set.rb +14 -26
  190. data/lib/rubygems/resolver/api_specification.rb +56 -15
  191. data/lib/rubygems/resolver/incompatibility.rb +10 -0
  192. data/lib/rubygems/resolver/index_specification.rb +6 -4
  193. data/lib/rubygems/resolver/installer_set.rb +2 -2
  194. data/lib/rubygems/resolver/lock_specification.rb +5 -1
  195. data/lib/rubygems/resolver/spec_specification.rb +4 -0
  196. data/lib/rubygems/resolver/specification.rb +16 -1
  197. data/lib/rubygems/resolver/strategy.rb +44 -0
  198. data/lib/rubygems/resolver.rb +471 -145
  199. data/lib/rubygems/safe_marshal.rb +2 -1
  200. data/lib/rubygems/safe_yaml.rb +20 -3
  201. data/lib/rubygems/security/policy.rb +11 -3
  202. data/lib/rubygems/security/signer.rb +15 -7
  203. data/lib/rubygems/security.rb +111 -17
  204. data/lib/rubygems/source/local.rb +7 -2
  205. data/lib/rubygems/source.rb +270 -23
  206. data/lib/rubygems/spec_fetcher.rb +47 -12
  207. data/lib/rubygems/specification.rb +76 -32
  208. data/lib/rubygems/specification_policy.rb +33 -6
  209. data/lib/rubygems/specification_record.rb +41 -2
  210. data/lib/rubygems/stub_specification.rb +39 -16
  211. data/lib/rubygems/uninstaller.rb +2 -0
  212. data/lib/rubygems/util/atomic_file_writer.rb +109 -0
  213. data/lib/rubygems/vendor/net-http/lib/net/http/exceptions.rb +2 -1
  214. data/lib/rubygems/vendor/net-http/lib/net/http/generic_request.rb +5 -6
  215. data/lib/rubygems/vendor/net-http/lib/net/http/header.rb +8 -4
  216. data/lib/rubygems/vendor/net-http/lib/net/http/requests.rb +15 -1
  217. data/lib/rubygems/vendor/net-http/lib/net/http/response.rb +2 -1
  218. data/lib/rubygems/vendor/net-http/lib/net/http/responses.rb +68 -0
  219. data/lib/rubygems/vendor/net-http/lib/net/http.rb +60 -49
  220. data/lib/rubygems/vendor/optparse/lib/optparse.rb +23 -30
  221. data/{bundler/lib/bundler → lib/rubygems}/vendor/pub_grub/lib/pub_grub/assignment.rb +1 -1
  222. data/{bundler/lib/bundler → lib/rubygems}/vendor/pub_grub/lib/pub_grub/basic_package_source.rb +7 -7
  223. data/{bundler/lib/bundler → lib/rubygems}/vendor/pub_grub/lib/pub_grub/failure_writer.rb +1 -1
  224. data/{bundler/lib/bundler → lib/rubygems}/vendor/pub_grub/lib/pub_grub/incompatibility.rb +4 -4
  225. data/{bundler/lib/bundler → lib/rubygems}/vendor/pub_grub/lib/pub_grub/package.rb +1 -1
  226. data/{bundler/lib/bundler → lib/rubygems}/vendor/pub_grub/lib/pub_grub/partial_solution.rb +1 -1
  227. data/{bundler/lib/bundler → lib/rubygems}/vendor/pub_grub/lib/pub_grub/rubygems.rb +3 -3
  228. data/{bundler/lib/bundler → lib/rubygems}/vendor/pub_grub/lib/pub_grub/solve_failure.rb +1 -1
  229. data/{bundler/lib/bundler → lib/rubygems}/vendor/pub_grub/lib/pub_grub/static_package_source.rb +3 -3
  230. data/{bundler/lib/bundler → lib/rubygems}/vendor/pub_grub/lib/pub_grub/strategy.rb +2 -2
  231. data/{bundler/lib/bundler → lib/rubygems}/vendor/pub_grub/lib/pub_grub/term.rb +1 -1
  232. data/{bundler/lib/bundler → lib/rubygems}/vendor/pub_grub/lib/pub_grub/version.rb +1 -1
  233. data/{bundler/lib/bundler → lib/rubygems}/vendor/pub_grub/lib/pub_grub/version_constraint.rb +3 -3
  234. data/{bundler/lib/bundler → lib/rubygems}/vendor/pub_grub/lib/pub_grub/version_range.rb +1 -1
  235. data/{bundler/lib/bundler → lib/rubygems}/vendor/pub_grub/lib/pub_grub/version_solver.rb +2 -2
  236. data/{bundler/lib/bundler → lib/rubygems}/vendor/pub_grub/lib/pub_grub/version_union.rb +1 -1
  237. data/lib/rubygems/vendor/pub_grub/lib/pub_grub.rb +57 -0
  238. data/lib/rubygems/vendor/resolv/lib/resolv.rb +3508 -0
  239. data/lib/rubygems/vendor/securerandom/lib/securerandom.rb +4 -0
  240. data/lib/rubygems/vendor/timeout/lib/timeout.rb +190 -77
  241. data/lib/rubygems/vendor/uri/lib/uri.rb +4 -0
  242. data/{bundler/lib/bundler → lib/rubygems}/vendored_pub_grub.rb +0 -1
  243. data/lib/rubygems/version.rb +129 -111
  244. data/lib/rubygems/version_option.rb +14 -0
  245. data/lib/rubygems/yaml_serializer.rb +853 -71
  246. data/lib/rubygems.rb +45 -11
  247. data/rubygems-update.gemspec +3 -4
  248. data/setup.rb +1 -0
  249. metadata +365 -410
  250. data/bundler/CHANGELOG.md +0 -5784
  251. data/bundler/LICENSE.md +0 -22
  252. data/bundler/README.md +0 -58
  253. data/bundler/bundler.gemspec +0 -46
  254. data/bundler/lib/bundler/compact_index_client/cache.rb +0 -107
  255. data/bundler/lib/bundler/compact_index_client/cache_file.rb +0 -148
  256. data/bundler/lib/bundler/compact_index_client/parser.rb +0 -87
  257. data/bundler/lib/bundler/compact_index_client/updater.rb +0 -105
  258. data/bundler/lib/bundler/compact_index_client.rb +0 -92
  259. data/bundler/lib/bundler/match_metadata.rb +0 -30
  260. data/bundler/lib/bundler/match_remote_metadata.rb +0 -29
  261. data/bundler/lib/bundler/vendor/connection_pool/LICENSE +0 -20
  262. data/bundler/lib/bundler/vendor/connection_pool/lib/connection_pool/timed_stack.rb +0 -227
  263. data/bundler/lib/bundler/vendor/connection_pool/lib/connection_pool/version.rb +0 -3
  264. data/bundler/lib/bundler/vendor/connection_pool/lib/connection_pool/wrapper.rb +0 -56
  265. data/bundler/lib/bundler/vendor/connection_pool/lib/connection_pool.rb +0 -230
  266. data/bundler/lib/bundler/vendor/net-http-persistent/README.rdoc +0 -82
  267. data/bundler/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/connection.rb +0 -41
  268. data/bundler/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/pool.rb +0 -65
  269. data/bundler/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/timed_stack_multi.rb +0 -80
  270. data/bundler/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb +0 -1153
  271. data/bundler/lib/bundler/vendor/pub_grub/lib/pub_grub.rb +0 -31
  272. data/bundler/lib/bundler/vendor/securerandom/lib/securerandom.rb +0 -102
  273. data/bundler/lib/bundler/vendor/uri/COPYING +0 -56
  274. data/bundler/lib/bundler/vendor/uri/lib/uri/common.rb +0 -922
  275. data/bundler/lib/bundler/vendor/uri/lib/uri/file.rb +0 -100
  276. data/bundler/lib/bundler/vendor/uri/lib/uri/ftp.rb +0 -267
  277. data/bundler/lib/bundler/vendor/uri/lib/uri/generic.rb +0 -1592
  278. data/bundler/lib/bundler/vendor/uri/lib/uri/http.rb +0 -137
  279. data/bundler/lib/bundler/vendor/uri/lib/uri/https.rb +0 -23
  280. data/bundler/lib/bundler/vendor/uri/lib/uri/ldap.rb +0 -261
  281. data/bundler/lib/bundler/vendor/uri/lib/uri/ldaps.rb +0 -22
  282. data/bundler/lib/bundler/vendor/uri/lib/uri/mailto.rb +0 -293
  283. data/bundler/lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rb +0 -547
  284. data/bundler/lib/bundler/vendor/uri/lib/uri/rfc3986_parser.rb +0 -206
  285. data/bundler/lib/bundler/vendor/uri/lib/uri/version.rb +0 -6
  286. data/bundler/lib/bundler/vendor/uri/lib/uri/ws.rb +0 -83
  287. data/bundler/lib/bundler/vendor/uri/lib/uri/wss.rb +0 -23
  288. data/bundler/lib/bundler/vendor/uri/lib/uri.rb +0 -104
  289. data/bundler/lib/bundler/vendored_persistent.rb +0 -11
  290. data/bundler/lib/bundler/vendored_securerandom.rb +0 -12
  291. data/bundler/lib/bundler/vendored_uri.rb +0 -21
  292. data/bundler/lib/bundler/yaml_serializer.rb +0 -98
  293. data/doc/rubygems/CONTRIBUTING.md +0 -231
  294. data/doc/rubygems/POLICIES.md +0 -60
  295. data/lib/rubygems/request_set/lockfile/parser.rb +0 -344
  296. data/lib/rubygems/request_set/lockfile/tokenizer.rb +0 -122
  297. data/lib/rubygems/resolver/conflict.rb +0 -146
  298. data/lib/rubygems/resolver/stats.rb +0 -46
  299. data/lib/rubygems/util/list.rb +0 -40
  300. data/lib/rubygems/vendor/molinillo/LICENSE +0 -9
  301. data/lib/rubygems/vendor/molinillo/lib/molinillo/delegates/resolution_state.rb +0 -57
  302. data/lib/rubygems/vendor/molinillo/lib/molinillo/delegates/specification_provider.rb +0 -88
  303. data/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/action.rb +0 -36
  304. data/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb +0 -66
  305. data/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/add_vertex.rb +0 -62
  306. data/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/delete_edge.rb +0 -63
  307. data/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb +0 -61
  308. data/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/log.rb +0 -126
  309. data/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/set_payload.rb +0 -46
  310. data/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/tag.rb +0 -36
  311. data/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/vertex.rb +0 -164
  312. data/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph.rb +0 -255
  313. data/lib/rubygems/vendor/molinillo/lib/molinillo/errors.rb +0 -149
  314. data/lib/rubygems/vendor/molinillo/lib/molinillo/gem_metadata.rb +0 -6
  315. data/lib/rubygems/vendor/molinillo/lib/molinillo/modules/specification_provider.rb +0 -112
  316. data/lib/rubygems/vendor/molinillo/lib/molinillo/modules/ui.rb +0 -67
  317. data/lib/rubygems/vendor/molinillo/lib/molinillo/resolution.rb +0 -839
  318. data/lib/rubygems/vendor/molinillo/lib/molinillo/resolver.rb +0 -46
  319. data/lib/rubygems/vendor/molinillo/lib/molinillo/state.rb +0 -58
  320. data/lib/rubygems/vendor/molinillo/lib/molinillo.rb +0 -11
  321. data/lib/rubygems/vendored_molinillo.rb +0 -3
  322. /data/{bundler/exe → exe}/bundle +0 -0
  323. /data/{bundler/exe → exe}/bundler +0 -0
  324. /data/{bundler/lib → lib}/bundler/.document +0 -0
  325. /data/{bundler/lib → lib}/bundler/capistrano.rb +0 -0
  326. /data/{bundler/lib → lib}/bundler/cli/binstubs.rb +0 -0
  327. /data/{bundler/lib → lib}/bundler/cli/check.rb +0 -0
  328. /data/{bundler/lib → lib}/bundler/cli/console.rb +0 -0
  329. /data/{bundler/lib → lib}/bundler/cli/doctor/diagnose.rb +0 -0
  330. /data/{bundler/lib → lib}/bundler/cli/doctor/ssl.rb +0 -0
  331. /data/{bundler/lib → lib}/bundler/cli/doctor.rb +0 -0
  332. /data/{bundler/lib → lib}/bundler/cli/exec.rb +0 -0
  333. /data/{bundler/lib → lib}/bundler/cli/fund.rb +0 -0
  334. /data/{bundler/lib → lib}/bundler/cli/info.rb +0 -0
  335. /data/{bundler/lib → lib}/bundler/cli/init.rb +0 -0
  336. /data/{bundler/lib → lib}/bundler/cli/issue.rb +0 -0
  337. /data/{bundler/lib → lib}/bundler/cli/list.rb +0 -0
  338. /data/{bundler/lib → lib}/bundler/cli/open.rb +0 -0
  339. /data/{bundler/lib → lib}/bundler/cli/platform.rb +0 -0
  340. /data/{bundler/lib → lib}/bundler/cli/plugin.rb +0 -0
  341. /data/{bundler/lib → lib}/bundler/cli/remove.rb +0 -0
  342. /data/{bundler/lib → lib}/bundler/cli/show.rb +0 -0
  343. /data/{bundler/lib → lib}/bundler/constants.rb +0 -0
  344. /data/{bundler/lib → lib}/bundler/current_ruby.rb +0 -0
  345. /data/{bundler/lib → lib}/bundler/deployment.rb +0 -0
  346. /data/{bundler/lib → lib}/bundler/deprecate.rb +0 -0
  347. /data/{bundler/lib → lib}/bundler/digest.rb +0 -0
  348. /data/{bundler/lib → lib}/bundler/environment_preserver.rb +0 -0
  349. /data/{bundler/lib → lib}/bundler/feature_flag.rb +0 -0
  350. /data/{bundler/lib → lib}/bundler/fetcher/base.rb +0 -0
  351. /data/{bundler/lib → lib}/bundler/fetcher/dependency.rb +0 -0
  352. /data/{bundler/lib → lib}/bundler/fetcher/gem_remote_fetcher.rb +0 -0
  353. /data/{bundler/lib → lib}/bundler/fetcher/index.rb +0 -0
  354. /data/{bundler/lib → lib}/bundler/force_platform.rb +0 -0
  355. /data/{bundler/lib → lib}/bundler/friendly_errors.rb +0 -0
  356. /data/{bundler/lib → lib}/bundler/gem_helper.rb +0 -0
  357. /data/{bundler/lib → lib}/bundler/gem_tasks.rb +0 -0
  358. /data/{bundler/lib → lib}/bundler/gem_version_promoter.rb +0 -0
  359. /data/{bundler/lib → lib}/bundler/index.rb +0 -0
  360. /data/{bundler/lib → lib}/bundler/installer/gem_installer.rb +0 -0
  361. /data/{bundler/lib → lib}/bundler/installer/standalone.rb +0 -0
  362. /data/{bundler/lib → lib}/bundler/man/.document +0 -0
  363. /data/{bundler/lib → lib}/bundler/man/bundle-binstubs.1.ronn +0 -0
  364. /data/{bundler/lib → lib}/bundler/man/bundle-check.1.ronn +0 -0
  365. /data/{bundler/lib → lib}/bundler/man/bundle-clean.1.ronn +0 -0
  366. /data/{bundler/lib → lib}/bundler/man/bundle-console.1.ronn +0 -0
  367. /data/{bundler/lib → lib}/bundler/man/bundle-doctor.1.ronn +0 -0
  368. /data/{bundler/lib → lib}/bundler/man/bundle-env.1.ronn +0 -0
  369. /data/{bundler/lib → lib}/bundler/man/bundle-exec.1.ronn +0 -0
  370. /data/{bundler/lib → lib}/bundler/man/bundle-fund.1.ronn +0 -0
  371. /data/{bundler/lib → lib}/bundler/man/bundle-gem.1.ronn +0 -0
  372. /data/{bundler/lib → lib}/bundler/man/bundle-help.1.ronn +0 -0
  373. /data/{bundler/lib → lib}/bundler/man/bundle-info.1.ronn +0 -0
  374. /data/{bundler/lib → lib}/bundler/man/bundle-init.1.ronn +0 -0
  375. /data/{bundler/lib → lib}/bundler/man/bundle-issue.1.ronn +0 -0
  376. /data/{bundler/lib → lib}/bundler/man/bundle-licenses.1.ronn +0 -0
  377. /data/{bundler/lib → lib}/bundler/man/bundle-list.1.ronn +0 -0
  378. /data/{bundler/lib → lib}/bundler/man/bundle-open.1.ronn +0 -0
  379. /data/{bundler/lib → lib}/bundler/man/bundle-outdated.1.ronn +0 -0
  380. /data/{bundler/lib → lib}/bundler/man/bundle-platform.1.ronn +0 -0
  381. /data/{bundler/lib → lib}/bundler/man/bundle-plugin.1.ronn +0 -0
  382. /data/{bundler/lib → lib}/bundler/man/bundle-pristine.1.ronn +0 -0
  383. /data/{bundler/lib → lib}/bundler/man/bundle-remove.1.ronn +0 -0
  384. /data/{bundler/lib → lib}/bundler/man/bundle-show.1.ronn +0 -0
  385. /data/{bundler/lib → lib}/bundler/man/bundle-version.1.ronn +0 -0
  386. /data/{bundler/lib → lib}/bundler/man/bundle.1.ronn +0 -0
  387. /data/{bundler/lib → lib}/bundler/man/index.txt +0 -0
  388. /data/{bundler/lib → lib}/bundler/mirror.rb +0 -0
  389. /data/{bundler/lib → lib}/bundler/plugin/api/source.rb +0 -0
  390. /data/{bundler/lib → lib}/bundler/plugin/api.rb +0 -0
  391. /data/{bundler/lib → lib}/bundler/plugin/installer/git.rb +0 -0
  392. /data/{bundler/lib → lib}/bundler/plugin/installer/rubygems.rb +0 -0
  393. /data/{bundler/lib → lib}/bundler/plugin/source_list.rb +0 -0
  394. /data/{bundler/lib → lib}/bundler/plugin/unloaded_source.rb +0 -0
  395. /data/{bundler/lib → lib}/bundler/process_lock.rb +0 -0
  396. /data/{bundler/lib → lib}/bundler/resolver/candidate.rb +0 -0
  397. /data/{bundler/lib → lib}/bundler/resolver/package.rb +0 -0
  398. /data/{bundler/lib → lib}/bundler/resolver/root.rb +0 -0
  399. /data/{bundler/lib → lib}/bundler/resolver/spec_group.rb +0 -0
  400. /data/{bundler/lib → lib}/bundler/resolver/strategy.rb +0 -0
  401. /data/{bundler/lib → lib}/bundler/retry.rb +0 -0
  402. /data/{bundler/lib → lib}/bundler/ruby_dsl.rb +0 -0
  403. /data/{bundler/lib → lib}/bundler/safe_marshal.rb +0 -0
  404. /data/{bundler/lib → lib}/bundler/settings/validator.rb +0 -0
  405. /data/{bundler/lib → lib}/bundler/setup.rb +0 -0
  406. /data/{bundler/lib → lib}/bundler/source/gemspec.rb +0 -0
  407. /data/{bundler/lib → lib}/bundler/source/metadata.rb +0 -0
  408. /data/{bundler/lib → lib}/bundler/source/path.rb +0 -0
  409. /data/{bundler/lib → lib}/bundler/source/rubygems_aggregate.rb +0 -0
  410. /data/{bundler/lib → lib}/bundler/source.rb +0 -0
  411. /data/{bundler/lib → lib}/bundler/source_list.rb +0 -0
  412. /data/{bundler/lib → lib}/bundler/source_map.rb +0 -0
  413. /data/{bundler/lib → lib}/bundler/templates/.document +0 -0
  414. /data/{bundler/lib → lib}/bundler/templates/Executable +0 -0
  415. /data/{bundler/lib → lib}/bundler/templates/Executable.standalone +0 -0
  416. /data/{bundler/lib → lib}/bundler/templates/Gemfile +0 -0
  417. /data/{bundler/lib → lib}/bundler/templates/newgem/CHANGELOG.md.tt +0 -0
  418. /data/{bundler/lib → lib}/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt +0 -0
  419. /data/{bundler/lib → lib}/bundler/templates/newgem/Cargo.toml.tt +0 -0
  420. /data/{bundler/lib → lib}/bundler/templates/newgem/LICENSE.txt.tt +0 -0
  421. /data/{bundler/lib → lib}/bundler/templates/newgem/README.md.tt +0 -0
  422. /data/{bundler/lib → lib}/bundler/templates/newgem/Rakefile.tt +0 -0
  423. /data/{bundler/lib → lib}/bundler/templates/newgem/bin/console.tt +0 -0
  424. /data/{bundler/lib → lib}/bundler/templates/newgem/bin/setup.tt +0 -0
  425. /data/{bundler/lib → lib}/bundler/templates/newgem/circleci/config.yml.tt +0 -0
  426. /data/{bundler/lib → lib}/bundler/templates/newgem/exe/newgem.tt +0 -0
  427. /data/{bundler/lib → lib}/bundler/templates/newgem/ext/newgem/Cargo.toml.tt +0 -0
  428. /data/{bundler/lib → lib}/bundler/templates/newgem/ext/newgem/build.rs.tt +0 -0
  429. /data/{bundler/lib → lib}/bundler/templates/newgem/ext/newgem/extconf-c.rb.tt +0 -0
  430. /data/{bundler/lib → lib}/bundler/templates/newgem/ext/newgem/extconf-go.rb.tt +0 -0
  431. /data/{bundler/lib → lib}/bundler/templates/newgem/ext/newgem/extconf-rust.rb.tt +0 -0
  432. /data/{bundler/lib → lib}/bundler/templates/newgem/ext/newgem/go.mod.tt +0 -0
  433. /data/{bundler/lib → lib}/bundler/templates/newgem/ext/newgem/newgem-go.c.tt +0 -0
  434. /data/{bundler/lib → lib}/bundler/templates/newgem/ext/newgem/newgem.c.tt +0 -0
  435. /data/{bundler/lib → lib}/bundler/templates/newgem/ext/newgem/newgem.go.tt +0 -0
  436. /data/{bundler/lib → lib}/bundler/templates/newgem/ext/newgem/newgem.h.tt +0 -0
  437. /data/{bundler/lib → lib}/bundler/templates/newgem/ext/newgem/src/lib.rs.tt +0 -0
  438. /data/{bundler/lib → lib}/bundler/templates/newgem/github/workflows/build-gems.yml.tt +0 -0
  439. /data/{bundler/lib → lib}/bundler/templates/newgem/github/workflows/main.yml.tt +0 -0
  440. /data/{bundler/lib → lib}/bundler/templates/newgem/gitignore.tt +0 -0
  441. /data/{bundler/lib → lib}/bundler/templates/newgem/gitlab-ci.yml.tt +0 -0
  442. /data/{bundler/lib → lib}/bundler/templates/newgem/lib/newgem/version.rb.tt +0 -0
  443. /data/{bundler/lib → lib}/bundler/templates/newgem/lib/newgem.rb.tt +0 -0
  444. /data/{bundler/lib → lib}/bundler/templates/newgem/rspec.tt +0 -0
  445. /data/{bundler/lib → lib}/bundler/templates/newgem/rubocop.yml.tt +0 -0
  446. /data/{bundler/lib → lib}/bundler/templates/newgem/sig/newgem.rbs.tt +0 -0
  447. /data/{bundler/lib → lib}/bundler/templates/newgem/spec/spec_helper.rb.tt +0 -0
  448. /data/{bundler/lib → lib}/bundler/templates/newgem/standard.yml.tt +0 -0
  449. /data/{bundler/lib → lib}/bundler/templates/newgem/test/minitest/test_helper.rb.tt +0 -0
  450. /data/{bundler/lib → lib}/bundler/templates/newgem/test/test-unit/newgem_test.rb.tt +0 -0
  451. /data/{bundler/lib → lib}/bundler/templates/newgem/test/test-unit/test_helper.rb.tt +0 -0
  452. /data/{bundler/lib → lib}/bundler/ui/rg_proxy.rb +0 -0
  453. /data/{bundler/lib → lib}/bundler/ui.rb +0 -0
  454. /data/{bundler/lib → lib}/bundler/uri_credentials_filter.rb +0 -0
  455. /data/{bundler/lib → lib}/bundler/uri_normalizer.rb +0 -0
  456. /data/{bundler/lib → lib}/bundler/vendor/.document +0 -0
  457. /data/{bundler/lib → lib}/bundler/vendor/fileutils/COPYING +0 -0
  458. /data/{bundler/lib → lib}/bundler/vendor/fileutils/lib/fileutils.rb +0 -0
  459. /data/{bundler/lib → lib}/bundler/vendor/thor/LICENSE.md +0 -0
  460. /data/{bundler/lib → lib}/bundler/vendor/thor/lib/thor/actions/create_file.rb +0 -0
  461. /data/{bundler/lib → lib}/bundler/vendor/thor/lib/thor/actions/create_link.rb +0 -0
  462. /data/{bundler/lib → lib}/bundler/vendor/thor/lib/thor/actions/directory.rb +0 -0
  463. /data/{bundler/lib → lib}/bundler/vendor/thor/lib/thor/actions/empty_directory.rb +0 -0
  464. /data/{bundler/lib → lib}/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb +0 -0
  465. /data/{bundler/lib → lib}/bundler/vendor/thor/lib/thor/actions.rb +0 -0
  466. /data/{bundler/lib → lib}/bundler/vendor/thor/lib/thor/command.rb +0 -0
  467. /data/{bundler/lib → lib}/bundler/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb +0 -0
  468. /data/{bundler/lib → lib}/bundler/vendor/thor/lib/thor/error.rb +0 -0
  469. /data/{bundler/lib → lib}/bundler/vendor/thor/lib/thor/group.rb +0 -0
  470. /data/{bundler/lib → lib}/bundler/vendor/thor/lib/thor/invocation.rb +0 -0
  471. /data/{bundler/lib → lib}/bundler/vendor/thor/lib/thor/line_editor/basic.rb +0 -0
  472. /data/{bundler/lib → lib}/bundler/vendor/thor/lib/thor/line_editor/readline.rb +0 -0
  473. /data/{bundler/lib → lib}/bundler/vendor/thor/lib/thor/line_editor.rb +0 -0
  474. /data/{bundler/lib → lib}/bundler/vendor/thor/lib/thor/nested_context.rb +0 -0
  475. /data/{bundler/lib → lib}/bundler/vendor/thor/lib/thor/parser/argument.rb +0 -0
  476. /data/{bundler/lib → lib}/bundler/vendor/thor/lib/thor/parser/arguments.rb +0 -0
  477. /data/{bundler/lib → lib}/bundler/vendor/thor/lib/thor/parser/option.rb +0 -0
  478. /data/{bundler/lib → lib}/bundler/vendor/thor/lib/thor/parser/options.rb +0 -0
  479. /data/{bundler/lib → lib}/bundler/vendor/thor/lib/thor/parser.rb +0 -0
  480. /data/{bundler/lib → lib}/bundler/vendor/thor/lib/thor/rake_compat.rb +0 -0
  481. /data/{bundler/lib → lib}/bundler/vendor/thor/lib/thor/runner.rb +0 -0
  482. /data/{bundler/lib → lib}/bundler/vendor/thor/lib/thor/shell/column_printer.rb +0 -0
  483. /data/{bundler/lib → lib}/bundler/vendor/thor/lib/thor/shell/html.rb +0 -0
  484. /data/{bundler/lib → lib}/bundler/vendor/thor/lib/thor/shell/table_printer.rb +0 -0
  485. /data/{bundler/lib → lib}/bundler/vendor/thor/lib/thor/shell/terminal.rb +0 -0
  486. /data/{bundler/lib → lib}/bundler/vendor/thor/lib/thor/shell/wrapped_printer.rb +0 -0
  487. /data/{bundler/lib → lib}/bundler/vendor/thor/lib/thor/shell.rb +0 -0
  488. /data/{bundler/lib → lib}/bundler/vendor/thor/lib/thor/util.rb +0 -0
  489. /data/{bundler/lib → lib}/bundler/vendored_fileutils.rb +0 -0
  490. /data/{bundler/lib → lib}/bundler/vendored_net_http.rb +0 -0
  491. /data/{bundler/lib → lib}/bundler/vendored_thor.rb +0 -0
  492. /data/{bundler/lib → lib}/bundler/vendored_timeout.rb +0 -0
  493. /data/{bundler/lib → lib}/bundler/vendored_tsort.rb +0 -0
  494. /data/{bundler/lib → lib}/bundler/vlad.rb +0 -0
  495. /data/{bundler/lib/bundler → lib/rubygems}/vendor/pub_grub/LICENSE.txt +0 -0
  496. /data/{bundler/lib/bundler/vendor/securerandom → lib/rubygems/vendor/resolv}/COPYING +0 -0
@@ -0,0 +1,3508 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'socket'
4
+ require_relative '../../../vendored_timeout'
5
+ require 'io/wait'
6
+ require_relative '../../../vendored_securerandom'
7
+ require 'rbconfig'
8
+
9
+ # Gem::Resolv is a thread-aware DNS resolver library written in Ruby. Gem::Resolv can
10
+ # handle multiple DNS requests concurrently without blocking the entire Ruby
11
+ # interpreter.
12
+ #
13
+ # See also resolv-replace.rb to replace the libc resolver with Gem::Resolv.
14
+ #
15
+ # Gem::Resolv can look up various DNS resources using the DNS module directly.
16
+ #
17
+ # Examples:
18
+ #
19
+ # p Gem::Resolv.getaddress "www.ruby-lang.org"
20
+ # p Gem::Resolv.getname "210.251.121.214"
21
+ #
22
+ # Gem::Resolv::DNS.open do |dns|
23
+ # ress = dns.getresources "www.ruby-lang.org", Gem::Resolv::DNS::Resource::IN::A
24
+ # p ress.map(&:address)
25
+ # ress = dns.getresources "ruby-lang.org", Gem::Resolv::DNS::Resource::IN::MX
26
+ # p ress.map { |r| [r.exchange.to_s, r.preference] }
27
+ # end
28
+ #
29
+ #
30
+ # == Bugs
31
+ #
32
+ # * NIS is not supported.
33
+ # * /etc/nsswitch.conf is not supported.
34
+
35
+ class Gem::Resolv
36
+
37
+ # The version string
38
+ VERSION = "0.7.1"
39
+
40
+ ##
41
+ # Looks up the first IP address for +name+.
42
+
43
+ def self.getaddress(name)
44
+ DefaultResolver.getaddress(name)
45
+ end
46
+
47
+ ##
48
+ # Looks up all IP address for +name+.
49
+
50
+ def self.getaddresses(name)
51
+ DefaultResolver.getaddresses(name)
52
+ end
53
+
54
+ ##
55
+ # Iterates over all IP addresses for +name+.
56
+
57
+ def self.each_address(name, &block)
58
+ DefaultResolver.each_address(name, &block)
59
+ end
60
+
61
+ ##
62
+ # Looks up the hostname of +address+.
63
+
64
+ def self.getname(address)
65
+ DefaultResolver.getname(address)
66
+ end
67
+
68
+ ##
69
+ # Looks up all hostnames for +address+.
70
+
71
+ def self.getnames(address)
72
+ DefaultResolver.getnames(address)
73
+ end
74
+
75
+ ##
76
+ # Iterates over all hostnames for +address+.
77
+
78
+ def self.each_name(address, &proc)
79
+ DefaultResolver.each_name(address, &proc)
80
+ end
81
+
82
+ ##
83
+ # Creates a new Gem::Resolv using +resolvers+.
84
+ #
85
+ # If +resolvers+ is not given, a hash, or +nil+, uses a Hosts resolver and
86
+ # and a DNS resolver. If +resolvers+ is a hash, uses the hash as
87
+ # configuration for the DNS resolver.
88
+
89
+ def initialize(resolvers=(arg_not_set = true; nil), use_ipv6: (keyword_not_set = true; nil))
90
+ if !keyword_not_set && !arg_not_set
91
+ warn "Support for separate use_ipv6 keyword is deprecated, as it is ignored if an argument is provided. Do not provide a positional argument if using the use_ipv6 keyword argument.", uplevel: 1
92
+ end
93
+
94
+ @resolvers = case resolvers
95
+ when Hash, nil
96
+ [Hosts.new, DNS.new(DNS::Config.default_config_hash.merge(resolvers || {}))]
97
+ else
98
+ resolvers
99
+ end
100
+ end
101
+
102
+ ##
103
+ # Looks up the first IP address for +name+.
104
+
105
+ def getaddress(name)
106
+ each_address(name) {|address| return address}
107
+ raise ResolvError.new("no address for #{name}")
108
+ end
109
+
110
+ ##
111
+ # Looks up all IP address for +name+.
112
+
113
+ def getaddresses(name)
114
+ ret = []
115
+ each_address(name) {|address| ret << address}
116
+ return ret
117
+ end
118
+
119
+ ##
120
+ # Iterates over all IP addresses for +name+.
121
+
122
+ def each_address(name)
123
+ if AddressRegex =~ name
124
+ yield name
125
+ return
126
+ end
127
+ yielded = false
128
+ @resolvers.each {|r|
129
+ r.each_address(name) {|address|
130
+ yield address.to_s
131
+ yielded = true
132
+ }
133
+ return if yielded
134
+ }
135
+ end
136
+
137
+ ##
138
+ # Looks up the hostname of +address+.
139
+
140
+ def getname(address)
141
+ each_name(address) {|name| return name}
142
+ raise ResolvError.new("no name for #{address}")
143
+ end
144
+
145
+ ##
146
+ # Looks up all hostnames for +address+.
147
+
148
+ def getnames(address)
149
+ ret = []
150
+ each_name(address) {|name| ret << name}
151
+ return ret
152
+ end
153
+
154
+ ##
155
+ # Iterates over all hostnames for +address+.
156
+
157
+ def each_name(address)
158
+ yielded = false
159
+ @resolvers.each {|r|
160
+ r.each_name(address) {|name|
161
+ yield name.to_s
162
+ yielded = true
163
+ }
164
+ return if yielded
165
+ }
166
+ end
167
+
168
+ ##
169
+ # Indicates a failure to resolve a name or address.
170
+
171
+ class ResolvError < StandardError; end
172
+
173
+ ##
174
+ # Indicates a timeout resolving a name or address.
175
+
176
+ class ResolvTimeout < Gem::Timeout::Error; end
177
+
178
+ ##
179
+ # Gem::Resolv::Hosts is a hostname resolver that uses the system hosts file.
180
+
181
+ class Hosts
182
+ if /mswin|cygwin|mingw|bccwin/ =~ RUBY_PLATFORM || ::RbConfig::CONFIG['host_os'] =~ /mswin/
183
+ begin
184
+ require 'win32/resolv' unless defined?(Win32::Resolv)
185
+ hosts = Win32::Resolv.get_hosts_path || IO::NULL
186
+ rescue LoadError
187
+ end
188
+ end
189
+ # The default file name for host names
190
+ DefaultFileName = hosts || '/etc/hosts'
191
+
192
+ ##
193
+ # Creates a new Gem::Resolv::Hosts, using +filename+ for its data source.
194
+
195
+ def initialize(filename = DefaultFileName)
196
+ @filename = filename
197
+ @mutex = Thread::Mutex.new
198
+ @initialized = nil
199
+ end
200
+
201
+ def lazy_initialize # :nodoc:
202
+ @mutex.synchronize {
203
+ unless @initialized
204
+ @name2addr = {}
205
+ @addr2name = {}
206
+ File.open(@filename, 'rb') {|f|
207
+ f.each {|line|
208
+ line.sub!(/#.*/, '')
209
+ addr, *hostnames = line.split(/\s+/)
210
+ next unless addr
211
+ (@addr2name[addr] ||= []).concat(hostnames)
212
+ hostnames.each {|hostname| (@name2addr[hostname] ||= []) << addr}
213
+ }
214
+ }
215
+ @name2addr.each {|name, arr| arr.reverse!}
216
+ @initialized = true
217
+ end
218
+ }
219
+ self
220
+ end
221
+
222
+ ##
223
+ # Gets the IP address of +name+ from the hosts file.
224
+
225
+ def getaddress(name)
226
+ each_address(name) {|address| return address}
227
+ raise ResolvError.new("#{@filename} has no name: #{name}")
228
+ end
229
+
230
+ ##
231
+ # Gets all IP addresses for +name+ from the hosts file.
232
+
233
+ def getaddresses(name)
234
+ ret = []
235
+ each_address(name) {|address| ret << address}
236
+ return ret
237
+ end
238
+
239
+ ##
240
+ # Iterates over all IP addresses for +name+ retrieved from the hosts file.
241
+
242
+ def each_address(name, &proc)
243
+ lazy_initialize
244
+ @name2addr[name]&.each(&proc)
245
+ end
246
+
247
+ ##
248
+ # Gets the hostname of +address+ from the hosts file.
249
+
250
+ def getname(address)
251
+ each_name(address) {|name| return name}
252
+ raise ResolvError.new("#{@filename} has no address: #{address}")
253
+ end
254
+
255
+ ##
256
+ # Gets all hostnames for +address+ from the hosts file.
257
+
258
+ def getnames(address)
259
+ ret = []
260
+ each_name(address) {|name| ret << name}
261
+ return ret
262
+ end
263
+
264
+ ##
265
+ # Iterates over all hostnames for +address+ retrieved from the hosts file.
266
+
267
+ def each_name(address, &proc)
268
+ lazy_initialize
269
+ @addr2name[address]&.each(&proc)
270
+ end
271
+ end
272
+
273
+ ##
274
+ # Gem::Resolv::DNS is a DNS stub resolver.
275
+ #
276
+ # Information taken from the following places:
277
+ #
278
+ # * STD0013
279
+ # * RFC 1035
280
+ # * ftp://ftp.isi.edu/in-notes/iana/assignments/dns-parameters
281
+ # * etc.
282
+
283
+ class DNS
284
+
285
+ ##
286
+ # Default DNS Port
287
+
288
+ Port = 53
289
+
290
+ ##
291
+ # Default DNS UDP packet size
292
+
293
+ UDPSize = 512
294
+
295
+ ##
296
+ # Creates a new DNS resolver. See Gem::Resolv::DNS.new for argument details.
297
+ #
298
+ # Yields the created DNS resolver to the block, if given, otherwise
299
+ # returns it.
300
+
301
+ def self.open(*args)
302
+ dns = new(*args)
303
+ return dns unless block_given?
304
+ begin
305
+ yield dns
306
+ ensure
307
+ dns.close
308
+ end
309
+ end
310
+
311
+ ##
312
+ # Creates a new DNS resolver.
313
+ #
314
+ # +config_info+ can be:
315
+ #
316
+ # nil:: Uses /etc/resolv.conf.
317
+ # String:: Path to a file using /etc/resolv.conf's format.
318
+ # Hash:: Must contain :nameserver, :search and :ndots keys.
319
+ # :nameserver_port can be used to specify port number of nameserver address.
320
+ # :raise_timeout_errors can be used to raise timeout errors
321
+ # as exceptions instead of treating the same as an NXDOMAIN response.
322
+ #
323
+ # The value of :nameserver should be an address string or
324
+ # an array of address strings.
325
+ # - :nameserver => '8.8.8.8'
326
+ # - :nameserver => ['8.8.8.8', '8.8.4.4']
327
+ #
328
+ # The value of :nameserver_port should be an array of
329
+ # pair of nameserver address and port number.
330
+ # - :nameserver_port => [['8.8.8.8', 53], ['8.8.4.4', 53]]
331
+ #
332
+ # Example:
333
+ #
334
+ # Gem::Resolv::DNS.new(:nameserver => ['210.251.121.21'],
335
+ # :search => ['ruby-lang.org'],
336
+ # :ndots => 1)
337
+
338
+ def initialize(config_info=nil)
339
+ @mutex = Thread::Mutex.new
340
+ @config = Config.new(config_info)
341
+ @initialized = nil
342
+ end
343
+
344
+ # Sets the resolver timeouts. This may be a single positive number
345
+ # or an array of positive numbers representing timeouts in seconds.
346
+ # If an array is specified, a DNS request will retry and wait for
347
+ # each successive interval in the array until a successful response
348
+ # is received. Specifying +nil+ reverts to the default timeouts:
349
+ # [ 5, second = 5 * 2 / nameserver_count, 2 * second, 4 * second ]
350
+ #
351
+ # Example:
352
+ #
353
+ # dns.timeouts = 3
354
+ #
355
+ def timeouts=(values)
356
+ @config.timeouts = values
357
+ end
358
+
359
+ def lazy_initialize # :nodoc:
360
+ @mutex.synchronize {
361
+ unless @initialized
362
+ @config.lazy_initialize
363
+ @initialized = true
364
+ end
365
+ }
366
+ self
367
+ end
368
+
369
+ ##
370
+ # Closes the DNS resolver.
371
+
372
+ def close
373
+ @mutex.synchronize {
374
+ if @initialized
375
+ @initialized = false
376
+ end
377
+ }
378
+ end
379
+
380
+ ##
381
+ # Gets the IP address of +name+ from the DNS resolver.
382
+ #
383
+ # +name+ can be a Gem::Resolv::DNS::Name or a String. Retrieved address will
384
+ # be a Gem::Resolv::IPv4 or Gem::Resolv::IPv6
385
+
386
+ def getaddress(name)
387
+ each_address(name) {|address| return address}
388
+ raise ResolvError.new("DNS result has no information for #{name}")
389
+ end
390
+
391
+ ##
392
+ # Gets all IP addresses for +name+ from the DNS resolver.
393
+ #
394
+ # +name+ can be a Gem::Resolv::DNS::Name or a String. Retrieved addresses will
395
+ # be a Gem::Resolv::IPv4 or Gem::Resolv::IPv6
396
+
397
+ def getaddresses(name)
398
+ ret = []
399
+ each_address(name) {|address| ret << address}
400
+ return ret
401
+ end
402
+
403
+ ##
404
+ # Iterates over all IP addresses for +name+ retrieved from the DNS
405
+ # resolver.
406
+ #
407
+ # +name+ can be a Gem::Resolv::DNS::Name or a String. Retrieved addresses will
408
+ # be a Gem::Resolv::IPv4 or Gem::Resolv::IPv6
409
+
410
+ def each_address(name)
411
+ if use_ipv6?
412
+ each_resource(name, Resource::IN::AAAA) {|resource| yield resource.address}
413
+ end
414
+ each_resource(name, Resource::IN::A) {|resource| yield resource.address}
415
+ end
416
+
417
+ def use_ipv6? # :nodoc:
418
+ @config.lazy_initialize unless @config.instance_variable_get(:@initialized)
419
+
420
+ use_ipv6 = @config.use_ipv6?
421
+ unless use_ipv6.nil?
422
+ return use_ipv6
423
+ end
424
+
425
+ begin
426
+ list = Socket.ip_address_list
427
+ rescue NotImplementedError
428
+ return true
429
+ end
430
+ list.any? {|a| a.ipv6? && !a.ipv6_loopback? && !a.ipv6_linklocal? }
431
+ end
432
+ private :use_ipv6?
433
+
434
+ ##
435
+ # Gets the hostname for +address+ from the DNS resolver.
436
+ #
437
+ # +address+ must be a Gem::Resolv::IPv4, Gem::Resolv::IPv6 or a String. Retrieved
438
+ # name will be a Gem::Resolv::DNS::Name.
439
+
440
+ def getname(address)
441
+ each_name(address) {|name| return name}
442
+ raise ResolvError.new("DNS result has no information for #{address}")
443
+ end
444
+
445
+ ##
446
+ # Gets all hostnames for +address+ from the DNS resolver.
447
+ #
448
+ # +address+ must be a Gem::Resolv::IPv4, Gem::Resolv::IPv6 or a String. Retrieved
449
+ # names will be Gem::Resolv::DNS::Name instances.
450
+
451
+ def getnames(address)
452
+ ret = []
453
+ each_name(address) {|name| ret << name}
454
+ return ret
455
+ end
456
+
457
+ ##
458
+ # Iterates over all hostnames for +address+ retrieved from the DNS
459
+ # resolver.
460
+ #
461
+ # +address+ must be a Gem::Resolv::IPv4, Gem::Resolv::IPv6 or a String. Retrieved
462
+ # names will be Gem::Resolv::DNS::Name instances.
463
+
464
+ def each_name(address)
465
+ case address
466
+ when Name
467
+ ptr = address
468
+ when IPv4, IPv6
469
+ ptr = address.to_name
470
+ when IPv4::Regex
471
+ ptr = IPv4.create(address).to_name
472
+ when IPv6::Regex
473
+ ptr = IPv6.create(address).to_name
474
+ else
475
+ raise ResolvError.new("cannot interpret as address: #{address}")
476
+ end
477
+ each_resource(ptr, Resource::IN::PTR) {|resource| yield resource.name}
478
+ end
479
+
480
+ ##
481
+ # Look up the +typeclass+ DNS resource of +name+.
482
+ #
483
+ # +name+ must be a Gem::Resolv::DNS::Name or a String.
484
+ #
485
+ # +typeclass+ should be one of the following:
486
+ #
487
+ # * Gem::Resolv::DNS::Resource::IN::A
488
+ # * Gem::Resolv::DNS::Resource::IN::AAAA
489
+ # * Gem::Resolv::DNS::Resource::IN::ANY
490
+ # * Gem::Resolv::DNS::Resource::IN::CAA
491
+ # * Gem::Resolv::DNS::Resource::IN::CNAME
492
+ # * Gem::Resolv::DNS::Resource::IN::HINFO
493
+ # * Gem::Resolv::DNS::Resource::IN::HTTPS
494
+ # * Gem::Resolv::DNS::Resource::IN::LOC
495
+ # * Gem::Resolv::DNS::Resource::IN::MINFO
496
+ # * Gem::Resolv::DNS::Resource::IN::MX
497
+ # * Gem::Resolv::DNS::Resource::IN::NS
498
+ # * Gem::Resolv::DNS::Resource::IN::PTR
499
+ # * Gem::Resolv::DNS::Resource::IN::SOA
500
+ # * Gem::Resolv::DNS::Resource::IN::SRV
501
+ # * Gem::Resolv::DNS::Resource::IN::SVCB
502
+ # * Gem::Resolv::DNS::Resource::IN::TXT
503
+ # * Gem::Resolv::DNS::Resource::IN::WKS
504
+ #
505
+ # Returned resource is represented as a Gem::Resolv::DNS::Resource instance,
506
+ # i.e. Gem::Resolv::DNS::Resource::IN::A.
507
+
508
+ def getresource(name, typeclass)
509
+ each_resource(name, typeclass) {|resource| return resource}
510
+ raise ResolvError.new("DNS result has no information for #{name}")
511
+ end
512
+
513
+ ##
514
+ # Looks up all +typeclass+ DNS resources for +name+. See #getresource for
515
+ # argument details.
516
+
517
+ def getresources(name, typeclass)
518
+ ret = []
519
+ each_resource(name, typeclass) {|resource| ret << resource}
520
+ return ret
521
+ end
522
+
523
+ ##
524
+ # Iterates over all +typeclass+ DNS resources for +name+. See
525
+ # #getresource for argument details.
526
+
527
+ def each_resource(name, typeclass, &proc)
528
+ fetch_resource(name, typeclass) {|reply, reply_name|
529
+ extract_resources(reply, reply_name, typeclass, &proc)
530
+ }
531
+ end
532
+
533
+ # :stopdoc:
534
+
535
+ def fetch_resource(name, typeclass)
536
+ lazy_initialize
537
+ truncated = {}
538
+ requesters = {}
539
+ udp_requester = begin
540
+ make_udp_requester
541
+ rescue Errno::EACCES
542
+ # fall back to TCP
543
+ end
544
+ senders = {}
545
+
546
+ begin
547
+ @config.resolv(name) do |candidate, tout, nameserver, port|
548
+ msg = Message.new
549
+ msg.rd = 1
550
+ msg.add_question(candidate, typeclass)
551
+
552
+ requester = requesters.fetch([nameserver, port]) do
553
+ if !truncated[candidate] && udp_requester
554
+ udp_requester
555
+ else
556
+ requesters[[nameserver, port]] = make_tcp_requester(nameserver, port)
557
+ end
558
+ end
559
+
560
+ unless sender = senders[[candidate, requester, nameserver, port]]
561
+ sender = requester.sender(msg, candidate, nameserver, port)
562
+ next if !sender
563
+ senders[[candidate, requester, nameserver, port]] = sender
564
+ end
565
+ reply, reply_name = requester.request(sender, tout)
566
+ case reply.rcode
567
+ when RCode::NoError
568
+ if reply.tc == 1 and not Requester::TCP === requester
569
+ # Retry via TCP:
570
+ truncated[candidate] = true
571
+ redo
572
+ else
573
+ yield(reply, reply_name)
574
+ end
575
+ return
576
+ when RCode::NXDomain
577
+ raise Config::NXDomain.new(reply_name.to_s)
578
+ else
579
+ raise Config::OtherResolvError.new(reply_name.to_s)
580
+ end
581
+ end
582
+ ensure
583
+ udp_requester&.close
584
+ requesters.each_value { |requester| requester&.close }
585
+ end
586
+ end
587
+
588
+ def make_udp_requester # :nodoc:
589
+ nameserver_port = @config.nameserver_port
590
+ if nameserver_port.length == 1
591
+ Requester::ConnectedUDP.new(*nameserver_port[0])
592
+ else
593
+ Requester::UnconnectedUDP.new(*nameserver_port)
594
+ end
595
+ end
596
+
597
+ def make_tcp_requester(host, port) # :nodoc:
598
+ return Requester::TCP.new(host, port)
599
+ rescue Errno::ECONNREFUSED
600
+ # Treat a refused TCP connection attempt to a nameserver like a timeout,
601
+ # as Gem::Resolv::DNS::Config#resolv considers ResolvTimeout exceptions as a
602
+ # hint to try the next nameserver:
603
+ raise ResolvTimeout
604
+ end
605
+
606
+ def extract_resources(msg, name, typeclass) # :nodoc:
607
+ if typeclass < Resource::ANY
608
+ n0 = Name.create(name)
609
+ msg.each_resource {|n, ttl, data|
610
+ yield data if n0 == n
611
+ }
612
+ end
613
+ yielded = false
614
+ n0 = Name.create(name)
615
+ msg.each_resource {|n, ttl, data|
616
+ if n0 == n
617
+ case data
618
+ when typeclass
619
+ yield data
620
+ yielded = true
621
+ when Resource::CNAME
622
+ n0 = data.name
623
+ end
624
+ end
625
+ }
626
+ return if yielded
627
+ msg.each_resource {|n, ttl, data|
628
+ if n0 == n
629
+ case data
630
+ when typeclass
631
+ yield data
632
+ end
633
+ end
634
+ }
635
+ end
636
+
637
+ def self.random(arg) # :nodoc:
638
+ begin
639
+ Gem::SecureRandom.random_number(arg)
640
+ rescue NotImplementedError
641
+ rand(arg)
642
+ end
643
+ end
644
+
645
+ RequestID = {} # :nodoc:
646
+ RequestIDMutex = Thread::Mutex.new # :nodoc:
647
+
648
+ def self.allocate_request_id(host, port) # :nodoc:
649
+ id = nil
650
+ RequestIDMutex.synchronize {
651
+ h = (RequestID[[host, port]] ||= {})
652
+ begin
653
+ id = random(0x0000..0xffff)
654
+ end while h[id]
655
+ h[id] = true
656
+ }
657
+ id
658
+ end
659
+
660
+ def self.free_request_id(host, port, id) # :nodoc:
661
+ RequestIDMutex.synchronize {
662
+ key = [host, port]
663
+ if h = RequestID[key]
664
+ h.delete id
665
+ if h.empty?
666
+ RequestID.delete key
667
+ end
668
+ end
669
+ }
670
+ end
671
+
672
+ case RUBY_PLATFORM
673
+ when *[
674
+ # https://www.rfc-editor.org/rfc/rfc6056.txt
675
+ # Appendix A. Survey of the Algorithms in Use by Some Popular Implementations
676
+ /freebsd/, /linux/, /netbsd/, /openbsd/, /solaris/,
677
+ /darwin/, # the same as FreeBSD
678
+ ] then
679
+ def self.bind_random_port(udpsock, bind_host="0.0.0.0") # :nodoc:
680
+ udpsock.bind(bind_host, 0)
681
+ end
682
+ else
683
+ # Sequential port assignment
684
+ def self.bind_random_port(udpsock, bind_host="0.0.0.0") # :nodoc:
685
+ # Ephemeral port number range recommended by RFC 6056
686
+ port = random(1024..65535)
687
+ udpsock.bind(bind_host, port)
688
+ rescue Errno::EADDRINUSE, # POSIX
689
+ Errno::EACCES, # SunOS: See PRIV_SYS_NFS in privileges(5)
690
+ Errno::EPERM # FreeBSD: security.mac.portacl.port_high is configurable. See mac_portacl(4).
691
+ retry
692
+ end
693
+ end
694
+
695
+ class Requester # :nodoc:
696
+ def initialize
697
+ @senders = {}
698
+ @socks = nil
699
+ end
700
+
701
+ def request(sender, tout)
702
+ start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
703
+ timelimit = start + tout
704
+ begin
705
+ sender.send
706
+ rescue Errno::EHOSTUNREACH, # multi-homed IPv6 may generate this
707
+ Errno::ENETUNREACH
708
+ raise ResolvTimeout
709
+ end
710
+ while true
711
+ before_select = Process.clock_gettime(Process::CLOCK_MONOTONIC)
712
+ timeout = timelimit - before_select
713
+ if timeout <= 0
714
+ raise ResolvTimeout
715
+ end
716
+ if @socks.size == 1
717
+ select_result = @socks[0].wait_readable(timeout) ? [ @socks ] : nil
718
+ else
719
+ select_result = IO.select(@socks, nil, nil, timeout)
720
+ end
721
+ if !select_result
722
+ after_select = Process.clock_gettime(Process::CLOCK_MONOTONIC)
723
+ next if after_select < timelimit
724
+ raise ResolvTimeout
725
+ end
726
+ begin
727
+ reply, from = recv_reply(select_result[0])
728
+ rescue Errno::ECONNREFUSED, # GNU/Linux, FreeBSD
729
+ Errno::ECONNRESET, # Windows
730
+ EOFError
731
+ # No name server running on the server?
732
+ # Don't wait anymore.
733
+ raise ResolvTimeout
734
+ end
735
+ begin
736
+ msg = Message.decode(reply)
737
+ rescue DecodeError
738
+ next # broken DNS message ignored
739
+ end
740
+ if sender == sender_for(from, msg)
741
+ break
742
+ else
743
+ # unexpected DNS message ignored
744
+ end
745
+ end
746
+ return msg, sender.data
747
+ end
748
+
749
+ def sender_for(addr, msg)
750
+ @senders[[addr,msg.id]]
751
+ end
752
+
753
+ def close
754
+ socks = @socks
755
+ @socks = nil
756
+ socks&.each(&:close)
757
+ end
758
+
759
+ class Sender # :nodoc:
760
+ def initialize(msg, data, sock)
761
+ @msg = msg
762
+ @data = data
763
+ @sock = sock
764
+ end
765
+ end
766
+
767
+ class UnconnectedUDP < Requester # :nodoc:
768
+ def initialize(*nameserver_port)
769
+ super()
770
+ @nameserver_port = nameserver_port
771
+ @initialized = false
772
+ @mutex = Thread::Mutex.new
773
+ end
774
+
775
+ def lazy_initialize
776
+ @mutex.synchronize {
777
+ next if @initialized
778
+ @initialized = true
779
+ @socks_hash = {}
780
+ @socks = []
781
+ @nameserver_port.each {|host, port|
782
+ if host.index(':')
783
+ bind_host = "::"
784
+ af = Socket::AF_INET6
785
+ else
786
+ bind_host = "0.0.0.0"
787
+ af = Socket::AF_INET
788
+ end
789
+ next if @socks_hash[bind_host]
790
+ begin
791
+ sock = UDPSocket.new(af)
792
+ rescue Errno::EAFNOSUPPORT, Errno::EPROTONOSUPPORT
793
+ next # The kernel doesn't support the address family.
794
+ end
795
+ @socks << sock
796
+ @socks_hash[bind_host] = sock
797
+ sock.do_not_reverse_lookup = true
798
+ DNS.bind_random_port(sock, bind_host)
799
+ }
800
+ }
801
+ self
802
+ end
803
+
804
+ def recv_reply(readable_socks)
805
+ lazy_initialize
806
+ reply, from = readable_socks[0].recvfrom(UDPSize)
807
+ return reply, [from[3],from[1]]
808
+ end
809
+
810
+ def sender(msg, data, host, port=Port)
811
+ host = Addrinfo.ip(host).ip_address
812
+ lazy_initialize
813
+ sock = @socks_hash[host.index(':') ? "::" : "0.0.0.0"]
814
+ return nil if !sock
815
+ service = [host, port]
816
+ id = DNS.allocate_request_id(host, port)
817
+ request = msg.encode
818
+ request[0,2] = [id].pack('n')
819
+ return @senders[[service, id]] =
820
+ Sender.new(request, data, sock, host, port)
821
+ end
822
+
823
+ def close
824
+ @mutex.synchronize {
825
+ if @initialized
826
+ super
827
+ @senders.each_key {|service, id|
828
+ DNS.free_request_id(service[0], service[1], id)
829
+ }
830
+ @initialized = false
831
+ end
832
+ }
833
+ end
834
+
835
+ class Sender < Requester::Sender # :nodoc:
836
+ def initialize(msg, data, sock, host, port)
837
+ super(msg, data, sock)
838
+ @host = host
839
+ @port = port
840
+ end
841
+ attr_reader :data
842
+
843
+ def send
844
+ raise "@sock is nil." if @sock.nil?
845
+ @sock.send(@msg, 0, @host, @port)
846
+ end
847
+ end
848
+ end
849
+
850
+ class ConnectedUDP < Requester # :nodoc:
851
+ def initialize(host, port=Port)
852
+ super()
853
+ @host = host
854
+ @port = port
855
+ @mutex = Thread::Mutex.new
856
+ @initialized = false
857
+ end
858
+
859
+ def lazy_initialize
860
+ @mutex.synchronize {
861
+ next if @initialized
862
+ @initialized = true
863
+ is_ipv6 = @host.index(':')
864
+ sock = UDPSocket.new(is_ipv6 ? Socket::AF_INET6 : Socket::AF_INET)
865
+ @socks = [sock]
866
+ sock.do_not_reverse_lookup = true
867
+ DNS.bind_random_port(sock, is_ipv6 ? "::" : "0.0.0.0")
868
+ sock.connect(@host, @port)
869
+ }
870
+ self
871
+ end
872
+
873
+ def recv_reply(readable_socks)
874
+ lazy_initialize
875
+ reply = readable_socks[0].recv(UDPSize)
876
+ return reply, nil
877
+ end
878
+
879
+ def sender(msg, data, host=@host, port=@port)
880
+ lazy_initialize
881
+ unless host == @host && port == @port
882
+ raise RequestError.new("host/port don't match: #{host}:#{port}")
883
+ end
884
+ id = DNS.allocate_request_id(@host, @port)
885
+ request = msg.encode
886
+ request[0,2] = [id].pack('n')
887
+ return @senders[[nil,id]] = Sender.new(request, data, @socks[0])
888
+ end
889
+
890
+ def close
891
+ @mutex.synchronize do
892
+ if @initialized
893
+ super
894
+ @senders.each_key {|from, id|
895
+ DNS.free_request_id(@host, @port, id)
896
+ }
897
+ @initialized = false
898
+ end
899
+ end
900
+ end
901
+
902
+ class Sender < Requester::Sender # :nodoc:
903
+ def send
904
+ raise "@sock is nil." if @sock.nil?
905
+ @sock.send(@msg, 0)
906
+ end
907
+ attr_reader :data
908
+ end
909
+ end
910
+
911
+ class MDNSOneShot < UnconnectedUDP # :nodoc:
912
+ def sender(msg, data, host, port=Port)
913
+ lazy_initialize
914
+ id = DNS.allocate_request_id(host, port)
915
+ request = msg.encode
916
+ request[0,2] = [id].pack('n')
917
+ sock = @socks_hash[host.index(':') ? "::" : "0.0.0.0"]
918
+ return @senders[id] =
919
+ UnconnectedUDP::Sender.new(request, data, sock, host, port)
920
+ end
921
+
922
+ def sender_for(addr, msg)
923
+ lazy_initialize
924
+ @senders[msg.id]
925
+ end
926
+ end
927
+
928
+ class TCP < Requester # :nodoc:
929
+ def initialize(host, port=Port)
930
+ super()
931
+ @host = host
932
+ @port = port
933
+ sock = TCPSocket.new(@host, @port)
934
+ @socks = [sock]
935
+ @senders = {}
936
+ end
937
+
938
+ def recv_reply(readable_socks)
939
+ len_data = readable_socks[0].read(2)
940
+ raise EOFError if len_data.nil? || len_data.bytesize != 2
941
+ len = len_data.unpack('n')[0]
942
+ reply = @socks[0].read(len)
943
+ raise EOFError if reply.nil? || reply.bytesize != len
944
+ return reply, nil
945
+ end
946
+
947
+ def sender(msg, data, host=@host, port=@port)
948
+ unless host == @host && port == @port
949
+ raise RequestError.new("host/port don't match: #{host}:#{port}")
950
+ end
951
+ id = DNS.allocate_request_id(@host, @port)
952
+ request = msg.encode
953
+ request[0,2] = [request.length, id].pack('nn')
954
+ return @senders[[nil,id]] = Sender.new(request, data, @socks[0])
955
+ end
956
+
957
+ class Sender < Requester::Sender # :nodoc:
958
+ def send
959
+ @sock.print(@msg)
960
+ @sock.flush
961
+ end
962
+ attr_reader :data
963
+ end
964
+
965
+ def close
966
+ super
967
+ @senders.each_key {|from,id|
968
+ DNS.free_request_id(@host, @port, id)
969
+ }
970
+ end
971
+ end
972
+
973
+ ##
974
+ # Indicates a problem with the DNS request.
975
+
976
+ class RequestError < StandardError
977
+ end
978
+ end
979
+
980
+ class Config # :nodoc:
981
+ def initialize(config_info=nil)
982
+ @mutex = Thread::Mutex.new
983
+ @config_info = config_info
984
+ @initialized = nil
985
+ @timeouts = nil
986
+ end
987
+
988
+ def timeouts=(values)
989
+ if values
990
+ values = Array(values)
991
+ values.each do |t|
992
+ Numeric === t or raise ArgumentError, "#{t.inspect} is not numeric"
993
+ t > 0.0 or raise ArgumentError, "timeout=#{t} must be positive"
994
+ end
995
+ @timeouts = values
996
+ else
997
+ @timeouts = nil
998
+ end
999
+ end
1000
+
1001
+ def Config.parse_resolv_conf(filename)
1002
+ nameserver = []
1003
+ search = nil
1004
+ ndots = 1
1005
+ File.open(filename, 'rb') {|f|
1006
+ f.each {|line|
1007
+ line.sub!(/[#;].*/, '')
1008
+ keyword, *args = line.split(/\s+/)
1009
+ next unless keyword
1010
+ case keyword
1011
+ when 'nameserver'
1012
+ nameserver.concat(args.each(&:freeze))
1013
+ when 'domain'
1014
+ next if args.empty?
1015
+ search = [args[0].freeze]
1016
+ when 'search'
1017
+ next if args.empty?
1018
+ search = args.each(&:freeze)
1019
+ when 'options'
1020
+ args.each {|arg|
1021
+ case arg
1022
+ when /\Andots:(\d+)\z/
1023
+ ndots = $1.to_i
1024
+ end
1025
+ }
1026
+ end
1027
+ }
1028
+ }
1029
+ return { :nameserver => nameserver.freeze, :search => search.freeze, :ndots => ndots.freeze }.freeze
1030
+ end
1031
+
1032
+ def Config.default_config_hash(filename="/etc/resolv.conf")
1033
+ if File.exist? filename
1034
+ Config.parse_resolv_conf(filename)
1035
+ elsif defined?(Win32::Resolv)
1036
+ search, nameserver = Win32::Resolv.get_resolv_info
1037
+ config_hash = {}
1038
+ config_hash[:nameserver] = nameserver if nameserver
1039
+ config_hash[:search] = [search].flatten if search
1040
+ config_hash
1041
+ else
1042
+ {}
1043
+ end
1044
+ end
1045
+
1046
+ def lazy_initialize
1047
+ @mutex.synchronize {
1048
+ unless @initialized
1049
+ @nameserver_port = []
1050
+ @use_ipv6 = nil
1051
+ @search = nil
1052
+ @ndots = 1
1053
+ case @config_info
1054
+ when nil
1055
+ config_hash = Config.default_config_hash
1056
+ when String
1057
+ config_hash = Config.parse_resolv_conf(@config_info)
1058
+ when Hash
1059
+ config_hash = @config_info.dup
1060
+ if String === config_hash[:nameserver]
1061
+ config_hash[:nameserver] = [config_hash[:nameserver]]
1062
+ end
1063
+ if String === config_hash[:search]
1064
+ config_hash[:search] = [config_hash[:search]]
1065
+ end
1066
+ else
1067
+ raise ArgumentError.new("invalid resolv configuration: #{@config_info.inspect}")
1068
+ end
1069
+ if config_hash.include? :nameserver
1070
+ @nameserver_port = config_hash[:nameserver].map {|ns| [ns, Port] }
1071
+ end
1072
+ if config_hash.include? :nameserver_port
1073
+ @nameserver_port = config_hash[:nameserver_port].map {|ns, port| [ns, (port || Port)] }
1074
+ end
1075
+ if config_hash.include? :use_ipv6
1076
+ @use_ipv6 = config_hash[:use_ipv6]
1077
+ end
1078
+ @search = config_hash[:search] if config_hash.include? :search
1079
+ @ndots = config_hash[:ndots] if config_hash.include? :ndots
1080
+ @raise_timeout_errors = config_hash[:raise_timeout_errors]
1081
+
1082
+ if @nameserver_port.empty?
1083
+ @nameserver_port << ['0.0.0.0', Port]
1084
+ end
1085
+ if @search
1086
+ @search = @search.map {|arg| Label.split(arg) }
1087
+ else
1088
+ hostname = Socket.gethostname
1089
+ if /\./ =~ hostname
1090
+ @search = [Label.split($')]
1091
+ else
1092
+ @search = [[]]
1093
+ end
1094
+ end
1095
+
1096
+ if !@nameserver_port.kind_of?(Array) ||
1097
+ @nameserver_port.any? {|ns_port|
1098
+ !(Array === ns_port) ||
1099
+ ns_port.length != 2
1100
+ !(String === ns_port[0]) ||
1101
+ !(Integer === ns_port[1])
1102
+ }
1103
+ raise ArgumentError.new("invalid nameserver config: #{@nameserver_port.inspect}")
1104
+ end
1105
+
1106
+ if !@search.kind_of?(Array) ||
1107
+ !@search.all? {|ls| ls.all? {|l| Label::Str === l } }
1108
+ raise ArgumentError.new("invalid search config: #{@search.inspect}")
1109
+ end
1110
+
1111
+ if !@ndots.kind_of?(Integer)
1112
+ raise ArgumentError.new("invalid ndots config: #{@ndots.inspect}")
1113
+ end
1114
+
1115
+ @initialized = true
1116
+ end
1117
+ }
1118
+ self
1119
+ end
1120
+
1121
+ def single?
1122
+ lazy_initialize
1123
+ if @nameserver_port.length == 1
1124
+ return @nameserver_port[0]
1125
+ else
1126
+ return nil
1127
+ end
1128
+ end
1129
+
1130
+ def nameserver_port
1131
+ @nameserver_port
1132
+ end
1133
+
1134
+ def use_ipv6?
1135
+ @use_ipv6
1136
+ end
1137
+
1138
+ def generate_candidates(name)
1139
+ candidates = nil
1140
+ name = Name.create(name)
1141
+ if name.absolute?
1142
+ candidates = [name]
1143
+ else
1144
+ if @ndots <= name.length - 1
1145
+ candidates = [Name.new(name.to_a)]
1146
+ else
1147
+ candidates = []
1148
+ end
1149
+ candidates.concat(@search.map {|domain| Name.new(name.to_a + domain)})
1150
+ fname = Name.create("#{name}.")
1151
+ if !candidates.include?(fname)
1152
+ candidates << fname
1153
+ end
1154
+ end
1155
+ return candidates
1156
+ end
1157
+
1158
+ InitialTimeout = 5
1159
+
1160
+ def generate_timeouts
1161
+ ts = [InitialTimeout]
1162
+ ts << ts[-1] * 2 / @nameserver_port.length
1163
+ ts << ts[-1] * 2
1164
+ ts << ts[-1] * 2
1165
+ return ts
1166
+ end
1167
+
1168
+ def resolv(name)
1169
+ candidates = generate_candidates(name)
1170
+ timeouts = @timeouts || generate_timeouts
1171
+ timeout_error = false
1172
+ begin
1173
+ candidates.each {|candidate|
1174
+ begin
1175
+ timeouts.each {|tout|
1176
+ @nameserver_port.each {|nameserver, port|
1177
+ begin
1178
+ yield candidate, tout, nameserver, port
1179
+ rescue ResolvTimeout
1180
+ end
1181
+ }
1182
+ }
1183
+ timeout_error = true
1184
+ raise ResolvError.new("DNS resolv timeout: #{name}")
1185
+ rescue NXDomain
1186
+ end
1187
+ }
1188
+ rescue ResolvError
1189
+ raise if @raise_timeout_errors && timeout_error
1190
+ end
1191
+ end
1192
+
1193
+ ##
1194
+ # Indicates no such domain was found.
1195
+
1196
+ class NXDomain < ResolvError
1197
+ end
1198
+
1199
+ ##
1200
+ # Indicates some other unhandled resolver error was encountered.
1201
+
1202
+ class OtherResolvError < ResolvError
1203
+ end
1204
+ end
1205
+
1206
+ module OpCode # :nodoc:
1207
+ Query = 0
1208
+ IQuery = 1
1209
+ Status = 2
1210
+ Notify = 4
1211
+ Update = 5
1212
+ end
1213
+
1214
+ module RCode # :nodoc:
1215
+ NoError = 0
1216
+ FormErr = 1
1217
+ ServFail = 2
1218
+ NXDomain = 3
1219
+ NotImp = 4
1220
+ Refused = 5
1221
+ YXDomain = 6
1222
+ YXRRSet = 7
1223
+ NXRRSet = 8
1224
+ NotAuth = 9
1225
+ NotZone = 10
1226
+ BADVERS = 16
1227
+ BADSIG = 16
1228
+ BADKEY = 17
1229
+ BADTIME = 18
1230
+ BADMODE = 19
1231
+ BADNAME = 20
1232
+ BADALG = 21
1233
+ end
1234
+
1235
+ ##
1236
+ # Indicates that the DNS response was unable to be decoded.
1237
+
1238
+ class DecodeError < StandardError
1239
+ end
1240
+
1241
+ ##
1242
+ # Indicates that the DNS request was unable to be encoded.
1243
+
1244
+ class EncodeError < StandardError
1245
+ end
1246
+
1247
+ module Label # :nodoc:
1248
+ def self.split(arg)
1249
+ labels = []
1250
+ arg.scan(/[^\.]+/) {labels << Str.new($&)}
1251
+ return labels
1252
+ end
1253
+
1254
+ class Str # :nodoc:
1255
+ def initialize(string)
1256
+ @string = string
1257
+ # case insensivity of DNS labels doesn't apply non-ASCII characters. [RFC 4343]
1258
+ # This assumes @string is given in ASCII compatible encoding.
1259
+ @downcase = string.b.downcase
1260
+ end
1261
+ attr_reader :string, :downcase
1262
+
1263
+ def to_s
1264
+ return @string
1265
+ end
1266
+
1267
+ def inspect
1268
+ return "#<#{self.class} #{self}>"
1269
+ end
1270
+
1271
+ def ==(other)
1272
+ return self.class == other.class && @downcase == other.downcase
1273
+ end
1274
+
1275
+ def eql?(other)
1276
+ return self == other
1277
+ end
1278
+
1279
+ def hash
1280
+ return @downcase.hash
1281
+ end
1282
+ end
1283
+ end
1284
+
1285
+ ##
1286
+ # A representation of a DNS name.
1287
+
1288
+ class Name
1289
+
1290
+ ##
1291
+ # Creates a new DNS name from +arg+. +arg+ can be:
1292
+ #
1293
+ # Name:: returns +arg+.
1294
+ # String:: Creates a new Name.
1295
+
1296
+ def self.create(arg)
1297
+ case arg
1298
+ when Name
1299
+ return arg
1300
+ when String
1301
+ return Name.new(Label.split(arg), /\.\z/ =~ arg ? true : false)
1302
+ else
1303
+ raise ArgumentError.new("cannot interpret as DNS name: #{arg.inspect}")
1304
+ end
1305
+ end
1306
+
1307
+ def initialize(labels, absolute=true) # :nodoc:
1308
+ labels = labels.map {|label|
1309
+ case label
1310
+ when String then Label::Str.new(label)
1311
+ when Label::Str then label
1312
+ else
1313
+ raise ArgumentError, "unexpected label: #{label.inspect}"
1314
+ end
1315
+ }
1316
+ @labels = labels
1317
+ @absolute = absolute
1318
+ end
1319
+
1320
+ def inspect # :nodoc:
1321
+ "#<#{self.class}: #{self}#{@absolute ? '.' : ''}>"
1322
+ end
1323
+
1324
+ ##
1325
+ # True if this name is absolute.
1326
+
1327
+ def absolute?
1328
+ return @absolute
1329
+ end
1330
+
1331
+ def ==(other) # :nodoc:
1332
+ return false unless Name === other
1333
+ return false unless @absolute == other.absolute?
1334
+ return @labels == other.to_a
1335
+ end
1336
+
1337
+ alias eql? == # :nodoc:
1338
+
1339
+ ##
1340
+ # Returns true if +other+ is a subdomain.
1341
+ #
1342
+ # Example:
1343
+ #
1344
+ # domain = Gem::Resolv::DNS::Name.create("y.z")
1345
+ # p Gem::Resolv::DNS::Name.create("w.x.y.z").subdomain_of?(domain) #=> true
1346
+ # p Gem::Resolv::DNS::Name.create("x.y.z").subdomain_of?(domain) #=> true
1347
+ # p Gem::Resolv::DNS::Name.create("y.z").subdomain_of?(domain) #=> false
1348
+ # p Gem::Resolv::DNS::Name.create("z").subdomain_of?(domain) #=> false
1349
+ # p Gem::Resolv::DNS::Name.create("x.y.z.").subdomain_of?(domain) #=> false
1350
+ # p Gem::Resolv::DNS::Name.create("w.z").subdomain_of?(domain) #=> false
1351
+ #
1352
+
1353
+ def subdomain_of?(other)
1354
+ raise ArgumentError, "not a domain name: #{other.inspect}" unless Name === other
1355
+ return false if @absolute != other.absolute?
1356
+ other_len = other.length
1357
+ return false if @labels.length <= other_len
1358
+ return @labels[-other_len, other_len] == other.to_a
1359
+ end
1360
+
1361
+ def hash # :nodoc:
1362
+ return @labels.hash ^ @absolute.hash
1363
+ end
1364
+
1365
+ def to_a # :nodoc:
1366
+ return @labels
1367
+ end
1368
+
1369
+ def length # :nodoc:
1370
+ return @labels.length
1371
+ end
1372
+
1373
+ def [](i) # :nodoc:
1374
+ return @labels[i]
1375
+ end
1376
+
1377
+ ##
1378
+ # returns the domain name as a string.
1379
+ #
1380
+ # The domain name doesn't have a trailing dot even if the name object is
1381
+ # absolute.
1382
+ #
1383
+ # Example:
1384
+ #
1385
+ # p Gem::Resolv::DNS::Name.create("x.y.z.").to_s #=> "x.y.z"
1386
+ # p Gem::Resolv::DNS::Name.create("x.y.z").to_s #=> "x.y.z"
1387
+
1388
+ def to_s
1389
+ return @labels.join('.')
1390
+ end
1391
+ end
1392
+
1393
+ class Message # :nodoc:
1394
+ @@identifier = -1
1395
+
1396
+ def initialize(id = (@@identifier += 1) & 0xffff)
1397
+ @id = id
1398
+ @qr = 0
1399
+ @opcode = 0
1400
+ @aa = 0
1401
+ @tc = 0
1402
+ @rd = 0 # recursion desired
1403
+ @ra = 0 # recursion available
1404
+ @rcode = 0
1405
+ @question = []
1406
+ @answer = []
1407
+ @authority = []
1408
+ @additional = []
1409
+ end
1410
+
1411
+ attr_accessor :id, :qr, :opcode, :aa, :tc, :rd, :ra, :rcode
1412
+ attr_reader :question, :answer, :authority, :additional
1413
+
1414
+ def ==(other)
1415
+ return @id == other.id &&
1416
+ @qr == other.qr &&
1417
+ @opcode == other.opcode &&
1418
+ @aa == other.aa &&
1419
+ @tc == other.tc &&
1420
+ @rd == other.rd &&
1421
+ @ra == other.ra &&
1422
+ @rcode == other.rcode &&
1423
+ @question == other.question &&
1424
+ @answer == other.answer &&
1425
+ @authority == other.authority &&
1426
+ @additional == other.additional
1427
+ end
1428
+
1429
+ def add_question(name, typeclass)
1430
+ @question << [Name.create(name), typeclass]
1431
+ end
1432
+
1433
+ def each_question
1434
+ @question.each {|name, typeclass|
1435
+ yield name, typeclass
1436
+ }
1437
+ end
1438
+
1439
+ def add_answer(name, ttl, data)
1440
+ @answer << [Name.create(name), ttl, data]
1441
+ end
1442
+
1443
+ def each_answer
1444
+ @answer.each {|name, ttl, data|
1445
+ yield name, ttl, data
1446
+ }
1447
+ end
1448
+
1449
+ def add_authority(name, ttl, data)
1450
+ @authority << [Name.create(name), ttl, data]
1451
+ end
1452
+
1453
+ def each_authority
1454
+ @authority.each {|name, ttl, data|
1455
+ yield name, ttl, data
1456
+ }
1457
+ end
1458
+
1459
+ def add_additional(name, ttl, data)
1460
+ @additional << [Name.create(name), ttl, data]
1461
+ end
1462
+
1463
+ def each_additional
1464
+ @additional.each {|name, ttl, data|
1465
+ yield name, ttl, data
1466
+ }
1467
+ end
1468
+
1469
+ def each_resource
1470
+ each_answer {|name, ttl, data| yield name, ttl, data}
1471
+ each_authority {|name, ttl, data| yield name, ttl, data}
1472
+ each_additional {|name, ttl, data| yield name, ttl, data}
1473
+ end
1474
+
1475
+ def encode
1476
+ return MessageEncoder.new {|msg|
1477
+ msg.put_pack('nnnnnn',
1478
+ @id,
1479
+ (@qr & 1) << 15 |
1480
+ (@opcode & 15) << 11 |
1481
+ (@aa & 1) << 10 |
1482
+ (@tc & 1) << 9 |
1483
+ (@rd & 1) << 8 |
1484
+ (@ra & 1) << 7 |
1485
+ (@rcode & 15),
1486
+ @question.length,
1487
+ @answer.length,
1488
+ @authority.length,
1489
+ @additional.length)
1490
+ @question.each {|q|
1491
+ name, typeclass = q
1492
+ msg.put_name(name)
1493
+ msg.put_pack('nn', typeclass::TypeValue, typeclass::ClassValue)
1494
+ }
1495
+ [@answer, @authority, @additional].each {|rr|
1496
+ rr.each {|r|
1497
+ name, ttl, data = r
1498
+ msg.put_name(name)
1499
+ msg.put_pack('nnN', data.class::TypeValue, data.class::ClassValue, ttl)
1500
+ msg.put_length16 {data.encode_rdata(msg)}
1501
+ }
1502
+ }
1503
+ }.to_s
1504
+ end
1505
+
1506
+ class MessageEncoder # :nodoc:
1507
+ def initialize
1508
+ @data = ''.dup
1509
+ @names = {}
1510
+ yield self
1511
+ end
1512
+
1513
+ def to_s
1514
+ return @data
1515
+ end
1516
+
1517
+ def put_bytes(d)
1518
+ @data << d
1519
+ end
1520
+
1521
+ def put_pack(template, *d)
1522
+ @data << d.pack(template)
1523
+ end
1524
+
1525
+ def put_length16
1526
+ length_index = @data.length
1527
+ @data << "\0\0"
1528
+ data_start = @data.length
1529
+ yield
1530
+ data_end = @data.length
1531
+ @data[length_index, 2] = [data_end - data_start].pack("n")
1532
+ end
1533
+
1534
+ def put_string(d)
1535
+ self.put_pack("C", d.length)
1536
+ @data << d
1537
+ end
1538
+
1539
+ def put_string_list(ds)
1540
+ ds.each {|d|
1541
+ self.put_string(d)
1542
+ }
1543
+ end
1544
+
1545
+ def put_name(d, compress: true)
1546
+ put_labels(d.to_a, compress: compress)
1547
+ end
1548
+
1549
+ def put_labels(d, compress: true)
1550
+ d.each_index {|i|
1551
+ domain = d[i..-1]
1552
+ if compress && idx = @names[domain]
1553
+ self.put_pack("n", 0xc000 | idx)
1554
+ return
1555
+ else
1556
+ if @data.length < 0x4000
1557
+ @names[domain] = @data.length
1558
+ end
1559
+ self.put_label(d[i])
1560
+ end
1561
+ }
1562
+ @data << "\0"
1563
+ end
1564
+
1565
+ def put_label(d)
1566
+ self.put_string(d.to_s)
1567
+ end
1568
+ end
1569
+
1570
+ def Message.decode(m)
1571
+ o = Message.new(0)
1572
+ MessageDecoder.new(m) {|msg|
1573
+ id, flag, qdcount, ancount, nscount, arcount =
1574
+ msg.get_unpack('nnnnnn')
1575
+ o.id = id
1576
+ o.tc = (flag >> 9) & 1
1577
+ o.rcode = flag & 15
1578
+ return o unless o.tc.zero?
1579
+
1580
+ o.qr = (flag >> 15) & 1
1581
+ o.opcode = (flag >> 11) & 15
1582
+ o.aa = (flag >> 10) & 1
1583
+ o.rd = (flag >> 8) & 1
1584
+ o.ra = (flag >> 7) & 1
1585
+ (1..qdcount).each {
1586
+ name, typeclass = msg.get_question
1587
+ o.add_question(name, typeclass)
1588
+ }
1589
+ (1..ancount).each {
1590
+ name, ttl, data = msg.get_rr
1591
+ o.add_answer(name, ttl, data)
1592
+ }
1593
+ (1..nscount).each {
1594
+ name, ttl, data = msg.get_rr
1595
+ o.add_authority(name, ttl, data)
1596
+ }
1597
+ (1..arcount).each {
1598
+ name, ttl, data = msg.get_rr
1599
+ o.add_additional(name, ttl, data)
1600
+ }
1601
+ }
1602
+ return o
1603
+ end
1604
+
1605
+ class MessageDecoder # :nodoc:
1606
+ def initialize(data)
1607
+ @data = data
1608
+ @index = 0
1609
+ @limit = data.bytesize
1610
+ yield self
1611
+ end
1612
+
1613
+ def inspect
1614
+ "\#<#{self.class}: #{@data.byteslice(0, @index).inspect} #{@data.byteslice(@index..-1).inspect}>"
1615
+ end
1616
+
1617
+ def get_length16
1618
+ len, = self.get_unpack('n')
1619
+ save_limit = @limit
1620
+ @limit = @index + len
1621
+ d = yield(len)
1622
+ if @index < @limit
1623
+ raise DecodeError.new("junk exists")
1624
+ elsif @limit < @index
1625
+ raise DecodeError.new("limit exceeded")
1626
+ end
1627
+ @limit = save_limit
1628
+ return d
1629
+ end
1630
+
1631
+ def get_bytes(len = @limit - @index)
1632
+ raise DecodeError.new("limit exceeded") if @limit < @index + len
1633
+ d = @data.byteslice(@index, len)
1634
+ @index += len
1635
+ return d
1636
+ end
1637
+
1638
+ def get_unpack(template)
1639
+ len = 0
1640
+ template.each_byte {|byte|
1641
+ byte = "%c" % byte
1642
+ case byte
1643
+ when ?c, ?C
1644
+ len += 1
1645
+ when ?n
1646
+ len += 2
1647
+ when ?N
1648
+ len += 4
1649
+ else
1650
+ raise StandardError.new("unsupported template: '#{byte.chr}' in '#{template}'")
1651
+ end
1652
+ }
1653
+ raise DecodeError.new("limit exceeded") if @limit < @index + len
1654
+ arr = @data.unpack("@#{@index}#{template}")
1655
+ @index += len
1656
+ return arr
1657
+ end
1658
+
1659
+ def get_string
1660
+ raise DecodeError.new("limit exceeded") if @limit <= @index
1661
+ len = @data.getbyte(@index)
1662
+ raise DecodeError.new("limit exceeded") if @limit < @index + 1 + len
1663
+ d = @data.byteslice(@index + 1, len)
1664
+ @index += 1 + len
1665
+ return d
1666
+ end
1667
+
1668
+ def get_string_list
1669
+ strings = []
1670
+ while @index < @limit
1671
+ strings << self.get_string
1672
+ end
1673
+ strings
1674
+ end
1675
+
1676
+ def get_list
1677
+ [].tap do |values|
1678
+ while @index < @limit
1679
+ values << yield
1680
+ end
1681
+ end
1682
+ end
1683
+
1684
+ def get_name
1685
+ return Name.new(self.get_labels)
1686
+ end
1687
+
1688
+ def get_labels
1689
+ prev_index = @index
1690
+ save_index = nil
1691
+ d = []
1692
+ size = -1
1693
+ while true
1694
+ raise DecodeError.new("limit exceeded") if @limit <= @index
1695
+ case @data.getbyte(@index)
1696
+ when 0
1697
+ @index += 1
1698
+ if save_index
1699
+ @index = save_index
1700
+ end
1701
+ return d
1702
+ when 192..255
1703
+ idx = self.get_unpack('n')[0] & 0x3fff
1704
+ if prev_index <= idx
1705
+ raise DecodeError.new("non-backward name pointer")
1706
+ end
1707
+ prev_index = idx
1708
+ if !save_index
1709
+ save_index = @index
1710
+ end
1711
+ @index = idx
1712
+ else
1713
+ l = self.get_label
1714
+ d << l
1715
+ size += 1 + l.string.bytesize
1716
+ raise DecodeError.new("name label data exceed 255 octets") if size > 255
1717
+ end
1718
+ end
1719
+ end
1720
+
1721
+ def get_label
1722
+ return Label::Str.new(self.get_string)
1723
+ end
1724
+
1725
+ def get_question
1726
+ name = self.get_name
1727
+ type, klass = self.get_unpack("nn")
1728
+ return name, Resource.get_class(type, klass)
1729
+ end
1730
+
1731
+ def get_rr
1732
+ name = self.get_name
1733
+ type, klass, ttl = self.get_unpack('nnN')
1734
+ typeclass = Resource.get_class(type, klass)
1735
+ res = self.get_length16 do
1736
+ begin
1737
+ typeclass.decode_rdata self
1738
+ rescue => e
1739
+ raise DecodeError, e.message, e.backtrace
1740
+ end
1741
+ end
1742
+ res.instance_variable_set :@ttl, ttl
1743
+ return name, ttl, res
1744
+ end
1745
+ end
1746
+ end
1747
+
1748
+ ##
1749
+ # SvcParams for service binding RRs. [RFC9460]
1750
+
1751
+ class SvcParams
1752
+ include Enumerable
1753
+
1754
+ ##
1755
+ # Create a list of SvcParams with the given initial content.
1756
+ #
1757
+ # +params+ has to be an enumerable of +SvcParam+s.
1758
+ # If its content has +SvcParam+s with the duplicate key,
1759
+ # the one appears last takes precedence.
1760
+
1761
+ def initialize(params = [])
1762
+ @params = {}
1763
+
1764
+ params.each do |param|
1765
+ add param
1766
+ end
1767
+ end
1768
+
1769
+ ##
1770
+ # Get SvcParam for the given +key+ in this list.
1771
+
1772
+ def [](key)
1773
+ @params[canonical_key(key)]
1774
+ end
1775
+
1776
+ ##
1777
+ # Get the number of SvcParams in this list.
1778
+
1779
+ def count
1780
+ @params.count
1781
+ end
1782
+
1783
+ ##
1784
+ # Get whether this list is empty.
1785
+
1786
+ def empty?
1787
+ @params.empty?
1788
+ end
1789
+
1790
+ ##
1791
+ # Add the SvcParam +param+ to this list, overwriting the existing one with the same key.
1792
+
1793
+ def add(param)
1794
+ @params[param.class.key_number] = param
1795
+ end
1796
+
1797
+ ##
1798
+ # Remove the +SvcParam+ with the given +key+ and return it.
1799
+
1800
+ def delete(key)
1801
+ @params.delete(canonical_key(key))
1802
+ end
1803
+
1804
+ ##
1805
+ # Enumerate the +SvcParam+s in this list.
1806
+
1807
+ def each(&block)
1808
+ return enum_for(:each) unless block
1809
+ @params.each_value(&block)
1810
+ end
1811
+
1812
+ def encode(msg) # :nodoc:
1813
+ @params.keys.sort.each do |key|
1814
+ msg.put_pack('n', key)
1815
+ msg.put_length16 do
1816
+ @params.fetch(key).encode(msg)
1817
+ end
1818
+ end
1819
+ end
1820
+
1821
+ def self.decode(msg) # :nodoc:
1822
+ params = msg.get_list do
1823
+ key, = msg.get_unpack('n')
1824
+ msg.get_length16 do
1825
+ SvcParam::ClassHash[key].decode(msg)
1826
+ end
1827
+ end
1828
+
1829
+ return self.new(params)
1830
+ end
1831
+
1832
+ private
1833
+
1834
+ def canonical_key(key) # :nodoc:
1835
+ case key
1836
+ when Integer
1837
+ key
1838
+ when /\Akey(\d+)\z/
1839
+ Integer($1)
1840
+ when Symbol
1841
+ SvcParam::ClassHash[key].key_number
1842
+ else
1843
+ raise TypeError, 'key must be either String or Symbol'
1844
+ end
1845
+ end
1846
+ end
1847
+
1848
+ ##
1849
+ # Base class for SvcParam. [RFC9460]
1850
+
1851
+ class SvcParam
1852
+
1853
+ ##
1854
+ # Get the presentation name of the SvcParamKey.
1855
+
1856
+ def self.key_name
1857
+ const_get(:KeyName)
1858
+ end
1859
+
1860
+ ##
1861
+ # Get the registered number of the SvcParamKey.
1862
+
1863
+ def self.key_number
1864
+ const_get(:KeyNumber)
1865
+ end
1866
+
1867
+ ClassHash = Hash.new do |h, key| # :nodoc:
1868
+ case key
1869
+ when Integer
1870
+ Generic.create(key)
1871
+ when /\Akey(?<key>\d+)\z/
1872
+ Generic.create(key.to_int)
1873
+ when Symbol
1874
+ raise KeyError, "unknown key #{key}"
1875
+ else
1876
+ raise TypeError, 'key must be either String or Symbol'
1877
+ end
1878
+ end
1879
+
1880
+ ##
1881
+ # Generic SvcParam abstract class.
1882
+
1883
+ class Generic < SvcParam
1884
+
1885
+ ##
1886
+ # SvcParamValue in wire-format byte string.
1887
+
1888
+ attr_reader :value
1889
+
1890
+ ##
1891
+ # Create generic SvcParam
1892
+
1893
+ def initialize(value)
1894
+ @value = value
1895
+ end
1896
+
1897
+ def encode(msg) # :nodoc:
1898
+ msg.put_bytes(@value)
1899
+ end
1900
+
1901
+ def self.decode(msg) # :nodoc:
1902
+ return self.new(msg.get_bytes)
1903
+ end
1904
+
1905
+ def self.create(key_number)
1906
+ c = Class.new(Generic)
1907
+ key_name = :"key#{key_number}"
1908
+ c.const_set(:KeyName, key_name)
1909
+ c.const_set(:KeyNumber, key_number)
1910
+ self.const_set(:"Key#{key_number}", c)
1911
+ ClassHash[key_name] = ClassHash[key_number] = c
1912
+ return c
1913
+ end
1914
+ end
1915
+
1916
+ ##
1917
+ # "mandatory" SvcParam -- Mandatory keys in service binding RR
1918
+
1919
+ class Mandatory < SvcParam
1920
+ KeyName = :mandatory
1921
+ KeyNumber = 0
1922
+ ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
1923
+
1924
+ ##
1925
+ # Mandatory keys.
1926
+
1927
+ attr_reader :keys
1928
+
1929
+ ##
1930
+ # Initialize "mandatory" ScvParam.
1931
+
1932
+ def initialize(keys)
1933
+ @keys = keys.map(&:to_int)
1934
+ end
1935
+
1936
+ def encode(msg) # :nodoc:
1937
+ @keys.sort.each do |key|
1938
+ msg.put_pack('n', key)
1939
+ end
1940
+ end
1941
+
1942
+ def self.decode(msg) # :nodoc:
1943
+ keys = msg.get_list { msg.get_unpack('n')[0] }
1944
+ return self.new(keys)
1945
+ end
1946
+ end
1947
+
1948
+ ##
1949
+ # "alpn" SvcParam -- Additional supported protocols
1950
+
1951
+ class ALPN < SvcParam
1952
+ KeyName = :alpn
1953
+ KeyNumber = 1
1954
+ ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
1955
+
1956
+ ##
1957
+ # Supported protocol IDs.
1958
+
1959
+ attr_reader :protocol_ids
1960
+
1961
+ ##
1962
+ # Initialize "alpn" ScvParam.
1963
+
1964
+ def initialize(protocol_ids)
1965
+ @protocol_ids = protocol_ids.map(&:to_str)
1966
+ end
1967
+
1968
+ def encode(msg) # :nodoc:
1969
+ msg.put_string_list(@protocol_ids)
1970
+ end
1971
+
1972
+ def self.decode(msg) # :nodoc:
1973
+ return self.new(msg.get_string_list)
1974
+ end
1975
+ end
1976
+
1977
+ ##
1978
+ # "no-default-alpn" SvcParam -- No support for default protocol
1979
+
1980
+ class NoDefaultALPN < SvcParam
1981
+ KeyName = :'no-default-alpn'
1982
+ KeyNumber = 2
1983
+ ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
1984
+
1985
+ def encode(msg) # :nodoc:
1986
+ # no payload
1987
+ end
1988
+
1989
+ def self.decode(msg) # :nodoc:
1990
+ return self.new
1991
+ end
1992
+ end
1993
+
1994
+ ##
1995
+ # "port" SvcParam -- Port for alternative endpoint
1996
+
1997
+ class Port < SvcParam
1998
+ KeyName = :port
1999
+ KeyNumber = 3
2000
+ ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
2001
+
2002
+ ##
2003
+ # Port number.
2004
+
2005
+ attr_reader :port
2006
+
2007
+ ##
2008
+ # Initialize "port" ScvParam.
2009
+
2010
+ def initialize(port)
2011
+ @port = port.to_int
2012
+ end
2013
+
2014
+ def encode(msg) # :nodoc:
2015
+ msg.put_pack('n', @port)
2016
+ end
2017
+
2018
+ def self.decode(msg) # :nodoc:
2019
+ port, = msg.get_unpack('n')
2020
+ return self.new(port)
2021
+ end
2022
+ end
2023
+
2024
+ ##
2025
+ # "ipv4hint" SvcParam -- IPv4 address hints
2026
+
2027
+ class IPv4Hint < SvcParam
2028
+ KeyName = :ipv4hint
2029
+ KeyNumber = 4
2030
+ ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
2031
+
2032
+ ##
2033
+ # Set of IPv4 addresses.
2034
+
2035
+ attr_reader :addresses
2036
+
2037
+ ##
2038
+ # Initialize "ipv4hint" ScvParam.
2039
+
2040
+ def initialize(addresses)
2041
+ @addresses = addresses.map {|address| IPv4.create(address) }
2042
+ end
2043
+
2044
+ def encode(msg) # :nodoc:
2045
+ @addresses.each do |address|
2046
+ msg.put_bytes(address.address)
2047
+ end
2048
+ end
2049
+
2050
+ def self.decode(msg) # :nodoc:
2051
+ addresses = msg.get_list { IPv4.new(msg.get_bytes(4)) }
2052
+ return self.new(addresses)
2053
+ end
2054
+ end
2055
+
2056
+ ##
2057
+ # "ipv6hint" SvcParam -- IPv6 address hints
2058
+
2059
+ class IPv6Hint < SvcParam
2060
+ KeyName = :ipv6hint
2061
+ KeyNumber = 6
2062
+ ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
2063
+
2064
+ ##
2065
+ # Set of IPv6 addresses.
2066
+
2067
+ attr_reader :addresses
2068
+
2069
+ ##
2070
+ # Initialize "ipv6hint" ScvParam.
2071
+
2072
+ def initialize(addresses)
2073
+ @addresses = addresses.map {|address| IPv6.create(address) }
2074
+ end
2075
+
2076
+ def encode(msg) # :nodoc:
2077
+ @addresses.each do |address|
2078
+ msg.put_bytes(address.address)
2079
+ end
2080
+ end
2081
+
2082
+ def self.decode(msg) # :nodoc:
2083
+ addresses = msg.get_list { IPv6.new(msg.get_bytes(16)) }
2084
+ return self.new(addresses)
2085
+ end
2086
+ end
2087
+
2088
+ ##
2089
+ # "dohpath" SvcParam -- DNS over HTTPS path template [RFC9461]
2090
+
2091
+ class DoHPath < SvcParam
2092
+ KeyName = :dohpath
2093
+ KeyNumber = 7
2094
+ ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
2095
+
2096
+ ##
2097
+ # URI template for DoH queries.
2098
+
2099
+ attr_reader :template
2100
+
2101
+ ##
2102
+ # Initialize "dohpath" ScvParam.
2103
+
2104
+ def initialize(template)
2105
+ @template = template.encode('utf-8')
2106
+ end
2107
+
2108
+ def encode(msg) # :nodoc:
2109
+ msg.put_bytes(@template)
2110
+ end
2111
+
2112
+ def self.decode(msg) # :nodoc:
2113
+ template = msg.get_bytes.force_encoding('utf-8')
2114
+ return self.new(template)
2115
+ end
2116
+ end
2117
+ end
2118
+
2119
+ ##
2120
+ # A DNS query abstract class.
2121
+
2122
+ class Query
2123
+ def encode_rdata(msg) # :nodoc:
2124
+ raise EncodeError.new("#{self.class} is query.")
2125
+ end
2126
+
2127
+ def self.decode_rdata(msg) # :nodoc:
2128
+ raise DecodeError.new("#{self.class} is query.")
2129
+ end
2130
+ end
2131
+
2132
+ ##
2133
+ # A DNS resource abstract class.
2134
+
2135
+ class Resource < Query
2136
+
2137
+ ##
2138
+ # Remaining Time To Live for this Resource.
2139
+
2140
+ attr_reader :ttl
2141
+
2142
+ ClassHash = Module.new do
2143
+ module_function
2144
+
2145
+ def []=(type_class_value, klass)
2146
+ type_value, class_value = type_class_value
2147
+ Resource.const_set(:"Type#{type_value}_Class#{class_value}", klass)
2148
+ end
2149
+ end
2150
+
2151
+ def encode_rdata(msg) # :nodoc:
2152
+ raise NotImplementedError.new
2153
+ end
2154
+
2155
+ def self.decode_rdata(msg) # :nodoc:
2156
+ raise NotImplementedError.new
2157
+ end
2158
+
2159
+ def ==(other) # :nodoc:
2160
+ return false unless self.class == other.class
2161
+ s_ivars = self.instance_variables
2162
+ s_ivars.sort!
2163
+ s_ivars.delete :@ttl
2164
+ o_ivars = other.instance_variables
2165
+ o_ivars.sort!
2166
+ o_ivars.delete :@ttl
2167
+ return s_ivars == o_ivars &&
2168
+ s_ivars.collect {|name| self.instance_variable_get name} ==
2169
+ o_ivars.collect {|name| other.instance_variable_get name}
2170
+ end
2171
+
2172
+ def eql?(other) # :nodoc:
2173
+ return self == other
2174
+ end
2175
+
2176
+ def hash # :nodoc:
2177
+ h = 0
2178
+ vars = self.instance_variables
2179
+ vars.delete :@ttl
2180
+ vars.each {|name|
2181
+ h ^= self.instance_variable_get(name).hash
2182
+ }
2183
+ return h
2184
+ end
2185
+
2186
+ def self.get_class(type_value, class_value) # :nodoc:
2187
+ cache = :"Type#{type_value}_Class#{class_value}"
2188
+
2189
+ return (const_defined?(cache) && const_get(cache)) ||
2190
+ Generic.create(type_value, class_value)
2191
+ end
2192
+
2193
+ ##
2194
+ # A generic resource abstract class.
2195
+
2196
+ class Generic < Resource
2197
+
2198
+ ##
2199
+ # Creates a new generic resource.
2200
+
2201
+ def initialize(data)
2202
+ @data = data
2203
+ end
2204
+
2205
+ ##
2206
+ # Data for this generic resource.
2207
+
2208
+ attr_reader :data
2209
+
2210
+ def encode_rdata(msg) # :nodoc:
2211
+ msg.put_bytes(data)
2212
+ end
2213
+
2214
+ def self.decode_rdata(msg) # :nodoc:
2215
+ return self.new(msg.get_bytes)
2216
+ end
2217
+
2218
+ def self.create(type_value, class_value) # :nodoc:
2219
+ c = Class.new(Generic)
2220
+ c.const_set(:TypeValue, type_value)
2221
+ c.const_set(:ClassValue, class_value)
2222
+ Generic.const_set("Type#{type_value}_Class#{class_value}", c)
2223
+ ClassHash[[type_value, class_value]] = c
2224
+ return c
2225
+ end
2226
+ end
2227
+
2228
+ ##
2229
+ # Domain Name resource abstract class.
2230
+
2231
+ class DomainName < Resource
2232
+
2233
+ ##
2234
+ # Creates a new DomainName from +name+.
2235
+
2236
+ def initialize(name)
2237
+ @name = name
2238
+ end
2239
+
2240
+ ##
2241
+ # The name of this DomainName.
2242
+
2243
+ attr_reader :name
2244
+
2245
+ def encode_rdata(msg) # :nodoc:
2246
+ msg.put_name(@name)
2247
+ end
2248
+
2249
+ def self.decode_rdata(msg) # :nodoc:
2250
+ return self.new(msg.get_name)
2251
+ end
2252
+ end
2253
+
2254
+ # Standard (class generic) RRs
2255
+
2256
+ ClassValue = nil # :nodoc:
2257
+
2258
+ ##
2259
+ # An authoritative name server.
2260
+
2261
+ class NS < DomainName
2262
+ TypeValue = 2 # :nodoc:
2263
+ end
2264
+
2265
+ ##
2266
+ # The canonical name for an alias.
2267
+
2268
+ class CNAME < DomainName
2269
+ TypeValue = 5 # :nodoc:
2270
+ end
2271
+
2272
+ ##
2273
+ # Start Of Authority resource.
2274
+
2275
+ class SOA < Resource
2276
+
2277
+ TypeValue = 6 # :nodoc:
2278
+
2279
+ ##
2280
+ # Creates a new SOA record. See the attr documentation for the
2281
+ # details of each argument.
2282
+
2283
+ def initialize(mname, rname, serial, refresh, retry_, expire, minimum)
2284
+ @mname = mname
2285
+ @rname = rname
2286
+ @serial = serial
2287
+ @refresh = refresh
2288
+ @retry = retry_
2289
+ @expire = expire
2290
+ @minimum = minimum
2291
+ end
2292
+
2293
+ ##
2294
+ # Name of the host where the master zone file for this zone resides.
2295
+
2296
+ attr_reader :mname
2297
+
2298
+ ##
2299
+ # The person responsible for this domain name.
2300
+
2301
+ attr_reader :rname
2302
+
2303
+ ##
2304
+ # The version number of the zone file.
2305
+
2306
+ attr_reader :serial
2307
+
2308
+ ##
2309
+ # How often, in seconds, a secondary name server is to check for
2310
+ # updates from the primary name server.
2311
+
2312
+ attr_reader :refresh
2313
+
2314
+ ##
2315
+ # How often, in seconds, a secondary name server is to retry after a
2316
+ # failure to check for a refresh.
2317
+
2318
+ attr_reader :retry
2319
+
2320
+ ##
2321
+ # Time in seconds that a secondary name server is to use the data
2322
+ # before refreshing from the primary name server.
2323
+
2324
+ attr_reader :expire
2325
+
2326
+ ##
2327
+ # The minimum number of seconds to be used for TTL values in RRs.
2328
+
2329
+ attr_reader :minimum
2330
+
2331
+ def encode_rdata(msg) # :nodoc:
2332
+ msg.put_name(@mname)
2333
+ msg.put_name(@rname)
2334
+ msg.put_pack('NNNNN', @serial, @refresh, @retry, @expire, @minimum)
2335
+ end
2336
+
2337
+ def self.decode_rdata(msg) # :nodoc:
2338
+ mname = msg.get_name
2339
+ rname = msg.get_name
2340
+ serial, refresh, retry_, expire, minimum = msg.get_unpack('NNNNN')
2341
+ return self.new(
2342
+ mname, rname, serial, refresh, retry_, expire, minimum)
2343
+ end
2344
+ end
2345
+
2346
+ ##
2347
+ # A Pointer to another DNS name.
2348
+
2349
+ class PTR < DomainName
2350
+ TypeValue = 12 # :nodoc:
2351
+ end
2352
+
2353
+ ##
2354
+ # Host Information resource.
2355
+
2356
+ class HINFO < Resource
2357
+
2358
+ TypeValue = 13 # :nodoc:
2359
+
2360
+ ##
2361
+ # Creates a new HINFO running +os+ on +cpu+.
2362
+
2363
+ def initialize(cpu, os)
2364
+ @cpu = cpu
2365
+ @os = os
2366
+ end
2367
+
2368
+ ##
2369
+ # CPU architecture for this resource.
2370
+
2371
+ attr_reader :cpu
2372
+
2373
+ ##
2374
+ # Operating system for this resource.
2375
+
2376
+ attr_reader :os
2377
+
2378
+ def encode_rdata(msg) # :nodoc:
2379
+ msg.put_string(@cpu)
2380
+ msg.put_string(@os)
2381
+ end
2382
+
2383
+ def self.decode_rdata(msg) # :nodoc:
2384
+ cpu = msg.get_string
2385
+ os = msg.get_string
2386
+ return self.new(cpu, os)
2387
+ end
2388
+ end
2389
+
2390
+ ##
2391
+ # Mailing list or mailbox information.
2392
+
2393
+ class MINFO < Resource
2394
+
2395
+ TypeValue = 14 # :nodoc:
2396
+
2397
+ def initialize(rmailbx, emailbx)
2398
+ @rmailbx = rmailbx
2399
+ @emailbx = emailbx
2400
+ end
2401
+
2402
+ ##
2403
+ # Domain name responsible for this mail list or mailbox.
2404
+
2405
+ attr_reader :rmailbx
2406
+
2407
+ ##
2408
+ # Mailbox to use for error messages related to the mail list or mailbox.
2409
+
2410
+ attr_reader :emailbx
2411
+
2412
+ def encode_rdata(msg) # :nodoc:
2413
+ msg.put_name(@rmailbx)
2414
+ msg.put_name(@emailbx)
2415
+ end
2416
+
2417
+ def self.decode_rdata(msg) # :nodoc:
2418
+ rmailbx = msg.get_string
2419
+ emailbx = msg.get_string
2420
+ return self.new(rmailbx, emailbx)
2421
+ end
2422
+ end
2423
+
2424
+ ##
2425
+ # Mail Exchanger resource.
2426
+
2427
+ class MX < Resource
2428
+
2429
+ TypeValue= 15 # :nodoc:
2430
+
2431
+ ##
2432
+ # Creates a new MX record with +preference+, accepting mail at
2433
+ # +exchange+.
2434
+
2435
+ def initialize(preference, exchange)
2436
+ @preference = preference
2437
+ @exchange = exchange
2438
+ end
2439
+
2440
+ ##
2441
+ # The preference for this MX.
2442
+
2443
+ attr_reader :preference
2444
+
2445
+ ##
2446
+ # The host of this MX.
2447
+
2448
+ attr_reader :exchange
2449
+
2450
+ def encode_rdata(msg) # :nodoc:
2451
+ msg.put_pack('n', @preference)
2452
+ msg.put_name(@exchange)
2453
+ end
2454
+
2455
+ def self.decode_rdata(msg) # :nodoc:
2456
+ preference, = msg.get_unpack('n')
2457
+ exchange = msg.get_name
2458
+ return self.new(preference, exchange)
2459
+ end
2460
+ end
2461
+
2462
+ ##
2463
+ # Unstructured text resource.
2464
+
2465
+ class TXT < Resource
2466
+
2467
+ TypeValue = 16 # :nodoc:
2468
+
2469
+ def initialize(first_string, *rest_strings)
2470
+ @strings = [first_string, *rest_strings]
2471
+ end
2472
+
2473
+ ##
2474
+ # Returns an Array of Strings for this TXT record.
2475
+
2476
+ attr_reader :strings
2477
+
2478
+ ##
2479
+ # Returns the concatenated string from +strings+.
2480
+
2481
+ def data
2482
+ @strings.join("")
2483
+ end
2484
+
2485
+ def encode_rdata(msg) # :nodoc:
2486
+ msg.put_string_list(@strings)
2487
+ end
2488
+
2489
+ def self.decode_rdata(msg) # :nodoc:
2490
+ strings = msg.get_string_list
2491
+ return self.new(*strings)
2492
+ end
2493
+ end
2494
+
2495
+ ##
2496
+ # Location resource
2497
+
2498
+ class LOC < Resource
2499
+
2500
+ TypeValue = 29 # :nodoc:
2501
+
2502
+ def initialize(version, ssize, hprecision, vprecision, latitude, longitude, altitude)
2503
+ @version = version
2504
+ @ssize = Gem::Resolv::LOC::Size.create(ssize)
2505
+ @hprecision = Gem::Resolv::LOC::Size.create(hprecision)
2506
+ @vprecision = Gem::Resolv::LOC::Size.create(vprecision)
2507
+ @latitude = Gem::Resolv::LOC::Coord.create(latitude)
2508
+ @longitude = Gem::Resolv::LOC::Coord.create(longitude)
2509
+ @altitude = Gem::Resolv::LOC::Alt.create(altitude)
2510
+ end
2511
+
2512
+ ##
2513
+ # Returns the version value for this LOC record which should always be 00
2514
+
2515
+ attr_reader :version
2516
+
2517
+ ##
2518
+ # The spherical size of this LOC
2519
+ # in meters using scientific notation as 2 integers of XeY
2520
+
2521
+ attr_reader :ssize
2522
+
2523
+ ##
2524
+ # The horizontal precision using ssize type values
2525
+ # in meters using scientific notation as 2 integers of XeY
2526
+ # for precision use value/2 e.g. 2m = +/-1m
2527
+
2528
+ attr_reader :hprecision
2529
+
2530
+ ##
2531
+ # The vertical precision using ssize type values
2532
+ # in meters using scientific notation as 2 integers of XeY
2533
+ # for precision use value/2 e.g. 2m = +/-1m
2534
+
2535
+ attr_reader :vprecision
2536
+
2537
+ ##
2538
+ # The latitude for this LOC where 2**31 is the equator
2539
+ # in thousandths of an arc second as an unsigned 32bit integer
2540
+
2541
+ attr_reader :latitude
2542
+
2543
+ ##
2544
+ # The longitude for this LOC where 2**31 is the prime meridian
2545
+ # in thousandths of an arc second as an unsigned 32bit integer
2546
+
2547
+ attr_reader :longitude
2548
+
2549
+ ##
2550
+ # The altitude of the LOC above a reference sphere whose surface sits 100km below the WGS84 spheroid
2551
+ # in centimeters as an unsigned 32bit integer
2552
+
2553
+ attr_reader :altitude
2554
+
2555
+ def encode_rdata(msg) # :nodoc:
2556
+ msg.put_bytes(@version)
2557
+ msg.put_bytes(@ssize.scalar)
2558
+ msg.put_bytes(@hprecision.scalar)
2559
+ msg.put_bytes(@vprecision.scalar)
2560
+ msg.put_bytes(@latitude.coordinates)
2561
+ msg.put_bytes(@longitude.coordinates)
2562
+ msg.put_bytes(@altitude.altitude)
2563
+ end
2564
+
2565
+ def self.decode_rdata(msg) # :nodoc:
2566
+ version = msg.get_bytes(1)
2567
+ ssize = msg.get_bytes(1)
2568
+ hprecision = msg.get_bytes(1)
2569
+ vprecision = msg.get_bytes(1)
2570
+ latitude = msg.get_bytes(4)
2571
+ longitude = msg.get_bytes(4)
2572
+ altitude = msg.get_bytes(4)
2573
+ return self.new(
2574
+ version,
2575
+ Gem::Resolv::LOC::Size.new(ssize),
2576
+ Gem::Resolv::LOC::Size.new(hprecision),
2577
+ Gem::Resolv::LOC::Size.new(vprecision),
2578
+ Gem::Resolv::LOC::Coord.new(latitude,"lat"),
2579
+ Gem::Resolv::LOC::Coord.new(longitude,"lon"),
2580
+ Gem::Resolv::LOC::Alt.new(altitude)
2581
+ )
2582
+ end
2583
+ end
2584
+
2585
+ ##
2586
+ # A Query type requesting any RR.
2587
+
2588
+ class ANY < Query
2589
+ TypeValue = 255 # :nodoc:
2590
+ end
2591
+
2592
+ ##
2593
+ # CAA resource record defined in RFC 8659
2594
+ #
2595
+ # These records identify certificate authority allowed to issue
2596
+ # certificates for the given domain.
2597
+
2598
+ class CAA < Resource
2599
+ TypeValue = 257
2600
+
2601
+ ##
2602
+ # Creates a new CAA for +flags+, +tag+ and +value+.
2603
+
2604
+ def initialize(flags, tag, value)
2605
+ unless (0..255) === flags
2606
+ raise ArgumentError.new('flags must be an Integer between 0 and 255')
2607
+ end
2608
+ unless (1..15) === tag.bytesize
2609
+ raise ArgumentError.new('length of tag must be between 1 and 15')
2610
+ end
2611
+
2612
+ @flags = flags
2613
+ @tag = tag
2614
+ @value = value
2615
+ end
2616
+
2617
+ ##
2618
+ # Flags for this property:
2619
+ # - Bit 0 : 0 = not critical, 1 = critical
2620
+
2621
+ attr_reader :flags
2622
+
2623
+ ##
2624
+ # Property tag ("issue", "issuewild", "iodef"...).
2625
+
2626
+ attr_reader :tag
2627
+
2628
+ ##
2629
+ # Property value.
2630
+
2631
+ attr_reader :value
2632
+
2633
+ ##
2634
+ # Whether the critical flag is set on this property.
2635
+
2636
+ def critical?
2637
+ flags & 0x80 != 0
2638
+ end
2639
+
2640
+ def encode_rdata(msg) # :nodoc:
2641
+ msg.put_pack('C', @flags)
2642
+ msg.put_string(@tag)
2643
+ msg.put_bytes(@value)
2644
+ end
2645
+
2646
+ def self.decode_rdata(msg) # :nodoc:
2647
+ flags, = msg.get_unpack('C')
2648
+ tag = msg.get_string
2649
+ value = msg.get_bytes
2650
+ self.new flags, tag, value
2651
+ end
2652
+ end
2653
+
2654
+ ClassInsensitiveTypes = [ # :nodoc:
2655
+ NS, CNAME, SOA, PTR, HINFO, MINFO, MX, TXT, LOC, ANY, CAA
2656
+ ]
2657
+
2658
+ ##
2659
+ # module IN contains ARPA Internet specific RRs.
2660
+
2661
+ module IN
2662
+
2663
+ ClassValue = 1 # :nodoc:
2664
+
2665
+ ClassInsensitiveTypes.each {|s|
2666
+ c = Class.new(s)
2667
+ c.const_set(:TypeValue, s::TypeValue)
2668
+ c.const_set(:ClassValue, ClassValue)
2669
+ ClassHash[[s::TypeValue, ClassValue]] = c
2670
+ self.const_set(s.name.sub(/.*::/, ''), c)
2671
+ }
2672
+
2673
+ ##
2674
+ # IPv4 Address resource
2675
+
2676
+ class A < Resource
2677
+ TypeValue = 1
2678
+ ClassValue = IN::ClassValue
2679
+ ClassHash[[TypeValue, ClassValue]] = self # :nodoc:
2680
+
2681
+ ##
2682
+ # Creates a new A for +address+.
2683
+
2684
+ def initialize(address)
2685
+ @address = IPv4.create(address)
2686
+ end
2687
+
2688
+ ##
2689
+ # The Gem::Resolv::IPv4 address for this A.
2690
+
2691
+ attr_reader :address
2692
+
2693
+ def encode_rdata(msg) # :nodoc:
2694
+ msg.put_bytes(@address.address)
2695
+ end
2696
+
2697
+ def self.decode_rdata(msg) # :nodoc:
2698
+ return self.new(IPv4.new(msg.get_bytes(4)))
2699
+ end
2700
+ end
2701
+
2702
+ ##
2703
+ # Well Known Service resource.
2704
+
2705
+ class WKS < Resource
2706
+ TypeValue = 11
2707
+ ClassValue = IN::ClassValue
2708
+ ClassHash[[TypeValue, ClassValue]] = self # :nodoc:
2709
+
2710
+ def initialize(address, protocol, bitmap)
2711
+ @address = IPv4.create(address)
2712
+ @protocol = protocol
2713
+ @bitmap = bitmap
2714
+ end
2715
+
2716
+ ##
2717
+ # The host these services run on.
2718
+
2719
+ attr_reader :address
2720
+
2721
+ ##
2722
+ # IP protocol number for these services.
2723
+
2724
+ attr_reader :protocol
2725
+
2726
+ ##
2727
+ # A bit map of enabled services on this host.
2728
+ #
2729
+ # If protocol is 6 (TCP) then the 26th bit corresponds to the SMTP
2730
+ # service (port 25). If this bit is set, then an SMTP server should
2731
+ # be listening on TCP port 25; if zero, SMTP service is not
2732
+ # supported.
2733
+
2734
+ attr_reader :bitmap
2735
+
2736
+ def encode_rdata(msg) # :nodoc:
2737
+ msg.put_bytes(@address.address)
2738
+ msg.put_pack("n", @protocol)
2739
+ msg.put_bytes(@bitmap)
2740
+ end
2741
+
2742
+ def self.decode_rdata(msg) # :nodoc:
2743
+ address = IPv4.new(msg.get_bytes(4))
2744
+ protocol, = msg.get_unpack("n")
2745
+ bitmap = msg.get_bytes
2746
+ return self.new(address, protocol, bitmap)
2747
+ end
2748
+ end
2749
+
2750
+ ##
2751
+ # An IPv6 address record.
2752
+
2753
+ class AAAA < Resource
2754
+ TypeValue = 28
2755
+ ClassValue = IN::ClassValue
2756
+ ClassHash[[TypeValue, ClassValue]] = self # :nodoc:
2757
+
2758
+ ##
2759
+ # Creates a new AAAA for +address+.
2760
+
2761
+ def initialize(address)
2762
+ @address = IPv6.create(address)
2763
+ end
2764
+
2765
+ ##
2766
+ # The Gem::Resolv::IPv6 address for this AAAA.
2767
+
2768
+ attr_reader :address
2769
+
2770
+ def encode_rdata(msg) # :nodoc:
2771
+ msg.put_bytes(@address.address)
2772
+ end
2773
+
2774
+ def self.decode_rdata(msg) # :nodoc:
2775
+ return self.new(IPv6.new(msg.get_bytes(16)))
2776
+ end
2777
+ end
2778
+
2779
+ ##
2780
+ # SRV resource record defined in RFC 2782
2781
+ #
2782
+ # These records identify the hostname and port that a service is
2783
+ # available at.
2784
+
2785
+ class SRV < Resource
2786
+ TypeValue = 33
2787
+ ClassValue = IN::ClassValue
2788
+ ClassHash[[TypeValue, ClassValue]] = self # :nodoc:
2789
+
2790
+ # Create a SRV resource record.
2791
+ #
2792
+ # See the documentation for #priority, #weight, #port and #target
2793
+ # for +priority+, +weight+, +port and +target+ respectively.
2794
+
2795
+ def initialize(priority, weight, port, target)
2796
+ @priority = priority.to_int
2797
+ @weight = weight.to_int
2798
+ @port = port.to_int
2799
+ @target = Name.create(target)
2800
+ end
2801
+
2802
+ # The priority of this target host.
2803
+ #
2804
+ # A client MUST attempt to contact the target host with the
2805
+ # lowest-numbered priority it can reach; target hosts with the same
2806
+ # priority SHOULD be tried in an order defined by the weight field.
2807
+ # The range is 0-65535. Note that it is not widely implemented and
2808
+ # should be set to zero.
2809
+
2810
+ attr_reader :priority
2811
+
2812
+ # A server selection mechanism.
2813
+ #
2814
+ # The weight field specifies a relative weight for entries with the
2815
+ # same priority. Larger weights SHOULD be given a proportionately
2816
+ # higher probability of being selected. The range of this number is
2817
+ # 0-65535. Domain administrators SHOULD use Weight 0 when there
2818
+ # isn't any server selection to do, to make the RR easier to read
2819
+ # for humans (less noisy). Note that it is not widely implemented
2820
+ # and should be set to zero.
2821
+
2822
+ attr_reader :weight
2823
+
2824
+ # The port on this target host of this service.
2825
+ #
2826
+ # The range is 0-65535.
2827
+
2828
+ attr_reader :port
2829
+
2830
+ # The domain name of the target host.
2831
+ #
2832
+ # A target of "." means that the service is decidedly not available
2833
+ # at this domain.
2834
+
2835
+ attr_reader :target
2836
+
2837
+ def encode_rdata(msg) # :nodoc:
2838
+ msg.put_pack("n", @priority)
2839
+ msg.put_pack("n", @weight)
2840
+ msg.put_pack("n", @port)
2841
+ msg.put_name(@target, compress: false)
2842
+ end
2843
+
2844
+ def self.decode_rdata(msg) # :nodoc:
2845
+ priority, = msg.get_unpack("n")
2846
+ weight, = msg.get_unpack("n")
2847
+ port, = msg.get_unpack("n")
2848
+ target = msg.get_name
2849
+ return self.new(priority, weight, port, target)
2850
+ end
2851
+ end
2852
+
2853
+ ##
2854
+ # Common implementation for SVCB-compatible resource records.
2855
+
2856
+ class ServiceBinding
2857
+
2858
+ ##
2859
+ # Create a service binding resource record.
2860
+
2861
+ def initialize(priority, target, params = [])
2862
+ @priority = priority.to_int
2863
+ @target = Name.create(target)
2864
+ @params = SvcParams.new(params)
2865
+ end
2866
+
2867
+ ##
2868
+ # The priority of this target host.
2869
+ #
2870
+ # The range is 0-65535.
2871
+ # If set to 0, this RR is in AliasMode. Otherwise, it is in ServiceMode.
2872
+
2873
+ attr_reader :priority
2874
+
2875
+ ##
2876
+ # The domain name of the target host.
2877
+
2878
+ attr_reader :target
2879
+
2880
+ ##
2881
+ # The service parameters for the target host.
2882
+
2883
+ attr_reader :params
2884
+
2885
+ ##
2886
+ # Whether this RR is in AliasMode.
2887
+
2888
+ def alias_mode?
2889
+ self.priority == 0
2890
+ end
2891
+
2892
+ ##
2893
+ # Whether this RR is in ServiceMode.
2894
+
2895
+ def service_mode?
2896
+ !alias_mode?
2897
+ end
2898
+
2899
+ def encode_rdata(msg) # :nodoc:
2900
+ msg.put_pack("n", @priority)
2901
+ msg.put_name(@target, compress: false)
2902
+ @params.encode(msg)
2903
+ end
2904
+
2905
+ def self.decode_rdata(msg) # :nodoc:
2906
+ priority, = msg.get_unpack("n")
2907
+ target = msg.get_name
2908
+ params = SvcParams.decode(msg)
2909
+ return self.new(priority, target, params)
2910
+ end
2911
+ end
2912
+
2913
+ ##
2914
+ # SVCB resource record [RFC9460]
2915
+
2916
+ class SVCB < ServiceBinding
2917
+ TypeValue = 64
2918
+ ClassValue = IN::ClassValue
2919
+ ClassHash[[TypeValue, ClassValue]] = self # :nodoc:
2920
+ end
2921
+
2922
+ ##
2923
+ # HTTPS resource record [RFC9460]
2924
+
2925
+ class HTTPS < ServiceBinding
2926
+ TypeValue = 65
2927
+ ClassValue = IN::ClassValue
2928
+ ClassHash[[TypeValue, ClassValue]] = self # :nodoc:
2929
+ end
2930
+ end
2931
+ end
2932
+ end
2933
+
2934
+ ##
2935
+ # A Gem::Resolv::DNS IPv4 address.
2936
+
2937
+ class IPv4
2938
+
2939
+ Regex256 = /0
2940
+ |1(?:[0-9][0-9]?)?
2941
+ |2(?:[0-4][0-9]?|5[0-5]?|[6-9])?
2942
+ |[3-9][0-9]?/x # :nodoc:
2943
+
2944
+ ##
2945
+ # Regular expression IPv4 addresses must match.
2946
+ Regex = /\A(#{Regex256})\.(#{Regex256})\.(#{Regex256})\.(#{Regex256})\z/
2947
+
2948
+ ##
2949
+ # Creates a new IPv4 address from +arg+ which may be:
2950
+ #
2951
+ # IPv4:: returns +arg+.
2952
+ # String:: +arg+ must match the IPv4::Regex constant
2953
+
2954
+ def self.create(arg)
2955
+ case arg
2956
+ when IPv4
2957
+ return arg
2958
+ when Regex
2959
+ if (0..255) === (a = $1.to_i) &&
2960
+ (0..255) === (b = $2.to_i) &&
2961
+ (0..255) === (c = $3.to_i) &&
2962
+ (0..255) === (d = $4.to_i)
2963
+ return self.new([a, b, c, d].pack("CCCC"))
2964
+ else
2965
+ raise ArgumentError.new("IPv4 address with invalid value: " + arg)
2966
+ end
2967
+ else
2968
+ raise ArgumentError.new("cannot interpret as IPv4 address: #{arg.inspect}")
2969
+ end
2970
+ end
2971
+
2972
+ def initialize(address) # :nodoc:
2973
+ unless address.kind_of?(String)
2974
+ raise ArgumentError, 'IPv4 address must be a string'
2975
+ end
2976
+ unless address.length == 4
2977
+ raise ArgumentError, "IPv4 address expects 4 bytes but #{address.length} bytes"
2978
+ end
2979
+ @address = address
2980
+ end
2981
+
2982
+ ##
2983
+ # A String representation of this IPv4 address.
2984
+
2985
+ ##
2986
+ # The raw IPv4 address as a String.
2987
+
2988
+ attr_reader :address
2989
+
2990
+ def to_s # :nodoc:
2991
+ return sprintf("%d.%d.%d.%d", *@address.unpack("CCCC"))
2992
+ end
2993
+
2994
+ def inspect # :nodoc:
2995
+ return "#<#{self.class} #{self}>"
2996
+ end
2997
+
2998
+ ##
2999
+ # Turns this IPv4 address into a Gem::Resolv::DNS::Name.
3000
+
3001
+ def to_name
3002
+ return DNS::Name.create(
3003
+ '%d.%d.%d.%d.in-addr.arpa.' % @address.unpack('CCCC').reverse)
3004
+ end
3005
+
3006
+ def ==(other) # :nodoc:
3007
+ return @address == other.address
3008
+ end
3009
+
3010
+ def eql?(other) # :nodoc:
3011
+ return self == other
3012
+ end
3013
+
3014
+ def hash # :nodoc:
3015
+ return @address.hash
3016
+ end
3017
+ end
3018
+
3019
+ ##
3020
+ # A Gem::Resolv::DNS IPv6 address.
3021
+
3022
+ class IPv6
3023
+
3024
+ ##
3025
+ # IPv6 address format a:b:c:d:e:f:g:h
3026
+ Regex_8Hex = /\A
3027
+ (?:[0-9A-Fa-f]{1,4}:){7}
3028
+ [0-9A-Fa-f]{1,4}
3029
+ \z/x
3030
+
3031
+ ##
3032
+ # Compressed IPv6 address format a::b
3033
+
3034
+ Regex_CompressedHex = /\A
3035
+ ((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?) ::
3036
+ ((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)
3037
+ \z/x
3038
+
3039
+ ##
3040
+ # IPv4 mapped IPv6 address format a:b:c:d:e:f:w.x.y.z
3041
+
3042
+ Regex_6Hex4Dec = /\A
3043
+ ((?:[0-9A-Fa-f]{1,4}:){6,6})
3044
+ (\d+)\.(\d+)\.(\d+)\.(\d+)
3045
+ \z/x
3046
+
3047
+ ##
3048
+ # Compressed IPv4 mapped IPv6 address format a::b:w.x.y.z
3049
+
3050
+ Regex_CompressedHex4Dec = /\A
3051
+ ((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?) ::
3052
+ ((?:[0-9A-Fa-f]{1,4}:)*)
3053
+ (\d+)\.(\d+)\.(\d+)\.(\d+)
3054
+ \z/x
3055
+
3056
+ ##
3057
+ # IPv6 link local address format fe80:b:c:d:e:f:g:h%em1
3058
+ Regex_8HexLinkLocal = /\A
3059
+ [Ff][Ee]80
3060
+ (?::[0-9A-Fa-f]{1,4}){7}
3061
+ %[-0-9A-Za-z._~]+
3062
+ \z/x
3063
+
3064
+ ##
3065
+ # Compressed IPv6 link local address format fe80::b%em1
3066
+
3067
+ Regex_CompressedHexLinkLocal = /\A
3068
+ [Ff][Ee]80:
3069
+ (?:
3070
+ ((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?) ::
3071
+ ((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)
3072
+ |
3073
+ :((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)
3074
+ )?
3075
+ :[0-9A-Fa-f]{1,4}%[-0-9A-Za-z._~]+
3076
+ \z/x
3077
+
3078
+ ##
3079
+ # A composite IPv6 address Regexp.
3080
+
3081
+ Regex = /
3082
+ (?:#{Regex_8Hex}) |
3083
+ (?:#{Regex_CompressedHex}) |
3084
+ (?:#{Regex_6Hex4Dec}) |
3085
+ (?:#{Regex_CompressedHex4Dec}) |
3086
+ (?:#{Regex_8HexLinkLocal}) |
3087
+ (?:#{Regex_CompressedHexLinkLocal})
3088
+ /x
3089
+
3090
+ ##
3091
+ # Creates a new IPv6 address from +arg+ which may be:
3092
+ #
3093
+ # IPv6:: returns +arg+.
3094
+ # String:: +arg+ must match one of the IPv6::Regex* constants
3095
+
3096
+ def self.create(arg)
3097
+ case arg
3098
+ when IPv6
3099
+ return arg
3100
+ when String
3101
+ address = ''.b
3102
+ if Regex_8Hex =~ arg
3103
+ arg.scan(/[0-9A-Fa-f]+/) {|hex| address << [hex.hex].pack('n')}
3104
+ elsif Regex_CompressedHex =~ arg
3105
+ prefix = $1
3106
+ suffix = $2
3107
+ a1 = ''.b
3108
+ a2 = ''.b
3109
+ prefix.scan(/[0-9A-Fa-f]+/) {|hex| a1 << [hex.hex].pack('n')}
3110
+ suffix.scan(/[0-9A-Fa-f]+/) {|hex| a2 << [hex.hex].pack('n')}
3111
+ omitlen = 16 - a1.length - a2.length
3112
+ address << a1 << "\0" * omitlen << a2
3113
+ elsif Regex_6Hex4Dec =~ arg
3114
+ prefix, a, b, c, d = $1, $2.to_i, $3.to_i, $4.to_i, $5.to_i
3115
+ if (0..255) === a && (0..255) === b && (0..255) === c && (0..255) === d
3116
+ prefix.scan(/[0-9A-Fa-f]+/) {|hex| address << [hex.hex].pack('n')}
3117
+ address << [a, b, c, d].pack('CCCC')
3118
+ else
3119
+ raise ArgumentError.new("not numeric IPv6 address: " + arg)
3120
+ end
3121
+ elsif Regex_CompressedHex4Dec =~ arg
3122
+ prefix, suffix, a, b, c, d = $1, $2, $3.to_i, $4.to_i, $5.to_i, $6.to_i
3123
+ if (0..255) === a && (0..255) === b && (0..255) === c && (0..255) === d
3124
+ a1 = ''.b
3125
+ a2 = ''.b
3126
+ prefix.scan(/[0-9A-Fa-f]+/) {|hex| a1 << [hex.hex].pack('n')}
3127
+ suffix.scan(/[0-9A-Fa-f]+/) {|hex| a2 << [hex.hex].pack('n')}
3128
+ omitlen = 12 - a1.length - a2.length
3129
+ address << a1 << "\0" * omitlen << a2 << [a, b, c, d].pack('CCCC')
3130
+ else
3131
+ raise ArgumentError.new("not numeric IPv6 address: " + arg)
3132
+ end
3133
+ else
3134
+ raise ArgumentError.new("not numeric IPv6 address: " + arg)
3135
+ end
3136
+ return IPv6.new(address)
3137
+ else
3138
+ raise ArgumentError.new("cannot interpret as IPv6 address: #{arg.inspect}")
3139
+ end
3140
+ end
3141
+
3142
+ def initialize(address) # :nodoc:
3143
+ unless address.kind_of?(String) && address.length == 16
3144
+ raise ArgumentError.new('IPv6 address must be 16 bytes')
3145
+ end
3146
+ @address = address
3147
+ end
3148
+
3149
+ ##
3150
+ # The raw IPv6 address as a String.
3151
+
3152
+ attr_reader :address
3153
+
3154
+ def to_s # :nodoc:
3155
+ sprintf("%x:%x:%x:%x:%x:%x:%x:%x", *@address.unpack("nnnnnnnn")).sub(/(^|:)0(:0)+(:|$)/, '::')
3156
+ end
3157
+
3158
+ def inspect # :nodoc:
3159
+ return "#<#{self.class} #{self}>"
3160
+ end
3161
+
3162
+ ##
3163
+ # Turns this IPv6 address into a Gem::Resolv::DNS::Name.
3164
+ #--
3165
+ # ip6.arpa should be searched too. [RFC3152]
3166
+
3167
+ def to_name
3168
+ return DNS::Name.new(
3169
+ @address.unpack("H32")[0].split(//).reverse + ['ip6', 'arpa'])
3170
+ end
3171
+
3172
+ def ==(other) # :nodoc:
3173
+ return @address == other.address
3174
+ end
3175
+
3176
+ def eql?(other) # :nodoc:
3177
+ return self == other
3178
+ end
3179
+
3180
+ def hash # :nodoc:
3181
+ return @address.hash
3182
+ end
3183
+ end
3184
+
3185
+ ##
3186
+ # Gem::Resolv::MDNS is a one-shot Multicast DNS (mDNS) resolver. It blindly
3187
+ # makes queries to the mDNS addresses without understanding anything about
3188
+ # multicast ports.
3189
+ #
3190
+ # Information taken form the following places:
3191
+ #
3192
+ # * RFC 6762
3193
+
3194
+ class MDNS < DNS
3195
+
3196
+ ##
3197
+ # Default mDNS Port
3198
+
3199
+ Port = 5353
3200
+
3201
+ ##
3202
+ # Default IPv4 mDNS address
3203
+
3204
+ AddressV4 = '224.0.0.251'
3205
+
3206
+ ##
3207
+ # Default IPv6 mDNS address
3208
+
3209
+ AddressV6 = 'ff02::fb'
3210
+
3211
+ ##
3212
+ # Default mDNS addresses
3213
+
3214
+ Addresses = [
3215
+ [AddressV4, Port],
3216
+ [AddressV6, Port],
3217
+ ]
3218
+
3219
+ ##
3220
+ # Creates a new one-shot Multicast DNS (mDNS) resolver.
3221
+ #
3222
+ # +config_info+ can be:
3223
+ #
3224
+ # nil::
3225
+ # Uses the default mDNS addresses
3226
+ #
3227
+ # Hash::
3228
+ # Must contain :nameserver or :nameserver_port like
3229
+ # Gem::Resolv::DNS#initialize.
3230
+
3231
+ def initialize(config_info=nil)
3232
+ if config_info then
3233
+ super({ nameserver_port: Addresses }.merge(config_info))
3234
+ else
3235
+ super(nameserver_port: Addresses)
3236
+ end
3237
+ end
3238
+
3239
+ ##
3240
+ # Iterates over all IP addresses for +name+ retrieved from the mDNS
3241
+ # resolver, provided name ends with "local". If the name does not end in
3242
+ # "local" no records will be returned.
3243
+ #
3244
+ # +name+ can be a Gem::Resolv::DNS::Name or a String. Retrieved addresses will
3245
+ # be a Gem::Resolv::IPv4 or Gem::Resolv::IPv6
3246
+
3247
+ def each_address(name)
3248
+ name = Gem::Resolv::DNS::Name.create(name)
3249
+
3250
+ return unless name[-1].to_s == 'local'
3251
+
3252
+ super(name)
3253
+ end
3254
+
3255
+ def make_udp_requester # :nodoc:
3256
+ nameserver_port = @config.nameserver_port
3257
+ Requester::MDNSOneShot.new(*nameserver_port)
3258
+ end
3259
+
3260
+ end
3261
+
3262
+ module LOC # :nodoc:
3263
+
3264
+ ##
3265
+ # A Gem::Resolv::LOC::Size
3266
+
3267
+ class Size
3268
+
3269
+ # Regular expression LOC size must match.
3270
+
3271
+ Regex = /^(\d+\.*\d*)[m]$/
3272
+
3273
+ ##
3274
+ # Creates a new LOC::Size from +arg+ which may be:
3275
+ #
3276
+ # LOC::Size:: returns +arg+.
3277
+ # String:: +arg+ must match the LOC::Size::Regex constant
3278
+
3279
+ def self.create(arg)
3280
+ case arg
3281
+ when Size
3282
+ return arg
3283
+ when String
3284
+ scalar = ''
3285
+ if Regex =~ arg
3286
+ scalar = [(($1.to_f*(1e2)).to_i.to_s[0].to_i*(2**4)+(($1.to_f*(1e2)).to_i.to_s.length-1))].pack("C")
3287
+ else
3288
+ raise ArgumentError.new("not a properly formed Size string: " + arg)
3289
+ end
3290
+ return Size.new(scalar)
3291
+ else
3292
+ raise ArgumentError.new("cannot interpret as Size: #{arg.inspect}")
3293
+ end
3294
+ end
3295
+
3296
+ # Internal use; use self.create.
3297
+ def initialize(scalar)
3298
+ @scalar = scalar
3299
+ end
3300
+
3301
+ ##
3302
+ # The raw size
3303
+
3304
+ attr_reader :scalar
3305
+
3306
+ def to_s # :nodoc:
3307
+ s = @scalar.unpack("H2").join.to_s
3308
+ return ((s[0].to_i)*(10**(s[1].to_i-2))).to_s << "m"
3309
+ end
3310
+
3311
+ def inspect # :nodoc:
3312
+ return "#<#{self.class} #{self}>"
3313
+ end
3314
+
3315
+ def ==(other) # :nodoc:
3316
+ return @scalar == other.scalar
3317
+ end
3318
+
3319
+ def eql?(other) # :nodoc:
3320
+ return self == other
3321
+ end
3322
+
3323
+ def hash # :nodoc:
3324
+ return @scalar.hash
3325
+ end
3326
+
3327
+ end
3328
+
3329
+ ##
3330
+ # A Gem::Resolv::LOC::Coord
3331
+
3332
+ class Coord
3333
+
3334
+ # Regular expression LOC Coord must match.
3335
+
3336
+ Regex = /^(\d+)\s(\d+)\s(\d+\.\d+)\s([NESW])$/
3337
+
3338
+ ##
3339
+ # Creates a new LOC::Coord from +arg+ which may be:
3340
+ #
3341
+ # LOC::Coord:: returns +arg+.
3342
+ # String:: +arg+ must match the LOC::Coord::Regex constant
3343
+
3344
+ def self.create(arg)
3345
+ case arg
3346
+ when Coord
3347
+ return arg
3348
+ when String
3349
+ coordinates = ''
3350
+ if Regex =~ arg && $1.to_f < 180
3351
+ m = $~
3352
+ hemi = (m[4][/[NE]/]) || (m[4][/[SW]/]) ? 1 : -1
3353
+ coordinates = [ ((m[1].to_i*(36e5)) + (m[2].to_i*(6e4)) +
3354
+ (m[3].to_f*(1e3))) * hemi+(2**31) ].pack("N")
3355
+ orientation = m[4][/[NS]/] ? 'lat' : 'lon'
3356
+ else
3357
+ raise ArgumentError.new("not a properly formed Coord string: " + arg)
3358
+ end
3359
+ return Coord.new(coordinates,orientation)
3360
+ else
3361
+ raise ArgumentError.new("cannot interpret as Coord: #{arg.inspect}")
3362
+ end
3363
+ end
3364
+
3365
+ # Internal use; use self.create.
3366
+ def initialize(coordinates,orientation)
3367
+ unless coordinates.kind_of?(String)
3368
+ raise ArgumentError.new("Coord must be a 32bit unsigned integer in hex format: #{coordinates.inspect}")
3369
+ end
3370
+ unless orientation.kind_of?(String) && orientation[/^lon$|^lat$/]
3371
+ raise ArgumentError.new('Coord expects orientation to be a String argument of "lat" or "lon"')
3372
+ end
3373
+ @coordinates = coordinates
3374
+ @orientation = orientation
3375
+ end
3376
+
3377
+ ##
3378
+ # The raw coordinates
3379
+
3380
+ attr_reader :coordinates
3381
+
3382
+ ## The orientation of the hemisphere as 'lat' or 'lon'
3383
+
3384
+ attr_reader :orientation
3385
+
3386
+ def to_s # :nodoc:
3387
+ c = @coordinates.unpack("N").join.to_i
3388
+ val = (c - (2**31)).abs
3389
+ fracsecs = (val % 1e3).to_i.to_s
3390
+ val = val / 1e3
3391
+ secs = (val % 60).to_i.to_s
3392
+ val = val / 60
3393
+ mins = (val % 60).to_i.to_s
3394
+ degs = (val / 60).to_i.to_s
3395
+ posi = (c >= 2**31)
3396
+ case posi
3397
+ when true
3398
+ hemi = @orientation[/^lat$/] ? "N" : "E"
3399
+ else
3400
+ hemi = @orientation[/^lon$/] ? "W" : "S"
3401
+ end
3402
+ return degs << " " << mins << " " << secs << "." << fracsecs << " " << hemi
3403
+ end
3404
+
3405
+ def inspect # :nodoc:
3406
+ return "#<#{self.class} #{self}>"
3407
+ end
3408
+
3409
+ def ==(other) # :nodoc:
3410
+ return @coordinates == other.coordinates
3411
+ end
3412
+
3413
+ def eql?(other) # :nodoc:
3414
+ return self == other
3415
+ end
3416
+
3417
+ def hash # :nodoc:
3418
+ return @coordinates.hash
3419
+ end
3420
+
3421
+ end
3422
+
3423
+ ##
3424
+ # A Gem::Resolv::LOC::Alt
3425
+
3426
+ class Alt
3427
+
3428
+ # Regular expression LOC Alt must match.
3429
+
3430
+ Regex = /^([+-]*\d+\.*\d*)[m]$/
3431
+
3432
+ ##
3433
+ # Creates a new LOC::Alt from +arg+ which may be:
3434
+ #
3435
+ # LOC::Alt:: returns +arg+.
3436
+ # String:: +arg+ must match the LOC::Alt::Regex constant
3437
+
3438
+ def self.create(arg)
3439
+ case arg
3440
+ when Alt
3441
+ return arg
3442
+ when String
3443
+ altitude = ''
3444
+ if Regex =~ arg
3445
+ altitude = [($1.to_f*(1e2))+(1e7)].pack("N")
3446
+ else
3447
+ raise ArgumentError.new("not a properly formed Alt string: " + arg)
3448
+ end
3449
+ return Alt.new(altitude)
3450
+ else
3451
+ raise ArgumentError.new("cannot interpret as Alt: #{arg.inspect}")
3452
+ end
3453
+ end
3454
+
3455
+ # Internal use; use self.create.
3456
+ def initialize(altitude)
3457
+ @altitude = altitude
3458
+ end
3459
+
3460
+ ##
3461
+ # The raw altitude
3462
+
3463
+ attr_reader :altitude
3464
+
3465
+ def to_s # :nodoc:
3466
+ a = @altitude.unpack("N").join.to_i
3467
+ return ((a.to_f/1e2)-1e5).to_s + "m"
3468
+ end
3469
+
3470
+ def inspect # :nodoc:
3471
+ return "#<#{self.class} #{self}>"
3472
+ end
3473
+
3474
+ def ==(other) # :nodoc:
3475
+ return @altitude == other.altitude
3476
+ end
3477
+
3478
+ def eql?(other) # :nodoc:
3479
+ return self == other
3480
+ end
3481
+
3482
+ def hash # :nodoc:
3483
+ return @altitude.hash
3484
+ end
3485
+
3486
+ end
3487
+
3488
+ end
3489
+
3490
+ ##
3491
+ # Default resolver to use for Gem::Resolv class methods.
3492
+
3493
+ DefaultResolver = self.new
3494
+
3495
+ ##
3496
+ # Replaces the resolvers in the default resolver with +new_resolvers+. This
3497
+ # allows resolvers to be changed for resolv-replace.
3498
+
3499
+ def DefaultResolver.replace_resolvers new_resolvers
3500
+ @resolvers = new_resolvers
3501
+ end
3502
+
3503
+ ##
3504
+ # Address Regexp to use for matching IP addresses.
3505
+
3506
+ AddressRegex = /(?:#{IPv4::Regex})|(?:#{IPv6::Regex})/
3507
+
3508
+ end