PageRenderTime 47ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/whois/server.rb

https://github.com/cblunt/whois
Ruby | 205 lines | 99 code | 24 blank | 82 comment | 21 complexity | d05ad6d622b876a197b6102d268517f3 MD5 | raw file
Possible License(s): MIT
  1. #
  2. # = Ruby Whois
  3. #
  4. # An intelligent pure Ruby WHOIS client and parser.
  5. #
  6. #
  7. # Category:: Net
  8. # Package:: Whois
  9. # Author:: Simone Carletti <weppos@weppos.net>
  10. # License:: MIT License
  11. #
  12. #--
  13. #
  14. #++
  15. require 'ipaddr'
  16. require 'whois/server/adapters/base'
  17. require 'whois/server/adapters/afilias'
  18. require 'whois/server/adapters/formatted'
  19. require 'whois/server/adapters/none'
  20. require 'whois/server/adapters/not_implemented'
  21. require 'whois/server/adapters/pir'
  22. require 'whois/server/adapters/standard'
  23. require 'whois/server/adapters/verisign'
  24. require 'whois/server/adapters/web'
  25. module Whois
  26. class Server
  27. @@definitions = {}
  28. # Searches the /definitions folder for definition files and loads them.
  29. # This method is automatically invoked when this file is parsed by the Ruby interpreter
  30. # (scroll down to the bottom of this file).
  31. def self.load_definitions
  32. Dir[File.dirname(__FILE__) + '/definitions/*.rb'].each { |file| load(file) }
  33. end
  34. # Returns the active definition list.
  35. # If <tt>type</tt>, returns only the definitions matching given type or
  36. # nil if no definition exists.
  37. #
  38. # Whois::Server.definitions
  39. # # => { :tld => [...], :ipv4 => [], ... }
  40. # Whois::Server.definitions(:tld)
  41. # # => [...]
  42. # Whois::Server.definitions(:invalid)
  43. # # => nil
  44. #
  45. def self.definitions(type = nil)
  46. if type.nil?
  47. @@definitions
  48. else
  49. @@definitions[type]
  50. end
  51. end
  52. # Defines a new server for <tt>:type</tt> queries.
  53. #
  54. # == Parameters
  55. #
  56. # type::
  57. # The type of whois server to define.
  58. # Allowed values are :tld, :ipv4, :ipv6.
  59. # allocation::
  60. # The allocation, range or hostname this server is responsible for.
  61. # host::
  62. # The server hostname.
  63. # options::
  64. # Additional options to customize Adpter behavior.
  65. #
  66. # ==== Examples
  67. #
  68. # # Define a server for the .it extension
  69. # Whois::Server.define :tld, ".it", "whois.nic.it"
  70. # # Define a new server for an range of IPv4 addresses
  71. # Whois::Server.define :ipv4, "61.192.0.0/12", "whois.nic.ad.jp"
  72. # # Define a new server for an range of IPv6 addresses
  73. # Whois::Server.define :ipv6, "2001:2000::/19", "whois.ripe.net"
  74. #
  75. def self.define(type, allocation, host, options = {})
  76. @@definitions[type] ||= []
  77. @@definitions[type] << [allocation, host, options]
  78. end
  79. # Creates a new server adapter from given arguments
  80. # and returns the server instance.
  81. #
  82. # By default returns a new Whois::Servers::Adapter::Standard instance.
  83. # You can customize the behavior passing a custom adapter class as :adapter option.
  84. #
  85. # Whois::Server.factory :tld, ".it", "whois.nic.it"
  86. # # => #<Whois::Servers::Adapter::Standard>
  87. # Whois::Server.factory :tld, ".it", "whois.nic.it", :option => Whois::Servers::Adapter::Custom
  88. # # => #<Whois::Servers::Adapter::Custom>
  89. #
  90. def self.factory(type, allocation, host, options = {})
  91. options = options.dup
  92. (options.delete(:adapter) || Adapters::Standard).new(type, allocation, host, options)
  93. end
  94. # Parses <tt>qstring</tt> and tries to guess the right server.
  95. #
  96. # It successfully detects the following query types:
  97. # * ipv6
  98. # * ipv4
  99. # * top level domains
  100. # * emails
  101. #
  102. # ==== Raises
  103. #
  104. # ServerNotFound::
  105. # When unable to find an appropriate whois server for <tt>qstring</tt>.
  106. #
  107. def self.guess(qstring)
  108. # IPv6 address (secure match)
  109. if valid_ipv6?(qstring)
  110. return find_for_ipv6(qstring)
  111. end
  112. # IPv4 address (secure match)
  113. if valid_ipv4?(qstring)
  114. return find_for_ipv4(qstring)
  115. end
  116. # Email Address (secure match)
  117. if qstring =~ /@/
  118. return find_for_email(qstring)
  119. end
  120. # TLD
  121. if server = find_for_tld(qstring)
  122. return server
  123. end
  124. # Gave Over
  125. raise ServerNotFound, "Unable to find a whois server for `#{qstring}'"
  126. end
  127. private
  128. def self.find_for_ipv6(qstring)
  129. ip = IPAddr.new(qstring)
  130. definitions(:ipv6).each do |definition|
  131. if IPAddr.new(definition.first).include?(ip)
  132. return factory(:ipv6, *definition)
  133. end
  134. end
  135. raise AllocationUnknown,
  136. "IP Allocation for `#{qstring}' unknown." +
  137. "Server definitions might be outdated."
  138. end
  139. def self.find_for_ipv4(qstring)
  140. ip = IPAddr.new(qstring)
  141. definitions(:ipv4).each do |definition|
  142. if IPAddr.new(definition.first).include?(ip)
  143. return factory(:ipv4, *definition)
  144. end
  145. end
  146. raise AllocationUnknown,
  147. "IP Allocation for `#{qstring}' unknown." +
  148. "Server definitions might be outdated."
  149. end
  150. def self.find_for_email(qstring)
  151. raise ServerNotSupported, "No whois server is known for email objects"
  152. end
  153. def self.find_for_tld(qstring)
  154. definitions(:tld).each do |definition|
  155. return factory(:tld, *definition) if /#{Regexp.escape(definition.first)}$/ =~ qstring
  156. end
  157. nil
  158. end
  159. def self.valid_ipv4?(addr)
  160. if /\A(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\Z/ =~ addr
  161. return $~.captures.all? {|i| i.to_i < 256}
  162. end
  163. false
  164. end
  165. def self.valid_ipv6?(addr)
  166. # IPv6 (normal)
  167. return true if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*\Z/ =~ addr
  168. return true if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*)?\Z/ =~ addr
  169. return true if /\A::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*)?\Z/ =~ addr
  170. # IPv6 (IPv4 compat)
  171. return true if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*:/ =~ addr && valid_ipv4?($')
  172. return true if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*:)?/ =~ addr && valid_ipv4?($')
  173. return true if /\A::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*:)?/ =~ addr && valid_ipv4?($')
  174. false
  175. end
  176. end
  177. end
  178. Whois::Server.load_definitions