PageRenderTime 26ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/ipaddress/prefix.rb

https://gitlab.com/intruxxer/ipaddress
Ruby | 265 lines | 85 code | 30 blank | 150 comment | 2 complexity | dfd5570ba4668c57b0bafb01111e6dca MD5 | raw file
  1. module IPAddress
  2. #
  3. # =NAME
  4. #
  5. # IPAddress::Prefix
  6. #
  7. # =SYNOPSIS
  8. #
  9. # Parent class for Prefix32 and Prefix128
  10. #
  11. # =DESCRIPTION
  12. #
  13. # IPAddress::Prefix is the parent class for IPAddress::Prefix32
  14. # and IPAddress::Prefix128, defining some modules in common for
  15. # both the subclasses.
  16. #
  17. # IPAddress::Prefix shouldn't be accesses directly, unless
  18. # for particular needs.
  19. #
  20. class Prefix
  21. include Comparable
  22. attr_reader :prefix
  23. #
  24. # Creates a new general prefix
  25. #
  26. def initialize(num)
  27. @prefix = num.to_i
  28. end
  29. #
  30. # Returns a string with the prefix
  31. #
  32. def to_s
  33. "#@prefix"
  34. end
  35. alias_method :inspect, :to_s
  36. #
  37. # Returns the prefix
  38. #
  39. def to_i
  40. @prefix
  41. end
  42. #
  43. # Compare the prefix
  44. #
  45. def <=>(oth)
  46. @prefix <=> oth.to_i
  47. end
  48. #
  49. # Sums two prefixes or a prefix to a
  50. # number, returns a Fixnum
  51. #
  52. def +(oth)
  53. if oth.is_a? Fixnum
  54. self.prefix + oth
  55. else
  56. self.prefix + oth.prefix
  57. end
  58. end
  59. #
  60. # Returns the difference between two
  61. # prefixes, or a prefix and a number,
  62. # as a Fixnum
  63. #
  64. def -(oth)
  65. if oth.is_a? Fixnum
  66. self.prefix - oth
  67. else
  68. (self.prefix - oth.prefix).abs
  69. end
  70. end
  71. end # class Prefix
  72. class Prefix32 < Prefix
  73. IN4MASK = 0xffffffff
  74. #
  75. # Creates a new prefix object for 32 bits IPv4 addresses
  76. #
  77. # prefix = IPAddress::Prefix32.new 24
  78. # #=> 24
  79. #
  80. def initialize(num)
  81. unless (0..32).include? num
  82. raise ArgumentError, "Prefix must be in range 0..32, got: #{num}"
  83. end
  84. super(num)
  85. end
  86. #
  87. # Returns the length of the host portion
  88. # of a netmask.
  89. #
  90. # prefix = Prefix32.new 24
  91. #
  92. # prefix.host_prefix
  93. # #=> 8
  94. #
  95. def host_prefix
  96. 32 - @prefix
  97. end
  98. #
  99. # Transforms the prefix into a string of bits
  100. # representing the netmask
  101. #
  102. # prefix = IPAddress::Prefix32.new 24
  103. #
  104. # prefix.bits
  105. # #=> "11111111111111111111111100000000"
  106. #
  107. def bits
  108. "%.32b" % to_u32
  109. end
  110. #
  111. # Gives the prefix in IPv4 dotted decimal format,
  112. # i.e. the canonical netmask we're all used to
  113. #
  114. # prefix = IPAddress::Prefix32.new 24
  115. #
  116. # prefix.to_ip
  117. # #=> "255.255.255.0"
  118. #
  119. def to_ip
  120. [bits].pack("B*").unpack("CCCC").join(".")
  121. end
  122. #
  123. # An array of octets of the IPv4 dotted decimal
  124. # format
  125. #
  126. # prefix = IPAddress::Prefix32.new 24
  127. #
  128. # prefix.octets
  129. # #=> [255, 255, 255, 0]
  130. #
  131. def octets
  132. to_ip.split(".").map{|i| i.to_i}
  133. end
  134. #
  135. # Unsigned 32 bits decimal number representing
  136. # the prefix
  137. #
  138. # prefix = IPAddress::Prefix32.new 24
  139. #
  140. # prefix.to_u32
  141. # #=> 4294967040
  142. #
  143. def to_u32
  144. (IN4MASK >> host_prefix) << host_prefix
  145. end
  146. #
  147. # Shortcut for the octecs in the dotted decimal
  148. # representation
  149. #
  150. # prefix = IPAddress::Prefix32.new 24
  151. #
  152. # prefix[2]
  153. # #=> 255
  154. #
  155. def [](index)
  156. octets[index]
  157. end
  158. #
  159. # The hostmask is the contrary of the subnet mask,
  160. # as it shows the bits that can change within the
  161. # hosts
  162. #
  163. # prefix = IPAddress::Prefix32.new 24
  164. #
  165. # prefix.hostmask
  166. # #=> "0.0.0.255"
  167. #
  168. def hostmask
  169. [~to_u32].pack("N").unpack("CCCC").join(".")
  170. end
  171. #
  172. # Creates a new prefix by parsing a netmask in
  173. # dotted decimal form
  174. #
  175. # prefix = IPAddress::Prefix32::parse_netmask "255.255.255.0"
  176. # #=> 24
  177. #
  178. def self.parse_netmask(netmask)
  179. octets = netmask.split(".").map{|i| i.to_i}
  180. num = octets.pack("C"*octets.size).unpack("B*").first.count "1"
  181. return self.new(num)
  182. end
  183. end # class Prefix32 < Prefix
  184. class Prefix128 < Prefix
  185. #
  186. # Creates a new prefix object for 128 bits IPv6 addresses
  187. #
  188. # prefix = IPAddress::Prefix128.new 64
  189. # #=> 64
  190. #
  191. def initialize(num=128)
  192. unless (1..128).include? num.to_i
  193. raise ArgumentError, "Prefix must be in range 1..128, got: #{num}"
  194. end
  195. super(num.to_i)
  196. end
  197. #
  198. # Transforms the prefix into a string of bits
  199. # representing the netmask
  200. #
  201. # prefix = IPAddress::Prefix128.new 64
  202. #
  203. # prefix.bits
  204. # #=> "1111111111111111111111111111111111111111111111111111111111111111"
  205. # "0000000000000000000000000000000000000000000000000000000000000000"
  206. #
  207. def bits
  208. "1" * @prefix + "0" * (128 - @prefix)
  209. end
  210. #
  211. # Unsigned 128 bits decimal number representing
  212. # the prefix
  213. #
  214. # prefix = IPAddress::Prefix128.new 64
  215. #
  216. # prefix.to_u128
  217. # #=> 340282366920938463444927863358058659840
  218. #
  219. def to_u128
  220. bits.to_i(2)
  221. end
  222. #
  223. # Returns the length of the host portion
  224. # of a netmask.
  225. #
  226. # prefix = Prefix128.new 96
  227. #
  228. # prefix.host_prefix
  229. # #=> 32
  230. #
  231. def host_prefix
  232. 128 - @prefix
  233. end
  234. end # class Prefix123 < Prefix
  235. end # module IPAddress